C++ compile support

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

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

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

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

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

gdb/ChangeLog:

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

gdb/testsuite/ChangeLog:

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

doc/ChangeLog:

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

View File

@ -1,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.

View File

@ -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 \

View File

@ -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

View File

@ -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
};

View File

@ -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) */

View File

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

View File

@ -0,0 +1,493 @@
/* Convert symbols from GDB to GCC
Copyright (C) 2014-2018 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
#include "compile-internal.h"
#include "compile-cplus.h"
#include "gdb_assert.h"
#include "symtab.h"
#include "parser-defs.h"
#include "block.h"
#include "objfiles.h"
#include "compile.h"
#include "value.h"
#include "exceptions.h"
#include "gdbtypes.h"
#include "dwarf2loc.h"
#include "cp-support.h"
#include "gdbcmd.h"
#include "compile-c.h"
/* Convert a given symbol, SYM, to the compiler's representation.
INSTANCE is the compiler instance. IS_GLOBAL is true if the
symbol came from the global scope. IS_LOCAL is true if the symbol
came from a local scope. (Note that the two are not strictly
inverses because the symbol might have come from the static
scope.) */
static void
convert_one_symbol (compile_cplus_instance *instance,
struct block_symbol sym, bool is_global, bool is_local)
{
/* Squash compiler warning. */
gcc_type sym_type = 0;
const char *filename = symbol_symtab (sym.symbol)->filename;
unsigned short line = SYMBOL_LINE (sym.symbol);
instance->error_symbol_once (sym.symbol);
if (SYMBOL_CLASS (sym.symbol) == LOC_LABEL)
sym_type = 0;
else
sym_type = instance->convert_type (SYMBOL_TYPE (sym.symbol));
if (SYMBOL_DOMAIN (sym.symbol) == STRUCT_DOMAIN)
{
/* Nothing to do. */
}
else
{
/* Squash compiler warning. */
gcc_cp_symbol_kind_flags kind = GCC_CP_FLAG_BASE;
CORE_ADDR addr = 0;
std::string name;
gdb::unique_xmalloc_ptr<char> symbol_name;
switch (SYMBOL_CLASS (sym.symbol))
{
case LOC_TYPEDEF:
if (TYPE_CODE (SYMBOL_TYPE (sym.symbol)) == TYPE_CODE_TYPEDEF)
kind = GCC_CP_SYMBOL_TYPEDEF;
else if (TYPE_CODE (SYMBOL_TYPE (sym.symbol)) == TYPE_CODE_NAMESPACE)
return;
break;
case LOC_LABEL:
kind = GCC_CP_SYMBOL_LABEL;
addr = SYMBOL_VALUE_ADDRESS (sym.symbol);
break;
case LOC_BLOCK:
{
kind = GCC_CP_SYMBOL_FUNCTION;
addr = BLOCK_START (SYMBOL_BLOCK_VALUE (sym.symbol));
if (is_global && TYPE_GNU_IFUNC (SYMBOL_TYPE (sym.symbol)))
addr = gnu_ifunc_resolve_addr (target_gdbarch (), addr);
}
break;
case LOC_CONST:
if (TYPE_CODE (SYMBOL_TYPE (sym.symbol)) == TYPE_CODE_ENUM)
{
/* Already handled by convert_enum. */
return;
}
instance->plugin ().build_constant
(sym_type, SYMBOL_NATURAL_NAME (sym.symbol),
SYMBOL_VALUE (sym.symbol), filename, line);
return;
case LOC_CONST_BYTES:
error (_("Unsupported LOC_CONST_BYTES for symbol \"%s\"."),
SYMBOL_PRINT_NAME (sym.symbol));
case LOC_UNDEF:
internal_error (__FILE__, __LINE__, _("LOC_UNDEF found for \"%s\"."),
SYMBOL_PRINT_NAME (sym.symbol));
case LOC_COMMON_BLOCK:
error (_("Fortran common block is unsupported for compilation "
"evaluaton of symbol \"%s\"."),
SYMBOL_PRINT_NAME (sym.symbol));
case LOC_OPTIMIZED_OUT:
error (_("Symbol \"%s\" cannot be used for compilation evaluation "
"as it is optimized out."),
SYMBOL_PRINT_NAME (sym.symbol));
case LOC_COMPUTED:
if (is_local)
goto substitution;
/* Probably TLS here. */
warning (_("Symbol \"%s\" is thread-local and currently can only "
"be referenced from the current thread in "
"compiled code."),
SYMBOL_PRINT_NAME (sym.symbol));
/* FALLTHROUGH */
case LOC_UNRESOLVED:
/* 'symbol_name' cannot be used here as that one is used only for
local variables from compile_dwarf_expr_to_c.
Global variables can be accessed by GCC only by their address, not
by their name. */
{
struct value *val;
struct frame_info *frame = nullptr;
if (symbol_read_needs_frame (sym.symbol))
{
frame = get_selected_frame (nullptr);
if (frame == nullptr)
error (_("Symbol \"%s\" cannot be used because "
"there is no selected frame"),
SYMBOL_PRINT_NAME (sym.symbol));
}
val = read_var_value (sym.symbol, sym.block, frame);
if (VALUE_LVAL (val) != lval_memory)
error (_("Symbol \"%s\" cannot be used for compilation "
"evaluation as its address has not been found."),
SYMBOL_PRINT_NAME (sym.symbol));
kind = GCC_CP_SYMBOL_VARIABLE;
addr = value_address (val);
}
break;
case LOC_REGISTER:
case LOC_ARG:
case LOC_REF_ARG:
case LOC_REGPARM_ADDR:
case LOC_LOCAL:
substitution:
kind = GCC_CP_SYMBOL_VARIABLE;
symbol_name = c_symbol_substitution_name (sym.symbol);
break;
case LOC_STATIC:
kind = GCC_CP_SYMBOL_VARIABLE;
addr = SYMBOL_VALUE_ADDRESS (sym.symbol);
break;
case LOC_FINAL_VALUE:
default:
gdb_assert_not_reached ("Unreachable case in convert_one_symbol.");
}
/* Don't emit local variable decls for a raw expression. */
if (instance->scope () != COMPILE_I_RAW_SCOPE || symbol_name == nullptr)
{
compile_scope scope;
/* For non-local symbols, create/push a new scope so that the
symbol is properly scoped to the plug-in. */
if (!is_local)
{
scope
= instance->new_scope (SYMBOL_NATURAL_NAME (sym.symbol),
SYMBOL_TYPE (sym.symbol));
if (scope.nested_type () != GCC_TYPE_NONE)
{
/* We found a symbol for this type that was defined inside
some other symbol, e.g., a class tyepdef defined. */
return;
}
instance->enter_scope (scope);
}
/* Get the `raw' name of the symbol. */
if (name.empty () && SYMBOL_NATURAL_NAME (sym.symbol) != nullptr)
name = compile_cplus_instance::decl_name
(SYMBOL_NATURAL_NAME (sym.symbol)).get ();
/* Define the decl. */
instance->plugin ().build_decl
("variable", name.c_str (), kind, sym_type,
symbol_name.get (), addr, filename, line);
/* Pop scope for non-local symbols. */
if (!is_local)
instance->leave_scope ();
}
}
}
/* Convert a full symbol to its gcc form. CONTEXT is the compiler to
use, IDENTIFIER is the name of the symbol, SYM is the symbol
itself, and DOMAIN is the domain which was searched. */
static void
convert_symbol_sym (compile_cplus_instance *instance,
const char *identifier, struct block_symbol sym,
domain_enum domain)
{
/* If we found a symbol and it is not in the static or global
scope, then we should first convert any static or global scope
symbol of the same name. This lets this unusual case work:
int x; // Global.
int func(void)
{
int x;
// At this spot, evaluate "extern int x; x"
}
*/
const struct block *static_block = block_static_block (sym.block);
/* STATIC_BLOCK is NULL if FOUND_BLOCK is the global block. */
bool is_local_symbol = (sym.block != static_block && static_block != nullptr);
if (is_local_symbol)
{
struct block_symbol global_sym;
global_sym = lookup_symbol (identifier, nullptr, domain, nullptr);
/* If the outer symbol is in the static block, we ignore it, as
it cannot be referenced. */
if (global_sym.symbol != nullptr
&& global_sym.block != block_static_block (global_sym.block))
{
if (compile_debug)
fprintf_unfiltered (gdb_stdlog,
"gcc_convert_symbol \"%s\": global symbol\n",
identifier);
convert_one_symbol (instance, global_sym, true, false);
}
}
if (compile_debug)
fprintf_unfiltered (gdb_stdlog,
"gcc_convert_symbol \"%s\": local symbol\n",
identifier);
convert_one_symbol (instance, sym, false, is_local_symbol);
}
/* Convert a minimal symbol to its gcc form. CONTEXT is the compiler
to use and BMSYM is the minimal symbol to convert. */
static void
convert_symbol_bmsym (compile_cplus_instance *instance,
struct bound_minimal_symbol bmsym)
{
struct minimal_symbol *msym = bmsym.minsym;
struct objfile *objfile = bmsym.objfile;
struct type *type;
gcc_cp_symbol_kind_flags kind;
gcc_type sym_type;
CORE_ADDR addr;
addr = MSYMBOL_VALUE_ADDRESS (objfile, msym);
/* Conversion copied from write_exp_msymbol. */
switch (MSYMBOL_TYPE (msym))
{
case mst_text:
case mst_file_text:
case mst_solib_trampoline:
type = objfile_type (objfile)->nodebug_text_symbol;
kind = GCC_CP_SYMBOL_FUNCTION;
break;
case mst_text_gnu_ifunc:
/* nodebug_text_gnu_ifunc_symbol would cause:
function return type cannot be function */
type = objfile_type (objfile)->nodebug_text_symbol;
kind = GCC_CP_SYMBOL_FUNCTION;
addr = gnu_ifunc_resolve_addr (target_gdbarch (), addr);
break;
case mst_data:
case mst_file_data:
case mst_bss:
case mst_file_bss:
type = objfile_type (objfile)->nodebug_data_symbol;
kind = GCC_CP_SYMBOL_VARIABLE;
break;
case mst_slot_got_plt:
type = objfile_type (objfile)->nodebug_got_plt_symbol;
kind = GCC_CP_SYMBOL_FUNCTION;
break;
default:
type = objfile_type (objfile)->nodebug_unknown_symbol;
kind = GCC_CP_SYMBOL_VARIABLE;
break;
}
sym_type = instance->convert_type (type);
instance->plugin ().push_namespace ("");
instance->plugin ().build_decl
("minsym", MSYMBOL_NATURAL_NAME (msym), kind, sym_type, nullptr, addr,
nullptr, 0);
instance->plugin ().pop_binding_level ("");
}
/* See compile-cplus.h. */
void
gcc_cplus_convert_symbol (void *datum,
struct gcc_cp_context *gcc_context,
enum gcc_cp_oracle_request request ATTRIBUTE_UNUSED,
const char *identifier)
{
if (compile_debug)
fprintf_unfiltered (gdb_stdlog,
"got oracle request for \"%s\"\n", identifier);
bool found = false;
compile_cplus_instance *instance = (compile_cplus_instance *) datum;
TRY
{
/* Symbol searching is a three part process unfortunately. */
/* First do a "standard" lookup, converting any found symbols.
This will find variables in the current scope. */
struct block_symbol sym
= lookup_symbol (identifier, instance->block (), VAR_DOMAIN, nullptr);
if (sym.symbol != nullptr)
{
found = true;
convert_symbol_sym (instance, identifier, sym, VAR_DOMAIN);
}
/* Then use linespec.c's multi-symbol search. This should find
all non-variable symbols for which we have debug info. */
symbol_searcher searcher;
searcher.find_all_symbols (identifier, current_language,
ALL_DOMAIN, nullptr, nullptr);
/* Convert any found symbols. */
for (const auto &it : searcher.matching_symbols ())
{
/* Don't convert the symbol found above, if any, twice! */
if (it.symbol != sym.symbol)
{
found = true;
convert_symbol_sym (instance, identifier, it,
SYMBOL_DOMAIN (it.symbol));
}
}
/* Finally, if no symbols have been found, fall back to minsyms. */
if (!found)
{
for (const auto &it : searcher.matching_msymbols ())
{
found = true;
convert_symbol_bmsym (instance, it);
}
}
}
CATCH (e, RETURN_MASK_ALL)
{
/* We can't allow exceptions to escape out of this callback. Safest
is to simply emit a gcc error. */
instance->plugin ().error (e.message);
}
END_CATCH
if (compile_debug && !found)
fprintf_unfiltered (gdb_stdlog,
"gcc_convert_symbol \"%s\": lookup_symbol failed\n",
identifier);
if (compile_debug)
{
if (found)
fprintf_unfiltered (gdb_stdlog, "found type for %s\n", identifier);
else
{
fprintf_unfiltered (gdb_stdlog, "did not find type for %s\n",
identifier);
}
}
return;
}
/* See compile-cplus.h. */
gcc_address
gcc_cplus_symbol_address (void *datum, struct gcc_cp_context *gcc_context,
const char *identifier)
{
compile_cplus_instance *instance = (compile_cplus_instance *) datum;
gcc_address result = 0;
int found = 0;
if (compile_debug)
fprintf_unfiltered (gdb_stdlog,
"got oracle request for address of %s\n", identifier);
/* We can't allow exceptions to escape out of this callback. Safest
is to simply emit a gcc error. */
TRY
{
struct symbol *sym
= lookup_symbol (identifier, nullptr, VAR_DOMAIN, nullptr).symbol;
if (sym != nullptr && SYMBOL_CLASS (sym) == LOC_BLOCK)
{
if (compile_debug)
fprintf_unfiltered (gdb_stdlog,
"gcc_symbol_address \"%s\": full symbol\n",
identifier);
result = BLOCK_START (SYMBOL_BLOCK_VALUE (sym));
if (TYPE_GNU_IFUNC (SYMBOL_TYPE (sym)))
result = gnu_ifunc_resolve_addr (target_gdbarch (), result);
found = 1;
}
else
{
struct bound_minimal_symbol msym;
msym = lookup_bound_minimal_symbol (identifier);
if (msym.minsym != nullptr)
{
if (compile_debug)
fprintf_unfiltered (gdb_stdlog,
"gcc_symbol_address \"%s\": minimal "
"symbol\n",
identifier);
result = BMSYMBOL_VALUE_ADDRESS (msym);
if (MSYMBOL_TYPE (msym.minsym) == mst_text_gnu_ifunc)
result = gnu_ifunc_resolve_addr (target_gdbarch (), result);
found = 1;
}
}
}
CATCH (e, RETURN_MASK_ERROR)
{
instance->plugin ().error (e.message);
}
END_CATCH
if (compile_debug && !found)
fprintf_unfiltered (gdb_stdlog,
"gcc_symbol_address \"%s\": failed\n",
identifier);
if (compile_debug)
{
if (found)
fprintf_unfiltered (gdb_stdlog, "found address for %s!\n", identifier);
else
fprintf_unfiltered (gdb_stdlog,
"did not find address for %s\n", identifier);
}
return result;
}

