mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-27 04:52:05 +08:00
078a020797
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.
348 lines
12 KiB
Plaintext
348 lines
12 KiB
Plaintext
# 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"
|
|
}
|