[2/6] DW attribute macro MACRO_AT_func and MACRO_AT_range

Message ID 1414195968-3333-3-git-send-email-yao@codesourcery.com
State New, archived
Headers

Commit Message

Yao Qi Oct. 25, 2014, 12:12 a.m. UTC
  This patch addes DW macro attributes MACRO_AT_func and MACRO_AT_range
in dwarf assembler, which emits "DW_AT_low_pc func_start addr" and
"DW_AT_high_pc func_end addr".  func_start and func_end are computed
automatically by proc function_range.

These two attributes are pseudo attribute or macro attribute, which
means they are not standard dwarf attribute in dwarf spec.  Then can
be substituted or expanded to standard attributes or macro attributes.
See details in the comments to them.  Dwarf assembler is extended to
handle them.

Now the attributes name/low_pc/high_pc can be replaced with
MACRO_AT_func like this:

    subprogram {
	{name main}
	{low_pc main_start addr}
	{high_pc main_end addr}
    }

becomes:

    subprogram {
	{MACRO_AT_func { main ${srcdir}/${subdir}/${srcfile} }}
    }

users don't have to worry about the start and end of function main, and
they only need to add a label main_label in main.

gdb/testsuite:

2014-10-24  Yao Qi  <yao@codesourcery.com>

	* lib/dwarf.exp (function_range): New procedure.
	(Dwarf::_handle_macro_attribute): New procedure.
	(Dwarf): Handle MACRO_AT_func and MACRO_AT_range.
---
 gdb/testsuite/lib/dwarf.exp | 128 +++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 122 insertions(+), 6 deletions(-)
  

Comments

