From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id cA7NJ4/CB2CaTgAAWB0awg (envelope-from ) for ; Wed, 20 Jan 2021 00:41:35 -0500 Received: by simark.ca (Postfix, from userid 112) id 7B0F91EF86; Wed, 20 Jan 2021 00:41:34 -0500 (EST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on simark.ca X-Spam-Level: X-Spam-Status: No, score=0.2 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,MAILING_LIST_MULTI,RDNS_NONE,URIBL_BLOCKED autolearn=no autolearn_force=no version=3.4.2 Received: from sourceware.org (unknown [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 8D1B21E939 for ; Wed, 20 Jan 2021 00:41:33 -0500 (EST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 4304C394800C; Wed, 20 Jan 2021 05:41:33 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 4304C394800C DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1611121293; bh=LgPYYRO93j9nRUAmYP2oKe2cgikgYEbLFK7EbveOUlw=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=m0cHfUv+Kf9Emt/tOYt5XI3Mas7cW5JcerGOGG105+U3782qf1bCXwpxr99Uggc5H lsijW7eX88gFof98Pw3P1mbOR+5XyTdA7TtKJTn8EfgaqgTM+qYDVNWAqwCJDxcl7l Nsnh7nSObo+5n2NW/LKqRfll3y3V67K0V65UwIk4= Received: from barracuda.ebox.ca (barracuda.ebox.ca [96.127.255.19]) by sourceware.org (Postfix) with ESMTPS id 4B07A3947C0D for ; Wed, 20 Jan 2021 05:41:28 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 4B07A3947C0D X-ASG-Debug-ID: 1611121286-0c856e6cd571f220001-fS2M51 Received: from smtp.ebox.ca (smtp.ebox.ca [96.127.255.82]) by barracuda.ebox.ca with ESMTP id 9QVSs6KVxHo4E8BO (version=TLSv1 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Wed, 20 Jan 2021 00:41:26 -0500 (EST) X-Barracuda-Envelope-From: simon.marchi@polymtl.ca X-Barracuda-RBL-Trusted-Forwarder: 96.127.255.82 Received: from simark.localdomain (192-222-157-6.qc.cable.ebox.net [192.222.157.6]) by smtp.ebox.ca (Postfix) with ESMTP id BFC2F441D65; Wed, 20 Jan 2021 00:41:26 -0500 (EST) X-Barracuda-RBL-IP: 192.222.157.6 X-Barracuda-Effective-Source-IP: 192-222-157-6.qc.cable.ebox.net[192.222.157.6] X-Barracuda-Apparent-Source-IP: 192.222.157.6 To: gdb-patches@sourceware.org Subject: [PATCH 10/13] gdb/testsuite: add .debug_loclists tests Date: Wed, 20 Jan 2021 00:39:22 -0500 X-ASG-Orig-Subj: [PATCH 10/13] gdb/testsuite: add .debug_loclists tests Message-Id: <20210120053925.142862-11-simon.marchi@polymtl.ca> X-Mailer: git-send-email 2.30.0 In-Reply-To: <20210120053925.142862-1-simon.marchi@polymtl.ca> References: <20210120053925.142862-1-simon.marchi@polymtl.ca> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Barracuda-Connect: smtp.ebox.ca[96.127.255.82] X-Barracuda-Start-Time: 1611121286 X-Barracuda-Encrypted: DHE-RSA-AES256-SHA X-Barracuda-URL: https://96.127.255.19:443/cgi-mod/mark.cgi X-Barracuda-BRTS-Status: 1 X-Virus-Scanned: by bsmtpd at ebox.ca X-Barracuda-Scan-Msg-Size: 19000 X-Barracuda-Spam-Score: 0.00 X-Barracuda-Spam-Status: No, SCORE=0.00 using global scores of TAG_LEVEL=1000.0 QUARANTINE_LEVEL=1000.0 KILL_LEVEL=8.0 tests= X-Barracuda-Spam-Report: Code version 3.2, rules version 3.2.3.87375 Rule breakdown below pts rule name description ---- ---------------------- -------------------------------------------------- X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Simon Marchi via Gdb-patches Reply-To: Simon Marchi Cc: Simon Marchi Errors-To: gdb-patches-bounces@sourceware.org Sender: "Gdb-patches" From: Simon Marchi Add tests for the various issues fixed in the previous patches. Add a new "loclists" procedure to the DWARF assembler, to allow generating .debug_loclists sections. gdb/testsuite/ChangeLog: * lib/dwarf.exp (_handle_DW_FORM): Handle DW_FORM_loclistx. (loclists): New proc. * gdb.dwarf2/loclists-multiple-cus.c: New. * gdb.dwarf2/loclists-multiple-cus.exp: New. * gdb.dwarf2/loclists-sec-offset.c: New. * gdb.dwarf2/loclists-sec-offset.exp: New. Change-Id: I209bcb2a9482762ae943e518998d1f7761f76928 --- .../gdb.dwarf2/loclists-multiple-cus.c | 37 ++++ .../gdb.dwarf2/loclists-multiple-cus.exp | 146 +++++++++++++ .../gdb.dwarf2/loclists-sec-offset.c | 37 ++++ .../gdb.dwarf2/loclists-sec-offset.exp | 125 +++++++++++ gdb/testsuite/lib/dwarf.exp | 196 ++++++++++++++++++ 5 files changed, 541 insertions(+) create mode 100644 gdb/testsuite/gdb.dwarf2/loclists-multiple-cus.c create mode 100644 gdb/testsuite/gdb.dwarf2/loclists-multiple-cus.exp create mode 100644 gdb/testsuite/gdb.dwarf2/loclists-sec-offset.c create mode 100644 gdb/testsuite/gdb.dwarf2/loclists-sec-offset.exp diff --git a/gdb/testsuite/gdb.dwarf2/loclists-multiple-cus.c b/gdb/testsuite/gdb.dwarf2/loclists-multiple-cus.c new file mode 100644 index 000000000000..2bffbf2ac4c0 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/loclists-multiple-cus.c @@ -0,0 +1,37 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + + This file is part of GDB. + + 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 . */ + +static int +func1 (void) +{ + asm ("func1_label: .global func1_label\n"); + return 1; +} + +static int +func2 (void) +{ + asm ("func2_label: .global func2_label\n"); + return 2; +} + +int +main (void) +{ + func1 (); + func2 (); +} diff --git a/gdb/testsuite/gdb.dwarf2/loclists-multiple-cus.exp b/gdb/testsuite/gdb.dwarf2/loclists-multiple-cus.exp new file mode 100644 index 000000000000..6b4f5c8cbb87 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/loclists-multiple-cus.exp @@ -0,0 +1,146 @@ +# Copyright 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 +# 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 . + +# Test to reproduce the crash described in PR 26813. +# +# When reading a list in any table in the .debug_loclists section, GDB would +# read the header at offset 0 in the section (the header of the first table). +# When the index of the list we read was greater than the number of lists of +# the first table, GDB would erroneously report that the index is invalid. +# +# So this test creates a .debug_loclists section with two tables. The second +# table has more lists than the first one and we try to read a high index in +# the second table. + +load_lib dwarf.exp + +if {![dwarf2_support]} { + return 0 +} + +# Test with 32-bit and 64-bit DWARF. +foreach_with_prefix is_64 {false true} { + if { $is_64 } { + standard_testfile .c -dw64.S + set testfile ${testfile}-dw64 + } else { + standard_testfile .c -dw32.S + set testfile ${testfile}-dw32 + } + + # Get the addresses / lengths of func1 and func2. + lassign [function_range func1 $srcdir/$subdir/$srcfile] func1_addr func1_len + lassign [function_range func2 $srcdir/$subdir/$srcfile] func2_addr func2_len + + set asm_file [standard_output_file $srcfile2] + Dwarf::assemble $asm_file { + global func1_addr func1_len + global func2_addr func2_len + global is_64 + + # The CU uses the DW_FORM_loclistx form to refer to the .debug_loclists + # section. + cu { + version 5 + is_64 $is_64 + } { + declare_labels int_type + + DW_TAG_compile_unit { + {DW_AT_loclists_base cu_table DW_FORM_sec_offset} + } { + int_type: DW_TAG_base_type { + {DW_AT_byte_size 4 DW_FORM_data1} + {DW_AT_encoding @DW_ATE_signed} + {DW_AT_name "int"} + } + + DW_TAG_variable { + {DW_AT_name "foo"} + {DW_AT_location 1 DW_FORM_loclistx} + {DW_AT_type :$int_type} + } + + DW_TAG_subprogram { + {DW_AT_name "func1"} + {DW_AT_low_pc $func1_addr} + {DW_AT_high_pc $func1_len DW_FORM_udata} + } + + DW_TAG_subprogram { + {DW_AT_name "func2"} + {DW_AT_low_pc $func2_addr} + {DW_AT_high_pc $func2_len DW_FORM_udata} + } + } + } + + loclists -is-64 $is_64 { + # This table is unused, but exists so that the used table is not at + # the beginning of the section. + table { + list_ { + start_length 0x1000 0x1000 { DW_OP_addr 0x100000 } + } + } + + # The lists in this table are accessed by index (DW_FORM_rnglistx). + table -post-header-label cu_table { + # This list is unused, but exists to offset the next ones. + list_ { + start_length 0x1000 0x1000 { DW_OP_addr 0x100000 } + } + + # For variable foo. + list_ { + # When in func1. + start_length $func1_addr $func1_len { + DW_OP_constu 0x123456 + DW_OP_stack_value + } + + # When in func2. + start_length $func2_addr $func2_len { + DW_OP_constu 0x234567 + DW_OP_stack_value + } + } + } + } + } + + if { [prepare_for_testing "failed to prepare" ${testfile} \ + [list $srcfile $asm_file] {nodebug}] } { + return -1 + } + + if { ![runto_main] } { + fail "can't run to main" + return + } + + gdb_breakpoint "func1" + gdb_breakpoint "func2" + + gdb_continue_to_breakpoint "func1" + with_test_prefix "at func1" { + gdb_test "print /x foo" " = 0x123456" + } + + gdb_continue_to_breakpoint "func2" + with_test_prefix "at func2" { + gdb_test "print /x foo" " = 0x234567" + } +} diff --git a/gdb/testsuite/gdb.dwarf2/loclists-sec-offset.c b/gdb/testsuite/gdb.dwarf2/loclists-sec-offset.c new file mode 100644 index 000000000000..2bffbf2ac4c0 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/loclists-sec-offset.c @@ -0,0 +1,37 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + + This file is part of GDB. + + 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 . */ + +static int +func1 (void) +{ + asm ("func1_label: .global func1_label\n"); + return 1; +} + +static int +func2 (void) +{ + asm ("func2_label: .global func2_label\n"); + return 2; +} + +int +main (void) +{ + func1 (); + func2 (); +} diff --git a/gdb/testsuite/gdb.dwarf2/loclists-sec-offset.exp b/gdb/testsuite/gdb.dwarf2/loclists-sec-offset.exp new file mode 100644 index 000000000000..9a9188b10744 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/loclists-sec-offset.exp @@ -0,0 +1,125 @@ +# Copyright 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 +# 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 . + +# Test DW_AT_location attributes referencing the .debug_loclists section using +# the DW_FORM_sec_offset form. + +load_lib dwarf.exp + +if {![dwarf2_support]} { + return 0 +} + +# Test with 32-bit and 64-bit DWARF. +foreach_with_prefix is_64 {false true} { + if { $is_64 } { + standard_testfile .c -dw64.S + set testfile ${testfile}-dw64 + } else { + standard_testfile .c -dw32.S + set testfile ${testfile}-dw32 + } + + # Get the addresses / lengths of func1 and func2. + lassign [function_range func1 $srcdir/$subdir/$srcfile] func1_addr func1_len + lassign [function_range func2 $srcdir/$subdir/$srcfile] func2_addr func2_len + + set asm_file [standard_output_file $srcfile2] + Dwarf::assemble $asm_file { + global func1_addr func1_len + global func2_addr func2_len + global is_64 + + declare_labels cu_range_list foo_range_list + + # This CU uses the DW_FORM_sec_offset form to refer to the .debug_rnglists + # section. + cu { + version 5 + is_64 $is_64 + } { + declare_labels int_type + declare_labels foo_location_list + + DW_TAG_compile_unit { + } { + int_type: DW_TAG_base_type { + {DW_AT_byte_size 4 DW_FORM_data1} + {DW_AT_encoding @DW_ATE_signed} + {DW_AT_name "int"} + } + + DW_TAG_variable { + {DW_AT_name "foo"} + {DW_AT_location $foo_location_list DW_FORM_sec_offset} + {DW_AT_type :$int_type} + } + + DW_TAG_subprogram { + {DW_AT_name "func1"} + {DW_AT_low_pc $func1_addr} + {DW_AT_high_pc $func1_len DW_FORM_udata} + } + + DW_TAG_subprogram { + {DW_AT_name "func2"} + {DW_AT_low_pc $func2_addr} + {DW_AT_high_pc $func2_len DW_FORM_udata} + } + } + } + + loclists -is-64 $is_64 { + # The lists in this table are accessed by direct offset + # (DW_FORM_sec_offset). + table { + foo_location_list: list_ { + start_length $func1_addr $func1_len { + DW_OP_constu 0x123456 + DW_OP_stack_value + } + + start_length $func2_addr $func2_len { + DW_OP_constu 0x234567 + DW_OP_stack_value + } + } + } + } + } + + if { [prepare_for_testing "failed to prepare" ${testfile} \ + [list $srcfile $asm_file] {nodebug}] } { + return -1 + } + + if { ![runto_main] } { + fail "can't run to main" + return + } + + gdb_breakpoint "func1" + gdb_breakpoint "func2" + + gdb_continue_to_breakpoint "func1" + with_test_prefix "at func1" { + gdb_test "print /x foo" " = 0x123456" + } + + gdb_continue_to_breakpoint "func2" + with_test_prefix "at func2" { + gdb_test "print /x foo" " = 0x234567" + } +} diff --git a/gdb/testsuite/lib/dwarf.exp b/gdb/testsuite/lib/dwarf.exp index f4f1cab05e68..b444ef36778a 100644 --- a/gdb/testsuite/lib/dwarf.exp +++ b/gdb/testsuite/lib/dwarf.exp @@ -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. -- 2.30.0