mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-12-27 09:38:57 +00:00
C++ compile support
This patch adds *basic* support for C++ to the compile feature. It does
most simple type conversions, including everything that C compile does and
your basic "with-classes" type of C++.
I've written a new compile-support.exp support file which adds a new test
facility for automating and simplifying "compile print" vs "compile code"
testing. See testsuite/lib/compile-support.exp and CompileExpression
for more on that. The tests use this facility extensively.
This initial support has several glaring omissions:
- No template support at all
I have follow-on patches for this, but they add much complexity
to this "basic" support. Consequently, they will be submitted separately.
- Cannot print functions
The code template needs tweaking, and I simply haven't gotten to it yet.
- So-called "special function" support is not included
Using constructors, destructors, operators, etc will not work. I have
follow-on patches for that, but they require some work because of the
recent churn in symbol searching.
- There are several test suite references to "compile/1234" bugs.
I will file bugs and update the test suite's bug references before pushing
these patches.
The test suite started as a copy of the original C-language support, but
I have written tests to exercise the basic functionality of the plug-in.
I've added a new option for outputting debug messages for C++ type-conversion
("debug compile-cplus-types").
gdb/ChangeLog:
* Makefile.in (SUBDIR_GCC_COMPILE_SRCS): Add compile-cplus-symbols.c
and compile-cplus-types.c.
(HFILES_NO_SRCDIR): Add gcc-cp-plugin.h.
* c-lang.c (cplus_language_defn): Set C++ compile functions.
* c-lang.h (cplus_get_compile_context, cplus_compute_program):
Declare.
* compile/compile-c-support.c: Include compile-cplus.h.
(load_libcompile): Templatize.
(get_compile_context): "New" function.
(c_get_compile_context): Use get_compile_context.
(cplus_get_compile_context): New function.
(cplus_push_user_expression, cplus_pop_user_expression)
(cplus_add_code_header, cplus_add_input, cplus_compile_program)
(cplus_compute_program): Define new structs/functions.
* compile/compile-cplus-symmbols.c: New file.
* compile/compile-cplus-types.c: New file.
* compile/compile-cplus.h: New file.
* compile/compile-internal.h (debug_compile_oracle, GCC_TYPE_NONE):
Declare.
* compile/compile-object-load.c (get_out_value_type): Use
strncmp_iw when comparing symbol names.
(compile_object_load): Add mst_bss and mst_data.
* compile/compile.c (_initialize_compile): Remove
-Wno-implicit-function-declaration from `compile_args'.
* compile/gcc-cp-plugin.h: New file.
* NEWS: Mention C++ compile support and new debug options.
gdb/testsuite/ChangeLog:
* gdb.compile/compile-cplus-anonymous.cc: New file.
* gdb.compile/compile-cplus-anonymous.exp: New file.
* gdb.compile/compile-cplus-array-decay.cc: New file.
* gdb.compile/compile-cplus-array-decay.exp: New file.
* gdb.compile/compile-cplus-inherit.cc: New file.
* gdb.compile/compile-cplus-inherit.exp: New file.
* gdb.compile/compile-cplus-member.cc: New file.
* gdb.compile/compile-cplus-member.exp: New file.
* gdb.compile/compile-cplus-method.cc: New file.
* gdb.compile/compile-cplus-method.exp: New file.
* gdb.compile/compile-cplus-mod.c: "New" file.
* gdb.compile/compile-cplus-namespace.cc: New file.
* gdb.compile/compile-cplus-namespace.exp: New file.
* gdb.compile/compile-cplus-nested.cc: New file.
* gdb.compile/compile-cplus-nested.exp: New file.
* gdb.compile/compile-cplus-print.c: "New" file.
* gdb.compile/compile-cplus-print.exp: "New" file.
* gdb.compile/compile-cplus-virtual.cc: New file.
* gdb.compile/compile-cplus-virtual.exp: New file.
* gdb.compile/compile-cplus.c: "New" file.
* gdb.compile/compile-cplus.exp: "New" file.
* lib/compile-support.exp: New file.
doc/ChangeLog:
* gdb.texinfo (Compiling and injecting code in GDB): Document
set/show "compile-oracle" and "compile-cplus-types" commands.
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
493
gdb/compile/compile-cplus-symbols.c
Normal file
493
gdb/compile/compile-cplus-symbols.c
Normal file
@@ -0,0 +1,493 @@
|
||||
/* Convert symbols from GDB to GCC
|
||||
|
||||
Copyright (C) 2014-2018 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
|
||||
#include "defs.h"
|
||||
#include "compile-internal.h"
|
||||
#include "compile-cplus.h"
|
||||
#include "gdb_assert.h"
|
||||
#include "symtab.h"
|
||||
#include "parser-defs.h"
|
||||
#include "block.h"
|
||||
#include "objfiles.h"
|
||||
#include "compile.h"
|
||||
#include "value.h"
|
||||
#include "exceptions.h"
|
||||
#include "gdbtypes.h"
|
||||
#include "dwarf2loc.h"
|
||||
#include "cp-support.h"
|
||||
#include "gdbcmd.h"
|
||||
#include "compile-c.h"
|
||||
|
||||
/* Convert a given symbol, SYM, to the compiler's representation.
|
||||
INSTANCE is the compiler instance. IS_GLOBAL is true if the
|
||||
symbol came from the global scope. IS_LOCAL is true if the symbol
|
||||
came from a local scope. (Note that the two are not strictly
|
||||
inverses because the symbol might have come from the static
|
||||
scope.) */
|
||||
|
||||
static void
|
||||
convert_one_symbol (compile_cplus_instance *instance,
|
||||
struct block_symbol sym, bool is_global, bool is_local)
|
||||
{
|
||||
/* Squash compiler warning. */
|
||||
gcc_type sym_type = 0;
|
||||
const char *filename = symbol_symtab (sym.symbol)->filename;
|
||||
unsigned short line = SYMBOL_LINE (sym.symbol);
|
||||
|
||||
instance->error_symbol_once (sym.symbol);
|
||||
|
||||
if (SYMBOL_CLASS (sym.symbol) == LOC_LABEL)
|
||||
sym_type = 0;
|
||||
else
|
||||
sym_type = instance->convert_type (SYMBOL_TYPE (sym.symbol));
|
||||
|
||||
if (SYMBOL_DOMAIN (sym.symbol) == STRUCT_DOMAIN)
|
||||
{
|
||||
/* Nothing to do. */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Squash compiler warning. */
|
||||
gcc_cp_symbol_kind_flags kind = GCC_CP_FLAG_BASE;
|
||||
CORE_ADDR addr = 0;
|
||||
std::string name;
|
||||
gdb::unique_xmalloc_ptr<char> symbol_name;
|
||||
|
||||
switch (SYMBOL_CLASS (sym.symbol))
|
||||
{
|
||||
case LOC_TYPEDEF:
|
||||
if (TYPE_CODE (SYMBOL_TYPE (sym.symbol)) == TYPE_CODE_TYPEDEF)
|
||||
kind = GCC_CP_SYMBOL_TYPEDEF;
|
||||
else if (TYPE_CODE (SYMBOL_TYPE (sym.symbol)) == TYPE_CODE_NAMESPACE)
|
||||
return;
|
||||
break;
|
||||
|
||||
case LOC_LABEL:
|
||||
kind = GCC_CP_SYMBOL_LABEL;
|
||||
addr = SYMBOL_VALUE_ADDRESS (sym.symbol);
|
||||
break;
|
||||
|
||||
case LOC_BLOCK:
|
||||
{
|
||||
kind = GCC_CP_SYMBOL_FUNCTION;
|
||||
addr = BLOCK_START (SYMBOL_BLOCK_VALUE (sym.symbol));
|
||||
if (is_global && TYPE_GNU_IFUNC (SYMBOL_TYPE (sym.symbol)))
|
||||
addr = gnu_ifunc_resolve_addr (target_gdbarch (), addr);
|
||||
}
|
||||
break;
|
||||
|
||||
case LOC_CONST:
|
||||
if (TYPE_CODE (SYMBOL_TYPE (sym.symbol)) == TYPE_CODE_ENUM)
|
||||
{
|
||||
/* Already handled by convert_enum. */
|
||||
return;
|
||||
}
|
||||
instance->plugin ().build_constant
|
||||
(sym_type, SYMBOL_NATURAL_NAME (sym.symbol),
|
||||
SYMBOL_VALUE (sym.symbol), filename, line);
|
||||
return;
|
||||
|
||||
case LOC_CONST_BYTES:
|
||||
error (_("Unsupported LOC_CONST_BYTES for symbol \"%s\"."),
|
||||
SYMBOL_PRINT_NAME (sym.symbol));
|
||||
|
||||
case LOC_UNDEF:
|
||||
internal_error (__FILE__, __LINE__, _("LOC_UNDEF found for \"%s\"."),
|
||||
SYMBOL_PRINT_NAME (sym.symbol));
|
||||
|
||||
case LOC_COMMON_BLOCK:
|
||||
error (_("Fortran common block is unsupported for compilation "
|
||||
"evaluaton of symbol \"%s\"."),
|
||||
SYMBOL_PRINT_NAME (sym.symbol));
|
||||
|
||||
case LOC_OPTIMIZED_OUT:
|
||||
error (_("Symbol \"%s\" cannot be used for compilation evaluation "
|
||||
"as it is optimized out."),
|
||||
SYMBOL_PRINT_NAME (sym.symbol));
|
||||
|
||||
case LOC_COMPUTED:
|
||||
if (is_local)
|
||||
goto substitution;
|
||||
/* Probably TLS here. */
|
||||
warning (_("Symbol \"%s\" is thread-local and currently can only "
|
||||
"be referenced from the current thread in "
|
||||
"compiled code."),
|
||||
SYMBOL_PRINT_NAME (sym.symbol));
|
||||
/* FALLTHROUGH */
|
||||
case LOC_UNRESOLVED:
|
||||
/* 'symbol_name' cannot be used here as that one is used only for
|
||||
local variables from compile_dwarf_expr_to_c.
|
||||
Global variables can be accessed by GCC only by their address, not
|
||||
by their name. */
|
||||
{
|
||||
struct value *val;
|
||||
struct frame_info *frame = nullptr;
|
||||
|
||||
if (symbol_read_needs_frame (sym.symbol))
|
||||
{
|
||||
frame = get_selected_frame (nullptr);
|
||||
if (frame == nullptr)
|
||||
error (_("Symbol \"%s\" cannot be used because "
|
||||
"there is no selected frame"),
|
||||
SYMBOL_PRINT_NAME (sym.symbol));
|
||||
}
|
||||
|
||||
val = read_var_value (sym.symbol, sym.block, frame);
|
||||
if (VALUE_LVAL (val) != lval_memory)
|
||||
error (_("Symbol \"%s\" cannot be used for compilation "
|
||||
"evaluation as its address has not been found."),
|
||||
SYMBOL_PRINT_NAME (sym.symbol));
|
||||
|
||||
kind = GCC_CP_SYMBOL_VARIABLE;
|
||||
addr = value_address (val);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case LOC_REGISTER:
|
||||
case LOC_ARG:
|
||||
case LOC_REF_ARG:
|
||||
case LOC_REGPARM_ADDR:
|
||||
case LOC_LOCAL:
|
||||
substitution:
|
||||
kind = GCC_CP_SYMBOL_VARIABLE;
|
||||
symbol_name = c_symbol_substitution_name (sym.symbol);
|
||||
break;
|
||||
|
||||
case LOC_STATIC:
|
||||
kind = GCC_CP_SYMBOL_VARIABLE;
|
||||
addr = SYMBOL_VALUE_ADDRESS (sym.symbol);
|
||||
break;
|
||||
|
||||
case LOC_FINAL_VALUE:
|
||||
default:
|
||||
gdb_assert_not_reached ("Unreachable case in convert_one_symbol.");
|
||||
}
|
||||
|
||||
/* Don't emit local variable decls for a raw expression. */
|
||||
if (instance->scope () != COMPILE_I_RAW_SCOPE || symbol_name == nullptr)
|
||||
{
|
||||
compile_scope scope;
|
||||
|
||||
/* For non-local symbols, create/push a new scope so that the
|
||||
symbol is properly scoped to the plug-in. */
|
||||
if (!is_local)
|
||||
{
|
||||
scope
|
||||
= instance->new_scope (SYMBOL_NATURAL_NAME (sym.symbol),
|
||||
SYMBOL_TYPE (sym.symbol));
|
||||
if (scope.nested_type () != GCC_TYPE_NONE)
|
||||
{
|
||||
/* We found a symbol for this type that was defined inside
|
||||
some other symbol, e.g., a class tyepdef defined. */
|
||||
return;
|
||||
}
|
||||
|
||||
instance->enter_scope (scope);
|
||||
}
|
||||
|
||||
/* Get the `raw' name of the symbol. */
|
||||
if (name.empty () && SYMBOL_NATURAL_NAME (sym.symbol) != nullptr)
|
||||
name = compile_cplus_instance::decl_name
|
||||
(SYMBOL_NATURAL_NAME (sym.symbol)).get ();
|
||||
|
||||
/* Define the decl. */
|
||||
instance->plugin ().build_decl
|
||||
("variable", name.c_str (), kind, sym_type,
|
||||
symbol_name.get (), addr, filename, line);
|
||||
|
||||
/* Pop scope for non-local symbols. */
|
||||
if (!is_local)
|
||||
instance->leave_scope ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert a full symbol to its gcc form. CONTEXT is the compiler to
|
||||
use, IDENTIFIER is the name of the symbol, SYM is the symbol
|
||||
itself, and DOMAIN is the domain which was searched. */
|
||||
|
||||
static void
|
||||
convert_symbol_sym (compile_cplus_instance *instance,
|
||||
const char *identifier, struct block_symbol sym,
|
||||
domain_enum domain)
|
||||
{
|
||||
/* If we found a symbol and it is not in the static or global
|
||||
scope, then we should first convert any static or global scope
|
||||
symbol of the same name. This lets this unusual case work:
|
||||
|
||||
int x; // Global.
|
||||
int func(void)
|
||||
{
|
||||
int x;
|
||||
// At this spot, evaluate "extern int x; x"
|
||||
}
|
||||
*/
|
||||
|
||||
const struct block *static_block = block_static_block (sym.block);
|
||||
/* STATIC_BLOCK is NULL if FOUND_BLOCK is the global block. */
|
||||
bool is_local_symbol = (sym.block != static_block && static_block != nullptr);
|
||||
if (is_local_symbol)
|
||||
{
|
||||
struct block_symbol global_sym;
|
||||
|
||||
global_sym = lookup_symbol (identifier, nullptr, domain, nullptr);
|
||||
/* If the outer symbol is in the static block, we ignore it, as
|
||||
it cannot be referenced. */
|
||||
if (global_sym.symbol != nullptr
|
||||
&& global_sym.block != block_static_block (global_sym.block))
|
||||
{
|
||||
if (compile_debug)
|
||||
fprintf_unfiltered (gdb_stdlog,
|
||||
"gcc_convert_symbol \"%s\": global symbol\n",
|
||||
identifier);
|
||||
convert_one_symbol (instance, global_sym, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (compile_debug)
|
||||
fprintf_unfiltered (gdb_stdlog,
|
||||
"gcc_convert_symbol \"%s\": local symbol\n",
|
||||
identifier);
|
||||
convert_one_symbol (instance, sym, false, is_local_symbol);
|
||||
}
|
||||
|
||||
/* Convert a minimal symbol to its gcc form. CONTEXT is the compiler
|
||||
to use and BMSYM is the minimal symbol to convert. */
|
||||
|
||||
static void
|
||||
convert_symbol_bmsym (compile_cplus_instance *instance,
|
||||
struct bound_minimal_symbol bmsym)
|
||||
{
|
||||
struct minimal_symbol *msym = bmsym.minsym;
|
||||
struct objfile *objfile = bmsym.objfile;
|
||||
struct type *type;
|
||||
gcc_cp_symbol_kind_flags kind;
|
||||
gcc_type sym_type;
|
||||
CORE_ADDR addr;
|
||||
|
||||
addr = MSYMBOL_VALUE_ADDRESS (objfile, msym);
|
||||
|
||||
/* Conversion copied from write_exp_msymbol. */
|
||||
switch (MSYMBOL_TYPE (msym))
|
||||
{
|
||||
case mst_text:
|
||||
case mst_file_text:
|
||||
case mst_solib_trampoline:
|
||||
type = objfile_type (objfile)->nodebug_text_symbol;
|
||||
kind = GCC_CP_SYMBOL_FUNCTION;
|
||||
break;
|
||||
|
||||
case mst_text_gnu_ifunc:
|
||||
/* nodebug_text_gnu_ifunc_symbol would cause:
|
||||
function return type cannot be function */
|
||||
type = objfile_type (objfile)->nodebug_text_symbol;
|
||||
kind = GCC_CP_SYMBOL_FUNCTION;
|
||||
addr = gnu_ifunc_resolve_addr (target_gdbarch (), addr);
|
||||
break;
|
||||
|
||||
case mst_data:
|
||||
case mst_file_data:
|
||||
case mst_bss:
|
||||
case mst_file_bss:
|
||||
type = objfile_type (objfile)->nodebug_data_symbol;
|
||||
kind = GCC_CP_SYMBOL_VARIABLE;
|
||||
break;
|
||||
|
||||
case mst_slot_got_plt:
|
||||
type = objfile_type (objfile)->nodebug_got_plt_symbol;
|
||||
kind = GCC_CP_SYMBOL_FUNCTION;
|
||||
break;
|
||||
|
||||
default:
|
||||
type = objfile_type (objfile)->nodebug_unknown_symbol;
|
||||
kind = GCC_CP_SYMBOL_VARIABLE;
|
||||
break;
|
||||
}
|
||||
|
||||
sym_type = instance->convert_type (type);
|
||||
instance->plugin ().push_namespace ("");
|
||||
instance->plugin ().build_decl
|
||||
("minsym", MSYMBOL_NATURAL_NAME (msym), kind, sym_type, nullptr, addr,
|
||||
nullptr, 0);
|
||||
instance->plugin ().pop_binding_level ("");
|
||||
}
|
||||
|
||||
/* See compile-cplus.h. */
|
||||
|
||||
void
|
||||
gcc_cplus_convert_symbol (void *datum,
|
||||
struct gcc_cp_context *gcc_context,
|
||||
enum gcc_cp_oracle_request request ATTRIBUTE_UNUSED,
|
||||
const char *identifier)
|
||||
{
|
||||
if (compile_debug)
|
||||
fprintf_unfiltered (gdb_stdlog,
|
||||
"got oracle request for \"%s\"\n", identifier);
|
||||
|
||||
bool found = false;
|
||||
compile_cplus_instance *instance = (compile_cplus_instance *) datum;
|
||||
|
||||
TRY
|
||||
{
|
||||
/* Symbol searching is a three part process unfortunately. */
|
||||
|
||||
/* First do a "standard" lookup, converting any found symbols.
|
||||
This will find variables in the current scope. */
|
||||
|
||||
struct block_symbol sym
|
||||
= lookup_symbol (identifier, instance->block (), VAR_DOMAIN, nullptr);
|
||||
|
||||
if (sym.symbol != nullptr)
|
||||
{
|
||||
found = true;
|
||||
convert_symbol_sym (instance, identifier, sym, VAR_DOMAIN);
|
||||
}
|
||||
|
||||
/* Then use linespec.c's multi-symbol search. This should find
|
||||
all non-variable symbols for which we have debug info. */
|
||||
|
||||
symbol_searcher searcher;
|
||||
searcher.find_all_symbols (identifier, current_language,
|
||||
ALL_DOMAIN, nullptr, nullptr);
|
||||
|
||||
/* Convert any found symbols. */
|
||||
for (const auto &it : searcher.matching_symbols ())
|
||||
{
|
||||
/* Don't convert the symbol found above, if any, twice! */
|
||||
if (it.symbol != sym.symbol)
|
||||
{
|
||||
found = true;
|
||||
convert_symbol_sym (instance, identifier, it,
|
||||
SYMBOL_DOMAIN (it.symbol));
|
||||
}
|
||||
}
|
||||
|
||||
/* Finally, if no symbols have been found, fall back to minsyms. */
|
||||
if (!found)
|
||||
{
|
||||
for (const auto &it : searcher.matching_msymbols ())
|
||||
{
|
||||
found = true;
|
||||
convert_symbol_bmsym (instance, it);
|
||||
}
|
||||
}
|
||||
}
|
||||
CATCH (e, RETURN_MASK_ALL)
|
||||
{
|
||||
/* We can't allow exceptions to escape out of this callback. Safest
|
||||
is to simply emit a gcc error. */
|
||||
instance->plugin ().error (e.message);
|
||||
}
|
||||
END_CATCH
|
||||
|
||||
if (compile_debug && !found)
|
||||
fprintf_unfiltered (gdb_stdlog,
|
||||
"gcc_convert_symbol \"%s\": lookup_symbol failed\n",
|
||||
identifier);
|
||||
|
||||
if (compile_debug)
|
||||
{
|
||||
if (found)
|
||||
fprintf_unfiltered (gdb_stdlog, "found type for %s\n", identifier);
|
||||
else
|
||||
{
|
||||
fprintf_unfiltered (gdb_stdlog, "did not find type for %s\n",
|
||||
identifier);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* See compile-cplus.h. */
|
||||
|
||||
gcc_address
|
||||
gcc_cplus_symbol_address (void *datum, struct gcc_cp_context *gcc_context,
|
||||
const char *identifier)
|
||||
{
|
||||
compile_cplus_instance *instance = (compile_cplus_instance *) datum;
|
||||
gcc_address result = 0;
|
||||
int found = 0;
|
||||
|
||||
if (compile_debug)
|
||||
fprintf_unfiltered (gdb_stdlog,
|
||||
"got oracle request for address of %s\n", identifier);
|
||||
|
||||
/* We can't allow exceptions to escape out of this callback. Safest
|
||||
is to simply emit a gcc error. */
|
||||
TRY
|
||||
{
|
||||
struct symbol *sym
|
||||
= lookup_symbol (identifier, nullptr, VAR_DOMAIN, nullptr).symbol;
|
||||
|
||||
if (sym != nullptr && SYMBOL_CLASS (sym) == LOC_BLOCK)
|
||||
{
|
||||
if (compile_debug)
|
||||
fprintf_unfiltered (gdb_stdlog,
|
||||
"gcc_symbol_address \"%s\": full symbol\n",
|
||||
identifier);
|
||||
result = BLOCK_START (SYMBOL_BLOCK_VALUE (sym));
|
||||
if (TYPE_GNU_IFUNC (SYMBOL_TYPE (sym)))
|
||||
result = gnu_ifunc_resolve_addr (target_gdbarch (), result);
|
||||
found = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct bound_minimal_symbol msym;
|
||||
|
||||
msym = lookup_bound_minimal_symbol (identifier);
|
||||
if (msym.minsym != nullptr)
|
||||
{
|
||||
if (compile_debug)
|
||||
fprintf_unfiltered (gdb_stdlog,
|
||||
"gcc_symbol_address \"%s\": minimal "
|
||||
"symbol\n",
|
||||
identifier);
|
||||
result = BMSYMBOL_VALUE_ADDRESS (msym);
|
||||
if (MSYMBOL_TYPE (msym.minsym) == mst_text_gnu_ifunc)
|
||||
result = gnu_ifunc_resolve_addr (target_gdbarch (), result);
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CATCH (e, RETURN_MASK_ERROR)
|
||||
{
|
||||
instance->plugin ().error (e.message);
|
||||
}
|
||||
END_CATCH
|
||||
|
||||
if (compile_debug && !found)
|
||||
fprintf_unfiltered (gdb_stdlog,
|
||||
"gcc_symbol_address \"%s\": failed\n",
|
||||
identifier);
|
||||
|
||||
if (compile_debug)
|
||||
{
|
||||
if (found)
|
||||
fprintf_unfiltered (gdb_stdlog, "found address for %s!\n", identifier);
|
||||
else
|
||||
fprintf_unfiltered (gdb_stdlog,
|
||||
"did not find address for %s\n", identifier);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
1427
gdb/compile/compile-cplus-types.c
Normal file
1427
gdb/compile/compile-cplus-types.c
Normal file
File diff suppressed because it is too large
Load Diff
205
gdb/compile/compile-cplus.h
Normal file
205
gdb/compile/compile-cplus.h
Normal file
@@ -0,0 +1,205 @@
|
||||
/* Header file for GDB compile C++ language support.
|
||||
Copyright (C) 2016-2018 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef GDB_COMPILE_CPLUS_H
|
||||
#define GDB_COMPILE_CPLUS_H
|
||||
|
||||
#include "common/enum-flags.h"
|
||||
#include "gcc-cp-plugin.h"
|
||||
|
||||
struct type;
|
||||
struct block;
|
||||
|
||||
/* enum-flags wrapper */
|
||||
DEF_ENUM_FLAGS_TYPE (enum gcc_cp_qualifiers, gcc_cp_qualifiers_flags);
|
||||
DEF_ENUM_FLAGS_TYPE (enum gcc_cp_ref_qualifiers, gcc_cp_ref_qualifiers_flags);
|
||||
DEF_ENUM_FLAGS_TYPE (enum gcc_cp_symbol_kind, gcc_cp_symbol_kind_flags);
|
||||
|
||||
class compile_cplus_instance;
|
||||
|
||||
/* A single component of a type's scope. Type names are broken into
|
||||
"components," a series of unqualified names comprising the type name,
|
||||
e.g., "namespace1", "namespace2", "myclass". */
|
||||
|
||||
struct scope_component
|
||||
{
|
||||
/* The unqualified name of this scope. */
|
||||
std::string name;
|
||||
|
||||
/* The block symbol for this type/scope. */
|
||||
struct block_symbol bsymbol;
|
||||
};
|
||||
|
||||
/* Comparison operators for scope_components. */
|
||||
|
||||
bool operator== (const scope_component &lhs, const scope_component &rhs);
|
||||
bool operator!= (const scope_component &lhs, const scope_component &rhs);
|
||||
|
||||
|
||||
/* A single compiler scope used to define a type.
|
||||
|
||||
A compile_scope is a list of scope_components, where all leading
|
||||
scope_components are namespaces, followed by a single non-namespace
|
||||
type component (the actual type we are converting). */
|
||||
|
||||
class compile_scope : private std::vector<scope_component>
|
||||
{
|
||||
public:
|
||||
|
||||
using std::vector<scope_component>::push_back;
|
||||
using std::vector<scope_component>::pop_back;
|
||||
using std::vector<scope_component>::back;
|
||||
using std::vector<scope_component>::empty;
|
||||
using std::vector<scope_component>::size;
|
||||
using std::vector<scope_component>::begin;
|
||||
using std::vector<scope_component>::end;
|
||||
using std::vector<scope_component>::operator[];
|
||||
|
||||
compile_scope ()
|
||||
: m_nested_type (GCC_TYPE_NONE), m_pushed (false)
|
||||
{
|
||||
}
|
||||
|
||||
/* Return the gcc_type of the type if it is a nested definition.
|
||||
Returns GCC_TYPE_NONE if this type was not nested. */
|
||||
gcc_type nested_type ()
|
||||
{
|
||||
return m_nested_type;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/* compile_cplus_instance is a friend class so that it can set the
|
||||
following private members when compile_scopes are created. */
|
||||
friend compile_cplus_instance;
|
||||
|
||||
/* If the type was actually a nested type, this will hold that nested
|
||||
type after the scope is pushed. */
|
||||
gcc_type m_nested_type;
|
||||
|
||||
/* If true, this scope was pushed to the compiler and all namespaces
|
||||
must be popped when leaving the scope. */
|
||||
bool m_pushed;
|
||||
};
|
||||
|
||||
/* Comparison operators for compile_scopes. */
|
||||
|
||||
bool operator== (const compile_scope &lhs, const compile_scope &rhs);
|
||||
bool operator!= (const compile_scope &lhs, const compile_scope &rhs);
|
||||
|
||||
/* Convert TYPENAME into a vector of namespace and top-most/super
|
||||
composite scopes.
|
||||
|
||||
For example, for the input "Namespace::classB::classInner", the
|
||||
resultant vector will contain the tokens "Namespace" and
|
||||
"classB". */
|
||||
|
||||
compile_scope type_name_to_scope (const char *type_name,
|
||||
const struct block *block);
|
||||
|
||||
/* A callback suitable for use as the GCC C++ symbol oracle. */
|
||||
|
||||
extern gcc_cp_oracle_function gcc_cplus_convert_symbol;
|
||||
|
||||
/* A callback suitable for use as the GCC C++ address oracle. */
|
||||
|
||||
extern gcc_cp_symbol_address_function gcc_cplus_symbol_address;
|
||||
|
||||
/* A subclass of compile_instance that is specific to the C++ front
|
||||
end. */
|
||||
|
||||
class compile_cplus_instance : public compile_instance
|
||||
{
|
||||
public:
|
||||
|
||||
explicit compile_cplus_instance (struct gcc_cp_context *gcc_cp)
|
||||
: compile_instance (&gcc_cp->base, m_default_cflags),
|
||||
m_plugin (gcc_cp)
|
||||
{
|
||||
m_plugin.set_callbacks (gcc_cplus_convert_symbol,
|
||||
gcc_cplus_symbol_address,
|
||||
gcc_cplus_enter_scope, gcc_cplus_leave_scope,
|
||||
this);
|
||||
}
|
||||
|
||||
/* Convert a gdb type, TYPE, to a GCC type.
|
||||
|
||||
If this type was defined in another type, NESTED_ACCESS should indicate
|
||||
the accessibility of this type (or GCC_CP_ACCESS_NONE if not a nested
|
||||
type). GCC_CP_ACCESS_NONE is the default nested access.
|
||||
|
||||
The new GCC type is returned. */
|
||||
gcc_type convert_type
|
||||
(struct type *type,
|
||||
enum gcc_cp_symbol_kind nested_access = GCC_CP_ACCESS_NONE);
|
||||
|
||||
/* Return a handle for the GCC plug-in. */
|
||||
gcc_cp_plugin &plugin () { return m_plugin; }
|
||||
|
||||
/* Factory method to create a new scope based on TYPE with name TYPE_NAME.
|
||||
[TYPE_NAME could be TYPE_NAME or SYMBOL_NATURAL_NAME.]
|
||||
|
||||
If TYPE is a nested or local definition, nested_type () will return
|
||||
the gcc_type of the conversion.
|
||||
|
||||
Otherwise, nested_type () is GCC_TYPE_NONE. */
|
||||
compile_scope new_scope (const char *type_name, struct type *type);
|
||||
|
||||
/* Enter the given NEW_SCOPE. */
|
||||
void enter_scope (compile_scope &scope);
|
||||
|
||||
/* Leave the current scope. */
|
||||
void leave_scope ();
|
||||
|
||||
/* Add the qualifiers given by QUALS to BASE. */
|
||||
gcc_type convert_qualified_base (gcc_type base,
|
||||
gcc_cp_qualifiers_flags quals);
|
||||
|
||||
/* Convert TARGET into a pointer type. */
|
||||
gcc_type convert_pointer_base (gcc_type target);
|
||||
|
||||
/* Convert BASE into a reference type. RQUALS describes the reference. */
|
||||
gcc_type convert_reference_base (gcc_type base,
|
||||
enum gcc_cp_ref_qualifiers rquals);
|
||||
|
||||
/* Return the declaration name of the symbol named NATURAL.
|
||||
This returns a name with no function arguments or template parameters,
|
||||
suitable for passing to the compiler plug-in. */
|
||||
static gdb::unique_xmalloc_ptr<char> decl_name (const char *natural);
|
||||
|
||||
private:
|
||||
|
||||
/* Callbacks suitable for use as the GCC C++ enter/leave scope requests. */
|
||||
static gcc_cp_enter_leave_user_expr_scope_function gcc_cplus_enter_scope;
|
||||
static gcc_cp_enter_leave_user_expr_scope_function gcc_cplus_leave_scope;
|
||||
|
||||
/* Default compiler flags for C++. */
|
||||
static const char *m_default_cflags;
|
||||
|
||||
/* The GCC plug-in. */
|
||||
gcc_cp_plugin m_plugin;
|
||||
|
||||
/* A list of scopes we are processing. */
|
||||
std::vector<compile_scope> m_scopes;
|
||||
};
|
||||
|
||||
/* Get the access flag for the NUM'th method of TYPE's FNI'th
|
||||
fieldlist. */
|
||||
|
||||
enum gcc_cp_symbol_kind get_method_access_flag (const struct type *type,
|
||||
int fni, int num);
|
||||
|
||||
#endif /* GDB_COMPILE_CPLUS_H */
|
||||
@@ -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. */
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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. */
|
||||
|
||||
85
gdb/compile/gcc-cp-plugin.h
Normal file
85
gdb/compile/gcc-cp-plugin.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/* GCC C++ plug-in wrapper for GDB.
|
||||
|
||||
Copyright (C) 2018 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* A class representing the GCC C++ plug-in. */
|
||||
|
||||
#include "gcc-cp-interface.h"
|
||||
|
||||
class gcc_cp_plugin
|
||||
{
|
||||
public:
|
||||
|
||||
explicit gcc_cp_plugin (struct gcc_cp_context *gcc_cp)
|
||||
: m_context (gcc_cp)
|
||||
{
|
||||
}
|
||||
|
||||
/* Set the oracle callbacks to be used by the compiler plug-in. */
|
||||
void set_callbacks (gcc_cp_oracle_function *binding_oracle,
|
||||
gcc_cp_symbol_address_function *address_oracle,
|
||||
gcc_cp_enter_leave_user_expr_scope_function *enter_scope,
|
||||
gcc_cp_enter_leave_user_expr_scope_function *leave_scope,
|
||||
void *datum)
|
||||
{
|
||||
m_context->cp_ops->set_callbacks (m_context, binding_oracle,
|
||||
address_oracle, enter_scope, leave_scope,
|
||||
datum);
|
||||
}
|
||||
|
||||
/* Returns the interface version of the compiler plug-in. */
|
||||
int version () const { return m_context->cp_ops->cp_version; }
|
||||
|
||||
#define GCC_METHOD0(R, N) R N () const;
|
||||
#define GCC_METHOD1(R, N, A) R N (A) const;
|
||||
#define GCC_METHOD2(R, N, A, B) R N (A, B) const;
|
||||
#define GCC_METHOD3(R, N, A, B, C) R N (A, B, C) const;
|
||||
#define GCC_METHOD4(R, N, A, B, C, D) R N (A, B, C, D) const;
|
||||
#define GCC_METHOD5(R, N, A, B, C, D, E) R N (A, B, C, D, E) const;
|
||||
#define GCC_METHOD7(R, N, A, B, C, D, E, F, G) R N (A, B, C, D, E, F, G) const;
|
||||
|
||||
#include "gcc-cp-fe.def"
|
||||
|
||||
#undef GCC_METHOD0
|
||||
#undef GCC_METHOD1
|
||||
#undef GCC_METHOD2
|
||||
#undef GCC_METHOD3
|
||||
#undef GCC_METHOD4
|
||||
#undef GCC_METHOD5
|
||||
#undef GCC_METHOD7
|
||||
|
||||
/* Special overloads of plug-in methods with added debugging information. */
|
||||
|
||||
gcc_expr build_decl (const char *debug_decltype, const char *name,
|
||||
enum gcc_cp_symbol_kind sym_kind, gcc_type sym_type,
|
||||
const char *substitution_name, gcc_address address,
|
||||
const char *filename, unsigned int line_number);
|
||||
|
||||
gcc_type start_class_type (const char *debug_name, gcc_decl typedecl,
|
||||
const struct gcc_vbase_array *base_classes,
|
||||
const char *filename, unsigned int line_number);
|
||||
|
||||
int finish_class_type (const char *debug_name, unsigned long size_in_bytes);
|
||||
|
||||
int pop_binding_level (const char *debug_name);
|
||||
|
||||
private:
|
||||
|
||||
/* The GCC C++ context. */
|
||||
struct gcc_cp_context *m_context;
|
||||
};
|
||||
Reference in New Issue
Block a user