[1/2,gdb/testsuite] Add proc _location_no_split

Message ID 20240906144225.29330-1-tdevries@suse.de
State New
Headers
Series [1/2,gdb/testsuite] Add proc _location_no_split |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gdb_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_gdb_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_gdb_check--master-aarch64 success Test passed

Commit Message

Tom de Vries Sept. 6, 2024, 2:42 p.m. UTC
  Proc _location splits its first argument into a list of lines.

That approach is somewhat cumbersome when using it recursively.

Add a variant _location_no_split that treats its first argument as a list of
lines.

Also factor out proc _location_line.

Tested on x86_64-linux.
---
 gdb/testsuite/lib/dwarf.exp | 268 +++++++++++++++++++-----------------
 1 file changed, 141 insertions(+), 127 deletions(-)


base-commit: 9772824e0e34a8e521559c448cce8f3e75b67fe7
  

Comments

Tom de Vries Sept. 23, 2024, 8:03 a.m. UTC | #1
On 9/6/24 16:42, Tom de Vries wrote:
> Proc _location splits its first argument into a list of lines.
> 
> That approach is somewhat cumbersome when using it recursively.
> 
> Add a variant _location_no_split that treats its first argument as a list of
> lines.
> 
> Also factor out proc _location_line.
> 

Ping.

Thanks,
- Tom