File diff suppressed because it is too large Load Diff

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

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,85 @@
/* GCC C++ plug-in wrapper for GDB.
Copyright (C) 2018 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* A class representing the GCC C++ plug-in. */
#include "gcc-cp-interface.h"
class gcc_cp_plugin
{
public:
explicit gcc_cp_plugin (struct gcc_cp_context *gcc_cp)
: m_context (gcc_cp)
{
}
/* Set the oracle callbacks to be used by the compiler plug-in. */
void set_callbacks (gcc_cp_oracle_function *binding_oracle,
gcc_cp_symbol_address_function *address_oracle,
gcc_cp_enter_leave_user_expr_scope_function *enter_scope,
gcc_cp_enter_leave_user_expr_scope_function *leave_scope,
void *datum)
{
m_context->cp_ops->set_callbacks (m_context, binding_oracle,
address_oracle, enter_scope, leave_scope,
datum);
}
/* Returns the interface version of the compiler plug-in. */
int version () const { return m_context->cp_ops->cp_version; }
#define GCC_METHOD0(R, N) R N () const;
#define GCC_METHOD1(R, N, A) R N (A) const;
#define GCC_METHOD2(R, N, A, B) R N (A, B) const;
#define GCC_METHOD3(R, N, A, B, C) R N (A, B, C) const;
#define GCC_METHOD4(R, N, A, B, C, D) R N (A, B, C, D) const;
#define GCC_METHOD5(R, N, A, B, C, D, E) R N (A, B, C, D, E) const;
#define GCC_METHOD7(R, N, A, B, C, D, E, F, G) R N (A, B, C, D, E, F, G) const;
#include "gcc-cp-fe.def"
#undef GCC_METHOD0
#undef GCC_METHOD1
#undef GCC_METHOD2
#undef GCC_METHOD3
#undef GCC_METHOD4
#undef GCC_METHOD5
#undef GCC_METHOD7
/* Special overloads of plug-in methods with added debugging information. */
gcc_expr build_decl (const char *debug_decltype, const char *name,
enum gcc_cp_symbol_kind sym_kind, gcc_type sym_type,
const char *substitution_name, gcc_address address,
const char *filename, unsigned int line_number);
gcc_type start_class_type (const char *debug_name, gcc_decl typedecl,
const struct gcc_vbase_array *base_classes,
const char *filename, unsigned int line_number);
int finish_class_type (const char *debug_name, unsigned long size_in_bytes);
int pop_binding_level (const char *debug_name);
private:
/* The GCC C++ context. */
struct gcc_cp_context *m_context;
};

View File

@ -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

View File

@ -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

View File

@ -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:

View 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
}

View 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

View 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
}

View 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\"\\}"

View 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;
}

View 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

View 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
}

View 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"

View 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);
}

View 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

View 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
}

View 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 ();
}

View 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

View 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 ();
}

View 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

View 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;
}

View 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}}

View 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;
}

View 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."

View 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;
}

View 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"
}

View 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.
}
}
}
}