]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gdb/testsuite/lib/dwarf.exp
gdb/testsuite: add .debug_loclists tests
[thirdparty/binutils-gdb.git] / gdb / testsuite / lib / dwarf.exp
index f4f1cab05e6825cc55927c158b65dc6eb5fda548..b444ef36778a6f1b3cab7025a23d22314971c5af 100644 (file)
@@ -474,6 +474,7 @@ namespace eval Dwarf {
 
            DW_FORM_ref_udata -
            DW_FORM_udata -
+           DW_FORM_loclistx -
            DW_FORM_rnglistx {
                _op .uleb128 $value
            }
@@ -1502,6 +1503,201 @@ namespace eval Dwarf {
        uplevel $body
     }
 
+    # Emit a DWARF .debug_loclists section.
+    #
+    # The target address size is based on the current target's address size.
+    #
+    # There is one mandatory positional argument, BODY, which must be Tcl code
+    # that emits the content of the section.  It is evaluated in the caller's
+    # context.
+    #
+    # The following option can be used:
+    #
+    #  - -is-64 true|false: Whether to use 64-bit DWARF instead of 32-bit DWARF.
+    #                       The default is 32-bit.
+
+    proc loclists { args } {
+       variable _debug_loclists_addr_size
+       variable _debug_loclists_offset_size
+       variable _debug_loclists_is_64_dwarf
+
+       parse_args {{"is-64" "false"}}
+
+       if { [llength $args] != 1 } {
+           error "loclists proc expects one positional argument (body)"
+       }
+
+       lassign $args body
+
+       if [is_64_target] {
+           set _debug_loclists_addr_size 8
+       } else {
+           set _debug_loclists_addr_size 4
+       }
+
+       if { ${is-64} } {
+           set _debug_loclists_offset_size 8
+           set _debug_loclists_is_64_dwarf true
+       } else {
+           set _debug_loclists_offset_size 4
+           set _debug_loclists_is_64_dwarf false
+       }
+
+       _section ".debug_loclists"
+
+       # Count of tables in the section.
+       variable _debug_loclists_table_count 0
+
+       # Compute the label name for list at index LIST_IDX, for the current
+       # table.
+
+       proc _compute_list_label { list_idx } {
+           variable _debug_loclists_table_count
+
+           return ".Lloclists_table_${_debug_loclists_table_count}_list_${list_idx}"
+       }
+
+       # Generate one table (header + offset array + location lists).
+       #
+       # Accepts one position argument, BODY.  BODY may call the LIST_
+       # procedure to generate loclists.
+       #
+       # The -post-header-label option can be used to define a label just after the
+       # header of the table.  This is the label that a DW_AT_loclists_base
+       # attribute will usually refer to.
+
+       proc table { args } {
+           variable _debug_loclists_table_count
+           variable _debug_loclists_addr_size
+           variable _debug_loclists_offset_size
+           variable _debug_loclists_is_64_dwarf
+
+           parse_args {{post-header-label ""}}
+
+           if { [llength $args] != 1 } {
+               error "table proc expects one positional argument (body)"
+           }
+
+           lassign $args body
+
+           # Generate one location list.
+           #
+           # BODY may call the various procs defined below to generate list
+           # entries.  They correspond to the location list entry kinds
+           # described in section 2.6.2 of the DWARF 5 spec.
+           #
+           # To define a label pointing to the beginning of the list, use
+           # the conventional way of declaring and defining labels:
+           #
+           #   declare_labels the_list
+           #
+           #   the_list: list_ {
+           #     ...
+           #   }
+
+           proc list_ { body } {
+               variable _debug_loclists_list_count
+
+               # Count the location descriptions in this list.
+               variable _debug_loclists_locdesc_count 0
+
+               # Define a label for this list.  It is used to build the offset
+               # array later.
+               set list_label [_compute_list_label $_debug_loclists_list_count]
+               define_label $list_label
+
+               # Emit a DW_LLE_start_length entry.
+
+               proc start_length { start length locdesc } {
+                   variable _debug_loclists_is_64_dwarf
+                   variable _debug_loclists_addr_size
+                   variable _debug_loclists_offset_size
+                   variable _debug_loclists_table_count
+                   variable _debug_loclists_list_count
+                   variable _debug_loclists_locdesc_count
+
+                   _op .byte 0x08 "DW_LLE_start_length"
+
+                   # Start and end of the address range.
+                   _op .${_debug_loclists_addr_size}byte $start "start"
+                   _op .uleb128 $length "length"
+
+                   # Length of location description.
+                   set locdesc_start_label ".Lloclists_table_${_debug_loclists_table_count}_list_${_debug_loclists_list_count}_locdesc_${_debug_loclists_locdesc_count}_start"
+                   set locdesc_end_label ".Lloclists_table_${_debug_loclists_table_count}_list_${_debug_loclists_list_count}_locdesc_${_debug_loclists_locdesc_count}_end"
+                   _op .uleb128 "$locdesc_end_label - $locdesc_start_label" "locdesc length"
+
+                   define_label $locdesc_start_label
+                   set dwarf_version 5
+                   _location $locdesc $dwarf_version $_debug_loclists_addr_size $_debug_loclists_offset_size
+                   define_label $locdesc_end_label
+
+                   incr _debug_loclists_locdesc_count
+               }
+
+               uplevel $body
+
+               # Emit end of list.
+               _op .byte 0x00 "DW_LLE_end_of_list"
+
+               incr _debug_loclists_list_count
+           }
+
+           # Count of lists in the table.
+           variable _debug_loclists_list_count 0
+
+           # Generate the lists ops first, because we need to know how many
+           # lists there are to generate the header and offset table.
+           set lists_ops [_defer_to_string {
+               uplevel $body
+           }]
+
+           set post_unit_len_label \
+               [_compute_label "loclists_table_${_debug_loclists_table_count}_post_unit_len"]
+           set post_header_label \
+               [_compute_label "loclists_table_${_debug_loclists_table_count}_post_header"]
+           set table_end_label \
+               [_compute_label "loclists_table_${_debug_loclists_table_count}_end"]
+
+           # Emit the table header.
+           if { $_debug_loclists_is_64_dwarf } {
+               _op .4byte 0xffffffff "unit length 1/2"
+               _op .8byte "$table_end_label - $post_unit_len_label" "unit length 2/2"
+           } else {
+               _op .4byte "$table_end_label - $post_unit_len_label" "unit length"
+           }
+
+           define_label $post_unit_len_label
+
+           _op .2byte 5 "DWARF version"
+           _op .byte $_debug_loclists_addr_size "address size"
+           _op .byte 0 "segment selector size"
+           _op .4byte $_debug_loclists_list_count "offset entry count"
+
+           define_label $post_header_label
+
+           # Define the user post-header label, if provided.
+           if { ${post-header-label} != "" } {
+               define_label ${post-header-label}
+           }
+
+           # Emit the offset array.
+           for {set list_idx 0} {$list_idx < $_debug_loclists_list_count} {incr list_idx} {
+               set list_label [_compute_list_label $list_idx]
+               _op .${_debug_loclists_offset_size}byte "$list_label - $post_header_label" "offset of list $list_idx"
+           }
+
+           # Emit the actual list data.
+           _emit "$lists_ops"
+
+           define_label $table_end_label
+
+           incr _debug_loclists_table_count
+       }
+
+       uplevel $body
+    }
+
     # Emit a DWARF .debug_line unit.
     # OPTIONS is a list with an even number of elements containing
     # option-name and option-value pairs.