From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gnu.wildebeest.org (wildebeest.demon.nl [212.238.236.112]) by sourceware.org (Postfix) with ESMTPS id 83090386EC54 for ; Mon, 14 Dec 2020 21:19:58 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 83090386EC54 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=klomp.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=mark@klomp.org Received: from tarox.wildebeest.org (tarox.wildebeest.org [172.31.17.39]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by gnu.wildebeest.org (Postfix) with ESMTPSA id B7DE93027324; Mon, 14 Dec 2020 22:19:56 +0100 (CET) Received: by tarox.wildebeest.org (Postfix, from userid 1000) id 7B8B34000B19; Mon, 14 Dec 2020 22:19:56 +0100 (CET) From: Mark Wielaard To: dwz@sourceware.org Cc: Mark Wielaard Subject: [PATCH] Update dwarf.exp assembler from gdb. Date: Mon, 14 Dec 2020 22:19:45 +0100 Message-Id: <20201214211945.9656-1-mark@klomp.org> X-Mailer: git-send-email 2.18.4 X-Spam-Status: No, score=-11.4 required=5.0 tests=BAYES_00, GIT_PATCH_0, JMQ_SPF_NEUTRAL, KAM_DMARC_STATUS, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: dwz@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Dwz mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 14 Dec 2020 21:20:01 -0000 Includes various fixes and features. Specifically it won't emit a block for a DWARF expression when the version is >= 4. The DWARF Assembler is used by invalid-dw-at-stmt-list-encoding.exp (pr24171.sh) and no-multifile-prop.exp (pr25109.sh) Also fix up the generated varval.S (pr24823.sh) to use DW_FORM_exprloc. --- testsuite/dwz.tests/varval.S | 26 ++-- testsuite/lib/dwarf.exp | 242 +++++++++++++++++++++++------------ 2 files changed, 176 insertions(+), 92 deletions(-) diff --git a/testsuite/dwz.tests/varval.S b/testsuite/dwz.tests/varval.S index be62e8b..126768c 100644 --- a/testsuite/dwz.tests/varval.S +++ b/testsuite/dwz.tests/varval.S @@ -241,7 +241,7 @@ .uleb128 0x3f /* DW_AT_external */ .uleb128 0x0c /* DW_FORM_flag */ .uleb128 0x02 /* DW_AT_location */ - .uleb128 0x09 /* SPECIAL_expr */ + .uleb128 0x18 /* DW_FORM_exprloc */ .byte 0x0 /* Terminator */ .byte 0x0 /* Terminator */ .uleb128 6 /* Abbrev start */ @@ -263,7 +263,7 @@ .uleb128 0x3f /* DW_AT_external */ .uleb128 0x0c /* DW_FORM_flag */ .uleb128 0x02 /* DW_AT_location */ - .uleb128 0x09 /* SPECIAL_expr */ + .uleb128 0x18 /* DW_FORM_exprloc */ .byte 0x0 /* Terminator */ .byte 0x0 /* Terminator */ .uleb128 8 /* Abbrev start */ @@ -289,7 +289,7 @@ .uleb128 0x3f /* DW_AT_external */ .uleb128 0x0c /* DW_FORM_flag */ .uleb128 0x02 /* DW_AT_location */ - .uleb128 0x09 /* SPECIAL_expr */ + .uleb128 0x18 /* DW_FORM_exprloc */ .byte 0x0 /* Terminator */ .byte 0x0 /* Terminator */ .uleb128 10 /* Abbrev start */ @@ -397,7 +397,7 @@ .uleb128 0x3f /* DW_AT_external */ .uleb128 0x0c /* DW_FORM_flag */ .uleb128 0x02 /* DW_AT_location */ - .uleb128 0x09 /* SPECIAL_expr */ + .uleb128 0x18 /* DW_FORM_exprloc */ .byte 0x0 /* Terminator */ .byte 0x0 /* Terminator */ .uleb128 20 /* Abbrev start */ @@ -408,7 +408,7 @@ .uleb128 0x3f /* DW_AT_external */ .uleb128 0x0c /* DW_FORM_flag */ .uleb128 0x02 /* DW_AT_location */ - .uleb128 0x09 /* SPECIAL_expr */ + .uleb128 0x18 /* DW_FORM_exprloc */ .byte 0x0 /* Terminator */ .byte 0x0 /* Terminator */ .uleb128 21 /* Abbrev start */ @@ -434,7 +434,7 @@ .uleb128 0x49 /* DW_AT_type */ .uleb128 0x13 /* DW_FORM_ref4 */ .uleb128 0x02 /* DW_AT_location */ - .uleb128 0x09 /* SPECIAL_expr */ + .uleb128 0x18 /* DW_FORM_exprloc */ .byte 0x0 /* Terminator */ .byte 0x0 /* Terminator */ .uleb128 23 /* Abbrev start */ @@ -445,7 +445,7 @@ .uleb128 0x49 /* DW_AT_type */ .uleb128 0x13 /* DW_FORM_ref4 */ .uleb128 0x02 /* DW_AT_location */ - .uleb128 0x09 /* SPECIAL_expr */ + .uleb128 0x18 /* DW_FORM_exprloc */ .byte 0x0 /* Terminator */ .byte 0x0 /* Terminator */ .uleb128 24 /* Abbrev start */ @@ -454,7 +454,7 @@ .uleb128 0x31 /* DW_AT_abstract_origin */ .uleb128 0x13 /* DW_FORM_ref4 */ .uleb128 0x02 /* DW_AT_location */ - .uleb128 0x09 /* SPECIAL_expr */ + .uleb128 0x18 /* DW_FORM_exprloc */ .byte 0x0 /* Terminator */ .byte 0x0 /* Terminator */ .uleb128 25 /* Abbrev start */ @@ -465,7 +465,7 @@ .uleb128 0x49 /* DW_AT_type */ .uleb128 0x13 /* DW_FORM_ref4 */ .uleb128 0x02 /* DW_AT_location */ - .uleb128 0x09 /* SPECIAL_expr */ + .uleb128 0x18 /* DW_FORM_exprloc */ .byte 0x0 /* Terminator */ .byte 0x0 /* Terminator */ .uleb128 26 /* Abbrev start */ @@ -476,7 +476,7 @@ .uleb128 0x49 /* DW_AT_type */ .uleb128 0x13 /* DW_FORM_ref4 */ .uleb128 0x02 /* DW_AT_location */ - .uleb128 0x09 /* SPECIAL_expr */ + .uleb128 0x18 /* DW_FORM_exprloc */ .byte 0x0 /* Terminator */ .byte 0x0 /* Terminator */ .uleb128 27 /* Abbrev start */ @@ -487,7 +487,7 @@ .uleb128 0x49 /* DW_AT_type */ .uleb128 0x13 /* DW_FORM_ref4 */ .uleb128 0x02 /* DW_AT_location */ - .uleb128 0x09 /* SPECIAL_expr */ + .uleb128 0x18 /* DW_FORM_exprloc */ .byte 0x0 /* Terminator */ .byte 0x0 /* Terminator */ .uleb128 28 /* Abbrev start */ @@ -498,7 +498,7 @@ .uleb128 0x49 /* DW_AT_type */ .uleb128 0x13 /* DW_FORM_ref4 */ .uleb128 0x02 /* DW_AT_location */ - .uleb128 0x09 /* SPECIAL_expr */ + .uleb128 0x18 /* DW_FORM_exprloc */ .byte 0x0 /* Terminator */ .byte 0x0 /* Terminator */ .uleb128 29 /* Abbrev start */ @@ -507,7 +507,7 @@ .uleb128 0x03 /* DW_AT_name */ .uleb128 0x08 /* DW_FORM_string */ .uleb128 0x02 /* DW_AT_location */ - .uleb128 0x09 /* SPECIAL_expr */ + .uleb128 0x18 /* DW_FORM_exprloc */ .byte 0x0 /* Terminator */ .byte 0x0 /* Terminator */ .byte 0x0 /* Terminator */ diff --git a/testsuite/lib/dwarf.exp b/testsuite/lib/dwarf.exp index d722982..8fc6da6 100644 --- a/testsuite/lib/dwarf.exp +++ b/testsuite/lib/dwarf.exp @@ -1,4 +1,4 @@ -# Copyright 2010-2019 Free Software Foundation, Inc. +# Copyright 2010-2020 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 @@ -117,12 +117,12 @@ proc build_executable_from_fission_assembler { testname executable sources optio # static void func (void) {} # -proc function_range { func src } { +proc function_range { func src {options {debug}} } { global decimal gdb_prompt set exe [standard_temp_file func_addr[pid].x] - gdb_compile $src $exe executable {debug} + gdb_compile $src $exe executable $options gdb_exit gdb_start @@ -167,6 +167,22 @@ proc function_range { func src } { return [list "${func}_label - $func_label_offset" $func_length] } +# Extract the start, length, and end for function called NAME and +# create suitable variables in the callers scope. +proc get_func_info { name {options {debug}} } { + global srcdir subdir srcfile + + upvar 1 "${name}_start" func_start + upvar 1 "${name}_len" func_len + upvar 1 "${name}_end" func_end + + lassign [function_range ${name} \ + [list ${srcdir}/${subdir}/$srcfile] \ + ${options}] \ + func_start func_len + set func_end "$func_start + $func_len" +} + # A DWARF assembler. # # All the variables in this namespace are private to the @@ -206,11 +222,11 @@ proc function_range { func src } { # which will be substituted by one or more standard or macro attributes. # supported macro attributes are: # -# - MACRO_AT_range { FUNC FILE } +# - MACRO_AT_range { FUNC } # It is substituted by DW_AT_low_pc and DW_AT_high_pc with the start and -# end address of function FUNC in file FILE. +# end address of function FUNC in file $srcdir/$subdir/$srcfile. # -# - MACRO_AT_func { FUNC FILE } +# - MACRO_AT_func { FUNC } # It is substituted by DW_AT_name with FUNC and MACRO_AT_range. # # If FORM is given, it should name a DW_FORM_ constant. @@ -221,8 +237,9 @@ proc function_range { func src } { # section automatically. # # If FORM is 'SPECIAL_expr', then VALUE is treated as a location -# expression. The effective form is then DW_FORM_block, and VALUE -# is passed to the (internal) '_location' proc to be translated. +# expression. The effective form is then DW_FORM_block or DW_FORM_exprloc +# for DWARF version >= 4, and VALUE is passed to the (internal) +# '_location' proc to be translated. # This proc implements a miniature DW_OP_ assembler. # # If FORM is not given, it is guessed: @@ -234,11 +251,10 @@ proc function_range { func src } { # and DW_FORM_ref4 is used. See 'new_label' and 'define_label'. # * If VALUE starts with the "%" character, then it is a label # reference too, but DW_FORM_ref_addr is used. -# * Otherwise, VALUE is taken to be a string and DW_FORM_string is -# used. In order to prevent bugs where a numeric value is given but -# no form is specified, it is an error if the value looks like a number -# (using Tcl's "string is integer") and no form is provided. -# More form-guessing functionality may be added. +# * Otherwise, if the attribute name has a default form (f.i. DW_FORM_addr for +# DW_AT_low_pc), then that one is used. +# * Otherwise, an error is reported. Either specify a form explicitly, or +# add a default for the the attribute name in _default_form. # # CHILDREN is just Tcl code that can be used to define child DIEs. It # is evaluated in the caller's context. @@ -377,7 +393,6 @@ namespace eval Dwarf { proc _read_constants {} { global srcdir hex decimal - variable _constants # DWARF name-matching regexp. set dwrx "DW_\[a-zA-Z0-9_\]+" @@ -404,8 +419,6 @@ namespace eval Dwarf { } } close $fd - - set _constants(SPECIAL_expr) $_constants(DW_FORM_block) } proc _quote {string} { @@ -577,9 +590,25 @@ namespace eval Dwarf { } default { + return "" + } + } + } + + proc _default_form { attr } { + switch -exact -- $attr { + DW_AT_low_pc { + return DW_FORM_addr + } + DW_AT_producer - + DW_AT_comp_dir - + DW_AT_linkage_name - + DW_AT_MIPS_linkage_name - + DW_AT_name { return DW_FORM_string } } + return "" } # Map NAME to its canonical form. @@ -596,24 +625,35 @@ namespace eval Dwarf { proc _handle_attribute { attr_name attr_value attr_form } { variable _abbrev_section variable _constants + variable _cu_version _handle_DW_FORM $attr_form $attr_value _defer_output $_abbrev_section { + if { $attr_form eq "SPECIAL_expr" } { + if { $_cu_version < 4 } { + set attr_form_comment "DW_FORM_block" + } else { + set attr_form_comment "DW_FORM_exprloc" + } + } else { + set attr_form_comment $attr_form + } _op .uleb128 $_constants($attr_name) $attr_name - _op .uleb128 $_constants($attr_form) $attr_form + _op .uleb128 $_constants($attr_form) $attr_form_comment } } # Handle macro attribute MACRO_AT_range. proc _handle_macro_at_range { attr_value } { - if {[llength $attr_value] != 2} { - error "usage: MACRO_AT_range { func file }" + if {[llength $attr_value] != 1} { + error "usage: MACRO_AT_range { func }" } set func [lindex $attr_value 0] - set src [lindex $attr_value 1] + global srcdir subdir srcfile + set src ${srcdir}/${subdir}/${srcfile} set result [function_range $func $src] _handle_attribute DW_AT_low_pc [lindex $result 0] \ @@ -625,7 +665,7 @@ namespace eval Dwarf { # Handle macro attribute MACRO_AT_func. proc _handle_macro_at_func { attr_value } { - if {[llength $attr_value] != 2} { + if {[llength $attr_value] != 1} { error "usage: MACRO_AT_func { func file }" } _handle_attribute DW_AT_name [lindex $attr_value 0] DW_FORM_string @@ -678,11 +718,13 @@ namespace eval Dwarf { _guess_form $attr_value attr_value } } else { - # If the value looks like an integer, a form is required. - if [string is integer $attr_value] { - error "Integer value requires a form" - } set attr_form [_guess_form $attr_value attr_value] + if { $attr_form eq "" } { + set attr_form [_default_form $attr_name] + } + if { $attr_form eq "" } { + error "No form for $attr_name $attr_value" + } } set attr_form [_map_name $attr_form _FORM] @@ -692,8 +734,8 @@ namespace eval Dwarf { _defer_output $_abbrev_section { # Terminator. - _op .byte 0x0 Terminator - _op .byte 0x0 Terminator + _op .byte 0x0 "DW_AT - Terminator" + _op .byte 0x0 "DW_FORM - Terminator" } if {$has_children} { @@ -809,15 +851,6 @@ namespace eval Dwarf { _emit "${name}:" } - # Declare a global label. This is typically used to refer to - # labels defined in other files, for example a function defined in - # a .c file. - proc extern {args} { - foreach name $args { - _op .global $name - } - } - # A higher-level interface to label handling. # # ARGS is a list of label descriptors. Each one is either a @@ -841,13 +874,13 @@ namespace eval Dwarf { set name [lindex $arg 0] set text [lindex $arg 1] - upvar $name label_var - if {$text == ""} { - set label_var [new_label] - } else { - set label_var [new_label $text] + if { $text == "" } { + set text $name } + upvar $name label_var + set label_var [new_label $text] + proc ${name}: {args} [format { define_label %s uplevel $args @@ -1013,13 +1046,14 @@ namespace eval Dwarf { # default = 0 (32-bit) # version n - DWARF version number to emit # default = 4 - # addr_size n - the size of addresses, 32, 64, or default + # addr_size n - the size of addresses in bytes: 4, 8, or default # default = default # fission 0|1 - boolean indicating if generating Fission debug info # default = 0 # BODY is Tcl code that emits the DIEs which make up the body of # the CU. It is evaluated in the caller's context. proc cu {options body} { + variable _constants variable _cu_count variable _abbrev_section variable _abbrev_num @@ -1059,6 +1093,12 @@ namespace eval Dwarf { set _abbrev_section ".debug_abbrev.dwo" } + if {$_cu_version < 4} { + set _constants(SPECIAL_expr) $_constants(DW_FORM_block) + } else { + set _constants(SPECIAL_expr) $_constants(DW_FORM_exprloc) + } + _section $section set cu_num [incr _cu_count] @@ -1089,8 +1129,7 @@ namespace eval Dwarf { _defer_output $_abbrev_section { # Emit the terminator. - _op .byte 0x0 Terminator - _op .byte 0x0 Terminator + _op .byte 0x0 "Abbrev end - Terminator" } define_label $end_label @@ -1104,7 +1143,7 @@ namespace eval Dwarf { # default = 0 (32-bit) # version n - DWARF version number to emit # default = 4 - # addr_size n - the size of addresses, 32, 64, or default + # addr_size n - the size of addresses in bytes: 4, 8, or default # default = default # fission 0|1 - boolean indicating if generating Fission debug info # default = 0 @@ -1198,8 +1237,7 @@ namespace eval Dwarf { _defer_output $_abbrev_section { # Emit the terminator. - _op .byte 0x0 Terminator - _op .byte 0x0 Terminator + _op .byte 0x0 "Abbrev end - Terminator" } define_label $end_label @@ -1227,42 +1265,37 @@ namespace eval Dwarf { set section ".debug_ranges" _section $section - proc sequence {{ranges {}}} { + proc sequence { body } { variable _debug_ranges_64_bit # Emit the sequence of addresses. - set base "" - foreach range $ranges { - set range [uplevel 1 "subst \"$range\""] - set type [lindex $range 0] - switch -exact -- $type { - base { - set base [lrange $range 1 end] - - if { $_debug_ranges_64_bit } then { - _op .8byte 0xffffffffffffffff "Base Marker" - _op .8byte $base "Base Address" - } else { - _op .4byte 0xffffffff "Base Marker" - _op .4byte $base "Base Address" - } - } - range { - set start [lindex $range 1] - set end [lrange $range 2 end] - - if { $_debug_ranges_64_bit } then { - _op .8byte $start "Start Address" - _op .8byte $end "End Address" - } else { - _op .4byte $start "Start Address" - _op .4byte $end "End Address" - } - } - default { error "unknown range type: $type " } + + proc base { addr } { + variable _debug_ranges_64_bit + + if { $_debug_ranges_64_bit } then { + _op .8byte 0xffffffffffffffff "Base Marker" + _op .8byte $addr "Base Address" + } else { + _op .4byte 0xffffffff "Base Marker" + _op .4byte $addr "Base Address" } } + proc range { start end } { + variable _debug_ranges_64_bit + + if { $_debug_ranges_64_bit } then { + _op .8byte $start "Start Address" + _op .8byte $end "End Address" + } else { + _op .4byte $start "Start Address" + _op .4byte $end "End Address" + } + } + + uplevel $body + # End of the sequence. if { $_debug_ranges_64_bit } then { _op .8byte 0x0 "End of Sequence Marker (Part 1)" @@ -1285,7 +1318,7 @@ namespace eval Dwarf { # default = 0 (32-bit) # version n - DWARF version number to emit # default = 4 - # addr_size n - the size of addresses, 32, 64, or default + # addr_size n - the size of addresses in bytes: 4, 8, or default # default = default # # LABEL is the label of the current unit (which is probably @@ -1312,12 +1345,16 @@ namespace eval Dwarf { set is_64 0 set _unit_version 4 set _unit_addr_size default + set _line_saw_program 0 + set _line_saw_file 0 + set _default_is_stmt 1 foreach { name value } $options { switch -exact -- $name { is_64 { set is_64 $value } version { set _unit_version $value } addr_size { set _unit_addr_size $value } + default_is_stmt { set _default_is_stmt $value } default { error "unknown option $name" } } } @@ -1364,7 +1401,7 @@ namespace eval Dwarf { define_label $header_len_label _op .byte 1 "minimum_instruction_length" - _op .byte 1 "default_is_stmt" + _op .byte $_default_is_stmt "default_is_stmt" _op .byte 1 "line_base" _op .byte 1 "line_range" _op .byte 10 "opcode_base" @@ -1406,6 +1443,9 @@ namespace eval Dwarf { proc program {statements} { variable _line_saw_program variable _line_header_end_label + variable _line + + set _line 1 if "! $_line_saw_program" { # Terminate the file list. @@ -1430,23 +1470,67 @@ namespace eval Dwarf { } proc DW_LNE_end_sequence {} { + variable _line _op .byte 0 _op .uleb128 1 _op .byte 1 + set _line 1 + } + + proc DW_LNE_user { len opcode } { + set DW_LNE_lo_usr 0x80 + set DW_LNE_hi_usr 0xff + if { $DW_LNE_lo_usr <= $opcode + && $opcode <= $DW_LNE_hi_usr } { + _op .byte 0 + _op .uleb128 $len + _op .byte $opcode + for {set i 1} {$i < $len} {incr i} { + _op .byte 0 + } + } else { + error "unknown vendor specific extended opcode: $opcode" + } } proc DW_LNS_copy {} { _op .byte 1 } + proc DW_LNS_negate_stmt {} { + _op .byte 6 + } + proc DW_LNS_advance_pc {offset} { _op .byte 2 _op .uleb128 ${offset} } proc DW_LNS_advance_line {offset} { + variable _line _op .byte 3 _op .sleb128 ${offset} + set _line [expr $_line + $offset] + } + + # A pseudo line number program instruction, that can be used instead + # of DW_LNS_advance_line. Rather than writing: + # {DW_LNS_advance_line [expr $line1 - 1]} + # {DW_LNS_advance_line [expr $line2 - $line1]} + # {DW_LNS_advance_line [expr $line3 - $line2]} + # we can just write: + # {line $line1} + # {line $line2} + # {line $line3} + proc line {line} { + variable _line + set offset [expr $line - $_line] + DW_LNS_advance_line $offset + } + + proc DW_LNS_set_file {num} { + _op .byte 4 + _op .sleb128 ${num} } foreach statement $statements { -- 2.18.4