Message ID | 1414195968-3333-3-git-send-email-yao@codesourcery.com |
---|---|
State | New |
Headers | show |
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?
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?
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.
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.
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 {