Doug Evans Nov. 4, 2014, 10:50 p.m. UTC | #1
Yao Qi writes:
 > This patch addes DW macro attributes MACRO_AT_func and MACRO_AT_range
 > in dwarf assembler, which emits "DW_AT_low_pc func_start addr" and
 > "DW_AT_high_pc func_end addr".  func_start and func_end are computed
 > automatically by proc function_range.
 > 
 > These two attributes are pseudo attribute or macro attribute, which
 > means they are not standard dwarf attribute in dwarf spec.  Then can
 > be substituted or expanded to standard attributes or macro attributes.
 > See details in the comments to them.  Dwarf assembler is extended to
 > handle them.
 > 
 > Now the attributes name/low_pc/high_pc can be replaced with
 > MACRO_AT_func like this:
 > 
 >     subprogram {
 > 	{name main}
 > 	{low_pc main_start addr}
 > 	{high_pc main_end addr}
 >     }
 > 
 > becomes:
 > 
 >     subprogram {
 > 	{MACRO_AT_func { main ${srcdir}/${subdir}/${srcfile} }}
 >     }
 > 
 > users don't have to worry about the start and end of function main, and
 > they only need to add a label main_label in main.
 > 
 > gdb/testsuite:
 > 
 > 2014-10-24  Yao Qi  <yao@codesourcery.com>
 > 
 > 	* lib/dwarf.exp (function_range): New procedure.
 > 	(Dwarf::_handle_macro_attribute): New procedure.
 > 	(Dwarf): Handle MACRO_AT_func and MACRO_AT_range.
 > ---
 >  gdb/testsuite/lib/dwarf.exp | 128 +++++++++++++++++++++++++++++++++++++++++---
 >  1 file changed, 122 insertions(+), 6 deletions(-)
 > 
 > diff --git a/gdb/testsuite/lib/dwarf.exp b/gdb/testsuite/lib/dwarf.exp
 > index 4986f83..401e791 100644
 > --- a/gdb/testsuite/lib/dwarf.exp
 > +++ b/gdb/testsuite/lib/dwarf.exp
 > @@ -86,6 +86,81 @@ proc build_executable_from_fission_assembler { testname executable sources optio
 >      return 0
 >  }
 >  
 > +# Return a list of expressions about function FUNC's address and length.
 > +# The first expression is the address of function FUNC, and the second
 > +# one is FUNC's length.  SRC is the source file having function FUNC.
 > +# An internal label ${func}_label must be defined inside FUNC:
 > +#
 > +#  int main (void)
 > +#  {
 > +#    asm ("main_label: .globl main_label");
 > +#    return 0;
 > +#  }
 > +#
 > +# This label is needed to compute the start address of function FUNC.
 > +# If the compiler is gcc, we can do the following to get function start
 > +# and end address too:
 > +#
 > +# asm ("func_start: .globl func_start");
 > +# static void func (void) {}
 > +# asm ("func_end: .globl func_end");
 > +#
 > +# however, this isn't portable, because other compilers, such as clang,
 > +# may not guarantee the order of global asms and function.  The code
 > +# becomes:
 > +#
 > +# asm ("func_start: .globl func_start");
 > +# asm ("func_end: .globl func_end");
 > +# static void func (void) {}
 > +#
 > +
 > +proc function_range { func src } {
 > +    global decimal gdb_prompt
 > +
 > +    set exe [standard_temp_file func_addr[pid].x]
 > +
 > +    gdb_compile $src $exe executable {debug}
 > +
 > +    gdb_exit
 > +    gdb_start
 > +    gdb_load "$exe"
 > +
 > +    # Compute the label offset, and we can get the function start address
 > +    # by "${func}_label - $func_label_offset".
 > +    set func_label_offset ""
 > +    set test "p ${func}_label - ${func}"
 > +    gdb_test_multiple $test $test {
 > +	-re ".* = ($decimal)\r\n$gdb_prompt $" {
 > +	    set func_label_offset $expect_out(1,string)
 > +	}
 > +    }
 > +
 > +    # Compute the function length.
 > +    global hex
 > +    set func_length ""
 > +    set test "disassemble $func"
 > +    gdb_test_multiple $test $test {
 > +	-re ".*$hex <\\+($decimal)>:\[^\r\n\]+\r\nEnd of assembler dump\.\r\n$gdb_prompt $" {
 > +	    set func_length $expect_out(1,string)
 > +	}
 > +    }
 > +
 > +    # Compute the size of the last instruction.
 > +    set test "x/2i $func+$func_length"
 > +    gdb_test_multiple $test $test {
 > +	-re ".*($hex) <$func\\+$func_length>:\[^\r\n\]+\r\n\[ \]+($hex).*\.\r\n$gdb_prompt $" {
 > +	    set start $expect_out(1,string)
 > +	    set end $expect_out(2,string)
 > +
 > +	    set func_length [expr $func_length + $end - $start]
 > +	}
 > +    }
 > +
 > +    file delete $exe
 > +
 > +    return [list "${func}_label - $func_label_offset" $func_length]
 > +}
 > +
 >  # A DWARF assembler.
 >  #
 >  # All the variables in this namespace are private to the
 > @@ -121,6 +196,17 @@ proc build_executable_from_fission_assembler { testname executable sources optio
 >  # This can either be the full name, like 'DW_AT_name', or a shortened
 >  # name, like 'name'.  These are fully equivalent.
 >  #
 > +# Besides DWARF standard attributes, assembler supports 'macro' attribute
 > +# which will be substituted by one or more standard or macro attributes.
 > +# supported macro attributes are:
 > +#
 > +#  - MACRO_AT_range { FUNC FILE }
 > +#  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.
 > +#
 > +#  - MACRO_AT_func { FUNC FILE }
 > +#  It is substituted by DW_AT_name with FUNC and MACRO_AT_range.
 > +#
 >  # If FORM is given, it should name a DW_FORM_ constant.
 >  # This can either be the short form, like 'DW_FORM_addr', or a
 >  # shortened version, like 'addr'.  If the form is given, VALUE
 > @@ -473,6 +559,31 @@ namespace eval Dwarf {
 >  	}
 >      }
 >  
 > +    proc _handle_macro_attribute { attr_name attr_value } {
 > +	switch -exact -- $attr_name {
 > +	    MACRO_AT_func  {
 > +		_handle_attribute DW_AT_name [lindex $attr_value 0] \
 > +		    DW_FORM_string
 > +
 > +		_handle_macro_attribute MACRO_AT_range $attr_value
 > +	    }
 > +	    MACRO_AT_range {
 > +		if {[llength $attr_value] != 2} {
 > +		    error "usage: $attr_name { func file }"
 > +		}
 > +		set func [lindex $attr_value 0]
 > +		set src [lindex $attr_value 1]
 > +
 > +		set result [function_range $func $src]
 > +		_handle_attribute DW_AT_low_pc [lindex $result 0] \
 > +		    DW_FORM_addr
 > +		_handle_attribute DW_AT_high_pc \
 > +		    "[lindex $result 0] + [lindex $result 1]" DW_FORM_addr
 > +	    }
 > +	    default { error "unknown macro attribute $attr_name" }
 > +	}
 > +    }
 > +
 >      proc _handle_DW_TAG {tag_name {attrs {}} {children {}}} {
 >  	variable _abbrev_section
 >  	variable _abbrev_num
 > @@ -494,14 +605,19 @@ namespace eval Dwarf {
 >  	foreach attr $attrs {
 >  	    set attr_name [_map_name [lindex $attr 0] _AT]
 >  	    set attr_value [uplevel 2 [list subst [lindex $attr 1]]]
 > -	    if {[llength $attr] > 2} {
 > -		set attr_form [lindex $attr 2]
 > +
 > +	    if { [string match "MACRO_AT_*" $attr_name] } {
 > +		_handle_macro_attribute $attr_name $attr_value
 >  	    } else {
 > -		set attr_form [_guess_form $attr_value attr_value]
 > -	    }
 > -	    set attr_form [_map_name $attr_form _FORM]
 > +		if {[llength $attr] > 2} {
 > +		    set attr_form [lindex $attr 2]
 > +		} else {
 > +		    set attr_form [_guess_form $attr_value attr_value]
 > +		}
 > +		set attr_form [_map_name $attr_form _FORM]
 >  
 > -	    _handle_attribute $attr_name $attr_value $attr_form
 > +		_handle_attribute $attr_name $attr_value $attr_form
 > +	    }
 >  	}
 >  
 >  	_defer_output $_abbrev_section {

Hi.

IWBN if one could add new macros simply by writing a new function.

Can _handle_macro_attribute be rewritten such that
MACRO_AT_{func,range} are themselves functions?
  
Doug Evans Nov. 4, 2014, 10:59 p.m. UTC | #2
Yao Qi writes:
 > This patch addes DW macro attributes MACRO_AT_func and MACRO_AT_range
 > in dwarf assembler, which emits "DW_AT_low_pc func_start addr" and
 > "DW_AT_high_pc func_end addr".  func_start and func_end are computed
 > automatically by proc function_range.
 > 
 > These two attributes are pseudo attribute or macro attribute, which
 > means they are not standard dwarf attribute in dwarf spec.  Then can
 > be substituted or expanded to standard attributes or macro attributes.
 > See details in the comments to them.  Dwarf assembler is extended to
 > handle them.
 > 
 > Now the attributes name/low_pc/high_pc can be replaced with
 > MACRO_AT_func like this:
 > 
 >     subprogram {
 > 	{name main}
 > 	{low_pc main_start addr}
 > 	{high_pc main_end addr}
 >     }
 > 
 > becomes:
 > 
 >     subprogram {
 > 	{MACRO_AT_func { main ${srcdir}/${subdir}/${srcfile} }}
 >     }
 > 
 > users don't have to worry about the start and end of function main, and
 > they only need to add a label main_label in main.
 > 
 > gdb/testsuite:
 > 
 > 2014-10-24  Yao Qi  <yao@codesourcery.com>
 > 
 > 	* lib/dwarf.exp (function_range): New procedure.
 > 	(Dwarf::_handle_macro_attribute): New procedure.
 > 	(Dwarf): Handle MACRO_AT_func and MACRO_AT_range.
 > ---
 >  gdb/testsuite/lib/dwarf.exp | 128 +++++++++++++++++++++++++++++++++++++++++---
 >  1 file changed, 122 insertions(+), 6 deletions(-)
 > 
 > diff --git a/gdb/testsuite/lib/dwarf.exp b/gdb/testsuite/lib/dwarf.exp
 > index 4986f83..401e791 100644
 > --- a/gdb/testsuite/lib/dwarf.exp
 > +++ b/gdb/testsuite/lib/dwarf.exp
 > @@ -86,6 +86,81 @@ proc build_executable_from_fission_assembler { testname executable sources optio
 >      return 0
 >  }
 >  
 > +# Return a list of expressions about function FUNC's address and length.
 > +# The first expression is the address of function FUNC, and the second
 > +# one is FUNC's length.  SRC is the source file having function FUNC.
 > +# An internal label ${func}_label must be defined inside FUNC:
 > +#
 > +#  int main (void)
 > +#  {
 > +#    asm ("main_label: .globl main_label");
 > +#    return 0;
 > +#  }
 > +#
 > +# This label is needed to compute the start address of function FUNC.
 > +# If the compiler is gcc, we can do the following to get function start
 > +# and end address too:
 > +#
 > +# asm ("func_start: .globl func_start");
 > +# static void func (void) {}
 > +# asm ("func_end: .globl func_end");
 > +#
 > +# however, this isn't portable, because other compilers, such as clang,
 > +# may not guarantee the order of global asms and function.  The code
 > +# becomes:
 > +#
 > +# asm ("func_start: .globl func_start");
 > +# asm ("func_end: .globl func_end");
 > +# static void func (void) {}
 > +#
 > +
 > +proc function_range { func src } {
 > +    global decimal gdb_prompt
 > +
 > +    set exe [standard_temp_file func_addr[pid].x]
 > +
 > +    gdb_compile $src $exe executable {debug}
 > +
 > +    gdb_exit
 > +    gdb_start
 > +    gdb_load "$exe"
 > +
 > +    # Compute the label offset, and we can get the function start address
 > +    # by "${func}_label - $func_label_offset".
 > +    set func_label_offset ""
 > +    set test "p ${func}_label - ${func}"
 > +    gdb_test_multiple $test $test {
 > +	-re ".* = ($decimal)\r\n$gdb_prompt $" {
 > +	    set func_label_offset $expect_out(1,string)
 > +	}
 > +    }
 > +
 > +    # Compute the function length.
 > +    global hex
 > +    set func_length ""
 > +    set test "disassemble $func"
 > +    gdb_test_multiple $test $test {
 > +	-re ".*$hex <\\+($decimal)>:\[^\r\n\]+\r\nEnd of assembler dump\.\r\n$gdb_prompt $" {
 > +	    set func_length $expect_out(1,string)
 > +	}
 > +    }
 > +
 > +    # Compute the size of the last instruction.
 > +    set test "x/2i $func+$func_length"
 > +    gdb_test_multiple $test $test {
 > +	-re ".*($hex) <$func\\+$func_length>:\[^\r\n\]+\r\n\[ \]+($hex).*\.\r\n$gdb_prompt $" {
 > +	    set start $expect_out(1,string)
 > +	    set end $expect_out(2,string)
 > +
 > +	    set func_length [expr $func_length + $end - $start]
 > +	}
 > +    }
 > +
 > +    file delete $exe
 > +
 > +    return [list "${func}_label - $func_label_offset" $func_length]
 > +}
 > +

In the immortal words of Shrek, "Hold the phone." ...

"file delete $exe" is a local operation.
While in general we don't delete test artifacts,
I'm left wondering if something about this won't
work with remote host testing.
Is that true?  Or can "file delete $exe" just be deleted?
  
Yao Qi Nov. 5, 2014, 1:49 a.m. UTC | #3
Doug Evans <dje@google.com> writes:

Doug,
Thanks for reviewing these patches.

> IWBN if one could add new macros simply by writing a new function.
>
> Can _handle_macro_attribute be rewritten such that
> MACRO_AT_{func,range} are themselves functions?

I don't see any difficulties to implement MACRO_AT_{func,range} as
functions here, but could you tell me why do you prefer to do that?
Is it because they are macros?

After all, in dwarf assembler, all attributes are handled in a single
function, rather than the way that each attribute is handled in the
separate function.  MACRO_AT_{func,range}, as special attributes from
the users' point of view, should be handled in a way consistent with
other attributes, IMO.
  
Doug Evans Nov. 7, 2014, 4:54 p.m. UTC | #4
On Tue, Nov 4, 2014 at 5:49 PM, Yao Qi <yao@codesourcery.com> wrote:
> Doug Evans <dje@google.com> writes:
>
> Doug,
> Thanks for reviewing these patches.
>
>> IWBN if one could add new macros simply by writing a new function.
>>
>> Can _handle_macro_attribute be rewritten such that
>> MACRO_AT_{func,range} are themselves functions?
>
> I don't see any difficulties to implement MACRO_AT_{func,range} as
> functions here, but could you tell me why do you prefer to do that?
> Is it because they are macros?

I was thinking long term I'd rather maintain the individual functions
instead of one large switch statement, all else being equal, and if I
have the choice.

> After all, in dwarf assembler, all attributes are handled in a single
> function, rather than the way that each attribute is handled in the
> separate function.  MACRO_AT_{func,range}, as special attributes from
> the users' point of view, should be handled in a way consistent with
> other attributes, IMO.
  

Patch

diff --git a/gdb/testsuite/lib/dwarf.exp b/gdb/testsuite/lib/dwarf.exp
index 4986f83..401e791 100644
--- a/gdb/testsuite/lib/dwarf.exp
+++ b/gdb/testsuite/lib/dwarf.exp
@@ -86,6 +86,81 @@  proc build_executable_from_fission_assembler { testname executable sources optio
     return 0
 }
 
+# Return a list of expressions about function FUNC's address and length.
+# The first expression is the address of function FUNC, and the second
+# one is FUNC's length.  SRC is the source file having function FUNC.
+# An internal label ${func}_label must be defined inside FUNC:
+#
+#  int main (void)
+#  {
+#    asm ("main_label: .globl main_label");
+#    return 0;
+#  }
+#
+# This label is needed to compute the start address of function FUNC.
+# If the compiler is gcc, we can do the following to get function start
+# and end address too:
+#
+# asm ("func_start: .globl func_start");
+# static void func (void) {}
+# asm ("func_end: .globl func_end");
+#
+# however, this isn't portable, because other compilers, such as clang,
+# may not guarantee the order of global asms and function.  The code
+# becomes:
+#
+# asm ("func_start: .globl func_start");
+# asm ("func_end: .globl func_end");
+# static void func (void) {}
+#
+
+proc function_range { func src } {
+    global decimal gdb_prompt
+
+    set exe [standard_temp_file func_addr[pid].x]
+
+    gdb_compile $src $exe executable {debug}
+
+    gdb_exit
+    gdb_start
+    gdb_load "$exe"
+
+    # Compute the label offset, and we can get the function start address
+    # by "${func}_label - $func_label_offset".
+    set func_label_offset ""
+    set test "p ${func}_label - ${func}"
+    gdb_test_multiple $test $test {
+	-re ".* = ($decimal)\r\n$gdb_prompt $" {
+	    set func_label_offset $expect_out(1,string)
+	}
+    }
+
+    # Compute the function length.
+    global hex
+    set func_length ""
+    set test "disassemble $func"
+    gdb_test_multiple $test $test {
+	-re ".*$hex <\\+($decimal)>:\[^\r\n\]+\r\nEnd of assembler dump\.\r\n$gdb_prompt $" {
+	    set func_length $expect_out(1,string)
+	}
+    }
+
+    # Compute the size of the last instruction.
+    set test "x/2i $func+$func_length"
+    gdb_test_multiple $test $test {
+	-re ".*($hex) <$func\\+$func_length>:\[^\r\n\]+\r\n\[ \]+($hex).*\.\r\n$gdb_prompt $" {
+	    set start $expect_out(1,string)
+	    set end $expect_out(2,string)
+
+	    set func_length [expr $func_length + $end - $start]
+	}
+    }
+
+    file delete $exe
+
+    return [list "${func}_label - $func_label_offset" $func_length]
+}
+
 # A DWARF assembler.
 #
 # All the variables in this namespace are private to the
@@ -121,6 +196,17 @@  proc build_executable_from_fission_assembler { testname executable sources optio
 # This can either be the full name, like 'DW_AT_name', or a shortened
 # name, like 'name'.  These are fully equivalent.
 #
+# Besides DWARF standard attributes, assembler supports 'macro' attribute
+# which will be substituted by one or more standard or macro attributes.
+# supported macro attributes are:
+#
+#  - MACRO_AT_range { FUNC FILE }
+#  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.
+#
+#  - MACRO_AT_func { FUNC FILE }
+#  It is substituted by DW_AT_name with FUNC and MACRO_AT_range.
+#
 # If FORM is given, it should name a DW_FORM_ constant.
 # This can either be the short form, like 'DW_FORM_addr', or a
 # shortened version, like 'addr'.  If the form is given, VALUE
@@ -473,6 +559,31 @@  namespace eval Dwarf {
 	}
     }
 
+    proc _handle_macro_attribute { attr_name attr_value } {
+	switch -exact -- $attr_name {
+	    MACRO_AT_func  {
+		_handle_attribute DW_AT_name [lindex $attr_value 0] \
+		    DW_FORM_string
+
+		_handle_macro_attribute MACRO_AT_range $attr_value
+	    }
+	    MACRO_AT_range {
+		if {[llength $attr_value] != 2} {
+		    error "usage: $attr_name { func file }"
+		}
+		set func [lindex $attr_value 0]
+		set src [lindex $attr_value 1]
+
+		set result [function_range $func $src]
+		_handle_attribute DW_AT_low_pc [lindex $result 0] \
+		    DW_FORM_addr
+		_handle_attribute DW_AT_high_pc \
+		    "[lindex $result 0] + [lindex $result 1]" DW_FORM_addr
+	    }
+	    default { error "unknown macro attribute $attr_name" }
+	}
+    }
+
     proc _handle_DW_TAG {tag_name {attrs {}} {children {}}} {
 	variable _abbrev_section
 	variable _abbrev_num
@@ -494,14 +605,19 @@  namespace eval Dwarf {
 	foreach attr $attrs {
 	    set attr_name [_map_name [lindex $attr 0] _AT]
 	    set attr_value [uplevel 2 [list subst [lindex $attr 1]]]
-	    if {[llength $attr] > 2} {
-		set attr_form [lindex $attr 2]
+
+	    if { [string match "MACRO_AT_*" $attr_name] } {
+		_handle_macro_attribute $attr_name $attr_value
 	    } else {
-		set attr_form [_guess_form $attr_value attr_value]
-	    }
-	    set attr_form [_map_name $attr_form _FORM]
+		if {[llength $attr] > 2} {
+		    set attr_form [lindex $attr 2]
+		} else {
+		    set attr_form [_guess_form $attr_value attr_value]
+		}
+		set attr_form [_map_name $attr_form _FORM]
 
-	    _handle_attribute $attr_name $attr_value $attr_form
+		_handle_attribute $attr_name $attr_value $attr_form
+	    }
 	}
 
 	_defer_output $_abbrev_section {