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:
parent
fcaad03cc0
commit
078a020797
@ -1,3 +1,32 @@
|
||||
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.
|
||||
|
@ -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 \
|
||||
|
14
gdb/NEWS
14
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
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
19
gdb/c-lang.h
19
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) */
|
||||
|
@ -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;
|
||||
};
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
76
gdb/testsuite/gdb.compile/compile-cplus-anonymous.cc
Normal file
76
gdb/testsuite/gdb.compile/compile-cplus-anonymous.cc
Normal file
@ -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
|
||||
}
|
64
gdb/testsuite/gdb.compile/compile-cplus-anonymous.exp
Normal file
64
gdb/testsuite/gdb.compile/compile-cplus-anonymous.exp
Normal file
@ -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
|
31
gdb/testsuite/gdb.compile/compile-cplus-array-decay.cc
Normal file
31
gdb/testsuite/gdb.compile/compile-cplus-array-decay.cc
Normal file
@ -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
|
||||
}
|
50
gdb/testsuite/gdb.compile/compile-cplus-array-decay.exp
Normal file
50
gdb/testsuite/gdb.compile/compile-cplus-array-decay.exp
Normal file
@ -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\"\\}"
|
58
gdb/testsuite/gdb.compile/compile-cplus-inherit.cc
Normal file
58
gdb/testsuite/gdb.compile/compile-cplus-inherit.cc
Normal file
@ -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;
|
||||
}
|
53
gdb/testsuite/gdb.compile/compile-cplus-inherit.exp
Normal file
53
gdb/testsuite/gdb.compile/compile-cplus-inherit.exp
Normal file
@ -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
|
83
gdb/testsuite/gdb.compile/compile-cplus-member.cc
Normal file
83
gdb/testsuite/gdb.compile/compile-cplus-member.cc
Normal file
@ -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);
|
||||
|
||||
enum myenum {E_A = 10, E_B, E_C, E_D, E_E};
|
||||
|
||||
namespace N {
|
||||
typedef enum {NA = 20, NB, NC, ND} ANON_NE;
|
||||
}
|
||||
|
||||
namespace {
|
||||
typedef enum {AA = 40, AB, AC, AD} ANON_E;
|
||||
}
|
||||
|
||||
ANON_E g_e = AC;
|
||||
|
||||
class A
|
||||
{
|
||||
public:
|
||||
typedef int ATYPE;
|
||||
|
||||
A () : public_ (1), protected_ (N::NB), private_ (3) {}
|
||||
ATYPE public_;
|
||||
static const myenum s_public_;
|
||||
friend ATYPE get_values (const A&);
|
||||
|
||||
protected:
|
||||
N::ANON_NE protected_;
|
||||
static N::ANON_NE s_protected_;
|
||||
|
||||
private:
|
||||
ATYPE private_;
|
||||
static myenum s_private_;
|
||||
};
|
||||
|
||||
const myenum A::s_public_ = E_A;
|
||||
N::ANON_NE A::s_protected_ = N::NA;
|
||||
myenum A::s_private_ = E_C;
|
||||
|
||||
static A::ATYPE
|
||||
get_values (const A& a)
|
||||
{
|
||||
A::ATYPE val;
|
||||
|
||||
val = a.public_ + a.private_; // 1 + 3
|
||||
if (a.protected_ == N::NB) // + 21
|
||||
val += 21;
|
||||
if (a.s_public_ == E_A) // +10
|
||||
val += 10;
|
||||
if (a.s_protected_ == N::NA) // +20
|
||||
val += 20;
|
||||
if (a.s_private_ == E_C) // +30
|
||||
val += 30;
|
||||
if (g_e == AC) // +40
|
||||
val += 40;
|
||||
return val; // = 125
|
||||
}
|
||||
|
||||
typedef int A::*PMI;
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
A a;
|
||||
int var = 1234;
|
||||
PMI pmi = &A::public_;
|
||||
|
||||
return a.*pmi + get_values (a); // break here
|
||||
}
|
76
gdb/testsuite/gdb.compile/compile-cplus-member.exp
Normal file
76
gdb/testsuite/gdb.compile/compile-cplus-member.exp
Normal file
@ -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/>.
|
||||
|
||||
# Member 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 "a.public_" 1
|
||||
CompileExpression::test "a.protected_" {(21|N::NB)}
|
||||
CompileExpression::test "a.private_" 3
|
||||
CompileExpression::test "A::s_public_" {(10|E_A)}
|
||||
CompileExpression::test "A::s_protected_" {(20|N::NA)}
|
||||
CompileExpression::test "A::s_private_" {(12|E_C)}
|
||||
CompileExpression::test "A::ATYPE i = 10; var = i;" 10 -explicit
|
||||
CompileExpression::test "get_values (a)" 125
|
||||
CompileExpression::test "myenum me = E_B; var = me;" 11 -explicit
|
||||
CompileExpression::test "A::s_protected_ = N::NB; var = A::s_protected_;" \
|
||||
21 -explicit
|
||||
CompileExpression::test "A::s_private_ = E_B; var = A::s_private_;" 11 -explicit
|
||||
CompileExpression::test "N::ANON_NE ae = N::ND; var = ae;" 23 -explicit
|
||||
CompileExpression::test {a.*pmi} 1
|
||||
CompileExpression::test {a.public_ = 2; var = a.*pmi; a.public_ = 1} 2 -explicit
|
||||
CompileExpression::test "g_e" {(42|AC)}
|
||||
|
||||
# Test some compilation failures
|
||||
set failed {\r\nCompilation failed\.}
|
||||
gdb_test "compile code a.s_public_ = E_B" \
|
||||
".*assignment of read-only variable 'A::s_public_'$failed"
|
||||
|
||||
gdb_test "compile code get_values ()" \
|
||||
".*too few arguments to function.*$failed"
|
||||
|
||||
gdb_test "compile code ATYPE i;" \
|
||||
".*.ATYPE. was not declared in this scope$failed"
|
||||
|
||||
gdb_test "compile code N::ANON_NE nse = E_A" \
|
||||
".*cannot convert.*$failed"
|
91
gdb/testsuite/gdb.compile/compile-cplus-method.cc
Normal file
91
gdb/testsuite/gdb.compile/compile-cplus-method.cc
Normal file
@ -0,0 +1,91 @@
|
||||
/* 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_value (const A* a);
|
||||
|
||||
class A
|
||||
{
|
||||
public:
|
||||
typedef int ATYPE;
|
||||
|
||||
A () : a_ (21) {}
|
||||
ATYPE get_var () { return a_; }
|
||||
ATYPE get_var (unsigned long a) { return 100; }
|
||||
ATYPE get_var (ATYPE a) { return 101; }
|
||||
ATYPE get_var (float a) { return 102; }
|
||||
ATYPE get_var (void *a) { return 103;}
|
||||
ATYPE get_var (A& lr) { return 104; }
|
||||
ATYPE get_var (A const& lr) { return 105; }
|
||||
|
||||
ATYPE get_var1 (int n) { return a_ << n; }
|
||||
ATYPE get_var2 (int incr, unsigned n) { return (a_ + incr) << n; }
|
||||
|
||||
static ATYPE get_1 (int a) { return a + 1; }
|
||||
static ATYPE get_2 (int a, int b) { return a + b + 2; }
|
||||
|
||||
friend ATYPE get_value (const A*);
|
||||
|
||||
private:
|
||||
ATYPE a_;
|
||||
};
|
||||
|
||||
static A::ATYPE
|
||||
get_value (A::ATYPE a)
|
||||
{
|
||||
return a;
|
||||
}
|
||||
|
||||
static A::ATYPE
|
||||
get_value (const A* a)
|
||||
{
|
||||
return a->a_;
|
||||
}
|
||||
|
||||
static A::ATYPE
|
||||
get_value ()
|
||||
{
|
||||
return 200;
|
||||
}
|
||||
|
||||
typedef int (A::*PMF) (A::ATYPE);
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
A *a = new A ();
|
||||
int var = 1234;
|
||||
float f = 1.23;
|
||||
unsigned long ul = 0xdeadbeef;
|
||||
A const* ac = a;
|
||||
|
||||
PMF pmf = &A::get_var;
|
||||
PMF *pmf_p = &pmf;
|
||||
|
||||
var -= a->get_var (); // break here
|
||||
var -= a->get_var (1);
|
||||
var -= a->get_var (ul);
|
||||
var -= a->get_var (f);
|
||||
var -= a->get_var (a);
|
||||
var -= a->get_var (*a);
|
||||
var -= a->get_var (*ac);
|
||||
var -= a->get_var1 (1);
|
||||
var -= a->get_var2 (1, 2);
|
||||
var += (a->*pmf) (1);
|
||||
var -= (a->**pmf_p) (1);
|
||||
|
||||
return var - A::get_1 (1) + A::get_2 (1, 2) + get_value ()
|
||||
+ get_value (get_value ()) + get_value (a);
|
||||
}
|
67
gdb/testsuite/gdb.compile/compile-cplus-method.exp
Normal file
67
gdb/testsuite/gdb.compile/compile-cplus-method.exp
Normal file
@ -0,0 +1,67 @@
|
||||
# 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/>.
|
||||
|
||||
# Method 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 "a->get_var ()" 21
|
||||
CompileExpression::test "a->get_var (static_cast<unsigned long> (1))" 100
|
||||
CompileExpression::test "a->get_var (static_cast<int> (1))" 101
|
||||
CompileExpression::test "a->get_var (static_cast<float> (1))" 102
|
||||
CompileExpression::test "a->get_var (static_cast<void *> (a))" 103
|
||||
CompileExpression::test "a->get_var (*a)" 104
|
||||
CompileExpression::test "a->get_var (*ac)" 105
|
||||
CompileExpression::test "a->get_var1 (1)" 42
|
||||
CompileExpression::test "a->get_var2 (1, 2)" 88
|
||||
CompileExpression::test "A::get_1 (1)" 2
|
||||
CompileExpression::test "A::get_2 (1, 2)" 5
|
||||
CompileExpression::test "A::get_1 (a->get_var ())" 22
|
||||
CompileExpression::test "a->get_var1 (a->get_var () - 16)" 672
|
||||
CompileExpression::test "a->get_var2 (a->get_var (), A::get_1 (2))" 336
|
||||
CompileExpression::test "get_value ()" 200
|
||||
CompileExpression::test "get_value (a)" 21
|
||||
CompileExpression::test "get_value (get_value ())" 200
|
||||
CompileExpression::test {(a->*pmf) (1)} 101
|
||||
CompileExpression::test \
|
||||
{pmf = &A::get_var1; var = (a->*pmf) (2); pmf = &A::get_var} 84 -explicit
|
||||
CompileExpression::test {(a->**pmf_p) (1)} 101
|
28
gdb/testsuite/gdb.compile/compile-cplus-mod.c
Normal file
28
gdb/testsuite/gdb.compile/compile-cplus-mod.c
Normal file
@ -0,0 +1,28 @@
|
||||
/* This testcase is part of GDB, the GNU debugger.
|
||||
|
||||
Copyright 2014-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/>. */
|
||||
|
||||
extern "C" void
|
||||
_gdb_expr ()
|
||||
{
|
||||
// Make 'globalvar' lookup working.
|
||||
#pragma GCC push_user_expression
|
||||
|
||||
globalvar = 3;
|
||||
globalvar += 4;
|
||||
|
||||
#pragma GCC pop_user_expression
|
||||
}
|
52
gdb/testsuite/gdb.compile/compile-cplus-namespace.cc
Normal file
52
gdb/testsuite/gdb.compile/compile-cplus-namespace.cc
Normal file
@ -0,0 +1,52 @@
|
||||
/* 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 N1
|
||||
{
|
||||
namespace N2
|
||||
{
|
||||
namespace N3
|
||||
{
|
||||
namespace N4
|
||||
{
|
||||
static int n4static = 400;
|
||||
|
||||
struct S4
|
||||
{
|
||||
static int s4static;
|
||||
int s4int_;
|
||||
S4 () : s4int_ (4) {};
|
||||
~S4 () { --s4static; }
|
||||
|
||||
int get_var () { return s4int_; }
|
||||
static int get_svar () { return s4static; }
|
||||
};
|
||||
int S4::s4static = 40;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
using namespace N1::N2::N3::N4;
|
||||
|
||||
S4 s4;
|
||||
int var = 1234;
|
||||
|
||||
var += s4.s4int_; /* break here */
|
||||
return S4::get_svar () - 10 * s4.get_var ();
|
||||
}
|
51
gdb/testsuite/gdb.compile/compile-cplus-namespace.exp
Normal file
51
gdb/testsuite/gdb.compile/compile-cplus-namespace.exp
Normal file
@ -0,0 +1,51 @@
|
||||
# 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 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 "N1::N2::N3::N4::n4static" 400
|
||||
CompileExpression::test "N1::N2::N3::N4::S4::s4static" 40
|
||||
CompileExpression::test "s4.s4int_" 4
|
||||
CompileExpression::test "N1::N2::N3::N4::S4::get_svar ()" 40
|
||||
CompileExpression::test "s4.get_var ()" 4
|
58
gdb/testsuite/gdb.compile/compile-cplus-nested.cc
Normal file
58
gdb/testsuite/gdb.compile/compile-cplus-nested.cc
Normal file
@ -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/>. */
|
||||
|
||||
class A
|
||||
{
|
||||
public:
|
||||
A () : a_ (1) {}
|
||||
int get ();
|
||||
|
||||
protected:
|
||||
int a_;
|
||||
|
||||
private:
|
||||
/* It is important to not /not/ use the nested class definition in A.
|
||||
This exercises a different path through the code. */
|
||||
struct Inner1
|
||||
{
|
||||
int a_;
|
||||
Inner1 () : a_ (2) {}
|
||||
|
||||
struct Inner2
|
||||
{
|
||||
int a_;
|
||||
Inner2 () : a_ (3) {}
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
int
|
||||
A::get ()
|
||||
{
|
||||
A::Inner1 i1;
|
||||
A::Inner1::Inner2 i2;
|
||||
|
||||
return i1.a_ + i2.a_; // break here
|
||||
}
|
||||
|
||||
int var = 1234;
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
A a;
|
||||
|
||||
return a.get ();
|
||||
}
|
53
gdb/testsuite/gdb.compile/compile-cplus-nested.exp
Normal file
53
gdb/testsuite/gdb.compile/compile-cplus-nested.exp
Normal file
@ -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/>.
|
||||
|
||||
# Nested type 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 "i1.a_" 2
|
||||
CompileExpression::test "i2.a_" 3
|
||||
CompileExpression::test "A::Inner1 *i1p = &i1; var = i1p->a_;" 2 -explicit
|
||||
CompileExpression::test "A::Inner1::Inner2 *i2p = &i2; var = i2p->a_;" 3 \
|
||||
-explicit
|
||||
CompileExpression::test "A::Inner1 &r1 = i1; var = r1.a_;" 2 -explicit
|
||||
CompileExpression::test "A::Inner1::Inner2 &r2 = i2; var = r2.a_;" 3 -explicit
|
32
gdb/testsuite/gdb.compile/compile-cplus-print.c
Normal file
32
gdb/testsuite/gdb.compile/compile-cplus-print.c
Normal file
@ -0,0 +1,32 @@
|
||||
/* This testcase is part of GDB, the GNU debugger.
|
||||
|
||||
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/>. */
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
int varint = 10;
|
||||
int vararray[] = { 1, 2, 3, 4, 5 };
|
||||
int *vararrayp = vararray;
|
||||
struct object
|
||||
{
|
||||
int field;
|
||||
} varobject = { 1 };
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return 0;
|
||||
}
|
79
gdb/testsuite/gdb.compile/compile-cplus-print.exp
Normal file
79
gdb/testsuite/gdb.compile/compile-cplus-print.exp
Normal file
@ -0,0 +1,79 @@
|
||||
# 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/>.
|
||||
|
||||
load_lib compile-support.exp
|
||||
|
||||
standard_testfile
|
||||
|
||||
get_compiler_info
|
||||
set options {}
|
||||
if [test_compiler_info gcc*] {
|
||||
lappend options additional_flags=-g3
|
||||
lappend options additional_flags=-std=gnu++11
|
||||
lappend options c++
|
||||
}
|
||||
|
||||
set srcfilesoptions [list ${srcfile} ${options}]
|
||||
|
||||
if { [eval build_executable_from_specs ${testfile}.exp $testfile {$options} ${srcfilesoptions}] } {
|
||||
return -1
|
||||
}
|
||||
|
||||
clean_restart ${testfile}
|
||||
|
||||
if {[skip_compile_feature_tests]} {
|
||||
untested "compile command not supported (could not find libcc1 shared library?)"
|
||||
return -1
|
||||
}
|
||||
|
||||
gdb_test_no_output "set language c++" \
|
||||
"Set language to C++"
|
||||
|
||||
if ![runto_main] {
|
||||
return -1
|
||||
}
|
||||
|
||||
gdb_test "compile print varint" " = 10"
|
||||
gdb_test "compile print vararray" " = \\{1, 2, 3, 4, 5\\}"
|
||||
|
||||
setup_kfail compile/23586 *-*-*
|
||||
gdb_test "compile print main" " = \\{int \\(void\\)\\} 0x\[0-9a-f\]+"
|
||||
|
||||
setup_kfail compile/23587 *-*-*
|
||||
set test "compile print *vararray@3"
|
||||
gdb_test_multiple $test $test {
|
||||
-re " = \\{1, 2, 3\\}\r\n$gdb_prompt $" {
|
||||
pass $test
|
||||
}
|
||||
-re "warning: .*All references to this method will be undefined\.\r\n" {
|
||||
exp_continue
|
||||
}
|
||||
}
|
||||
|
||||
setup_kfail compile/23587 *-*-*
|
||||
set test "compile print *vararrayp@3"
|
||||
gdb_test_multiple $test $test {
|
||||
-re " = \\{1, 2, 3\\}\r\n$gdb_prompt $" {
|
||||
pass $test
|
||||
}
|
||||
-re "warning: .*All references to this method will be undefined\.\r\n" {
|
||||
exp_continue
|
||||
}
|
||||
}
|
||||
|
||||
gdb_test "compile print/x 256" " = 0x100"
|
||||
gdb_test {print $} " = 256"
|
||||
|
||||
gdb_test "compile print varobject" { = {field = 1}}
|
54
gdb/testsuite/gdb.compile/compile-cplus-virtual.cc
Normal file
54
gdb/testsuite/gdb.compile/compile-cplus-virtual.cc
Normal file
@ -0,0 +1,54 @@
|
||||
/* 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
|
||||
{
|
||||
virtual int doit () { return 1; }
|
||||
virtual int doit3 () { return -3; }
|
||||
virtual int doit2 () = 0;
|
||||
};
|
||||
|
||||
struct B : virtual A
|
||||
{
|
||||
int doit () { return 2; }
|
||||
int doit2 () { return 22; }
|
||||
};
|
||||
|
||||
struct C : virtual A
|
||||
{
|
||||
int doit () { return 3; }
|
||||
int doit2 () { return 33; }
|
||||
};
|
||||
|
||||
struct D : B, C
|
||||
{
|
||||
int doit () { return 4; }
|
||||
int doit2 () { return 44; }
|
||||
};
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
int var = 1234;
|
||||
B b;
|
||||
C c;
|
||||
D d;
|
||||
A *ap = &d;
|
||||
|
||||
var = (b.doit () + c.doit () + d.doit () + d.doit3 ()
|
||||
+ ap->doit () + ap->doit2 ()); // break here
|
||||
|
||||
return 0;
|
||||
}
|
71
gdb/testsuite/gdb.compile/compile-cplus-virtual.exp
Normal file
71
gdb/testsuite/gdb.compile/compile-cplus-virtual.exp
Normal file
@ -0,0 +1,71 @@
|
||||
# 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/>.
|
||||
|
||||
# Virtual method/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 "b.doit ()" 2
|
||||
CompileExpression::test "c.doit ()" 3
|
||||
CompileExpression::test "d.doit ()" 4
|
||||
CompileExpression::test "ap->doit ()" 4
|
||||
CompileExpression::test "b.doit2 ()" 22
|
||||
CompileExpression::test "c.doit2 ()" 33
|
||||
CompileExpression::test "d.doit2 ()" 44
|
||||
CompileExpression::test "ap->doit2 ()" 44
|
||||
CompileExpression::test "b.doit3 ()" -3
|
||||
CompileExpression::test "c.doit3 ()" -3
|
||||
CompileExpression::test "d.doit3 ()" -3
|
||||
|
||||
# These two tests are "disabled". They represent new/future features.
|
||||
# CompileExpression::test \
|
||||
[concat "struct ABC {int doit2() { return 3333; }} abc;" \
|
||||
"var = abc.doit2()"] \
|
||||
3333 -explicit
|
||||
# CompileExpression::test \
|
||||
[concat "struct ABC : A {int doit2() { return 4444; }} abc;" \
|
||||
"var = abc.doit2()"] \
|
||||
4444 -explicit
|
||||
|
||||
# Test some error conditions
|
||||
gdb_test "compile code A a;" \
|
||||
".*cannot declare variable .a. to be of abstract type.*Compilation failed."
|
241
gdb/testsuite/gdb.compile/compile-cplus.c
Normal file
241
gdb/testsuite/gdb.compile/compile-cplus.c
Normal file
@ -0,0 +1,241 @@
|
||||
/* This testcase is part of GDB, the GNU debugger.
|
||||
|
||||
Copyright 2014-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/>. */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <iostream>
|
||||
|
||||
#define SOME_MACRO 23
|
||||
#define ARG_MACRO(X, Y) ((X) + (Y) - 1)
|
||||
|
||||
|
||||
enum enum_type {
|
||||
ONE = 1,
|
||||
TWO = 2
|
||||
};
|
||||
|
||||
typedef int v4 __attribute__ ((vector_size (16)));
|
||||
|
||||
union union_type;
|
||||
|
||||
struct struct_type {
|
||||
char charfield;
|
||||
unsigned char ucharfield;
|
||||
short shortfield;
|
||||
unsigned short ushortfield;
|
||||
int intfield;
|
||||
unsigned int uintfield;
|
||||
unsigned int bitfield : 3;
|
||||
long longfield;
|
||||
unsigned long ulongfield;
|
||||
enum enum_type enumfield;
|
||||
float floatfield;
|
||||
double doublefield;
|
||||
const union union_type *ptrfield;
|
||||
struct struct_type *selffield;
|
||||
int arrayfield[5];
|
||||
_Complex double complexfield;
|
||||
_Bool boolfield;
|
||||
v4 vectorfield;
|
||||
};
|
||||
|
||||
typedef int inttypedef;
|
||||
|
||||
union union_type {
|
||||
int intfield;
|
||||
inttypedef typedeffield;
|
||||
};
|
||||
|
||||
/* volatile provides some coverage of the conversion code. */
|
||||
volatile struct struct_type struct_object;
|
||||
|
||||
union union_type union_object;
|
||||
|
||||
|
||||
enum ulonger_enum_type {
|
||||
REALLY_MINUS_1 = -1UL,
|
||||
};
|
||||
|
||||
enum ulonger_enum_type ulonger;
|
||||
|
||||
enum longer_enum_type {
|
||||
MINUS_1 = -1,
|
||||
FORCE_TO_LONG = 1L << ((8 * sizeof (long)) - 2)
|
||||
};
|
||||
|
||||
enum longer_enum_type longer;
|
||||
|
||||
int globalvar = 10;
|
||||
|
||||
static void
|
||||
func_static (int addend)
|
||||
{
|
||||
globalvar += addend;
|
||||
}
|
||||
|
||||
void
|
||||
func_global (int subtrahend)
|
||||
{
|
||||
globalvar -= subtrahend;
|
||||
}
|
||||
|
||||
void
|
||||
no_args_or_locals ()
|
||||
{
|
||||
/* no_args_or_locals breakpoint */
|
||||
}
|
||||
|
||||
int *intptr;
|
||||
int globalshadow = 10;
|
||||
static int staticshadow = 20;
|
||||
int externed = 7;
|
||||
|
||||
class Base
|
||||
{
|
||||
virtual int pure_virt () = 0;
|
||||
public:
|
||||
int return_value () {return a;}
|
||||
private:
|
||||
int a = 1;
|
||||
int b = 2;
|
||||
};
|
||||
|
||||
class Base2
|
||||
{
|
||||
virtual int non_pure () {return 84;}
|
||||
public:
|
||||
int return_value () {return b;}
|
||||
private:
|
||||
int a = 3;
|
||||
int b = 4;
|
||||
};
|
||||
|
||||
class Base3
|
||||
{
|
||||
public:
|
||||
int return_value () {return b;}
|
||||
private:
|
||||
int b = 5;
|
||||
};
|
||||
|
||||
|
||||
class Multiple : public Base, public Base2
|
||||
{
|
||||
int pure_virt ()
|
||||
{
|
||||
int a = Base::return_value ();
|
||||
return a + 42;
|
||||
}
|
||||
};
|
||||
//struct foo { foo(); virtual ~foo(); }; struct bar : virtual foo { bar(); ~bar(); }; struct baz : bar {}; bar::bar() {} bar::~bar() {} bar t; baz u;
|
||||
struct VirtualOnly
|
||||
{
|
||||
VirtualOnly();
|
||||
virtual ~VirtualOnly()=0;
|
||||
};
|
||||
|
||||
VirtualOnly::VirtualOnly ()
|
||||
{
|
||||
}
|
||||
|
||||
VirtualOnly::~VirtualOnly ()
|
||||
{
|
||||
}
|
||||
|
||||
struct VirtualBase : virtual VirtualOnly
|
||||
{
|
||||
int z = 22;
|
||||
VirtualBase ();
|
||||
~VirtualBase ();
|
||||
};
|
||||
|
||||
struct VirtualBase2 : VirtualBase {};
|
||||
|
||||
VirtualBase::VirtualBase ()
|
||||
{
|
||||
z = 24;
|
||||
}
|
||||
|
||||
VirtualBase::~VirtualBase ()
|
||||
{
|
||||
z = 22;
|
||||
}
|
||||
|
||||
class Foo
|
||||
{
|
||||
int var;
|
||||
static const int public_static_var = 12;
|
||||
|
||||
private:
|
||||
int private_var = 0;
|
||||
int private_method ();
|
||||
|
||||
public:
|
||||
int public_var = 0;
|
||||
int public_method ();
|
||||
void set_private_var (int);
|
||||
};
|
||||
|
||||
void Foo::set_private_var (int i)
|
||||
{
|
||||
private_var = i;
|
||||
}
|
||||
|
||||
int Foo::private_method ()
|
||||
{
|
||||
return private_var;
|
||||
}
|
||||
|
||||
int Foo::public_method ()
|
||||
{
|
||||
return public_var;
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
int localvar = 50;
|
||||
int shadowed = 51;
|
||||
int bound = 3;
|
||||
int unresolved = 10;
|
||||
int globalshadow = 100;
|
||||
int staticshadow = 200;
|
||||
int externed = 9;
|
||||
int f = 0;
|
||||
int var = 0;
|
||||
Foo foovar;
|
||||
Multiple *multivar = new Multiple;
|
||||
VirtualBase vbase;
|
||||
VirtualBase2 vbase2;
|
||||
static int static_local = 77000;
|
||||
|
||||
foovar.public_var = 42;
|
||||
foovar.set_private_var (42);
|
||||
multivar->Base2::return_value();
|
||||
{
|
||||
int another_local = 7;
|
||||
int shadowed = 52;
|
||||
extern int unresolved;
|
||||
extern int externed;
|
||||
|
||||
int vla[bound];
|
||||
|
||||
func_static (0); /* break-here */
|
||||
no_args_or_locals ();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
347
gdb/testsuite/gdb.compile/compile-cplus.exp
Normal file
347
gdb/testsuite/gdb.compile/compile-cplus.exp
Normal file
@ -0,0 +1,347 @@
|
||||
# Copyright 2014-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/>.
|
||||
|
||||
load_lib compile-support.exp
|
||||
|
||||
standard_testfile .c compile-shlib.c compile-constvar.S compile-nodebug.c
|
||||
|
||||
get_compiler_info
|
||||
set options {}
|
||||
if [test_compiler_info gcc*] {
|
||||
lappend options additional_flags=-g3
|
||||
lappend options additional_flags=-std=gnu++11
|
||||
lappend options c++
|
||||
}
|
||||
|
||||
if { ![istarget x86_64-*-* ] || ![is_lp64_target] } {
|
||||
verbose "Skipping x86_64 LOC_CONST test."
|
||||
set srcfile3 ""
|
||||
}
|
||||
|
||||
set srcfilesoptions [list ${srcfile} ${options}]
|
||||
if { $srcfile3 != "" } {
|
||||
lappend srcfilesoptions $srcfile3 ${options}
|
||||
}
|
||||
lappend srcfilesoptions $srcfile4 "nodebug c++"
|
||||
if { [eval build_executable_from_specs ${testfile}.exp $testfile {$options} ${srcfilesoptions}] } {
|
||||
return -1
|
||||
}
|
||||
|
||||
clean_restart ${testfile}
|
||||
|
||||
#
|
||||
# FIXME: Right now, for C++ we just duplicate the C tests, but force
|
||||
# the language to C++
|
||||
#
|
||||
gdb_test_no_output "set language c++" \
|
||||
"Set language to C++"
|
||||
|
||||
if ![runto_main] {
|
||||
return -1
|
||||
}
|
||||
|
||||
if {[skip_compile_feature_tests]} {
|
||||
untested "compile command not supported (could not find libcc1 shared library?)"
|
||||
return -1
|
||||
}
|
||||
|
||||
#
|
||||
# Test delimiter for code, and arguments.
|
||||
#
|
||||
|
||||
|
||||
gdb_test_no_output "compile code globalvar = SOME_MACRO;" \
|
||||
"set variable from macro"
|
||||
gdb_test "p globalvar" " = 23" "expect 23"
|
||||
|
||||
gdb_test_no_output "compile code globalvar = ARG_MACRO(0, 0);" \
|
||||
"set variable from function-like macro"
|
||||
gdb_test "p globalvar" " = -1" "expect -1"
|
||||
|
||||
gdb_test_no_output "compile code globalvar = 42;" "set variable"
|
||||
gdb_test "p globalvar" " = 42" "expect 42"
|
||||
|
||||
gdb_test_no_output "compile code globalvar *= 2;" "modify variable"
|
||||
gdb_test "p globalvar" " = 84" "expect 84"
|
||||
|
||||
gdb_test_no_output "compile file -r ${srcdir}/${subdir}/${testfile}-mod.c" \
|
||||
"use external source file"
|
||||
gdb_test "p globalvar" " = 7" "expect 7"
|
||||
|
||||
gdb_test_no_output "compile code func_static (2);" "call static function"
|
||||
gdb_test "p globalvar" " = 9" "expect 9"
|
||||
gdb_test_no_output "compile code func_global (1);" "call global function"
|
||||
gdb_test "p globalvar" " = 8" "expect 8"
|
||||
|
||||
gdb_test_no_output \
|
||||
"compile code globalvar = (sizeof (ulonger) == sizeof (long))" \
|
||||
"compute size of ulonger"
|
||||
gdb_test "p globalvar" " = 1" "check size of ulonger"
|
||||
gdb_test_no_output \
|
||||
"compile code globalvar = (sizeof (longer) == sizeof (long))" \
|
||||
"compute size of longer"
|
||||
gdb_test "p globalvar" " = 1" "check size of longer"
|
||||
gdb_test_no_output "compile code globalvar = MINUS_1"
|
||||
gdb_test "p globalvar" " = -1" "check MINUS_1"
|
||||
|
||||
gdb_test_no_output "compile code globalvar = static_local"
|
||||
gdb_test "p globalvar" " = 77000" "check static_local"
|
||||
|
||||
gdb_test_no_output \
|
||||
"compile code static int staticvar = 5; intptr = &staticvar" \
|
||||
"do not keep jit in memory"
|
||||
gdb_test "p *intptr" "Cannot access memory at address 0x\[0-9a-f\]+" \
|
||||
"expect 5"
|
||||
|
||||
gdb_test "compile code func_doesnotexist ();" "error: \'func_doesnotexist\' was not declared in this scope.*"
|
||||
|
||||
gdb_test "compile code *(volatile int *) 0 = 0;" \
|
||||
"The program being debugged was signaled while in a function called from GDB\\.\r\nGDB remains in the frame where the signal was received\\.\r\n.*" \
|
||||
"compile code segfault first"
|
||||
gdb_test "bt" \
|
||||
"\r\n#0 \[^\r\n\]* in _gdb_expr \[^\r\n\]*\r\n#1 <function called from gdb>\r\n.*"
|
||||
|
||||
set test "p/x \$pc"
|
||||
set infcall_pc 0
|
||||
gdb_test_multiple $test $test {
|
||||
-re " = (0x\[0-9a-f\]+)\r\n$gdb_prompt $" {
|
||||
set infcall_pc $expect_out(1,string)
|
||||
pass $test
|
||||
}
|
||||
}
|
||||
|
||||
gdb_test "info sym $infcall_pc" "\r\n_gdb_expr.*" "info sym found"
|
||||
gdb_test "return" "\r\n#0 main .*" "return" \
|
||||
"Make _gdb_expr\\(__gdb_regs\\*\\) return now\\? \\(y or n\\) " "y"
|
||||
gdb_test "info sym $infcall_pc" "\r\nNo symbol matches .*" "info sym not found"
|
||||
|
||||
gdb_test_no_output "set unwindonsignal on"
|
||||
gdb_test "compile code *(volatile int *) 0 = 0;" \
|
||||
"The program being debugged was signaled while in a function called from GDB\\.\r\nGDB has restored the context to what it was before the call\\.\r\n.*" \
|
||||
"compile code segfault second"
|
||||
|
||||
gdb_breakpoint [gdb_get_line_number "break-here"]
|
||||
gdb_continue_to_breakpoint "break-here" ".* break-here .*"
|
||||
|
||||
# C++ Specific tests.
|
||||
## Public methods and members
|
||||
|
||||
gdb_test "print foovar.public_var" "42" \
|
||||
"Test compile code foovar.public_var = 42 setting."
|
||||
gdb_test_no_output "compile code foovar.public_var = 43;" \
|
||||
"set foobar.public_var to 43"
|
||||
gdb_test "print foovar.public_var" "43" \
|
||||
"Test compile code foovar.public_var = 43 setting."
|
||||
gdb_test "print foovar.public_method ()" "43" \
|
||||
"Test compile code foovar.public_method = 43 setting."
|
||||
|
||||
## Private methods and members
|
||||
gdb_test_no_output "compile code foovar.set_private_var (84);" \
|
||||
"Call class function to set private_var"
|
||||
gdb_test "print foovar.private_var" "84" \
|
||||
"Test compile code foovar.set_private_var = 84 setting."
|
||||
gdb_test_no_output "compile code foovar.private_var = 85" \
|
||||
"Directly set a private member in GDB compile5"
|
||||
gdb_test "print foovar.private_var" "85" \
|
||||
"Test compile code foovar.set_private_var = 85 setting."
|
||||
|
||||
## Simple inheritance
|
||||
CompileExpression::new "var"
|
||||
CompileExpression::test "class Baz: public Foo {public: int z = 12;}; Baz bazvar; bazvar.z = 24; var = bazvar.z" 24 -explicit
|
||||
## Multiple inheritance
|
||||
CompileExpression::test "class MI: public Base, public Base2 {int pure_virt () {return 42;}}; MI MIVar; var = MIVar.pure_virt();" 42 -explicit
|
||||
CompileExpression::test "class MI: public Base, public Base2 {int pure_virt () {return Base::return_value() + 42;}}; MI MIVar; var = MIVar.pure_virt();" 43 -explicit
|
||||
CompileExpression::test "class Base3 {public: int z = 99;}; class MI: public Base, public Base3 {int pure_virt () {return Base3::z + 42;}}; MI MIVar; var = MIVar.pure_virt();" 141 -explicit
|
||||
|
||||
gdb_test "p localvar" " = 50" "expect localvar 50"
|
||||
|
||||
gdb_test_no_output "compile code localvar = 12;" "set localvar"
|
||||
gdb_test "p localvar" " = 12" "expect 12"
|
||||
|
||||
gdb_test_no_output "compile code localvar *= 2;" "modify localvar"
|
||||
gdb_test "p localvar" " = 24" "expect 24"
|
||||
|
||||
gdb_test_no_output "compile code localvar = shadowed" \
|
||||
"test shadowing"
|
||||
gdb_test "p localvar" " = 52" "expect 52"
|
||||
|
||||
gdb_test_no_output "compile code localvar = externed"
|
||||
gdb_test "p localvar" " = 7" "test extern in inner scope"
|
||||
|
||||
gdb_test_no_output "compile code vla\[2\] = 7"
|
||||
gdb_test "p vla\[2\]" " = 7"
|
||||
gdb_test_no_output \
|
||||
"compile code localvar = (sizeof (vla) == bound * sizeof (vla\[0\]))"
|
||||
gdb_test "p localvar" " = 1"
|
||||
|
||||
#
|
||||
# Test setting fields and also many different types.
|
||||
#
|
||||
|
||||
gdb_test_no_output "compile code struct_object.selffield = (struct_type*)&struct_object"
|
||||
gdb_test "print struct_object.selffield == &struct_object" " = true"
|
||||
|
||||
gdb_test_no_output "compile code struct_object.charfield = 1"
|
||||
gdb_test "print struct_object.charfield" " = 1 '\\\\001'"
|
||||
gdb_test_no_output "compile code struct_object.ucharfield = 1"
|
||||
gdb_test "print struct_object.ucharfield" " = 1 '\\\\001'"
|
||||
|
||||
foreach {field value} {
|
||||
shortfield -5
|
||||
ushortfield 5
|
||||
intfield -7
|
||||
uintfield 7
|
||||
bitfield 2
|
||||
longfield -9
|
||||
ulongfield 9
|
||||
enumfield ONE
|
||||
floatfield 1
|
||||
doublefield 2
|
||||
} {
|
||||
gdb_test_no_output "compile code struct_object.$field = $value"
|
||||
gdb_test "print struct_object.$field" " = $value"
|
||||
}
|
||||
|
||||
gdb_test_no_output "compile code struct_object.arrayfield\[2\] = 7"
|
||||
gdb_test "print struct_object.arrayfield" \
|
||||
" = \\{0, 0, 7, 0, 0\\}"
|
||||
|
||||
gdb_test_no_output "compile code struct_object.complexfield = 7 + 5i"
|
||||
gdb_test "print struct_object.complexfield" " = 7 \\+ 5 \\* I"
|
||||
|
||||
gdb_test_no_output "compile code struct_object.boolfield = 1"
|
||||
gdb_test "print struct_object.boolfield" " = true"
|
||||
|
||||
gdb_test_no_output "compile code struct_object.vectorfield\[2\] = 7"
|
||||
gdb_test "print struct_object.vectorfield" \
|
||||
" = \\{0, 0, 7, 0\\}"
|
||||
|
||||
gdb_test_no_output "compile code union_object.typedeffield = 7"
|
||||
gdb_test "print union_object.typedeffield" " = 7"
|
||||
gdb_test "print union_object.intfield" " = 7"
|
||||
|
||||
|
||||
# LOC_UNRESOLVED tests.
|
||||
|
||||
gdb_test "print unresolved" " = 20"
|
||||
gdb_test "compile code globalvar = unresolved;"
|
||||
gdb_test "print globalvar" " = 20" "print unresolved value"
|
||||
|
||||
# Test shadowing with global and static variables.
|
||||
|
||||
gdb_test_no_output "compile code globalshadow += 1;"
|
||||
gdb_test "print globalshadow" " = 101"
|
||||
gdb_test_no_output "compile code extern int globalshadow; globalshadow += 5;"
|
||||
gdb_test "print 'compile-cplus.c'::globalshadow" " = 15"
|
||||
gdb_test "print globalshadow" " = 101" "print globalshadow second time"
|
||||
gdb_test_no_output "compile code staticshadow += 2;"
|
||||
gdb_test "print staticshadow" " = 202"
|
||||
# "extern int staticshadow;" cannot access static variable.
|
||||
|
||||
# Raw code cannot refer to locals.
|
||||
# As it references global variable we need the #pragma.
|
||||
# For #pragma we need multiline input.
|
||||
gdb_test_multiple "compile code -r" "compile code -r multiline 1" { -re "\r\n>$" {} }
|
||||
gdb_test_multiple "void _gdb_expr(void) {" "compile code -r multiline 2" { -re "\r\n>$" {} }
|
||||
gdb_test_multiple "#pragma GCC push_user_expression" "compile code -r multiline 3" { -re "\r\n>$" {} }
|
||||
gdb_test_multiple " globalshadow = 77000;" "compile code -r multiline 4" { -re "\r\n>$" {} }
|
||||
gdb_test_multiple "#pragma GCC pop_user_expression" "compile code -r multiline 5" { -re "\r\n>$" {} }
|
||||
gdb_test_multiple "}" "compile code -r multiline 6" { -re "\r\n>$" {} }
|
||||
gdb_test_no_output "end" "compile code -r multiline 7"
|
||||
gdb_test "print 'compile-cplus.c'::globalshadow" " = 77000" \
|
||||
"check globalshadow with -r"
|
||||
|
||||
# Test GOT vs. resolving jit function pointers.
|
||||
|
||||
gdb_test_no_output "compile -raw -- extern \"C\" void abort(); int func(){return 21;} void _gdb_expr(){int (*funcp)()=func; if (funcp()!=21) abort();}" \
|
||||
"pointer to jit function"
|
||||
|
||||
#
|
||||
# Test the case where the registers structure would not normally have
|
||||
# any fields.
|
||||
#
|
||||
|
||||
gdb_breakpoint [gdb_get_line_number "no_args_or_locals breakpoint"]
|
||||
gdb_continue_to_breakpoint "no_args_or_locals"
|
||||
|
||||
gdb_test_no_output "compile code globalvar = 77;" "set variable to 77"
|
||||
gdb_test "p globalvar" " = 77" "expect 77"
|
||||
|
||||
|
||||
# Test reference to minimal_symbol, not (full) symbol.
|
||||
|
||||
setup_kfail compile/23585 *-*-*
|
||||
gdb_test_no_output "compile code globalvar = func_nodebug (75);" \
|
||||
"call func_nodebug"
|
||||
|
||||
setup_kfail compile/23585 *-*-*
|
||||
gdb_test "p globalvar" " = -75" "expect -75"
|
||||
|
||||
setup_kfail compile/23585 *-*-*
|
||||
gdb_test_no_output \
|
||||
"compile code int (*funcp) (int) = (int(*)(int))func_nodebug; globalvar = funcp (76);" \
|
||||
"call func_nodebug indirectly"
|
||||
setup_kfail compile/23585 *-*-*
|
||||
gdb_test "p globalvar" " = -76" "expect -76"
|
||||
|
||||
|
||||
# Test compiled module memory protection.
|
||||
|
||||
gdb_test_no_output "set debug compile on"
|
||||
gdb_test "compile code static const int readonly = 1; *(int *) &readonly = 2;" \
|
||||
"The program being debugged was signaled while in a function called from GDB\\.\r\nGDB has restored the context to what it was before the call\\.\r\n.*"
|
||||
gdb_test_no_output "set debug compile off"
|
||||
|
||||
|
||||
#
|
||||
# Some simple coverage tests.
|
||||
#
|
||||
|
||||
gdb_test "show debug compile" "Compile debugging is .*"
|
||||
gdb_test "show compile-args" \
|
||||
"Compile command command-line arguments are .*"
|
||||
gdb_test "compile code -z" "Unknown argument.*"
|
||||
|
||||
gdb_test "set lang rust" \
|
||||
"Warning: the current language does not match this frame."
|
||||
gdb_test "compile code globalvar" "No compiler support for language rust\."
|
||||
gdb_test_no_output "set lang auto"
|
||||
|
||||
gdb_test_no_output "compile code union union_type newdecl_u"
|
||||
gdb_test_no_output "compile code struct struct_type newdecl_s"
|
||||
gdb_test_no_output "compile code inttypedef newdecl_i"
|
||||
|
||||
gdb_test "compile file" \
|
||||
"You must provide a filename for this command.*" \
|
||||
"Test compile file without a filename"
|
||||
gdb_test "compile file -r" \
|
||||
"You must provide a filename with the raw option set.*" \
|
||||
"Test compile file and raw option without a filename"
|
||||
gdb_test "compile file -z" \
|
||||
"Unknown argument.*" \
|
||||
"Test compile file with unknown argument"
|
||||
|
||||
|
||||
# LOC_CONST tests.
|
||||
|
||||
if { $srcfile3 != "" } {
|
||||
gdb_test "p constvar" " = 3"
|
||||
gdb_test "info addr constvar" {Symbol "constvar" is constant\.}
|
||||
|
||||
gdb_test_no_output "compile code globalvar = constvar;"
|
||||
gdb_test "print globalvar" " = 3" "print constvar value"
|
||||
} else {
|
||||
untested "print constvar value"
|
||||
}
|
227
gdb/testsuite/lib/compile-support.exp
Normal file
227
gdb/testsuite/lib/compile-support.exp
Normal file
@ -0,0 +1,227 @@
|
||||
# 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/>.
|
||||
|
||||
# Generic/oft used support routines for testing GDB's compile feature.
|
||||
|
||||
# Return 1 if we should skip tests of the "compile" feature.
|
||||
# This must be invoked after the inferior has been started.
|
||||
|
||||
proc skip_compile_feature_tests {} {
|
||||
global gdb_prompt
|
||||
|
||||
set result 0
|
||||
gdb_test_multiple "compile code -- ;" "check for working compile command" {
|
||||
"Could not load libcc1.*\r\n$gdb_prompt $" {
|
||||
set result 1
|
||||
}
|
||||
-re "Command not supported on this host\\..*\r\n$gdb_prompt $" {
|
||||
set result 1
|
||||
}
|
||||
-re "\r\n$gdb_prompt $" {
|
||||
}
|
||||
}
|
||||
return $result
|
||||
}
|
||||
|
||||
# This namespace provides some convenience functions for running
|
||||
# "compile code" and "compile print" tests.
|
||||
#
|
||||
# Exported functions are defined inline below.
|
||||
#
|
||||
# General usage:
|
||||
#
|
||||
# Start a new session, noting that the variable "var" will be used for
|
||||
# "compile code" expressions. This variable /must/ exist in the stopped
|
||||
# location.
|
||||
#
|
||||
# CompileExpression::new "var"
|
||||
#
|
||||
# Test the implicit expression "foo;" with result/value 3.
|
||||
# CompileExpression::test "foo" 3
|
||||
# ---> Runs the following tests (name of tests ignored for illustration)
|
||||
# gdb_test_no_output "compile code var = foo"
|
||||
# gdb_test "p var" "= 3"
|
||||
# gdb_test "compile print foo;" "= 3"
|
||||
#
|
||||
# Test the explicit expression "a = function (3); var = a;" with the result 21.
|
||||
# CompileExpression::test "a = function (3); var = a;" 21 -explicit
|
||||
# ---> Runs the following tests (name of tests ignored for illustration)
|
||||
# gdb_test_no_output "compile code a = function (3); var = a;"
|
||||
# gdb_test "p var" "= 21"
|
||||
#
|
||||
# Additional option flags may be passed to test to control the behavior
|
||||
# of the test harness:
|
||||
#
|
||||
# Pass -explicit to specify that the test uses an explicit expression,
|
||||
# one which sets the value of the variable (see above). Only the code test
|
||||
# will be run.
|
||||
#
|
||||
# Pass -value and/or -print to indicate that the value and/or print steps
|
||||
# will optionally fail. Specify "xfail" or "kfail" to indicate how
|
||||
# particular step will fail. These may be followed by any accepted DejaGNU
|
||||
# parameters such as architecture and bug#. [See examples below.]
|
||||
#
|
||||
# To specify that the compile (and consequently print and value tests) is
|
||||
# expected to kfail/xfail, use -kfail or -xfail with any appropriate
|
||||
# DejaGNU parameters. Both options override -print and -value.
|
||||
# [-xfail is given precedence over -kfail should both be given.]
|
||||
#
|
||||
# -value is used when a "code" test is run, specifying that the "compile
|
||||
# code" and "print VAR" steps will fail in the prescribed manner.
|
||||
# [If the print step generates a PASS, the test is considered invalidly
|
||||
# written. VAR's value should /always/ be invalidated before a test is
|
||||
# run.]
|
||||
#
|
||||
# -print is used to specify that an expression will fail in the prescribed
|
||||
# manner when "print" test is executed.
|
||||
#
|
||||
# Pass "-name NAME" to set an optional test name. If not specified,
|
||||
# the harness will use test names such as "compile code EXPR" and
|
||||
# "result of compile code EXPR".
|
||||
#
|
||||
# Pass "-noprint" or "-nocode" to suppress print or code tests, respectively,
|
||||
# This is useful when the expression being tested modifies the object
|
||||
# being tested, e.g., "a++".
|
||||
#
|
||||
# These options must be passed LAST to CompileExpression::test.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# Both "code" and "print" tests are expected to xfail:
|
||||
# CompileExpression add_imp "foo" 3 -compile {xfail *-*-*} -print {xfail *-*-*}
|
||||
#
|
||||
# The "print $VARIABLE" portion of the "code" test is expected to kfail
|
||||
# (the actual "compile code" GDB command will succeed), but the "print"
|
||||
# test should pass:
|
||||
# CompileExpression add_imp "foo" 3 -value {kfail *-*-* gdb/1234}
|
||||
|
||||
namespace eval ::CompileExpression {
|
||||
|
||||
# The variable name to check testing results. This variable
|
||||
# must be in scope when tests are run.
|
||||
variable varName_ {}
|
||||
|
||||
# Start a new expression list. VARNAME is the name of the variable
|
||||
# that will be printed to check if the result of the test was
|
||||
# successful.
|
||||
proc new {varname} {
|
||||
variable varName_
|
||||
|
||||
set varName_ $varname
|
||||
}
|
||||
|
||||
# Test an expression.
|
||||
#
|
||||
# See the preamble for a list of valid optional arguments.
|
||||
#
|
||||
# Implicit expressions will be sent to GDB in the form
|
||||
# "$varName = $EXP". "p $varName" will be used to decide the pass
|
||||
# or fail status of the test.
|
||||
#
|
||||
# Explicit expressions will be sent to GDB as-is and tested using only
|
||||
# "compile code". The expression should set the value of the variable
|
||||
# $varName, which is then printed to determine whether the test passed
|
||||
# or failed.
|
||||
#
|
||||
# Unlike explicit expressions, implicit expressions are tested with both
|
||||
# "compile print" and "compile code".
|
||||
|
||||
proc test {exp result args} {
|
||||
parse_args {{value {"" ""}} {print {"" ""}} {name ""}
|
||||
{noprint} {nocode} {explicit} {xfail {"" ""}} {kfail {"" ""}}}
|
||||
|
||||
if {[lindex $xfail 0] != ""} {
|
||||
set l "xfail $xfail"
|
||||
} elseif {[lindex $kfail 0] != ""} {
|
||||
set l "kfail $kfail"
|
||||
} else {
|
||||
set l ""
|
||||
set compile {"" ""}
|
||||
}
|
||||
if {$l != ""} {
|
||||
set compile $l
|
||||
set print $l
|
||||
set value $l
|
||||
}
|
||||
|
||||
if {!$nocode} {
|
||||
do_test_ code $exp $result $explicit $name \
|
||||
[list $compile $value $print]
|
||||
}
|
||||
if {!$noprint} {
|
||||
do_test_ print $exp $result $explicit $name \
|
||||
[list $compile $value $print]
|
||||
}
|
||||
}
|
||||
|
||||
# Run a compile test for CMD ("print" or "code").
|
||||
|
||||
proc do_test_ {cmd exp result is_explicit tst fail_list} {
|
||||
variable varName_
|
||||
|
||||
if {![string match $cmd "code"]
|
||||
&& ![string match $cmd "print"]} {
|
||||
error "invalid command, $cmd; should be \"print\" or \"compile\""
|
||||
}
|
||||
|
||||
# Get expected result of test. Will be "" if test is
|
||||
# expected to PASS.
|
||||
lassign $fail_list fail_compile fail_value fail_print
|
||||
|
||||
# Set a test name if one hasn't been provided.
|
||||
if {$tst == ""} {
|
||||
set tst "compile $cmd $exp"
|
||||
}
|
||||
|
||||
if {[string match $cmd "print"]} {
|
||||
if {!$is_explicit} {
|
||||
eval setup_failures_ $fail_print
|
||||
gdb_test "compile print $exp" $result $tst
|
||||
}
|
||||
} else {
|
||||
if {$is_explicit} {
|
||||
set command "compile code $exp"
|
||||
} else {
|
||||
set command "compile code $varName_ = $exp"
|
||||
}
|
||||
eval setup_failures_ $fail_compile
|
||||
gdb_test_no_output $command $tst
|
||||
eval setup_failures_ $fail_value
|
||||
gdb_test "p $varName_" "= $result" "result of $tst"
|
||||
}
|
||||
}
|
||||
|
||||
# A convenience proc used to set up xfail and kfail tests.
|
||||
# HOW is either xfail or kfail (case is ignored). ARGS is any
|
||||
# optional architecture, bug number, or other string to pass to
|
||||
# respective DejaGNU setup_$how routines.
|
||||
|
||||
proc setup_failures_ {how args} {
|
||||
switch -nocase $how {
|
||||
xfail {
|
||||
eval setup_xfail $args
|
||||
}
|
||||
|
||||
kfail {
|
||||
eval setup_kfail $args
|
||||
}
|
||||
|
||||
default {
|
||||
# Do nothing. Either the test is expected to PASS
|
||||
# or we have an unhandled failure mode.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user