> Tested on x86_64-linux.
> ---
>   gdb/testsuite/lib/dwarf.exp | 268 +++++++++++++++++++-----------------
>   1 file changed, 141 insertions(+), 127 deletions(-)
> 
> diff --git a/gdb/testsuite/lib/dwarf.exp b/gdb/testsuite/lib/dwarf.exp
> index 995cdcac941..58e1a116bd8 100644
> --- a/gdb/testsuite/lib/dwarf.exp
> +++ b/gdb/testsuite/lib/dwarf.exp
> @@ -1226,7 +1226,7 @@ namespace eval Dwarf {
>       # suitable for use in the attributes to a DIE.  Its output is
>       # prefixed with "=" to make it automatically use DW_FORM_block.
>       #
> -    # BODY is split by lines, and each line is taken to be a list.
> +    # LINE is a location expression.
>       #
>       # DWARF_VERSION is the DWARF version for the section where the location
>       # description is found.
> @@ -1245,169 +1245,183 @@ namespace eval Dwarf {
>       # forms are accepted.
>       # FIXME argument handling
>       # FIXME move docs
> -    proc _location { body dwarf_version addr_size offset_size } {
> +    proc _location_line { line dwarf_version addr_size offset_size } {
>   	variable _constants
>   
> -	foreach line [split $body \n] {
> -	    # Ignore blank lines, and allow embedded comments.
> -	    if {[lindex $line 0] == "" || [regexp -- {^[ \t]*#} $line]} {
> -		continue
> -	    }
> -	    set opcode [_map_name [lindex $line 0] _OP]
> -	    _op .byte $_constants($opcode) $opcode
> +	# Ignore blank lines, and allow embedded comments.
> +	if {[lindex $line 0] == "" || [regexp -- {^[ \t]*#} $line]} {
> +	    return
> +	}
> +	set opcode [_map_name [lindex $line 0] _OP]
> +	_op .byte $_constants($opcode) $opcode
>   
> -	    array unset argvec *
> -	    switch -exact -- $opcode {
> -		DW_OP_addr {
> -		    _get_args $line $opcode size
> -		    _op .${addr_size}byte $argvec(size)
> -		}
> +	array unset argvec *
> +	switch -exact -- $opcode {
> +	    DW_OP_addr {
> +		_get_args $line $opcode size
> +		_op .${addr_size}byte $argvec(size)
> +	    }
>   
> -		DW_OP_GNU_addr_index {
> -		    variable _debug_addr_index
> -		    variable _cu_addr_size
> +	    DW_OP_GNU_addr_index {
> +		variable _debug_addr_index
> +		variable _cu_addr_size
>   
> -		    _op .uleb128 ${_debug_addr_index}
> -		    incr _debug_addr_index
> +		_op .uleb128 ${_debug_addr_index}
> +		incr _debug_addr_index
>   
> -		    _defer_output .debug_addr {
> -			_op .${_cu_addr_size}byte [lindex $line 1]
> -		    }
> +		_defer_output .debug_addr {
> +		    _op .${_cu_addr_size}byte [lindex $line 1]
>   		}
> +	    }
>   
> -		DW_OP_regx {
> -		    _get_args $line $opcode register
> -		    _op .uleb128 $argvec(register)
> -		}
> +	    DW_OP_regx {
> +		_get_args $line $opcode register
> +		_op .uleb128 $argvec(register)
> +	    }
>   
> -		DW_OP_pick -
> -		DW_OP_const1u -
> -		DW_OP_const1s {
> -		    _get_args $line $opcode const
> -		    _op .byte $argvec(const)
> -		}
> +	    DW_OP_pick -
> +	    DW_OP_const1u -
> +	    DW_OP_const1s {
> +		_get_args $line $opcode const
> +		_op .byte $argvec(const)
> +	    }
>   
> -		DW_OP_const2u -
> -		DW_OP_const2s {
> -		    _get_args $line $opcode const
> -		    _op .2byte $argvec(const)
> -		}
> +	    DW_OP_const2u -
> +	    DW_OP_const2s {
> +		_get_args $line $opcode const
> +		_op .2byte $argvec(const)
> +	    }
>   
> -		DW_OP_const4u -
> -		DW_OP_const4s {
> -		    _get_args $line $opcode const
> -		    _op .4byte $argvec(const)
> -		}
> +	    DW_OP_const4u -
> +	    DW_OP_const4s {
> +		_get_args $line $opcode const
> +		_op .4byte $argvec(const)
> +	    }
>   
> -		DW_OP_const8u -
> -		DW_OP_const8s {
> -		    _get_args $line $opcode const
> -		    _op .8byte $argvec(const)
> -		}
> +	    DW_OP_const8u -
> +	    DW_OP_const8s {
> +		_get_args $line $opcode const
> +		_op .8byte $argvec(const)
> +	    }
>   
> -		DW_OP_constu {
> -		    _get_args $line $opcode const
> -		    _op .uleb128 $argvec(const)
> -		}
> -		DW_OP_consts {
> -		    _get_args $line $opcode const
> -		    _op .sleb128 $argvec(const)
> -		}
> +	    DW_OP_constu {
> +		_get_args $line $opcode const
> +		_op .uleb128 $argvec(const)
> +	    }
> +	    DW_OP_consts {
> +		_get_args $line $opcode const
> +		_op .sleb128 $argvec(const)
> +	    }
>   
> -		DW_OP_plus_uconst {
> -		    _get_args $line $opcode const
> -		    _op .uleb128 $argvec(const)
> -		}
> +	    DW_OP_plus_uconst {
> +		_get_args $line $opcode const
> +		_op .uleb128 $argvec(const)
> +	    }
>   
> -		DW_OP_piece {
> -		    _get_args $line $opcode size
> -		    _op .uleb128 $argvec(size)
> -		}
> +	    DW_OP_piece {
> +		_get_args $line $opcode size
> +		_op .uleb128 $argvec(size)
> +	    }
>   
> -		DW_OP_bit_piece {
> -		    _get_args $line $opcode size offset
> -		    _op .uleb128 $argvec(size)
> -		    _op .uleb128 $argvec(offset)
> -		}
> +	    DW_OP_bit_piece {
> +		_get_args $line $opcode size offset
> +		_op .uleb128 $argvec(size)
> +		_op .uleb128 $argvec(offset)
> +	    }
>   
> -		DW_OP_skip -
> -		DW_OP_bra {
> -		    _get_args $line $opcode label
> -		    _op .2byte $argvec(label)
> -		}
> +	    DW_OP_skip -
> +	    DW_OP_bra {
> +		_get_args $line $opcode label
> +		_op .2byte $argvec(label)
> +	    }
>   
> -		DW_OP_implicit_value {
> -		    set l1 [new_label "value_start"]
> -		    set l2 [new_label "value_end"]
> -		    _op .uleb128 "$l2 - $l1"
> -		    define_label $l1
> -		    foreach value [lrange $line 1 end] {
> -			switch -regexp -- $value {
> -			    {^0x[[:xdigit:]]{1,2}$} {_op .byte $value}
> -			    {^0x[[:xdigit:]]{4}$} {_op .2byte $value}
> -			    {^0x[[:xdigit:]]{8}$} {_op .4byte $value}
> -			    {^0x[[:xdigit:]]{16}$} {_op .8byte $value}
> -			    default {
> -				error "bad value '$value' in DW_OP_implicit_value"
> -			    }
> +	    DW_OP_implicit_value {
> +		set l1 [new_label "value_start"]
> +		set l2 [new_label "value_end"]
> +		_op .uleb128 "$l2 - $l1"
> +		define_label $l1
> +		foreach value [lrange $line 1 end] {
> +		    switch -regexp -- $value {
> +			{^0x[[:xdigit:]]{1,2}$} {_op .byte $value}
> +			{^0x[[:xdigit:]]{4}$} {_op .2byte $value}
> +			{^0x[[:xdigit:]]{8}$} {_op .4byte $value}
> +			{^0x[[:xdigit:]]{16}$} {_op .8byte $value}
> +			default {
> +			    error "bad value '$value' in DW_OP_implicit_value"
>   			}
>   		    }
> -		    define_label $l2
>   		}
> +		define_label $l2
> +	    }
>   
> -		DW_OP_implicit_pointer -
> -		DW_OP_GNU_implicit_pointer {
> -		    _get_args $line $opcode label offset
> +	    DW_OP_implicit_pointer -
> +	    DW_OP_GNU_implicit_pointer {
> +		_get_args $line $opcode label offset
>   
> -		    # Here label is a section offset.
> -		    if { $dwarf_version == 2 } {
> -			_op .${addr_size}byte $argvec(label)
> -		    } else {
> -			_op_offset $offset_size $argvec(label)
> -		    }
> -		    _op .sleb128 $argvec(offset)
> +		# Here label is a section offset.
> +		if { $dwarf_version == 2 } {
> +		    _op .${addr_size}byte $argvec(label)
> +		} else {
> +		    _op_offset $offset_size $argvec(label)
>   		}
> +		_op .sleb128 $argvec(offset)
> +	    }
>   
> -		DW_OP_GNU_variable_value {
> -		    _get_args $line $opcode label
> +	    DW_OP_GNU_variable_value {
> +		_get_args $line $opcode label
>   
> -		    # Here label is a section offset.
> -		    if { $dwarf_version == 2 } {
> -			_op .${addr_size}byte $argvec(label)
> -		    } else {
> -			_op_offset $offset_size $argvec(label)
> -		    }
> +		# Here label is a section offset.
> +		if { $dwarf_version == 2 } {
> +		    _op .${addr_size}byte $argvec(label)
> +		} else {
> +		    _op_offset $offset_size $argvec(label)
>   		}
> +	    }
>   
> -		DW_OP_deref_size {
> -		    _get_args $line $opcode size
> -		    _op .byte $argvec(size)
> -		}
> +	    DW_OP_deref_size {
> +		_get_args $line $opcode size
> +		_op .byte $argvec(size)
> +	    }
>   
> -		DW_OP_bregx {
> -		    _get_args $line $opcode register offset
> -		    _op .uleb128 $argvec(register)
> -		    _op .sleb128 $argvec(offset)
> -		}
> +	    DW_OP_bregx {
> +		_get_args $line $opcode register offset
> +		_op .uleb128 $argvec(register)
> +		_op .sleb128 $argvec(offset)
> +	    }
>   
> -		DW_OP_fbreg {
> -		    _get_args $line $opcode offset
> -		    _op .sleb128 $argvec(offset)
> -		}
> +	    DW_OP_fbreg {
> +		_get_args $line $opcode offset
> +		_op .sleb128 $argvec(offset)
> +	    }
>   
> -		DW_OP_fbreg {
> -		    _op .sleb128 [lindex $line 1]
> -		}
> +	    DW_OP_fbreg {
> +		_op .sleb128 [lindex $line 1]
> +	    }
>   
> -		default {
> -		    if {[llength $line] > 1} {
> -			error "Unimplemented: operands in location for $opcode"
> -		    }
> +	    default {
> +		if {[llength $line] > 1} {
> +		    error "Unimplemented: operands in location for $opcode"
>   		}
>   	    }
>   	}
>       }
>   
> +    # BODY is a list, and each list item is handled by _location_line.
> +    proc _location_no_split { body args } {
> +	variable _constants
> +
> +	foreach line $body {
> +	    _location_line $line {*}$args
> +	}
> +    }
> +
> +    # BODY is split by lines, and each line is handled by _location_line.
> +    proc _location { body args } {
> +	variable _constants
> +
> +	_location_no_split [split $body \n] {*}$args
> +    }
> +
>       # Return a label that references the current position in the
>       # .debug_addr table.  When a user is creating split DWARF they
>       # will define two CUs, the first will be the split DWARF content,
> 
> base-commit: 9772824e0e34a8e521559c448cce8f3e75b67fe7
  
Tom Tromey Sept. 23, 2024, 6:57 p.m. UTC | #2
>>>>> "Tom" == Tom de Vries <tdevries@suse.de> writes:

Tom> Proc _location splits its first argument into a list of lines.
Tom> That approach is somewhat cumbersome when using it recursively.

Tom> Add a variant _location_no_split that treats its first argument as a list of
Tom> lines.

This is also kind of cumbersome though as it leads to weird-looking
"double quoted" code.

I think a more Tcl-ish approach would be to split by lines, and then
reassemble lines by reading until "info complete" reports a complete
line.

There's a FIXME to this effect just before the proc... I just didn't do
this since I was feeling lazy & didn't need it.

Then your test:

+		    { DW_AT_location {
+			DW_OP_entry_value { {DW_OP_bregx $::dwarf_regnum 0} {DW_OP_deref_size 4 } }
+			DW_OP_stack_value
+		    } SPECIAL_expr }

could be written as

    DW_OP_entry_value {
      DW_OP_bregx $::dwarf_regnum 0
      DW_OP_deref_size 4
    }

... and I think this would work fine.

thanks,
Tom
  

Patch

diff --git a/gdb/testsuite/lib/dwarf.exp b/gdb/testsuite/lib/dwarf.exp
index 995cdcac941..58e1a116bd8 100644
--- a/gdb/testsuite/lib/dwarf.exp
+++ b/gdb/testsuite/lib/dwarf.exp
@@ -1226,7 +1226,7 @@  namespace eval Dwarf {
     # suitable for use in the attributes to a DIE.  Its output is
     # prefixed with "=" to make it automatically use DW_FORM_block.
     #
-    # BODY is split by lines, and each line is taken to be a list.
+    # LINE is a location expression.
     #
     # DWARF_VERSION is the DWARF version for the section where the location
     # description is found.
@@ -1245,169 +1245,183 @@  namespace eval Dwarf {
     # forms are accepted.
     # FIXME argument handling
     # FIXME move docs
-    proc _location { body dwarf_version addr_size offset_size } {
+    proc _location_line { line dwarf_version addr_size offset_size } {
 	variable _constants
 
-	foreach line [split $body \n] {
-	    # Ignore blank lines, and allow embedded comments.
-	    if {[lindex $line 0] == "" || [regexp -- {^[ \t]*#} $line]} {
-		continue
-	    }
-	    set opcode [_map_name [lindex $line 0] _OP]
-	    _op .byte $_constants($opcode) $opcode
+	# Ignore blank lines, and allow embedded comments.
+	if {[lindex $line 0] == "" || [regexp -- {^[ \t]*#} $line]} {
+	    return
+	}
+	set opcode [_map_name [lindex $line 0] _OP]
+	_op .byte $_constants($opcode) $opcode
 
-	    array unset argvec *
-	    switch -exact -- $opcode {
-		DW_OP_addr {
-		    _get_args $line $opcode size
-		    _op .${addr_size}byte $argvec(size)
-		}
+	array unset argvec *
+	switch -exact -- $opcode {
+	    DW_OP_addr {
+		_get_args $line $opcode size
+		_op .${addr_size}byte $argvec(size)
+	    }
 
-		DW_OP_GNU_addr_index {
-		    variable _debug_addr_index
-		    variable _cu_addr_size
+	    DW_OP_GNU_addr_index {
+		variable _debug_addr_index
+		variable _cu_addr_size
 
-		    _op .uleb128 ${_debug_addr_index}
-		    incr _debug_addr_index
+		_op .uleb128 ${_debug_addr_index}
+		incr _debug_addr_index
 
-		    _defer_output .debug_addr {
-			_op .${_cu_addr_size}byte [lindex $line 1]
-		    }
+		_defer_output .debug_addr {
+		    _op .${_cu_addr_size}byte [lindex $line 1]
 		}
+	    }
 
-		DW_OP_regx {
-		    _get_args $line $opcode register
-		    _op .uleb128 $argvec(register)
-		}
+	    DW_OP_regx {
+		_get_args $line $opcode register
+		_op .uleb128 $argvec(register)
+	    }
 
-		DW_OP_pick -
-		DW_OP_const1u -
-		DW_OP_const1s {
-		    _get_args $line $opcode const
-		    _op .byte $argvec(const)
-		}
+	    DW_OP_pick -
+	    DW_OP_const1u -
+	    DW_OP_const1s {
+		_get_args $line $opcode const
+		_op .byte $argvec(const)
+	    }
 
-		DW_OP_const2u -
-		DW_OP_const2s {
-		    _get_args $line $opcode const
-		    _op .2byte $argvec(const)
-		}
+	    DW_OP_const2u -
+	    DW_OP_const2s {
+		_get_args $line $opcode const
+		_op .2byte $argvec(const)
+	    }
 
-		DW_OP_const4u -
-		DW_OP_const4s {
-		    _get_args $line $opcode const
-		    _op .4byte $argvec(const)
-		}
+	    DW_OP_const4u -
+	    DW_OP_const4s {
+		_get_args $line $opcode const
+		_op .4byte $argvec(const)
+	    }
 
-		DW_OP_const8u -
-		DW_OP_const8s {
-		    _get_args $line $opcode const
-		    _op .8byte $argvec(const)
-		}
+	    DW_OP_const8u -
+	    DW_OP_const8s {
+		_get_args $line $opcode const
+		_op .8byte $argvec(const)
+	    }
 
-		DW_OP_constu {
-		    _get_args $line $opcode const
-		    _op .uleb128 $argvec(const)
-		}
-		DW_OP_consts {
-		    _get_args $line $opcode const
-		    _op .sleb128 $argvec(const)
-		}
+	    DW_OP_constu {
+		_get_args $line $opcode const
+		_op .uleb128 $argvec(const)
+	    }
+	    DW_OP_consts {
+		_get_args $line $opcode const
+		_op .sleb128 $argvec(const)
+	    }
 
-		DW_OP_plus_uconst {
-		    _get_args $line $opcode const
-		    _op .uleb128 $argvec(const)
-		}
+	    DW_OP_plus_uconst {
+		_get_args $line $opcode const
+		_op .uleb128 $argvec(const)
+	    }
 
-		DW_OP_piece {
-		    _get_args $line $opcode size
-		    _op .uleb128 $argvec(size)
-		}
+	    DW_OP_piece {
+		_get_args $line $opcode size
+		_op .uleb128 $argvec(size)
+	    }
 
-		DW_OP_bit_piece {
-		    _get_args $line $opcode size offset
-		    _op .uleb128 $argvec(size)
-		    _op .uleb128 $argvec(offset)
-		}
+	    DW_OP_bit_piece {
+		_get_args $line $opcode size offset
+		_op .uleb128 $argvec(size)
+		_op .uleb128 $argvec(offset)
+	    }
 
-		DW_OP_skip -
-		DW_OP_bra {
-		    _get_args $line $opcode label
-		    _op .2byte $argvec(label)
-		}
+	    DW_OP_skip -
+	    DW_OP_bra {
+		_get_args $line $opcode label
+		_op .2byte $argvec(label)
+	    }
 
-		DW_OP_implicit_value {
-		    set l1 [new_label "value_start"]
-		    set l2 [new_label "value_end"]
-		    _op .uleb128 "$l2 - $l1"
-		    define_label $l1
-		    foreach value [lrange $line 1 end] {
-			switch -regexp -- $value {
-			    {^0x[[:xdigit:]]{1,2}$} {_op .byte $value}
-			    {^0x[[:xdigit:]]{4}$} {_op .2byte $value}
-			    {^0x[[:xdigit:]]{8}$} {_op .4byte $value}
-			    {^0x[[:xdigit:]]{16}$} {_op .8byte $value}
-			    default {
-				error "bad value '$value' in DW_OP_implicit_value"
-			    }
+	    DW_OP_implicit_value {
+		set l1 [new_label "value_start"]
+		set l2 [new_label "value_end"]
+		_op .uleb128 "$l2 - $l1"
+		define_label $l1
+		foreach value [lrange $line 1 end] {
+		    switch -regexp -- $value {
+			{^0x[[:xdigit:]]{1,2}$} {_op .byte $value}
+			{^0x[[:xdigit:]]{4}$} {_op .2byte $value}
+			{^0x[[:xdigit:]]{8}$} {_op .4byte $value}
+			{^0x[[:xdigit:]]{16}$} {_op .8byte $value}
+			default {
+			    error "bad value '$value' in DW_OP_implicit_value"
 			}
 		    }
-		    define_label $l2
 		}
+		define_label $l2
+	    }
 
-		DW_OP_implicit_pointer -
-		DW_OP_GNU_implicit_pointer {
-		    _get_args $line $opcode label offset
+	    DW_OP_implicit_pointer -
+	    DW_OP_GNU_implicit_pointer {
+		_get_args $line $opcode label offset
 
-		    # Here label is a section offset.
-		    if { $dwarf_version == 2 } {
-			_op .${addr_size}byte $argvec(label)
-		    } else {
-			_op_offset $offset_size $argvec(label)
-		    }
-		    _op .sleb128 $argvec(offset)
+		# Here label is a section offset.
+		if { $dwarf_version == 2 } {
+		    _op .${addr_size}byte $argvec(label)
+		} else {
+		    _op_offset $offset_size $argvec(label)
 		}
+		_op .sleb128 $argvec(offset)
+	    }
 
-		DW_OP_GNU_variable_value {
-		    _get_args $line $opcode label
+	    DW_OP_GNU_variable_value {
+		_get_args $line $opcode label
 
-		    # Here label is a section offset.
-		    if { $dwarf_version == 2 } {
-			_op .${addr_size}byte $argvec(label)
-		    } else {
-			_op_offset $offset_size $argvec(label)
-		    }
+		# Here label is a section offset.
+		if { $dwarf_version == 2 } {
+		    _op .${addr_size}byte $argvec(label)
+		} else {
+		    _op_offset $offset_size $argvec(label)
 		}
+	    }
 
-		DW_OP_deref_size {
-		    _get_args $line $opcode size
-		    _op .byte $argvec(size)
-		}
+	    DW_OP_deref_size {
+		_get_args $line $opcode size
+		_op .byte $argvec(size)
+	    }
 
-		DW_OP_bregx {
-		    _get_args $line $opcode register offset
-		    _op .uleb128 $argvec(register)
-		    _op .sleb128 $argvec(offset)
-		}
+	    DW_OP_bregx {
+		_get_args $line $opcode register offset
+		_op .uleb128 $argvec(register)
+		_op .sleb128 $argvec(offset)
+	    }
 
-		DW_OP_fbreg {
-		    _get_args $line $opcode offset
-		    _op .sleb128 $argvec(offset)
-		}
+	    DW_OP_fbreg {
+		_get_args $line $opcode offset
+		_op .sleb128 $argvec(offset)
+	    }
 
-		DW_OP_fbreg {
-		    _op .sleb128 [lindex $line 1]
-		}
+	    DW_OP_fbreg {
+		_op .sleb128 [lindex $line 1]
+	    }
 
-		default {
-		    if {[llength $line] > 1} {
-			error "Unimplemented: operands in location for $opcode"
-		    }
+	    default {
+		if {[llength $line] > 1} {
+		    error "Unimplemented: operands in location for $opcode"
 		}
 	    }
 	}
     }
 
+    # BODY is a list, and each list item is handled by _location_line.
+    proc _location_no_split { body args } {
+	variable _constants
+
+	foreach line $body {
+	    _location_line $line {*}$args
+	}
+    }
+
+    # BODY is split by lines, and each line is handled by _location_line.
+    proc _location { body args } {
+	variable _constants
+
+	_location_no_split [split $body \n] {*}$args
+    }
+
     # Return a label that references the current position in the
     # .debug_addr table.  When a user is creating split DWARF they
     # will define two CUs, the first will be the split DWARF content,