# Copyright 2018-2024 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 . # Test support for DW_OP_GNU_variable_value. load_lib dwarf.exp # This test can only be run on targets which support DWARF-2 and use gas. require dwarf2_support # We'll place the output of Dwarf::assemble in varval.S. standard_testfile .c .S # ${testfile} is now "varval". srcfile2 is "varval.S". set executable ${testfile} set asm_file [standard_output_file ${srcfile2}] # We need to know the size of integer and address types in order # to write some of the debugging info we'd like to generate. # # For that, we ask GDB by debugging our varval program. # Any program would do, but since we already have varval # specifically for this testcase, might as well use that. if [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] { return -1 } set int_size [get_sizeof "int" -1] # gdb always assumes references are implemented as pointers. set addr_size [get_sizeof "void *" -1] proc setup_exec { arg_bad } { global asm_file executable srcfile bad set bad ${arg_bad} # Create the DWARF. Dwarf::assemble ${asm_file} { global bad int_size addr_size cu {} { DW_TAG_compile_unit { {DW_AT_language @DW_LANG_C_plus_plus} } { declare_labels int_label ptr_label struct_label var_a_label \ var_b_label var_c_label var_p_label var_bad_label \ varval_label var_s_label var_untyped_label \ var_a_abstract_label var_a_concrete_label \ varval2_label varval3_def_label varval3_decl_label \ int_array_label int_array_of_1_label int_label: DW_TAG_base_type { {DW_AT_byte_size ${int_size} DW_FORM_udata} {DW_AT_encoding @DW_ATE_signed} {DW_AT_name "int"} } ptr_label: DW_TAG_pointer_type { {DW_AT_type :$int_label} } var_a_label: DW_TAG_variable { {DW_AT_name "var_a"} {DW_AT_type :${int_label}} {DW_AT_external 1 DW_FORM_flag} {DW_AT_location {DW_OP_addr [gdb_target_symbol "var_a"]} SPECIAL_expr} } var_a_abstract_label: DW_TAG_variable { {DW_AT_type :${int_label}} {DW_AT_external 1 DW_FORM_flag} } var_b_label: DW_TAG_variable { {DW_AT_name "var_b"} {DW_AT_type :${int_label}} {DW_AT_external 1 DW_FORM_flag} {DW_AT_location {DW_OP_addr [gdb_target_symbol "var_b"]} SPECIAL_expr} } var_c_label: DW_TAG_variable { {DW_AT_name "var_c"} {DW_AT_type :${int_label}} {DW_AT_external 1 DW_FORM_flag} {DW_AT_const_value 53 DW_FORM_sdata} } var_p_label: DW_TAG_variable { {DW_AT_name "var_p"} {DW_AT_type :${ptr_label}} {DW_AT_external 1 DW_FORM_flag} {DW_AT_location {DW_OP_addr [gdb_target_symbol "var_p"]} SPECIAL_expr} } if { $bad } { var_bad_label: DW_TAG_variable { {DW_AT_name "var_bad"} {DW_AT_type :${int_label}} {DW_AT_external 1 DW_FORM_flag} } } struct_label: DW_TAG_structure_type { {DW_AT_byte_size 8*$int_size DW_FORM_sdata} } { DW_TAG_member { {DW_AT_name "a"} {DW_AT_type :$int_label} {DW_AT_data_member_location 0*$int_size DW_FORM_udata} } DW_TAG_member { {DW_AT_name "b"} {DW_AT_type :$int_label} {DW_AT_data_member_location 1*$int_size DW_FORM_udata} } DW_TAG_member { {DW_AT_name "c"} {DW_AT_type :$int_label} {DW_AT_data_member_location 2*$int_size DW_FORM_udata} } DW_TAG_member { {DW_AT_name "d"} {DW_AT_type :$int_label} {DW_AT_data_member_location 3*$int_size DW_FORM_udata} } DW_TAG_member { {DW_AT_name "e"} {DW_AT_type :$int_label} {DW_AT_data_member_location 4*$int_size DW_FORM_udata} } DW_TAG_member { {DW_AT_name "f"} {DW_AT_type :$int_label} {DW_AT_data_member_location 5*$int_size DW_FORM_udata} } DW_TAG_member { {DW_AT_name "g"} {DW_AT_type :$int_label} {DW_AT_data_member_location 6*$int_size DW_FORM_udata} } DW_TAG_member { {DW_AT_name "h"} {DW_AT_type :$int_label} {DW_AT_data_member_location 7*$int_size DW_FORM_udata} } } var_s_label: DW_TAG_variable { {DW_AT_name "var_s"} {DW_AT_type :${struct_label}} {DW_AT_external 1 DW_FORM_flag} {DW_AT_location {DW_OP_addr [gdb_target_symbol "var_s"]} SPECIAL_expr} } var_untyped_label: DW_TAG_variable { {DW_AT_name "var_untyped"} {DW_AT_external 1 DW_FORM_flag} {DW_AT_location {DW_OP_addr [gdb_target_symbol "var_b"]} SPECIAL_expr} } int_array_label: DW_TAG_array_type { {DW_AT_type :${int_label}} } { DW_TAG_subrange_type {} } varval3_decl_label: DW_TAG_variable { {DW_AT_name "varval3"} {DW_AT_type :${int_array_label}} {DW_AT_external 1 DW_FORM_flag} {DW_AT_declaration 1 DW_FORM_flag} } int_array_of_1_label: DW_TAG_array_type { {DW_AT_type :${int_label}} } { DW_TAG_subrange_type { {DW_AT_type :$int_label} {DW_AT_upper_bound 0 DW_FORM_data1} } } varval3_def_label: DW_TAG_variable { {DW_AT_name "varval3"} {DW_AT_external 1 DW_FORM_flag} {DW_AT_type :${int_array_of_1_label}} {DW_AT_location {DW_OP_addr [gdb_target_symbol "var_a"]} SPECIAL_expr} } DW_TAG_subprogram { {MACRO_AT_func { "main" }} {DW_AT_type :${int_label}} {DW_AT_external 1 DW_FORM_flag} } { varval_label: DW_TAG_variable { {DW_AT_name "varval"} {DW_AT_type :${int_label}} {DW_AT_location { DW_OP_GNU_variable_value ${var_a_label} DW_OP_const1s 0 DW_OP_or DW_OP_stack_value } SPECIAL_expr} } varval2_label: DW_TAG_variable { {DW_AT_name "varval2"} {DW_AT_type :${int_label}} {DW_AT_location { DW_OP_GNU_variable_value ${var_a_abstract_label} DW_OP_stack_value } SPECIAL_expr} } var_a_concrete_label: DW_TAG_variable { {DW_AT_abstract_origin :${var_a_abstract_label}} {DW_AT_location {DW_OP_addr [gdb_target_symbol "var_a"]} SPECIAL_expr} } DW_TAG_variable { {DW_AT_name "constval"} {DW_AT_type :${int_label}} {DW_AT_location { DW_OP_GNU_variable_value ${var_c_label} DW_OP_stack_value } SPECIAL_expr} } DW_TAG_variable { {DW_AT_name "mixedval"} {DW_AT_type :${int_label}} {DW_AT_location { DW_OP_GNU_variable_value ${var_c_label} DW_OP_GNU_variable_value ${var_b_label} DW_OP_div DW_OP_GNU_variable_value ${varval_label} DW_OP_plus DW_OP_dup DW_OP_plus DW_OP_GNU_variable_value ${varval_label} DW_OP_minus DW_OP_stack_value } SPECIAL_expr} } DW_TAG_variable { {DW_AT_name "pointerval"} {DW_AT_type :${ptr_label}} {DW_AT_location { DW_OP_GNU_variable_value ${var_p_label} DW_OP_stack_value } SPECIAL_expr} } if { $bad } { DW_TAG_variable { {DW_AT_name "badval"} {DW_AT_type :${int_label}} {DW_AT_location { DW_OP_GNU_variable_value ${var_bad_label} DW_OP_stack_value } SPECIAL_expr} } } DW_TAG_variable { {DW_AT_name "structval"} {DW_AT_type :${struct_label}} {DW_AT_location { DW_OP_GNU_variable_value ${var_s_label} DW_OP_stack_value } SPECIAL_expr} } DW_TAG_variable { {DW_AT_name "untypedval"} {DW_AT_location { DW_OP_GNU_variable_value ${var_untyped_label} DW_OP_stack_value } SPECIAL_expr} } if { $bad } { DW_TAG_variable { {DW_AT_name "bad_die_val1"} {DW_AT_location { DW_OP_GNU_variable_value 0xabcdef11 DW_OP_stack_value } SPECIAL_expr} } DW_TAG_variable { {DW_AT_name "bad_die_val2"} {DW_AT_location { DW_OP_GNU_variable_value ${ptr_label}+1 DW_OP_stack_value } SPECIAL_expr} } } } } } } if [prepare_for_testing "failed to prepare" ${executable} [list ${asm_file} ${srcfile}] {}] { return -1 } } if { [setup_exec 0] == -1 } { return -1 } with_test_prefix "pre-main" { gdb_test "print varval3" "= \\{8\\}" "" } # DW_OP_GNU_variable_value implementation requires a valid frame. if ![runto_main] { return -1 } gdb_test "print varval" "= 8" gdb_test "print varval2" "= 8" gdb_test "print varval3" "= \\{8\\}" gdb_test "print constval" "= 53" gdb_test "print mixedval" "= 42" gdb_test "print pointerval" "= \\(int \\*\\) $hex " gdb_test "print *pointerval" "= 3" # Jakub says: "The intended behavior is that the debug info consumer # computes the value of that referenced variable at the current PC, # and if it can compute it and pushes the value as a generic type # integer into the DWARF stack (it is really only meaningful when # referring to integral/pointer typed variables)." gdb_test "print structval" \ "Type of DW_OP_GNU_variable_value DIE must be an integer or pointer\\." gdb_test "print untypedval" \ "Type of DW_OP_GNU_variable_value DIE must be an integer or pointer\\." if { [setup_exec 1] == -1 } { return -1 } # DW_OP_GNU_variable_value implementation requires a valid frame. if ![runto_main] { return -1 } gdb_test "print badval" "value has been optimized out" gdb_test "print bad_die_val1" \ "invalid dwarf2 offset 0xabcdef11" gdb_test "print bad_die_val2" \ "Bad DW_OP_GNU_variable_value DIE\\."