This is the mail archive of the
gdb-cvs@sourceware.org
mailing list for the GDB project.
[binutils-gdb] C++ compile support
- From: Keith Seitz <kseitz at sourceware dot org>
- To: gdb-cvs at sourceware dot org
- Date: 29 Aug 2018 22:28:59 -0000
- Subject: [binutils-gdb] C++ compile support
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=078a020797210f4d8f9491bbfe16ec31e9efb652
commit 078a020797210f4d8f9491bbfe16ec31e9efb652
Author: Keith Seitz <keiths@redhat.com>
Date: Wed Aug 29 15:12:24 2018 -0700
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.
Diff:
---
gdb/ChangeLog | 29 +
gdb/Makefile.in | 4 +
gdb/NEWS | 14 +
gdb/c-lang.c | 4 +-
gdb/c-lang.h | 19 +
gdb/compile/compile-c-support.c | 205 ++-
gdb/compile/compile-cplus-symbols.c | 493 +++++++
gdb/compile/compile-cplus-types.c | 1427 ++++++++++++++++++++
gdb/compile/compile-cplus.h | 205 +++
gdb/compile/compile-internal.h | 4 +
gdb/compile/compile-object-load.c | 7 +-
gdb/compile/compile.c | 1 -
gdb/compile/gcc-cp-plugin.h | 85 ++
gdb/doc/ChangeLog | 5 +
gdb/doc/gdb.texinfo | 10 +
gdb/testsuite/ChangeLog | 25 +
.../gdb.compile/compile-cplus-anonymous.cc | 76 ++
.../gdb.compile/compile-cplus-anonymous.exp | 64 +
.../gdb.compile/compile-cplus-array-decay.cc | 31 +
.../gdb.compile/compile-cplus-array-decay.exp | 50 +
gdb/testsuite/gdb.compile/compile-cplus-inherit.cc | 58 +
.../gdb.compile/compile-cplus-inherit.exp | 53 +
gdb/testsuite/gdb.compile/compile-cplus-member.cc | 83 ++
gdb/testsuite/gdb.compile/compile-cplus-member.exp | 76 ++
gdb/testsuite/gdb.compile/compile-cplus-method.cc | 91 ++
gdb/testsuite/gdb.compile/compile-cplus-method.exp | 67 +
gdb/testsuite/gdb.compile/compile-cplus-mod.c | 28 +
.../gdb.compile/compile-cplus-namespace.cc | 52 +
.../gdb.compile/compile-cplus-namespace.exp | 51 +
gdb/testsuite/gdb.compile/compile-cplus-nested.cc | 58 +
gdb/testsuite/gdb.compile/compile-cplus-nested.exp | 53 +
gdb/testsuite/gdb.compile/compile-cplus-print.c | 32 +
gdb/testsuite/gdb.compile/compile-cplus-print.exp | 79 ++
gdb/testsuite/gdb.compile/compile-cplus-virtual.cc | 54 +
.../gdb.compile/compile-cplus-virtual.exp | 71 +
gdb/testsuite/gdb.compile/compile-cplus.c | 241 ++++
gdb/testsuite/gdb.compile/compile-cplus.exp | 347 +++++
gdb/testsuite/lib/compile-support.exp | 227 ++++
38 files changed, 4449 insertions(+), 30 deletions(-)
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index d82257e..43e22e2 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,34 @@
2018-08-29 Keith Seitz <keiths@redhat.com>
+ * 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.
+
+2018-08-29 Keith Seitz <keiths@redhat.com>
+
* linespec.c (collect_info::add_symbol): Make virtual.
(struct symbol_searcher_collect_info): New struct.
(symbol_searcher::find_all_symbols): New method.
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 542170f..438379e 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -317,6 +317,8 @@ SUBDIR_GCC_COMPILE_SRCS = \
compile/compile-c-support.c \
compile/compile-c-symbols.c \
compile/compile-c-types.c \
+ compile/compile-cplus-symbols.c \
+ compile/compile-cplus-types.c \
compile/compile-loc2c.c \
compile/compile-object-load.c \
compile/compile-object-run.c
@@ -1464,10 +1466,12 @@ HFILES_NO_SRCDIR = \
common/xml-utils.h \
compile/compile.h \
compile/compile-c.h \
+ compile/compile-cplus.h \
compile/compile-internal.h \
compile/compile-object-load.h \
compile/compile-object-run.h \
compile/gcc-c-plugin.h \
+ compile/gcc-cp-plugin.h \
config/nm-linux.h \
config/nm-nto.h \
config/djgpp/langinfo.h \
diff --git a/gdb/NEWS b/gdb/NEWS
index 0ad8ae5..75436b0 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,14 @@
*** Changes since GDB 8.2
+* GDB now has experimental support for the compilation and injection of
+ C++ source code into the inferior. This beta release does not include
+ support for several language features, such as templates, constructors,
+ and operators.
+
+ This feature requires GCC 7.1 or higher built with libcp1.so
+ (the C++ plug-in).
+
* GDB and GDBserver now support IPv6 connections. IPv6 addresses
can be passed using the '[ADDRESS]:PORT' notation, or the regular
'ADDRESS:PORT' method.
@@ -15,6 +23,12 @@
* New commands
+set debug compile-cplus-types
+show debug compile-cplus-types
+ Control the display of debug output about type conversion in the
+ C++ compile feature. Commands have no effect while compiliong
+ for other languages.
+
frame apply [all | COUNT | -COUNT | level LEVEL...] [FLAG]... COMMAND
Apply a command to some frames.
FLAG arguments allow to control what output to produce and how to handle
diff --git a/gdb/c-lang.c b/gdb/c-lang.c
index 5ad5801..6bae4c1 100644
--- a/gdb/c-lang.c
+++ b/gdb/c-lang.c
@@ -1017,8 +1017,8 @@ extern const struct language_defn cplus_language_defn =
iterate_over_symbols,
cp_search_name_hash,
&cplus_varobj_ops,
- NULL,
- NULL,
+ cplus_get_compile_context,
+ cplus_compute_program,
LANG_MAGIC
};
diff --git a/gdb/c-lang.h b/gdb/c-lang.h
index b7bf089..ae17abd 100644
--- a/gdb/c-lang.h
+++ b/gdb/c-lang.h
@@ -160,6 +160,14 @@ extern int c_textual_element_type (struct type *, char);
extern compile_instance *c_get_compile_context (void);
+/* Create a new instance of the C++ compiler and return it. The new
+ compiler is owned by the caller and must be freed using the destroy
+ method. This function never returns NULL, but rather throws an
+ exception on failure. This is suitable for use as the
+ la_get_compile_instance language method. */
+
+extern compile_instance *cplus_get_compile_context ();
+
/* This takes the user-supplied text and returns a new bit of code to
compile.
@@ -172,4 +180,15 @@ extern std::string c_compute_program (compile_instance *inst,
const struct block *expr_block,
CORE_ADDR expr_pc);
+/* This takes the user-supplied text and returns a new bit of code to compile.
+
+ This is used as the la_compute_program language method; see that
+ for a description of the arguments. */
+
+extern std::string cplus_compute_program (compile_instance *inst,
+ const char *input,
+ struct gdbarch *gdbarch,
+ const struct block *expr_block,
+ CORE_ADDR expr_pc);
+
#endif /* !defined (C_LANG_H) */
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;
+};
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index c637d39..58e01e4 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,3 +1,8 @@
+2018-08-29 Keith Seitz <keiths@redhat.com>
+
+ * gdb.texinfo (Compiling and injecting code in GDB): Document
+ set/show "compile-oracle" and "compile-cplus-types" commands.
+
2018-08-22 Jan Vrany <jan.vrany@fit.cvut.cz>
* gdb.texinfo (The -stack-list-frames Command): Update description
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 5068c0a..f2d1155 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -18689,6 +18689,16 @@ injecting the code. The default is off.
@item show debug compile
Displays the current state of displaying @value{GDBN} process of
compiling and injecting the code.
+
+@anchor{set debug compile-cplus-types}
+@item set debug compile-cplus-types
+@cindex compile C@t{++} type conversion
+Turns on or off the display of C@t{++} type conversion debugging information.
+The default is off.
+
+@item show debug compile-cplus-types
+Displays the current state of displaying debugging information for
+C@t{++} type conversion.
@end table
@subsection Compilation options for the @code{compile} command
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 5145fd6..0164558 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,28 @@
+2018-08-29 Keith Seitz <keiths@redhat.com>
+
+ * 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.
+
2018-08-16 Gary Benson <gbenson@redhat.com>
PR gdb/13000:
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-anonymous.cc b/gdb/testsuite/gdb.compile/compile-cplus-anonymous.cc
new file mode 100644
index 0000000..95c4430
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-anonymous.cc
@@ -0,0 +1,76 @@
+/* Copyright 2015-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/>. */
+
+namespace {
+ static enum {ABC = 1, DEF, GHI, JKL} anon_e = GHI;
+ static union
+ {
+ char aa;
+ int bb;
+ float ff;
+ double dd;
+ void *pp;
+ } anon_u = { 'a' };
+
+ static struct
+ {
+ char *ptr;
+ int len;
+ struct
+ {
+ unsigned MAGIC;
+ };
+ union
+ {
+ int ua;
+ char *ub;
+ };
+ } anon_s = {"abracadabra", 11, 0xdead, 0xbeef};
+
+ struct A
+ {
+ A () : e (AA)
+ {
+ this->u.b = 0;
+ this->s.ptr = "hello";
+ this->s.len = 5;
+ }
+
+ enum {AA = 10, BB, CC, DD} e;
+ union
+ {
+ char a;
+ int b;
+ float f;
+ double d;
+ void *p;
+ } u;
+ struct
+ {
+ char *ptr;
+ int len;
+ } s;
+ };
+};
+
+int
+main ()
+{
+ A a;
+ int var = 1234;
+
+ return a.u.b + a.s.len + static_cast<int> (a.e)
+ + static_cast<int> (anon_e) + anon_u.bb + anon_s.len; // break here
+}
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-anonymous.exp b/gdb/testsuite/gdb.compile/compile-cplus-anonymous.exp
new file mode 100644
index 0000000..ebfb941
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-anonymous.exp
@@ -0,0 +1,64 @@
+# Copyright 2015-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/>.
+
+# Anonymous type conversion tests for GDB's C++ compile feature.
+
+load_lib compile-support.exp
+
+standard_testfile .cc
+
+if {[skip_cplus_tests]} {
+ untested "skipping C++ tests"
+ return
+}
+
+if {[prepare_for_testing $testfile $testfile $srcfile \
+ {debug nowarnings c++}]} {
+ return -1
+}
+
+if {![runto_main]} {
+ untested "could not run to main"
+ return -1
+}
+
+if {[skip_compile_feature_tests]} {
+ untested \
+ "compile command not supported (could not find libcc1 shared library?)"
+ return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "break here" $srcfile]
+gdb_continue_to_breakpoint "testing location"
+
+# Reminder, "var" is an integer; all these types get converted to `int'.
+CompileExpression::new "var"
+CompileExpression::test "anon_e" {(3|GHI)}
+CompileExpression::test "anon_u.aa" {97( 'a')?}
+CompileExpression::test "a.u.b" 0
+CompileExpression::test "a.s.len" 5
+CompileExpression::test "a.e" {(10|A::AA)}
+CompileExpression::test "(*a.s.ptr != 'h')" (0|false)
+CompileExpression::test "A::BB" {(11|A::BB)}
+CompileExpression::test "ABC" {(1|ABC)}
+CompileExpression::test "DEF" {(2|DEF)}
+CompileExpression::test "GHI" {(3|GHI)}
+CompileExpression::test "JKL" {(4|JKL)}
+
+set k "compile/23588 *-*-*"
+CompileExpression::test "anon_s.len" 11 -kfail $k
+CompileExpression::test "anon_s.MAGIC" "57005" -kfail $k
+CompileExpression::test "anon_s.ua" "48879" -kfail $k
+CompileExpression::test "(*anon_s.ptr == 'a')" (1|true) -kfail $k
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-array-decay.cc b/gdb/testsuite/gdb.compile/compile-cplus-array-decay.cc
new file mode 100644
index 0000000..da51a65
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-array-decay.cc
@@ -0,0 +1,31 @@
+/* Copyright 2017-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/>. */
+
+static const char *g_string_initializer = "hello";
+
+int
+main ()
+{
+ int integers[10];
+ const char *strings[10];
+
+ for (auto &i : integers)
+ i = 0;
+
+ for (auto &i : strings)
+ i = g_string_initializer;
+
+ return 0; // break here
+}
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-array-decay.exp b/gdb/testsuite/gdb.compile/compile-cplus-array-decay.exp
new file mode 100644
index 0000000..fb3e63f
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-array-decay.exp
@@ -0,0 +1,50 @@
+# Copyright 2017-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/>.
+
+# Test whether GDB's C++ compile feature is decaying arrays into pointers.
+
+load_lib compile-support.exp
+
+standard_testfile .cc
+
+if {[skip_cplus_tests]} {
+ untested "skipping C++ tests"
+ return
+}
+
+if {[prepare_for_testing $testfile $testfile $srcfile \
+ {debug nowarnings c++}]} {
+ return -1
+}
+
+if {![runto_main]} {
+ untested "could not run to main"
+ return -1
+}
+
+if {[skip_compile_feature_tests]} {
+ untested \
+ "compile command not supported (could not find libcc1 shared library?)"
+ return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "break here" $srcfile]
+gdb_continue_to_breakpoint "testing location"
+
+gdb_test "compile print integers" " = \\{0, 0, 0, 0, 0, 0, 0, 0, 0, 0\\}"
+
+gdb_test "compile print strings" " = \\{$hex \"hello\", $hex \"hello\",\
+ $hex \"hello\", $hex \"hello\", $hex \"hello\", $hex \"hello\",\
+ $hex \"hello\", $hex \"hello\", $hex \"hello\", $hex \"hello\"\\}"
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-inherit.cc b/gdb/testsuite/gdb.compile/compile-cplus-inherit.cc
new file mode 100644
index 0000000..1d93f9c
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-inherit.cc
@@ -0,0 +1,58 @@
+/* Copyright 2015-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/>. */
+
+struct A
+{
+ A () : a_ (1) {}
+ int do_it (int amount) { return a_ + amount; }
+
+ int a_;
+};
+
+struct B
+{
+ B () : b_ (2) {}
+ int do_it (int amount) { return b_ - amount; }
+
+ int b_;
+};
+
+struct C
+{
+ C () : c_ (3) {}
+ int do_it (int amount) { return c_ * amount; }
+
+ int c_;
+};
+
+struct D : public A, B, C
+{
+ D () : d_ (4) {}
+
+ int d_;
+};
+
+int
+main ()
+{
+ D d;
+ int var = 1234;
+
+ var = d.A::do_it (1)
+ + d.B::do_it (2)
+ + d.C::do_it (3); // break here
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-inherit.exp b/gdb/testsuite/gdb.compile/compile-cplus-inherit.exp
new file mode 100644
index 0000000..1978cb5
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-inherit.exp
@@ -0,0 +1,53 @@
+# Copyright 2015-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/>.
+
+# Inheritance tests for GDB's C++ compile feature.
+
+load_lib compile-support.exp
+
+standard_testfile .cc
+
+if {[skip_cplus_tests]} {
+ untested "skipping C++ tests"
+ return
+}
+
+if {[prepare_for_testing $testfile $testfile $srcfile \
+ {debug nowarnings c++}]} {
+ return -1
+}
+
+if {![runto_main]} {
+ untested "could not run to main"
+ return -1
+}
+
+if {[skip_compile_feature_tests]} {
+ untested \
+ "compile command not supported (could not find libcc1 shared library?)"
+ return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "break here" $srcfile]
+gdb_continue_to_breakpoint "testing location"
+
+CompileExpression::new "var"
+CompileExpression::test "d.a_" 1
+CompileExpression::test "d.b_" 2
+CompileExpression::test "d.c_" 3
+CompileExpression::test "d.d_" 4
+CompileExpression::test "d.A::do_it (1)" 2
+CompileExpression::test "d.B::do_it (1)" 1
+CompileExpression::test "d.C::do_it (1)" 3
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-member.cc b/gdb/testsuite/gdb.compile/compile-cplus-member.cc
new file mode 100644
index 0000000..d742318
--- /dev/null
+++ b/gdb/testsuite/gdb.compile/compile-cplus-member.cc
@@ -0,0 +1,83 @@
+/* Copyright 2015-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/>. */
+
+class A;
+static int get_values (const A& a);
+
[...]
[diff truncated at 100000 bytes]