From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mx2.suse.de (mx2.suse.de [195.135.220.15]) by sourceware.org (Postfix) with ESMTPS id 49B673858038 for ; Sun, 20 Dec 2020 08:33:45 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 49B673858038 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=tdevries@suse.de X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id 66876AC7F; Sun, 20 Dec 2020 08:33:44 +0000 (UTC) Subject: Re: [PATCH] Update dwarf.exp assembler from gdb. To: Mark Wielaard , dwz@sourceware.org References: <20201214211945.9656-1-mark@klomp.org> From: Tom de Vries Message-ID: Date: Sun, 20 Dec 2020 09:33:43 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.5.0 MIME-Version: 1.0 In-Reply-To: <20201214211945.9656-1-mark@klomp.org> Content-Type: text/plain; charset=utf-8 Content-Language: en-US Content-Transfer-Encoding: 7bit X-Spam-Status: No, score=-13.7 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_STATUS, NICE_REPLY_A, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, 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: Sun, 20 Dec 2020 08:33:48 -0000 On 12/14/20 10:19 PM, Mark Wielaard wrote: > 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) > Thanks for the update. > Also fix up the generated varval.S (pr24823.sh) to use DW_FORM_exprloc. Yeah, that's from the time we didn't have the DWARF assembler in dwz sources yet, I think eventually we want that test-case rewritting to use dwarf assembly. Anyway, this is fine for now. LGTM, please commit. Thanks, - Tom > --- > 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 { >