From: Tom de Vries <tdevries@suse.de>
To: Mark Wielaard <mark@klomp.org>, dwz@sourceware.org
Subject: Re: [PATCH] Update dwarf.exp assembler from gdb.
Date: Sun, 20 Dec 2020 09:33:43 +0100 [thread overview]
Message-ID: <f213cf3a-1a75-98b8-bf0c-62c33fed185a@suse.de> (raw)
In-Reply-To: <20201214211945.9656-1-mark@klomp.org>
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 {
>
prev parent reply other threads:[~2020-12-20 8:33 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-12-14 21:19 Mark Wielaard
2020-12-20 8:33 ` Tom de Vries [this message]
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=f213cf3a-1a75-98b8-bf0c-62c33fed185a@suse.de \
--to=tdevries@suse.de \
--cc=dwz@sourceware.org \
--cc=mark@klomp.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).