aboutsummaryrefslogtreecommitdiff
path: root/gdb/compile
diff options
context:
space:
mode:
authorKeith Seitz <keiths@redhat.com>2018-08-29 15:12:24 -0700
committerKeith Seitz <keiths@redhat.com>2018-08-29 15:12:24 -0700
commit078a020797210f4d8f9491bbfe16ec31e9efb652 (patch)
tree278f541a2e88d33fcc3c4f782b5265a477abb540 /gdb/compile
parentfcaad03cc027ec2cdf7f2cff70d792867d43c57f (diff)
downloadgdb-078a020797210f4d8f9491bbfe16ec31e9efb652.zip
gdb-078a020797210f4d8f9491bbfe16ec31e9efb652.tar.gz
gdb-078a020797210f4d8f9491bbfe16ec31e9efb652.tar.bz2
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.
Diffstat (limited to 'gdb/compile')
-rw-r--r--gdb/compile/compile-c-support.c205
-rw-r--r--gdb/compile/compile-cplus-symbols.c493
-rw-r--r--gdb/compile/compile-cplus-types.c1427
-rw-r--r--gdb/compile/compile-cplus.h205
-rw-r--r--gdb/compile/compile-internal.h4
-rw-r--r--gdb/compile/compile-object-load.c7
-rw-r--r--gdb/compile/compile.c1
-rw-r--r--gdb/compile/gcc-cp-plugin.h85
8 files changed, 2399 insertions, 28 deletions
diff --git a/gdb/compile/compile-c-support.c b/gdb/compile/compile-c-support.c
index e8993aa..5c700bb 100644
--- a/gdb/compile/compile-c-support.c
+++ b/gdb/compile/compile-c-support.c
@@ -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);
+}
diff --git a/gdb/compile/compile-cplus-symbols.c b/gdb/compile/compile-cplus-symbols.c
new file mode 100644
index 0000000..0f849fe
--- /dev/null
+++ b/gdb/compile/compile-cplus-symbols.c
@@ -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;
+}
diff --git a/gdb/compile/compile-cplus-types.c b/gdb/compile/compile-cplus-types.c
new file mode 100644
index 0000000..9425fc6
--- /dev/null
+++ b/gdb/compile/compile-cplus-types.c
@@ -0,0 +1,1427 @@
+/* Convert types 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 "common/preprocessor.h"
+#include "gdbtypes.h"
+#include "compile-internal.h"
+#include "compile-cplus.h"
+#include "gdb_assert.h"
+#include "symtab.h"
+#include "source.h"
+#include "cp-support.h"
+#include "cp-abi.h"
+#include "symtab.h"
+#include "objfiles.h"
+#include "block.h"
+#include "gdbcmd.h"
+#include "c-lang.h"
+#include "compile-c.h" /* Included for c_get_range_decl_name
+ et al. */
+#include <algorithm>
+
+/* Default compile flags for C++. */
+
+const char *compile_cplus_instance::m_default_cflags = "-std=gnu++11";
+
+/* Flag to enable internal debugging. */
+
+static int debug_compile_cplus_types = 0;
+
+/* Flag to enable internal scope switching debugging. */
+
+static int debug_compile_cplus_scopes = 0;
+
+/* Forward declarations. */
+
+static gcc_type compile_cplus_convert_func (compile_cplus_instance *instance,
+ struct type *type,
+ bool strip_artificial);
+
+/* See description in compile-cplus.h. */
+
+gdb::unique_xmalloc_ptr<char>
+compile_cplus_instance::decl_name (const char *natural)
+{
+ if (natural == nullptr)
+ return nullptr;
+
+ char *name = cp_func_name (natural);
+ if (name != nullptr)
+ return gdb::unique_xmalloc_ptr<char> (name);
+
+ return gdb::unique_xmalloc_ptr<char> (xstrdup (natural));
+}
+
+/* Get the access flag for the NUM'th field of TYPE. */
+
+static enum gcc_cp_symbol_kind
+get_field_access_flag (const struct type *type, int num)
+{
+ if (TYPE_FIELD_PROTECTED (type, num))
+ return GCC_CP_ACCESS_PROTECTED;
+ else if (TYPE_FIELD_PRIVATE (type, num))
+ return GCC_CP_ACCESS_PRIVATE;
+
+ /* GDB assumes everything else is public. */
+ return GCC_CP_ACCESS_PUBLIC;
+}
+
+/* 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)
+{
+ gdb_assert (TYPE_CODE (type) == TYPE_CODE_STRUCT);
+
+ /* If this type was not declared a class, everything is public. */
+ if (!TYPE_DECLARED_CLASS (type))
+ return GCC_CP_ACCESS_PUBLIC;
+
+ /* Otherwise, read accessibility from the fn_field. */
+ const struct fn_field *methods = TYPE_FN_FIELDLIST1 (type, fni);
+ if (TYPE_FN_FIELD_PROTECTED (methods, num))
+ return GCC_CP_ACCESS_PROTECTED;
+ else if (TYPE_FN_FIELD_PRIVATE (methods, num))
+ return GCC_CP_ACCESS_PRIVATE;
+ else
+ return GCC_CP_ACCESS_PUBLIC;
+}
+
+/* A useful debugging function to output the scope SCOPE to stdout. */
+
+static void __attribute__ ((used))
+debug_print_scope (const compile_scope &scope)
+{
+ for (const auto &comp: scope)
+ {
+ const char *symbol = (comp.bsymbol.symbol != nullptr
+ ? SYMBOL_NATURAL_NAME (comp.bsymbol.symbol)
+ : "<none>");
+
+ printf_unfiltered ("\tname = %s, symbol = %s\n", comp.name.c_str (),
+ symbol);
+ }
+}
+
+/* See description in compile-cplus.h. */
+
+compile_scope
+type_name_to_scope (const char *type_name, const struct block *block)
+{
+ compile_scope scope;
+
+ if (type_name == nullptr)
+ {
+ /* An anonymous type. We cannot really do much here. We simply cannot
+ look up anonymous types easily/at all. */
+ return scope;
+ }
+
+ const char *p = type_name;
+ std::string lookup_name;
+
+ while (*p != '\0')
+ {
+ /* Create a string token of the first component of TYPE_NAME. */
+ int len = cp_find_first_component (p);
+ std::string s (p, len);
+
+ /* Advance past the last token. */
+ p += len;
+
+ /* Look up the symbol and decide when to stop. */
+ if (!lookup_name.empty ())
+ lookup_name += "::";
+ lookup_name += s;
+
+ /* Look up the resulting name. */
+ struct block_symbol bsymbol
+ = lookup_symbol (lookup_name.c_str (), block, VAR_DOMAIN, nullptr);
+
+ if (bsymbol.symbol != nullptr)
+ {
+ scope_component comp = {s, bsymbol};
+
+ scope.push_back (comp);
+
+ if (TYPE_CODE (SYMBOL_TYPE (bsymbol.symbol)) != TYPE_CODE_NAMESPACE)
+ {
+ /* We're done. */
+ break;
+ }
+ }
+
+ if (*p == ':')
+ {
+ ++p;
+ if (*p == ':')
+ ++p;
+ else
+ {
+ /* This shouldn't happen since we are not attempting to
+ loop over user input. This name is generated by GDB
+ from debug info. */
+ internal_error (__FILE__, __LINE__,
+ _("malformed TYPE_NAME during parsing"));
+ }
+ }
+ }
+
+ return scope;
+}
+
+/* Compare two scope_components for equality. These are equal if the names
+ of the two components' are the same. */
+
+bool
+operator== (const scope_component &lhs, const scope_component &rhs)
+{
+ return lhs.name == rhs.name;
+}
+
+/* Compare two scope_components for inequality. These are not equal if
+ the two components' names are not equal. */
+
+bool
+operator!= (const scope_component &lhs, const scope_component &rhs)
+{
+ return lhs.name != rhs.name;
+}
+
+/* Compare two compile_scopes for equality. These are equal if they are both
+ contain the same number of components and each component is equal. */
+
+bool
+operator== (const compile_scope &lhs, const compile_scope &rhs)
+{
+ if (lhs.size () != rhs.size ())
+ return false;
+
+ for (int i = 0; i < lhs.size (); ++i)
+ {
+ if (lhs[i] != rhs[i])
+ return false;
+ }
+
+ return true;
+}
+
+/* Compare two compile_scopes for inequality. These are inequal if they
+ contain unequal number of elements or if any of the components are not
+ the same. */
+
+bool
+operator!= (const compile_scope &lhs, const compile_scope &rhs)
+{
+ if (lhs.size () != rhs.size ())
+ return true;
+
+ for (int i = 0; i < lhs.size (); ++i)
+ {
+ if (lhs[i] != rhs[i])
+ return true;
+ }
+
+ return false;
+}
+
+/* See description in compile-cplus.h. */
+
+void
+compile_cplus_instance::enter_scope (compile_scope &new_scope)
+{
+ bool must_push = m_scopes.empty () || m_scopes.back () != new_scope;
+
+ new_scope.m_pushed = must_push;
+
+ /* Save the new scope. */
+ m_scopes.push_back (new_scope);
+
+ if (must_push)
+ {
+ if (debug_compile_cplus_scopes)
+ fprintf_unfiltered (gdb_stdlog, "entering new scope %p\n", new_scope);
+
+ /* Push the global namespace. */
+ plugin ().push_namespace ("");
+
+ /* Push all other namespaces. Note that we do not push the last
+ scope_component -- that's the actual type we are converting. */
+ std::for_each
+ (new_scope.begin (), new_scope.end () - 1,
+ [this] (const scope_component &comp)
+ {
+ gdb_assert (TYPE_CODE (SYMBOL_TYPE (comp.bsymbol.symbol))
+ == TYPE_CODE_NAMESPACE);
+
+ const char *ns = (comp.name == CP_ANONYMOUS_NAMESPACE_STR ? nullptr
+ : comp.name.c_str ());
+
+ this->plugin ().push_namespace (ns);
+ });
+ }
+ else
+ {
+ if (debug_compile_cplus_scopes)
+ {
+ fprintf_unfiltered (gdb_stdlog, "staying in current scope -- "
+ "scopes are identical\n");
+ }
+ }
+}
+
+/* See description in compile-cplus.h. */
+
+void
+compile_cplus_instance::leave_scope ()
+{
+ /* Get the current scope and remove it from the internal list of
+ scopes. */
+ compile_scope current = m_scopes.back ();
+
+ m_scopes.pop_back ();
+
+ if (current.m_pushed)
+ {
+ if (debug_compile_cplus_scopes)
+ fprintf_unfiltered (gdb_stdlog, "leaving scope %p\n", current);
+
+ /* Pop namespaces. */
+ std::for_each
+ (current.begin (),current.end () - 1,
+ [this] (const scope_component &comp) {
+ gdb_assert (TYPE_CODE (SYMBOL_TYPE (comp.bsymbol.symbol))
+ == TYPE_CODE_NAMESPACE);
+ this->plugin ().pop_binding_level (comp.name.c_str ());
+ });
+
+ /* Pop global namespace. */
+ plugin ().pop_binding_level ("");
+ }
+ else
+ {
+ if (debug_compile_cplus_scopes)
+ fprintf_unfiltered (gdb_stdlog,
+ "identical scopes -- not leaving scope\n");
+ }
+}
+
+/* See description in compile-cplus.h. */
+
+compile_scope
+compile_cplus_instance::new_scope (const char *type_name, struct type *type)
+{
+ /* Break the type name into components. If TYPE was defined in some
+ superclass, we do not process TYPE but process the enclosing type
+ instead. */
+ compile_scope scope = type_name_to_scope (type_name, block ());
+
+ if (!scope.empty ())
+ {
+ /* Get the name of the last component, which should be the
+ unqualified name of the type to process. */
+ scope_component &comp = scope.back ();
+
+ if (!types_equal (type, SYMBOL_TYPE (comp.bsymbol.symbol))
+ && (m_scopes.empty ()
+ || (m_scopes.back ().back ().bsymbol.symbol
+ != comp.bsymbol.symbol)))
+ {
+ /* The type is defined inside another class(es). Convert that
+ type instead of defining this type. */
+ convert_type (SYMBOL_TYPE (comp.bsymbol.symbol));
+
+ /* If the original type (passed in to us) is defined in a nested
+ class, the previous call will give us that type's gcc_type.
+ Upper layers are expecting to get the original type's
+ gcc_type! */
+ get_cached_type (type, scope.m_nested_type);
+ return scope;
+ }
+ }
+ else
+ {
+ if (TYPE_NAME (type) == nullptr)
+ {
+ /* Anonymous type */
+
+ /* We don't have a qualified name for this to look up, but
+ we need a scope. We have to assume, then, that it is the same
+ as the current scope, if any. */
+ if (!m_scopes.empty ())
+ {
+ scope = m_scopes.back ();
+ scope.m_pushed = false;
+ }
+ else
+ scope.push_back (scope_component ());
+ }
+ else
+ {
+ scope_component comp
+ = {
+ decl_name (TYPE_NAME (type)).get (),
+ lookup_symbol (TYPE_NAME (type), block (), VAR_DOMAIN, nullptr)
+ };
+ scope.push_back (comp);
+ }
+ }
+
+ /* There must be at least one component in the compile_scope. */
+ gdb_assert (scope.size () > 0);
+ return scope;
+}
+
+/* See description in compile-cplus.h. */
+
+gcc_type
+compile_cplus_instance::convert_reference_base
+ (gcc_type base, enum gcc_cp_ref_qualifiers rquals)
+{
+ return this->plugin ().build_reference_type (base, rquals);
+}
+
+/* Convert a reference type to its gcc representation. */
+
+static gcc_type
+compile_cplus_convert_reference (compile_cplus_instance *instance,
+ struct type *type)
+{
+ gcc_type target = instance->convert_type (TYPE_TARGET_TYPE (type));
+
+ enum gcc_cp_ref_qualifiers quals = GCC_CP_REF_QUAL_NONE;
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_REF:
+ quals = GCC_CP_REF_QUAL_LVALUE;
+ break;
+ case TYPE_CODE_RVALUE_REF:
+ quals = GCC_CP_REF_QUAL_RVALUE;
+ break;
+ default:
+ gdb_assert_not_reached ("unexpected type code for reference type");
+ }
+
+ return instance->convert_reference_base (target, quals);
+}
+
+/* See description in compile-cplus.h. */
+
+gcc_type
+compile_cplus_instance::convert_pointer_base(gcc_type target)
+{
+ return plugin ().build_pointer_type (target);
+}
+
+/* Convert a pointer type to its gcc representation. */
+
+static gcc_type
+compile_cplus_convert_pointer (compile_cplus_instance *instance,
+ struct type *type)
+{
+ gcc_type target = instance->convert_type (TYPE_TARGET_TYPE (type));
+
+ return instance->convert_pointer_base (target);
+}
+
+/* Convert an array type to its gcc representation. */
+
+static gcc_type
+compile_cplus_convert_array (compile_cplus_instance *instance,
+ struct type *type)
+{
+ struct type *range = TYPE_INDEX_TYPE (type);
+ gcc_type element_type = instance->convert_type (TYPE_TARGET_TYPE (type));
+
+ if (TYPE_LOW_BOUND_KIND (range) != PROP_CONST)
+ {
+ const char *s = _("array type with non-constant"
+ " lower bound is not supported");
+
+ return instance->plugin ().error (s);
+ }
+
+ if (TYPE_LOW_BOUND (range) != 0)
+ {
+ const char *s = _("cannot convert array type with "
+ "non-zero lower bound to C");
+
+ return instance->plugin ().error (s);
+ }
+
+ if (TYPE_HIGH_BOUND_KIND (range) == PROP_LOCEXPR
+ || TYPE_HIGH_BOUND_KIND (range) == PROP_LOCLIST)
+ {
+ if (TYPE_VECTOR (type))
+ {
+ const char *s = _("variably-sized vector type is not supported");
+
+ return instance->plugin ().error (s);
+ }
+
+ std::string upper_bound
+ = c_get_range_decl_name (&TYPE_RANGE_DATA (range)->high);
+ return instance->plugin ().build_vla_array_type (element_type,
+ upper_bound.c_str ());
+ }
+ else
+ {
+ LONGEST low_bound, high_bound, count;
+
+ if (get_array_bounds (type, &low_bound, &high_bound) == 0)
+ count = -1;
+ else
+ {
+ gdb_assert (low_bound == 0); /* Ensured above. */
+ count = high_bound + 1;
+ }
+
+ if (TYPE_VECTOR (type))
+ return instance->plugin ().build_vector_type (element_type, count);
+
+ return instance->plugin ().build_array_type (element_type, count);
+ }
+}
+
+/* Convert a typedef of TYPE. If not GCC_CP_ACCESS_NONE, NESTED_ACCESS
+ will define the accessibility of the typedef definition in its
+ containing class. */
+
+static gcc_type
+compile_cplus_convert_typedef (compile_cplus_instance *instance,
+ struct type *type,
+ enum gcc_cp_symbol_kind nested_access)
+{
+ compile_scope scope = instance->new_scope (TYPE_NAME (type), type);
+
+ if (scope.nested_type () != GCC_TYPE_NONE)
+ return scope.nested_type ();
+
+ gdb::unique_xmalloc_ptr<char> name
+ = compile_cplus_instance::decl_name (TYPE_NAME (type));
+
+ /* Make sure the scope for this type has been pushed. */
+ instance->enter_scope (scope);
+
+ /* Convert the typedef's real type. */
+ gcc_type typedef_type = instance->convert_type (check_typedef (type));
+
+ instance->plugin ().build_decl ("typedef", name.get (),
+ GCC_CP_SYMBOL_TYPEDEF | nested_access,
+ typedef_type, 0, 0, nullptr, 0);
+
+ /* Completed this scope. */
+ instance->leave_scope ();
+ return typedef_type;
+}
+
+/* Convert types defined in TYPE. */
+
+static void
+compile_cplus_convert_type_defns (compile_cplus_instance *instance,
+ struct type *type)
+{
+ int i;
+ enum gcc_cp_symbol_kind accessibility;
+
+ /* Convert typedefs. */
+ for (i = 0; i < TYPE_TYPEDEF_FIELD_COUNT (type); ++i)
+ {
+ if (TYPE_TYPEDEF_FIELD_PROTECTED (type, i))
+ accessibility = GCC_CP_ACCESS_PROTECTED;
+ else if (TYPE_TYPEDEF_FIELD_PRIVATE (type, i))
+ accessibility = GCC_CP_ACCESS_PRIVATE;
+ else
+ accessibility = GCC_CP_ACCESS_PUBLIC;
+ instance->convert_type (TYPE_TYPEDEF_FIELD_TYPE (type, i), accessibility);
+ }
+
+ /* Convert nested types. */
+ for (i = 0; i < TYPE_NESTED_TYPES_COUNT (type); ++i)
+ {
+ if (TYPE_NESTED_TYPES_FIELD_PROTECTED (type, i))
+ accessibility = GCC_CP_ACCESS_PROTECTED;
+ else if (TYPE_NESTED_TYPES_FIELD_PRIVATE (type, i))
+ accessibility = GCC_CP_ACCESS_PRIVATE;
+ else
+ accessibility = GCC_CP_ACCESS_PUBLIC;
+ instance->convert_type (TYPE_NESTED_TYPES_FIELD_TYPE (type, i),
+ accessibility);
+ }
+}
+
+/* Convert data members defined in TYPE, which should be struct/class/union
+ with gcc_type COMP_TYPE. */
+
+static void
+compile_cplus_convert_struct_or_union_members
+ (compile_cplus_instance *instance, struct type *type, gcc_type comp_type)
+{
+ for (int i = TYPE_N_BASECLASSES (type); i < TYPE_NFIELDS (type); ++i)
+ {
+ const char *field_name = TYPE_FIELD_NAME (type, i);
+
+ if (TYPE_FIELD_IGNORE (type, i)
+ || TYPE_FIELD_ARTIFICIAL (type, i))
+ continue;
+
+ /* GDB records unnamed/anonymous fields with empty string names. */
+ if (*field_name == '\0')
+ field_name = nullptr;
+
+ gcc_type field_type
+ = instance->convert_type (TYPE_FIELD_TYPE (type, i));
+
+ if (field_is_static (&TYPE_FIELD (type, i)))
+ {
+ CORE_ADDR physaddr;
+
+ switch (TYPE_FIELD_LOC_KIND (type, i))
+ {
+ case FIELD_LOC_KIND_PHYSADDR:
+ {
+ physaddr = TYPE_FIELD_STATIC_PHYSADDR (type, i);
+
+ instance->plugin ().build_decl
+ ("field physaddr", field_name,
+ (GCC_CP_SYMBOL_VARIABLE | get_field_access_flag (type, i)),
+ field_type, nullptr, physaddr, nullptr, 0);
+ }
+ break;
+
+ case FIELD_LOC_KIND_PHYSNAME:
+ {
+ const char *physname = TYPE_FIELD_STATIC_PHYSNAME (type, i);
+ struct block_symbol sym
+ = lookup_symbol (physname, instance->block (),
+ VAR_DOMAIN, nullptr);
+
+ if (sym.symbol == nullptr)
+ {
+ /* We didn't actually find the symbol. There's little
+ we can do but ignore this member. */
+ continue;
+ }
+ const char *filename = symbol_symtab (sym.symbol)->filename;
+ unsigned int line = SYMBOL_LINE (sym.symbol);
+
+ physaddr = SYMBOL_VALUE_ADDRESS (sym.symbol);
+ instance->plugin ().build_decl
+ ("field physname", field_name,
+ (GCC_CP_SYMBOL_VARIABLE| get_field_access_flag (type, i)),
+ field_type, nullptr, physaddr, filename, line);
+ }
+ break;
+
+ default:
+ gdb_assert_not_reached
+ ("unexpected static field location kind");
+ }
+ }
+ else
+ {
+ unsigned long bitsize = TYPE_FIELD_BITSIZE (type, i);
+ enum gcc_cp_symbol_kind field_flags = GCC_CP_SYMBOL_FIELD
+ | get_field_access_flag (type, i);
+
+ if (bitsize == 0)
+ bitsize = 8 * TYPE_LENGTH (TYPE_FIELD_TYPE (type, i));
+
+ instance->plugin ().build_field
+ (field_name, field_type, field_flags, bitsize,
+ TYPE_FIELD_BITPOS (type, i));
+ }
+ }
+}
+
+/* Convert a method type to its gcc representation. */
+
+static gcc_type
+compile_cplus_convert_method (compile_cplus_instance *instance,
+ struct type *parent_type,
+ struct type *method_type)
+{
+ /* Get the actual function type of the method, the corresponding class's
+ type and corresponding qualifier flags. */
+ gcc_type func_type = compile_cplus_convert_func (instance, method_type, true);
+ gcc_type class_type = instance->convert_type (parent_type);
+ gcc_cp_qualifiers_flags quals = (enum gcc_cp_qualifiers) 0;
+
+ if (TYPE_CONST (method_type))
+ quals |= GCC_CP_QUALIFIER_CONST;
+ if (TYPE_VOLATILE (method_type))
+ quals |= GCC_CP_QUALIFIER_VOLATILE;
+ if (TYPE_RESTRICT (method_type))
+ quals |= GCC_CP_QUALIFIER_RESTRICT;
+
+ /* Not yet implemented. */
+ gcc_cp_ref_qualifiers_flags rquals = GCC_CP_REF_QUAL_NONE;
+
+ return instance->plugin ().build_method_type
+ (class_type, func_type, quals, rquals);
+}
+
+/* Convert a member or method pointer represented by TYPE. */
+
+static gcc_type
+compile_cplus_convert_memberptr (compile_cplus_instance *instance,
+ struct type *type)
+{
+ struct type *containing_class = TYPE_SELF_TYPE (type);
+
+ if (containing_class == nullptr)
+ return GCC_TYPE_NONE;
+
+ gcc_type class_type = instance->convert_type (containing_class);
+ gcc_type member_type
+ = instance->convert_type (TYPE_TARGET_TYPE (type));
+
+ return instance->plugin ().build_pointer_to_member_type
+ (class_type, member_type);
+}
+
+/* Convert all methods defined in TYPE, which should be a class/struct/union
+ with gcc_type CLASS_TYPE. */
+
+static void
+compile_cplus_convert_struct_or_union_methods (compile_cplus_instance *instance,
+ struct type *type,
+ gcc_type class_type)
+{
+ for (int i = 0; i < TYPE_NFN_FIELDS (type); ++i)
+ {
+ struct fn_field *methods = TYPE_FN_FIELDLIST1 (type, i);
+ gdb::unique_xmalloc_ptr<char> overloaded_name
+ = compile_cplus_instance::decl_name (TYPE_FN_FIELDLIST_NAME (type, i));
+
+ /* Loop through the fieldlist, adding decls to the compiler's
+ representation of the class. */
+ for (int j = 0; j < TYPE_FN_FIELDLIST_LENGTH (type, i); ++j)
+ {
+ /* Skip artificial methods. */
+ if (TYPE_FN_FIELD_ARTIFICIAL (methods, j))
+ continue;
+
+ gcc_cp_symbol_kind_flags sym_kind = GCC_CP_SYMBOL_FUNCTION;
+ gcc_type method_type;
+ struct block_symbol sym
+ = lookup_symbol (TYPE_FN_FIELD_PHYSNAME (methods, j),
+ instance->block (), VAR_DOMAIN, nullptr);
+
+ if (sym.symbol == nullptr)
+ {
+ if (TYPE_FN_FIELD_VIRTUAL_P (methods, j))
+ {
+ /* This is beyond hacky, and is really only a workaround for
+ detecting pure virtual methods. */
+ method_type = compile_cplus_convert_method
+ (instance, type, TYPE_FN_FIELD_TYPE (methods, j));
+
+ instance->plugin ().build_decl
+ ("pure virtual method", overloaded_name.get (),
+ (sym_kind
+ | get_method_access_flag (type, i, j)
+ | GCC_CP_FLAG_VIRTUAL_FUNCTION
+ | GCC_CP_FLAG_PURE_VIRTUAL_FUNCTION),
+ method_type, nullptr, 0, nullptr, 0);
+ continue;
+ }
+
+ /* This can happen if we have a DW_AT_declaration DIE
+ for the method, but no "definition"-type DIE (with
+ DW_AT_specification referencing the decl DIE), i.e.,
+ the compiler has probably optimized the method away.
+
+ In this case, all we can hope to do is issue a warning
+ to the user letting him know. If the user has not actually
+ requested using this method, things should still work. */
+ warning (_("Method %s appears to be optimized out.\n"
+ "All references to this method will be undefined."),
+ TYPE_FN_FIELD_PHYSNAME (methods, j));
+ continue;
+ }
+
+ const char *filename = symbol_symtab (sym.symbol)->filename;
+ unsigned int line = SYMBOL_LINE (sym.symbol);
+ CORE_ADDR address = BLOCK_START (SYMBOL_BLOCK_VALUE (sym.symbol));
+ const char *kind;
+
+ if (TYPE_FN_FIELD_STATIC_P (methods, j))
+ {
+ kind = "static method";
+ method_type = compile_cplus_convert_func
+ (instance, TYPE_FN_FIELD_TYPE (methods, j), true);
+ }
+ else
+ {
+ kind = "method";
+ method_type = (compile_cplus_convert_method
+ (instance, type, TYPE_FN_FIELD_TYPE (methods, j)));
+ }
+
+ if (TYPE_FN_FIELD_VIRTUAL_P (methods, j))
+ sym_kind |= GCC_CP_FLAG_VIRTUAL_FUNCTION;
+
+ instance->plugin ().build_decl
+ (kind, overloaded_name.get (),
+ sym_kind | get_method_access_flag (type, i, j),
+ method_type, nullptr, address, filename, line);
+ }
+ }
+}
+
+/* Convert a struct or union type to its gcc representation. If this type
+ was defined in another type, NESTED_ACCESS should indicate the
+ accessibility of this type. */
+
+static gcc_type
+compile_cplus_convert_struct_or_union (compile_cplus_instance *instance,
+ struct type *type,
+ enum gcc_cp_symbol_kind nested_access)
+{
+ const char *filename = nullptr;
+ unsigned short line = 0;
+
+ /* Get the decl name of this type. */
+ gdb::unique_xmalloc_ptr<char> name
+ = compile_cplus_instance::decl_name (TYPE_NAME (type));
+
+ /* Create a new scope for TYPE. */
+ compile_scope scope = instance->new_scope (TYPE_NAME (type), type);
+
+ if (scope.nested_type () != GCC_TYPE_NONE)
+ {
+ /* The type requested was actually defined inside another type,
+ such as a nested class definition. Return that type. */
+ return scope.nested_type ();
+ }
+
+ /* Push all scopes. */
+ instance->enter_scope (scope);
+
+ /* First we create the resulting type and enter it into our hash
+ table. This lets recursive types work. */
+
+ gcc_decl resuld;
+ if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
+ {
+ const char *what = TYPE_DECLARED_CLASS (type) ? "struct" : "class";
+
+ resuld = instance->plugin ().build_decl
+ (what, name.get (), (GCC_CP_SYMBOL_CLASS | nested_access
+ | (TYPE_DECLARED_CLASS (type)
+ ? GCC_CP_FLAG_CLASS_NOFLAG
+ : GCC_CP_FLAG_CLASS_IS_STRUCT)),
+ 0, nullptr, 0, filename, line);
+ }
+ else
+ {
+ gdb_assert (TYPE_CODE (type) == TYPE_CODE_UNION);
+ resuld = instance->plugin ().build_decl
+ ("union", name.get (), GCC_CP_SYMBOL_UNION | nested_access,
+ 0, nullptr, 0, filename, line);
+ }
+
+ gcc_type result;
+ if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
+ {
+ struct gcc_vbase_array bases;
+ int num_baseclasses = TYPE_N_BASECLASSES (type);
+
+ memset (&bases, 0, sizeof (bases));
+
+ if (num_baseclasses > 0)
+ {
+ bases.elements = XNEWVEC (gcc_type, num_baseclasses);
+ bases.flags = XNEWVEC (enum gcc_cp_symbol_kind, num_baseclasses);
+ bases.n_elements = num_baseclasses;
+ for (int i = 0; i < num_baseclasses; ++i)
+ {
+ struct type *base_type = TYPE_BASECLASS (type, i);
+
+ bases.flags[i] = GCC_CP_SYMBOL_BASECLASS
+ | get_field_access_flag (type, i)
+ | (BASETYPE_VIA_VIRTUAL (type, i)
+ ? GCC_CP_FLAG_BASECLASS_VIRTUAL
+ : GCC_CP_FLAG_BASECLASS_NOFLAG);
+ bases.elements[i] = instance->convert_type (base_type);
+ }
+ }
+
+ result = instance->plugin ().start_class_type
+ (name.get (), resuld, &bases, filename, line);
+ xfree (bases.flags);
+ xfree (bases.elements);
+ }
+ else
+ {
+ gdb_assert (TYPE_CODE (type) == TYPE_CODE_UNION);
+ result = instance->plugin ().start_class_type
+ (name.get (), resuld, nullptr, filename, line);
+ }
+
+ instance->insert_type (type, result);
+
+ /* Add definitions. */
+ compile_cplus_convert_type_defns (instance, type);
+
+ /* Add methods. */
+ compile_cplus_convert_struct_or_union_methods (instance, type, result);
+
+ /* Add members. */
+ compile_cplus_convert_struct_or_union_members (instance, type, result);
+
+ /* All finished. */
+ instance->plugin ().finish_class_type (name.get (), TYPE_LENGTH (type));
+
+ /* Pop all scopes. */
+ instance->leave_scope ();
+ return result;
+}
+
+/* Convert an enum type to its gcc representation. If this type
+ was defined in another type, NESTED_ACCESS should indicate the
+ accessibility of this type.*/
+
+static gcc_type
+compile_cplus_convert_enum (compile_cplus_instance *instance, struct type *type,
+ enum gcc_cp_symbol_kind nested_access)
+{
+ int scoped_enum_p = FALSE;
+
+ /* Create a new scope for this type. */
+ compile_scope scope = instance->new_scope (TYPE_NAME (type), type);
+
+ if (scope.nested_type () != GCC_TYPE_NONE)
+ {
+ /* The type requested was actually defined inside another type,
+ such as a nested class definition. Return that type. */
+ return scope.nested_type ();
+ }
+
+ gdb::unique_xmalloc_ptr<char> name
+ = compile_cplus_instance::decl_name (TYPE_NAME (type));
+
+ /* Push all scopes. */
+ instance->enter_scope (scope);
+
+ gcc_type int_type
+ = instance->plugin ().get_int_type (TYPE_UNSIGNED (type),
+ TYPE_LENGTH (type), nullptr);
+ gcc_type result
+ = instance->plugin ().start_enum_type (name.get (), int_type,
+ GCC_CP_SYMBOL_ENUM | nested_access
+ | (scoped_enum_p
+ ? GCC_CP_FLAG_ENUM_SCOPED
+ : GCC_CP_FLAG_ENUM_NOFLAG),
+ nullptr, 0);
+ for (int i = 0; i < TYPE_NFIELDS (type); ++i)
+ {
+ gdb::unique_xmalloc_ptr<char> fname
+ = compile_cplus_instance::decl_name (TYPE_FIELD_NAME (type, i));
+
+ if (TYPE_FIELD_LOC_KIND (type, i) != FIELD_LOC_KIND_ENUMVAL
+ || fname == nullptr)
+ continue;
+
+ instance->plugin ().build_enum_constant (result, fname.get (),
+ TYPE_FIELD_ENUMVAL (type, i));
+ }
+
+ /* Finish enum definition and pop scopes. */
+ instance->plugin ().finish_enum_type (result);
+ instance->leave_scope ();
+ return result;
+}
+
+/* Convert a function type to its gcc representation. This function does
+ not deal with function templates. */
+
+static gcc_type
+compile_cplus_convert_func (compile_cplus_instance *instance,
+ struct type *type, bool strip_artificial)
+{
+ int is_varargs = TYPE_VARARGS (type);
+ struct type *target_type = TYPE_TARGET_TYPE (type);
+
+ /* Functions with no debug info have no return type. Ideally we'd
+ want to fallback to the type of the cast just before the
+ function, like GDB's built-in expression parser, but we don't
+ have access to that type here. For now, fallback to int, like
+ GDB's parser used to do. */
+ if (target_type == nullptr)
+ {
+ if (TYPE_OBJFILE_OWNED (type))
+ target_type = objfile_type (TYPE_OWNER (type).objfile)->builtin_int;
+ else
+ target_type = builtin_type (TYPE_OWNER (type).gdbarch)->builtin_int;
+ warning (_("function has unknown return type; assuming int"));
+ }
+
+ /* This approach means we can't make self-referential function
+ types. Those are impossible in C, though. */
+ gcc_type return_type = instance->convert_type (target_type);
+
+ struct gcc_type_array array =
+ { TYPE_NFIELDS (type), XNEWVEC (gcc_type, TYPE_NFIELDS (type)) };
+ int artificials = 0;
+ for (int i = 0; i < TYPE_NFIELDS (type); ++i)
+ {
+ if (strip_artificial && TYPE_FIELD_ARTIFICIAL (type, i))
+ {
+ --array.n_elements;
+ ++artificials;
+ }
+ else
+ {
+ array.elements[i - artificials]
+ = instance->convert_type (TYPE_FIELD_TYPE (type, i));
+ }
+ }
+
+ /* We omit setting the argument types to `void' to be a little flexible
+ with some minsyms like printf (compile-cplus.exp has examples). */
+ gcc_type result = instance->plugin ().build_function_type
+ (return_type, &array, is_varargs);
+ xfree (array.elements);
+ return result;
+}
+
+/* Convert an integer type to its gcc representation. */
+
+static gcc_type
+compile_cplus_convert_int (compile_cplus_instance *instance, struct type *type)
+{
+ if (TYPE_NOSIGN (type))
+ {
+ gdb_assert (TYPE_LENGTH (type) == 1);
+ return instance->plugin ().get_char_type ();
+ }
+
+ return instance->plugin ().get_int_type
+ (TYPE_UNSIGNED (type), TYPE_LENGTH (type), TYPE_NAME (type));
+}
+
+/* Convert a floating-point type to its gcc representation. */
+
+static gcc_type
+compile_cplus_convert_float (compile_cplus_instance *instance,
+ struct type *type)
+{
+ return instance->plugin ().get_float_type
+ (TYPE_LENGTH (type), TYPE_NAME (type));
+}
+
+/* Convert the 'void' type to its gcc representation. */
+
+static gcc_type
+compile_cplus_convert_void (compile_cplus_instance *instance, struct type *type)
+{
+ return instance->plugin ().get_void_type ();
+}
+
+/* Convert a boolean type to its gcc representation. */
+
+static gcc_type
+compile_cplus_convert_bool (compile_cplus_instance *instance, struct type *type)
+{
+ return instance->plugin ().get_bool_type ();
+}
+
+/* See description in compile-cplus.h. */
+
+gcc_type
+compile_cplus_instance::convert_qualified_base (gcc_type base,
+ gcc_cp_qualifiers_flags quals)
+{
+ gcc_type result = base;
+
+ if (quals != GCC_CP_REF_QUAL_NONE)
+ result = plugin ().build_qualified_type (base, quals);
+
+ return result;
+}
+
+/* See description in compile-cplus.h. */
+
+static gcc_type
+compile_cplus_convert_qualified (compile_cplus_instance *instance,
+ struct type *type)
+{
+ struct type *unqual = make_unqualified_type (type);
+ gcc_cp_qualifiers_flags quals = (enum gcc_cp_qualifiers) 0;
+ gcc_type unqual_converted = instance->convert_type (unqual);
+
+ if (TYPE_CONST (type))
+ quals |= GCC_CP_QUALIFIER_CONST;
+ if (TYPE_VOLATILE (type))
+ quals |= GCC_CP_QUALIFIER_VOLATILE;
+ if (TYPE_RESTRICT (type))
+ quals |= GCC_CP_QUALIFIER_RESTRICT;
+
+ return instance->convert_qualified_base (unqual_converted, quals);
+}
+
+/* Convert a complex type to its gcc representation. */
+
+static gcc_type
+compile_cplus_convert_complex (compile_cplus_instance *instance,
+ struct type *type)
+{
+ gcc_type base = instance->convert_type (TYPE_TARGET_TYPE (type));
+
+ return instance->plugin ().build_complex_type (base);
+}
+
+/* Convert a namespace of TYPE. */
+
+static gcc_type
+compile_cplus_convert_namespace (compile_cplus_instance *instance,
+ struct type *type)
+{
+ compile_scope scope = instance->new_scope (TYPE_NAME (type), type);
+ gdb::unique_xmalloc_ptr<char> name
+ = compile_cplus_instance::decl_name (TYPE_NAME (type));
+
+ /* Push scope. */
+ instance->enter_scope (scope);
+
+ /* Convert this namespace. */
+ instance->plugin ().push_namespace (name.get ());
+ instance->plugin ().pop_binding_level (name.get ());
+
+ /* Pop scope. */
+ instance->leave_scope ();
+
+ /* Namespaces are non-cacheable types. */
+ return GCC_TYPE_NONE;
+}
+
+/* A helper function which knows how to convert most types from their
+ gdb representation to the corresponding gcc form. This examines
+ the TYPE and dispatches to the appropriate conversion function. It
+ returns the gcc type.
+
+ If the type was defined in another type, NESTED_ACCESS should indicate the
+ accessibility of this type. */
+
+static gcc_type
+convert_type_cplus_basic (compile_cplus_instance *instance,
+ struct type *type,
+ enum gcc_cp_symbol_kind nested_access)
+{
+ /* If we are converting a qualified type, first convert the
+ unqualified type and then apply the qualifiers. */
+ if ((TYPE_INSTANCE_FLAGS (type) & (TYPE_INSTANCE_FLAG_CONST
+ | TYPE_INSTANCE_FLAG_VOLATILE
+ | TYPE_INSTANCE_FLAG_RESTRICT)) != 0)
+ return compile_cplus_convert_qualified (instance, type);
+
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_REF:
+ case TYPE_CODE_RVALUE_REF:
+ return compile_cplus_convert_reference (instance, type);
+
+ case TYPE_CODE_PTR:
+ return compile_cplus_convert_pointer (instance, type);
+
+ case TYPE_CODE_ARRAY:
+ return compile_cplus_convert_array (instance, type);
+
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ return
+ compile_cplus_convert_struct_or_union (instance, type, nested_access);
+
+ case TYPE_CODE_ENUM:
+ return compile_cplus_convert_enum (instance, type, nested_access);
+
+ case TYPE_CODE_FUNC:
+ return compile_cplus_convert_func (instance, type, false);
+
+ case TYPE_CODE_METHOD:
+ return
+ compile_cplus_convert_method (instance, TYPE_SELF_TYPE (type), type);
+
+ case TYPE_CODE_MEMBERPTR:
+ case TYPE_CODE_METHODPTR:
+ return compile_cplus_convert_memberptr (instance, type);
+ break;
+
+ case TYPE_CODE_INT:
+ return compile_cplus_convert_int (instance, type);
+
+ case TYPE_CODE_FLT:
+ return compile_cplus_convert_float (instance, type);
+
+ case TYPE_CODE_VOID:
+ return compile_cplus_convert_void (instance, type);
+
+ case TYPE_CODE_BOOL:
+ return compile_cplus_convert_bool (instance, type);
+
+ case TYPE_CODE_COMPLEX:
+ return compile_cplus_convert_complex (instance, type);
+
+ case TYPE_CODE_NAMESPACE:
+ return compile_cplus_convert_namespace (instance, type);
+
+ case TYPE_CODE_TYPEDEF:
+ return compile_cplus_convert_typedef (instance, type, nested_access);
+
+ default:
+ break;
+ }
+
+ std::string s = string_printf (_("unhandled TYPE_CODE %d"),
+ TYPE_CODE (type));
+
+ return instance->plugin ().error (s.c_str ());
+}
+
+gcc_type
+compile_cplus_instance::convert_type (struct type *type,
+ enum gcc_cp_symbol_kind nested_access)
+{
+ /* Check if TYPE has already been converted. */
+ gcc_type result;
+ if (get_cached_type (type, result))
+ return result;
+
+ /* It is the first time this type has been seen -- convert it
+ and cache it, if appropriate.. */
+ result = convert_type_cplus_basic (this, type, nested_access);
+ if (result != GCC_TYPE_NONE)
+ insert_type (type, result);
+ return result;
+}
+
+void
+compile_cplus_instance::gcc_cplus_enter_scope
+ (void *datum, struct gcc_cp_context *gcc_context)
+{
+}
+
+void
+compile_cplus_instance::gcc_cplus_leave_scope
+ (void *datum, struct gcc_cp_context *gcc_context)
+{
+}
+
+
+
+/* Plug-in forwards. */
+
+/* C++ plug-in wrapper. */
+
+/* A result printer for plug-in calls that return a gcc_type or
+ gcc_decl. */
+
+static void
+compile_cplus_debug_output_1 (gcc_type arg)
+{
+ fprintf_unfiltered (gdb_stdlog, "%lld", arg);
+}
+
+static void
+compile_cplus_debug_output_1 (const char *arg)
+{
+ if (arg == nullptr)
+ fputs_unfiltered ("NULL", gdb_stdlog);
+ else
+ fputs_unfiltered (arg, gdb_stdlog);
+}
+
+static void
+compile_cplus_debug_output ()
+{
+}
+
+template <typename T>
+static void
+compile_cplus_debug_output_1 (const T *arg)
+{
+}
+
+template <typename T, typename... Targs>
+static void
+compile_cplus_debug_output (T arg, Targs... Args)
+{
+ compile_cplus_debug_output_1 (arg);
+ fputc_unfiltered (' ', gdb_stdlog);
+ compile_cplus_debug_output (Args...);
+}
+
+#define FORWARD(OP,...) m_context->cp_ops->OP(m_context, ##__VA_ARGS__)
+#define OUTPUT_DEBUG_RESULT(R) \
+ if (debug_compile_cplus_types) \
+ { \
+ fputs_unfiltered (": ", gdb_stdlog); \
+ compile_cplus_debug_output (R); \
+ fputc_unfiltered ('\n', gdb_stdlog); \
+ } \
+
+#define GCC_METHOD0(R, N) \
+ R gcc_cp_plugin::N () const \
+ { \
+ if (debug_compile_cplus_types) \
+ compile_cplus_debug_output (STRINGIFY (N)); \
+ auto result = FORWARD (N); \
+ OUTPUT_DEBUG_RESULT (result); \
+ return result; \
+ }
+#define GCC_METHOD1(R, N, A) \
+ R gcc_cp_plugin::N (A a) const \
+ { \
+ if (debug_compile_cplus_types) \
+ compile_cplus_debug_output (STRINGIFY (N), a); \
+ auto result = FORWARD (N, a); \
+ OUTPUT_DEBUG_RESULT (result); \
+ return result; \
+ }
+#define GCC_METHOD2(R, N, A, B) \
+ R gcc_cp_plugin::N (A a, B b) const \
+ { \
+ if (debug_compile_cplus_types) \
+ compile_cplus_debug_output (STRINGIFY (N), a, b); \
+ auto result = FORWARD (N, a, b); \
+ OUTPUT_DEBUG_RESULT (result); \
+ return result; \
+ }
+#define GCC_METHOD3(R, N, A, B, C) \
+ R gcc_cp_plugin::N (A a, B b, C c) const \
+ { \
+ if (debug_compile_cplus_types) \
+ compile_cplus_debug_output (STRINGIFY (N), a, b, c); \
+ auto result = FORWARD (N, a, b, c); \
+ OUTPUT_DEBUG_RESULT (result); \
+ return result; \
+ }
+#define GCC_METHOD4(R, N, A, B, C, D) \
+ R gcc_cp_plugin::N (A a, B b, C c, D d) const \
+ { \
+ if (debug_compile_cplus_types) \
+ compile_cplus_debug_output (STRINGIFY (N), a, b, c, d); \
+ auto result = FORWARD (N, a, b, c, d); \
+ OUTPUT_DEBUG_RESULT (result); \
+ return result; \
+ }
+#define GCC_METHOD5(R, N, A, B, C, D, E) \
+ R gcc_cp_plugin::N (A a, B b, C c, D d, E e) const \
+ { \
+ if (debug_compile_cplus_types) \
+ compile_cplus_debug_output (STRINGIFY (N), a, b, c, d, e); \
+ auto result = FORWARD (N, a, b, c, d, e); \
+ OUTPUT_DEBUG_RESULT (result); \
+ return result; \
+ }
+#define GCC_METHOD7(R, N, A, B, C, D, E, F, G) \
+ R gcc_cp_plugin::N (A a, B b, C c, D d, E e, F f, G g) const \
+ { \
+ if (debug_compile_cplus_types) \
+ compile_cplus_debug_output (STRINGIFY (N), a, b, c, d, e, f, g); \
+ auto result = FORWARD (N, a, b, c, d, e, f, g); \
+ OUTPUT_DEBUG_RESULT (result); \
+ return result; \
+ }
+
+#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
+#undef FORWARD
+#undef OUTPUT_DEBUG_RESULT
+
+gcc_expr
+gcc_cp_plugin::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)
+{
+ if (debug_compile_cplus_types)
+ fprintf_unfiltered (gdb_stdlog, "<%s> ", debug_decltype);
+
+ return build_decl (name, sym_kind, sym_type, substitution_name,
+ address, filename, line_number);
+}
+
+gcc_type
+gcc_cp_plugin::start_class_type (const char *debug_name, gcc_decl typedecl,
+ const struct gcc_vbase_array *base_classes,
+ const char *filename, unsigned int line_number)
+{
+ if (debug_compile_cplus_types)
+ fprintf_unfiltered (gdb_stdlog, "<%s> ", debug_name);
+
+ return start_class_type (typedecl, base_classes, filename, line_number);
+}
+
+int
+gcc_cp_plugin::finish_class_type (const char *debug_name,
+ unsigned long size_in_bytes)
+{
+ if (debug_compile_cplus_types)
+ fprintf_unfiltered (gdb_stdlog, "<%s> ", debug_name);
+
+ return finish_class_type (size_in_bytes);
+}
+
+int
+gcc_cp_plugin::pop_binding_level (const char *debug_name)
+{
+ if (debug_compile_cplus_types)
+ fprintf_unfiltered (gdb_stdlog, "<%s> ", debug_name);
+
+ return pop_binding_level ();
+}
+
+void
+_initialize_compile_cplus_types ()
+{
+ add_setshow_boolean_cmd ("compile-cplus-types", no_class,
+ &debug_compile_cplus_types, _("\
+Set debugging of C++ compile type conversion."), _("\
+Show debugging of C++ compile type conversion."), _("\
+When enabled debugging messages are printed during C++ type conversion for\n\
+the compile commands."),
+ nullptr,
+ nullptr,
+ &setdebuglist,
+ &showdebuglist);
+
+ add_setshow_boolean_cmd ("compile-cplus-scopes", no_class,
+ &debug_compile_cplus_scopes, _("\
+Set debugging of C++ compile scopes."), _("\
+Show debugging of C++ compile scopes."), _("\
+When enabled debugging messages are printed about definition scopes during\n\
+C++ type conversion for the compile commands."),
+ nullptr,
+ nullptr,
+ &setdebuglist,
+ &showdebuglist);
+}
diff --git a/gdb/compile/compile-cplus.h b/gdb/compile/compile-cplus.h
new file mode 100644
index 0000000..7baa57d
--- /dev/null
+++ b/gdb/compile/compile-cplus.h
@@ -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 */
diff --git a/gdb/compile/compile-internal.h b/gdb/compile/compile-internal.h
index c8d2d2f..a6e7330 100644
--- a/gdb/compile/compile-internal.h
+++ b/gdb/compile/compile-internal.h
@@ -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. */
diff --git a/gdb/compile/compile-object-load.c b/gdb/compile/compile-object-load.c
index a83f95d..873750b 100644
--- a/gdb/compile/compile-object-load.c
+++ b/gdb/compile/compile-object-load.c
@@ -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,
diff --git a/gdb/compile/compile.c b/gdb/compile/compile.c
index 20d81cb..6d51006 100644
--- a/gdb/compile/compile.c
+++ b/gdb/compile/compile.c
@@ -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. */
diff --git a/gdb/compile/gcc-cp-plugin.h b/gdb/compile/gcc-cp-plugin.h
new file mode 100644
index 0000000..1b72726
--- /dev/null
+++ b/gdb/compile/gcc-cp-plugin.h
@@ -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;
+};