forked from Imagelibrary/binutils-gdb
This recent commit: commitb1c0ab2080Date: Wed Jul 12 21:56:50 2023 +0100 gdb: avoid double stop after failed breakpoint condition check Addressed a problem where two MI stopped events would be reported if a breakpoint condition failed due to a signal, this commit was a replacement for this commit: commit2e411b8c68Date: Fri Oct 14 14:53:15 2022 +0100 gdb: don't always print breakpoint location after failed condition check which solved the two stop problem, but only for the CLI. Before both of these commits, if a b/p condition failed due to a signal then the user would see two stops reported, the first at the location where the signal occurred, and the second at the location of the breakpoint. By default GDB remains at the location where the signal occurred, so the second reported stop can be confusing, this is the problem that commit2e411b8c68tried to solve (for the CLI) andb1c0ab2080extended also address the issue for MI too. However, while working on another patch I realised that there was a problem with GDB after the above commits. Neither of the above commits considered 'set unwindonsignal on'. With this setting on, when an inferior function call fails with a signal GDB will unwind the stack back to the location where the inferior function call started. In the b/p case we're looking at, the stop should be reported at the location of the breakpoint, not at the location where the signal occurred, and this isn't what happens. This commit fixes this by ensuring that when unwindonsignal is 'on', GDB reports a single stop event at the location of the breakpoint, this fixes things for both CLI and MI. The function call_thread_fsm::should_notify_stop is called when the inferior function call completes and GDB is figuring out if the user should be notified about this stop event by calling normal_stop from fetch_inferior_event in infrun.c. If normal_stop is called, then this notification will be for the location where the inferior call stopped, which will be the location at which the signal occurred. Prior to this commit, the only time that normal_stop was not called, was if the inferior function call completed successfully, this was controlled by ::should_notify_stop, which only turns false when the inferior function call has completed successfully. In this commit I have extended the logic in ::should_notify_stop. Now there are three cases in which ::should_notify_stop will return false, and we will not announce the first stop (by calling normal_stop). These three reasons are: 1. If the inferior function call completes successfully, this is unchanged behaviour, 2. If the inferior function call stopped due to a signal and 'set unwindonsignal on' is in effect, and 3. If the inferior function call stopped due to an uncaught C++ exception, and 'set unwind-on-terminating-exception on' is in effect. However, if we don't call normal_stop then we need to call async_enable_stdin in call_thread_fsm::should_stop. Prior to this commit this was only done for the case where the inferior function call completed successfully. In this commit I now call ::should_notify_stop and use this to determine if we need to call async_enable_stdin. With this done we now call async_enable_stdin for each of the three cases listed above, which means that GDB will exit wait_sync_command_done correctly (see run_inferior_call in infcall.c). With these two changes the problem is mostly resolved. However, the solution isn't ideal, we've still lost some information. Here is how GDB 13.1 behaves, this is before commitsb1c0ab2080and2e411b8c68: $ gdb -q /tmp/mi-condbreak-fail \ -ex 'set unwindonsignal on' \ -ex 'break 30 if (cond_fail())' \ -ex 'run' Reading symbols from /tmp/mi-condbreak-fail... Breakpoint 1 at 0x40111e: file /tmp/mi-condbreak-fail.c, line 30. Starting program: /tmp/mi-condbreak-fail Program received signal SIGSEGV, Segmentation fault. 0x0000000000401116 in cond_fail () at /tmp/mi-condbreak-fail.c:24 24 return *p; /* Crash here. */ Error in testing breakpoint condition: The program being debugged was signaled while in a function called from GDB. GDB has restored the context to what it was before the call. To change this behavior use "set unwindonsignal off". Evaluation of the expression containing the function (cond_fail) will be abandoned. Breakpoint 1, foo () at /tmp/mi-condbreak-fail.c:30 30 global_counter += 1; /* Set breakpoint here. */ (gdb) In this state we see two stop notifications, the first is where the signal occurred, while the second is where the breakpoint is located. As GDB has unwound the stack (thanks to unwindonsignal) the second stop notification reflects where the inferior is actually located. Then after commitsb1c0ab2080and2e411b8c68the behaviour changed to this: $ gdb -q /tmp/mi-condbreak-fail \ -ex 'set unwindonsignal on' \ -ex 'break 30 if (cond_fail())' \ -ex 'run' Reading symbols from /tmp/mi-condbreak-fail... Breakpoint 1 at 0x40111e: file /tmp/mi-condbreak-fail.c, line 30. Starting program: /tmp/mi-condbreak-fail Program received signal SIGSEGV, Segmentation fault. 0x0000000000401116 in cond_fail () at /tmp/mi-condbreak-fail.c:24 24 return *p; /* Crash here. */ Error in testing condition for breakpoint 1: The program being debugged was signaled while in a function called from GDB. GDB has restored the context to what it was before the call. To change this behavior use "set unwindonsignal off". Evaluation of the expression containing the function (cond_fail) will be abandoned. (gdb) bt 1 #0 foo () at /tmp/mi-condbreak-fail.c:30 (More stack frames follow...) (gdb) This is the broken state. GDB is reports the SIGSEGV location, but not the unwound breakpoint location. The final 'bt 1' shows that the inferior is not located in cond_fail, which is the only location GDB reported, so this is clearly wrong. After implementing the fixes described above we now get this behaviour: $ gdb -q /tmp/mi-condbreak-fail \ -ex 'set unwindonsignal on' \ -ex 'break 30 if (cond_fail())' \ -ex 'run' Reading symbols from /tmp/mi-condbreak-fail... Breakpoint 1 at 0x40111e: file /tmp/mi-condbreak-fail.c, line 30. Starting program: /tmp/mi-condbreak-fail Error in testing breakpoint condition for breakpoint 1: The program being debugged was signaled while in a function called from GDB. GDB has restored the context to what it was before the call. To change this behavior use "set unwindonsignal off". Evaluation of the expression containing the function (cond_fail) will be abandoned. Breakpoint 1, foo () at /tmp/mi-condbreak-fail.c:30 30 global_counter += 1; /* Set breakpoint here. */ (gdb) This is better. GDB now reports a single stop at the location of the breakpoint, which is where the inferior is actually located. However, by removing the first stop notification we have lost some potentially useful information about which signal caused the inferior to stop. To address this I've reworked the message that is printed to include the signal information. GDB now reports this: $ gdb -q /tmp/mi-condbreak-fail \ -ex 'set unwindonsignal on' \ -ex 'break 30 if (cond_fail())' \ -ex 'run' Reading symbols from /tmp/mi-condbreak-fail... Breakpoint 1 at 0x40111e: file /tmp/mi-condbreak-fail.c, line 30. Starting program: /tmp/mi-condbreak-fail Error in testing condition for breakpoint 1: The program being debugged received signal SIGSEGV, Segmentation fault while in a function called from GDB. GDB has restored the context to what it was before the call. To change this behavior use "set unwindonsignal off". Evaluation of the expression containing the function (cond_fail) will be abandoned. Breakpoint 1, foo () at /tmp/mi-condbreak-fail.c:30 30 global_counter += 1; /* Set breakpoint here. */ (gdb) This is better, the user now sees a single stop notification at the correct location, and the error message describes which signal caused the inferior function call to stop. However, we have lost the information about where the signal occurred. I did consider trying to include this information in the error message, but, in the end, I opted not too. I wasn't sure it was worth the effort. If the user has selected to unwind on signal, then surely this implies they maybe aren't interested in debugging failed inferior calls, so, hopefully, just knowing the signal name will be enough. I figure we can always add this information in later if there's a demand for it.
360 lines
13 KiB
Plaintext
360 lines
13 KiB
Plaintext
# Copyright 2014-2023 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
|
|
|
|
require is_c_compiler_gcc
|
|
|
|
set options {}
|
|
if { [test_compiler_info gcc*] || [test_compiler_info clang*] } {
|
|
lappend options additional_flags=-g3
|
|
lappend options additional_flags=-std=gnu++11
|
|
lappend options c++
|
|
}
|
|
|
|
if { ![is_x86_64_m64_target] } {
|
|
verbose "Skipping x86_64 LOC_CONST test."
|
|
set srcfile3 ""
|
|
}
|
|
|
|
set srcfilesoptions [list ${srcfile} ${options}]
|
|
if { $srcfile3 != "" } {
|
|
lappend srcfilesoptions $srcfile3 {}
|
|
}
|
|
set srcfile4options "nodebug c++"
|
|
lappend srcfilesoptions $srcfile4 $srcfile4options
|
|
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
|
|
}
|
|
|
|
gdb_breakpoint [gdb_get_line_number "break-here"]
|
|
gdb_continue_to_breakpoint "break-here" ".* break-here .*"
|
|
|
|
if {[skip_compile_feature_untested "var = 0"]} {
|
|
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\]*_gdb_expr \[^\r\n\]*\r\n#1 <function called from gdb>.*"
|
|
|
|
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;" \
|
|
[multi_line \
|
|
"The program being debugged received signal SIGSEGV, Segmentation fault" \
|
|
"while in a function called from GDB\\. GDB has restored the context" \
|
|
"to what it was before the call\\. To change this behavior use" \
|
|
"\"set unwindonsignal off\"\\. Evaluation of the expression containing" \
|
|
"the function \\(_gdb_expr\\(__gdb_regs\\*\\)\\) will be abandoned\\."] \
|
|
"compile code segfault second"
|
|
|
|
# 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 \\+ 5i"
|
|
|
|
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"
|
|
setup_kfail {no bug filed} *-*-*
|
|
gdb_test_no_output "compile code extern int globalshadow; globalshadow += 5;"
|
|
setup_kfail {fails due to previous test} *-*-*
|
|
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;" \
|
|
[multi_line \
|
|
"The program being debugged received signal SIGSEGV, Segmentation fault" \
|
|
"while in a function called from GDB\\. GDB has restored the context" \
|
|
"to what it was before the call\\. To change this behavior use" \
|
|
"\"set unwindonsignal off\"\\. Evaluation of the expression containing" \
|
|
"the function \\(_gdb_expr\\(__gdb_regs\\*\\)\\) will be abandoned\\."]
|
|
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" "Unrecognized option at: -z"
|
|
|
|
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 for this command.*" \
|
|
"Test compile file and raw option without a filename"
|
|
gdb_test "compile file -z" \
|
|
"Unrecognized option at: -z" \
|
|
"test compile file with unknown option"
|
|
|
|
# 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"
|
|
}
|