From: Mark Wielaard <mark@klomp.org>
To: dwz@sourceware.org
Cc: Mark Wielaard <mark@klomp.org>
Subject: [PATCH] Update dwarf.exp assembler from gdb.
Date: Mon, 14 Dec 2020 22:19:45 +0100 [thread overview]
Message-ID: <20201214211945.9656-1-mark@klomp.org> (raw)
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
next reply other threads:[~2020-12-14 21:19 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-12-14 21:19 Mark Wielaard [this message]
2020-12-20 8:33 ` Tom de Vries
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20201214211945.9656-1-mark@klomp.org \
--to=mark@klomp.org \
--cc=dwz@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).