--- /dev/null
+# Copyright 2022 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
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+load_lib dwarf.exp
+
+# This test can only be run on targets which support DWARF-2 and use gas.
+if {![dwarf2_support]} {
+ return 0
+}
+
+standard_testfile _start.c debug-names.S
+
+set func_info_vars \
+ [get_func_info _start [list debug additional_flags=-nostartfiles]]
+
+# Create the DWARF.
+set asm_file [standard_output_file $srcfile2]
+Dwarf::assemble {
+ filename $asm_file
+ add_dummy_cus 0
+} {
+ global func_info_vars
+ foreach var $func_info_vars {
+ global $var
+ }
+
+ cu { label cu_label } {
+ compile_unit {{language @DW_LANG_C}} {
+ subprogram {
+ {DW_AT_name _start}
+ {DW_AT_low_pc $_start_start DW_FORM_addr}
+ {DW_AT_high_pc $_start_end DW_FORM_addr}
+ }
+ base_type {
+ {name int}
+ {byte_size 4 sdata}
+ {encoding @DW_ATE_signed}
+ }
+ }
+ }
+
+ debug_names {} {
+ cu cu_label
+ name _start subprogram cu_label 0xEDDB6232
+ name int base_type cu_label 0xB888030
+ }
+}
+
+if [prepare_for_testing "failed to prepare" $testfile "${asm_file} ${srcfile}" \
+ [list additional_flags=-nostartfiles]] {
+ return -1
+}
+
+# Verify that .debug_names section is not ignored.
+set index [have_index $binfile]
+gdb_assert { [string equal $index "debug_names"] } ".debug_names used"
+
+# Verify that initially no symtab is expanded.
+gdb_test_no_output "maint info symtabs"
+
+if ![runto _start] {
+ return -1
+}
+
+# Verify that breaking on _start actually expanded a symtab, rather than
+# falling back on minimal symbols.
+gdb_test "maint info symtabs" "name <unknown>.*" "break _start expanded symtab"
}
}
+ # Emit a DWARF .debug_names section.
+ #
+ # OPTIONS is a list with an even number of elements containing
+ # option-name and option-value pairs.
+ # Current options are:
+ # is_64 0|1 - boolean indicating if the section contains 64-bit DWARF.
+ # default = 0 (32-bit)
+ # version n - section version.
+ # default = 5.
+ #
+ # BODY is Tcl code that emits the parts which make up the body of
+ # the .debug_names section. It is evaluated in the caller's context.
+ # The following commands are available for the BODY section:
+ #
+ # cu <cu-label>
+ # -- add a CU.
+ #
+ # name <name> <tag> <cu> <hash>
+ # -- add a name.
+
+ proc debug_names { options body } {
+ parse_options {
+ { is_64 0 }
+ { version 5 }
+ }
+
+ variable _debug_names_offset_size
+ if { $is_64 == 1 } {
+ set _debug_names_offset_size 8
+ } else {
+ set _debug_names_offset_size 4
+ }
+
+ # Section start.
+ set section ".debug_names"
+ _section $section
+
+ # Header - initial length.
+ declare_labels debug_names_start debug_names_end
+ set length "$debug_names_end - $debug_names_start"
+ set comment "Initial_length"
+ if { $is_64 } {
+ _op .4byte 0xffffffff
+ _op .8byte $length $comment
+ } else {
+ _op .4byte $length $comment
+ }
+
+ # Header - start label.
+ debug_names_start:
+
+ # Header - version + padding.
+ _op .2byte $version "Version"
+ _op .2byte 0 "Padding"
+
+ # Parse the body.
+ variable _debug_names_cus
+ set _debug_names_cus []
+ proc _debug_names_cu { cu } {
+ variable _debug_names_cus
+ lappend _debug_names_cus $cu
+ }
+ variable _debug_names
+ set _debug_names []
+ proc _debug_names_name { name tag cu hash } {
+ variable _debug_names
+ declare_labels entry_pool_offset
+ lappend _debug_names [list $name $tag $cu $hash $entry_pool_offset]
+ }
+ with_override Dwarf::cu Dwarf::_debug_names_cu {
+ with_override Dwarf::name Dwarf::_debug_names_name {
+ uplevel $body
+ }}
+
+ # Header - CU / TU / foreign TU count.
+ _op .4byte [llength $_debug_names_cus] "Comp_unit_count"
+ _op .4byte 0 "Local_type_unit_count"
+ _op .4byte 0 "Foreign_type_unit_count"
+
+ # Header - bucket count.
+ _op .4byte 1 "Bucket_count"
+
+ # Header - name count.
+ _op .4byte [llength $_debug_names] "Name_count"
+
+ # Header - abbreviation table size.
+ declare_labels debug_names_abbrev_table_start \
+ debug_names_abbrev_table_end
+ set abbrev_table_size \
+ "$debug_names_abbrev_table_end - $debug_names_abbrev_table_start"
+ _op .4byte $abbrev_table_size "Abbrev_table_size"
+
+ # Header - augmentation string.
+ _op .4byte 4 "Augmentation_string_size"
+ _op .ascii [_quote GDB] "Augmentation_string"
+
+ # List of CUs.
+ set comment "CU offset"
+ foreach cu $_debug_names_cus {
+ upvar $cu tmp
+ if { $is_64 } {
+ _op .8byte $tmp $comment
+ } else {
+ _op .4byte $tmp $comment
+ }
+ }
+
+ # List of Local TUs.
+ #
+
+ # List of Foreign TUs.
+ #
+
+ # Hash Lookup Table - array of buckets.
+ _op .4byte 1 "bucket: hash array index 1"
+
+ # Hash Lookup Table - array of hashes.
+ foreach idx $_debug_names {
+ set name [lindex $idx 0]
+ set hash [lindex $idx 3]
+ _op .4byte $hash "hash: $name"
+ }
+
+ # Name Table - array of string offsets.
+ foreach idx $_debug_names {
+ set name [lindex $idx 0]
+
+ variable _strings
+ if {![info exists _strings($name)]} {
+ set _strings($name) [new_label strp]
+ _defer_output .debug_str {
+ define_label $_strings($name)
+ _op .ascii [_quote $name]
+ }
+ }
+
+ _op_offset $_debug_names_offset_size $_strings($name) "name: $name"
+ }
+
+ # Name Table - array of entry offsets.
+ set base_label ""
+ foreach idx $_debug_names {
+ set name [lindex $idx 0]
+ set label [lindex $idx 4]
+ if { [string equal $base_label ""]} {
+ set base_label $label
+ }
+ _op_offset $_debug_names_offset_size "$label - $base_label" \
+ "entry pool offset: $name"
+ }
+
+ # Abbreviations Table.
+ debug_names_abbrev_table_start:
+ set abbrev 1
+ variable _constants
+ foreach idx $_debug_names {
+ set name [lindex $idx 0]
+ set tag [lindex $idx 1]
+ _op .byte $abbrev "abbrev $abbrev"
+ _op .uleb128 $_constants(DW_TAG_$tag) "DW_TAG_$tag"
+ _op .byte 1 "DW_IDX_compile_unit (attribute)"
+ _op .byte 0x0f "DW_FORM_udata (form)"
+ _op .byte 0 "abbrev terminator (attribute)"
+ _op .byte 0 "abbrev terminator (form)"
+ incr abbrev
+ }
+ _op .byte 0 "Abbreviations Table terminator"
+ debug_names_abbrev_table_end:
+
+ # Entry Pool
+ set abbrev 1
+ foreach idx $_debug_names {
+ set name [lindex $idx 0]
+ set cu [lindex $idx 2]
+ set label [lindex $idx 4]
+
+ set cu_index 0
+ foreach idx2 $_debug_names_cus {
+ if { $idx2 == $cu } {
+ break
+ }
+ incr cu_index
+ }
+
+ define_label $label
+ _op .byte $abbrev "$name: abbrev"
+ _op .uleb128 $cu_index "$name: CU index"
+ _op .byte 0 "$name: terminator"
+ incr abbrev
+ }
+
+ # Section end.
+ debug_names_end:
+ }
+
# The top-level interface to the DWARF assembler.
- # FILENAME is the name of the file where the generated assembly
- # code is written.
+ # OPTIONS is a list with an even number of elements containing
+ # option-name and option-value pairs.
+ # Current options are:
+ # filename <string>
+ # - the name of the file where the generated assembly
+ # code is written.
+ # default = "".
+ # add_dummy_cus <0|1>
+ # - Whether to add dummy CUs before and after the CUs
+ # added in the BODY.
+ # default = 1.
+ # As a special case, if OPTIONS is a list of length 1, it's
+ # interpreted as specifing the filename.
# BODY is Tcl code to emit the assembly. It is evaluated via
# "eval" -- not uplevel as you might expect, because it is
# important to run the body in the Dwarf namespace.
# ...
# }
# }
- proc assemble {filename body} {
+ proc assemble {options body} {
variable _initialized
variable _output_file
variable _deferred_output
variable _debug_ranges_64_bit
variable _debug_addr_index
+ if { [llength $options] == 1 } {
+ set options [list filename [lindex $options 0]]
+ }
+
+ parse_options {
+ { filename "" }
+ { add_dummy_cus 1 }
+ }
+
if {!$_initialized} {
_read_constants
set _initialized 1
# Dummy CU at the start to ensure that the first CU in $body is not
# the first in .debug_info.
- dummy_cu
+ if { $add_dummy_cus } {
+ dummy_cu
+ }
with_shared_gdb {
# Not "uplevel" here, because we want to evaluate in this
# Dummy CU at the end to ensure that the last CU in $body is not
# the last in .debug_info.
- dummy_cu
+ if { $add_dummy_cus } {
+ dummy_cu
+ }
_write_deferred_output