From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-wm1-x341.google.com (mail-wm1-x341.google.com [IPv6:2a00:1450:4864:20::341]) by sourceware.org (Postfix) with ESMTPS id E3DD5395B836 for ; Wed, 27 May 2020 13:10:26 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org E3DD5395B836 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=embecosm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=andrew.burgess@embecosm.com Received: by mail-wm1-x341.google.com with SMTP id j198so2251964wmj.0 for ; Wed, 27 May 2020 06:10:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=embecosm.com; s=google; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to; bh=fGmvt0yMC08cga8zaGUCmdMKW08zscJQuoN9YvC49J4=; b=cdNLASjiN9NwFMt+cS2E8rua01D3frIvPWOULPaRPUt+3GcN9y61aiERVS5LUa7Sak yzlrqvlJj8ZKBaN0YBcpsQsn0bkbcYIhUB+27YTX0yCcoNIyuky14imIsMKWLnvYAFDu Argc+abWy3Lu2ueLJ+R3OV857DSzqCK/81m5hxPYCG4NFlq9aJ6MhhVVtrTI25yH5OIF 9rMGyqtEhq1hKNUcPSKqiGv5YNk6N609JM0AzfHVg7kXmVwbUQqhA4pAXPH5ZdiquS60 aK05avUDWmNNbfMKDlQLfXRoBFJMVmxGI5ggM3kFOxjaCDAC46Ik4iht9gTP297lYIFj cd4w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to; bh=fGmvt0yMC08cga8zaGUCmdMKW08zscJQuoN9YvC49J4=; b=W5RIVcPe7WjDfQlmB5eoehke5VFKJViNdTTqZHZumSbn28pMeWF31qvd+PPo/9Q+re ugmA9XUERwH/k/LlbWoFOadnE1Q7OIJwwyStwSU06wwn+Rb8ecywt9mO7ch7BZbeeubk yX0LLC2X1N7z6HkCvo7/hhGPlS7+t1Dn2vVpGRfpA1X7+rRSj3YH7jI7umNrNyfFxQNE MX17oHovzStSpE1R90w33GYzlqsuU7w095n356nxq96sP5Qxecf3jt1cEy+QmE5HOb40 0UU68p2DB7SQJ+5TIWAPn4NPQo3jjBUktA32maqi19YIcC349lPavvf8hWVSyh8JBccT Qxmw== X-Gm-Message-State: AOAM530opUNSSw1o+15nYvpXnKK6TbyetSRji0hymP0e0317fARe5fsK m0sA27i1WsXyxq/DeTzKnsyGJw== X-Google-Smtp-Source: ABdhPJw7CbP443W5IxLWrMf3ptuUqYp2eQzcT1SIVncZh9PJuXF04FcWsYpZdi362j0Cx8VU50M1Nw== X-Received: by 2002:a1c:9e43:: with SMTP id h64mr4162612wme.0.1590585024416; Wed, 27 May 2020 06:10:24 -0700 (PDT) Received: from localhost (host86-128-12-16.range86-128.btcentralplus.com. [86.128.12.16]) by smtp.gmail.com with ESMTPSA id c14sm2685572wme.8.2020.05.27.06.10.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 27 May 2020 06:10:23 -0700 (PDT) Date: Wed, 27 May 2020 14:10:22 +0100 From: Andrew Burgess To: Bernd Edlinger Cc: Tom Tromey , gdb-patches@sourceware.org, Alexandre Oliva Subject: Re: [PATCH 2/2] gdb: Preserve is-stmt lines when switch between files Message-ID: <20200527131022.GW3522@embecosm.com> References: <20200414112841.GC2366@embecosm.com> <20200416171809.GJ2366@embecosm.com> <87lfmnql4g.fsf@tromey.com> <20200427103418.GF3522@embecosm.com> <87r1vmuv6j.fsf@tromey.com> <20200514223925.GS3522@embecosm.com> <20200520182658.GU3522@embecosm.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20200520182658.GU3522@embecosm.com> X-Operating-System: Linux/5.5.17-200.fc31.x86_64 (x86_64) X-Uptime: 13:37:37 up 37 days, 3:12, X-Editor: GNU Emacs [ http://www.gnu.org/software/emacs ] X-Spam-Status: No, score=-12.1 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_BARRACUDACENTRAL, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org 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: , X-List-Received-Date: Wed, 27 May 2020 13:10:31 -0000 Below is an updated version of the previous work in progress patch. I'm posting it here so there's a record, however, I don't think this patch should be merged into upstream. While working on this solution the problems with it became apparent to me. I've tried to describe my issues with this approach in the commit message of the patch. It is now my intention to merge the patch I posted here: https://sourceware.org/pipermail/gdb-patches/2020-May/168611.html which I'll do in a couple of days unless anyone would like to discuss this further. Thanks, Andrew --- commit 79719063c19b3906fda9d9e7fa0b8c009716b53a Author: Andrew Burgess Date: Wed May 20 19:16:05 2020 +0100 gdb: Don't delete empty lines when changing symtabs ***** NOT FOR MERGING INTO UPSTREAM ***** This patch is based on the work of Bernd Edlinger here: https://sourceware.org/pipermail/gdb-patches/2020-May/168591.html After the is-stmt support commit: commit 8c95582da858ac981f689a6f599acacb8c5c490f Date: Mon Dec 30 21:04:51 2019 +0000 gdb: Add support for tracking the DWARF line table is-stmt field A regression was observed where a breakpoint could no longer be placed in some cases. Consider a line table like this: File 1: test.c File 2: test.h | Addr | File | Line | Stmt | |------|------|------|------| | 1 | 1 | 16 | Y | | 2 | 1 | 17 | Y | | 3 | 2 | 21 | Y | | 4 | 2 | 22 | Y | | 4 | 1 | 18 | N | | 5 | 2 | 23 | N | | 6 | 1 | 24 | Y | | 7 | 1 | END | Y | |------|------|------|------| Before the is-stmt patch GDB would ignore any non-stmt lines, so GDB built two line table structures: File 1 File 2 ------ ------ | Addr | Line | | Addr | Line | |------|------| |------|------| | 1 | 16 | | 3 | 21 | | 2 | 17 | | 4 | 22 | | 3 | END | | 6 | END | | 6 | 24 | |------|------| | 7 | END | |------|------| After the is-stmt patch GDB now records non-stmt lines, so the generated line table structures look like this: File 1 File 2 ------ ------ | Addr | Line | Stmt | | Addr | Line | Stmt | |------|------|------| |------|------|------| | 1 | 16 | Y | | 3 | 21 | Y | | 2 | 17 | Y | | 4 | 22 | Y | | 3 | END | Y | | 4 | END | Y | | 4 | 18 | N | | 5 | 23 | N | | 5 | END | Y | | 6 | END | Y | | 6 | 24 | Y | |------|------|------| | 7 | END | Y | |------|------|------| The problem is that in 'File 2', end END marker at address 4 causes the previous line table entry to be discarded, so we actually end up with this: File 2 ------ | Addr | Line | Stmt | |------|------|------| | 3 | 21 | Y | | 4 | END | Y | | 5 | 23 | N | | 6 | END | Y | |------|------|------| When a user tries to place a breakpoint in file 2 at line 22, this is no longer possible. In order to understand the solution presented here, we must first remind ourselves why we delete line table entries that occur at the same address as an END marker. The problem this (deleting lines) is trying to solve is that if the last real line within a line table is empty (maybe due to optimisation) then the line will be at the same address as the end marker. If the user tries to place a breakpoint at this address then we actually end up with a breakpoint at whatever is _after_ the location of that empty line, which is likely some other random function. However, when a line table switches subfiles we also insert end markers, this is because the GDB internal line table is split per-subfile, so the end markers allow us to see and "end" for the line just before the switch. Without this, the line table entry just before the we switch subfiles would appear to extend over the entire region covered by the subfile we switch too. If we further consider the end markers inserted for switching subfiles, there are two common cases when this can occur, these are, first when one file is fully included inside another, and secondly when a function from one (header) file is inlined within a function in a different file. In the first of these situations GDB is exposed to the same risk as for the classic end marker case, if the last line before the subfile switch is empty, then when we switch subfiles we should be deleting the empty line, otherwise a user placing a breakpoint on this line, will end up with a breakpoint in a potentially different function. However, for the case of the inlined function the argument for deleting lines is harder to make, indeed if we consider a function inlined from another file compared to a function inlined from within the same file then it is obvious that in the case where the inlined callee is within the same file there will be no subfile switch, and hence no end of sequence markers inserted, and as a consequence no deleted line entries. It is tempting then to think that, when we switch subfiles as part of an inlined function we would like to preserve line table entries where possible. The problem is how to distinguish between the case of an inlined function subfile switch, and a general inclusion subfile switch? Though I'm sure we can solve this problem, I think it is worth considering if this is even a problem worth solving. First, the act of deleting line table entries only occurs when entries in the original debug information "pile up" and occur at the same address, consider this imagined input line table: | Addr | File | Line | Stmt | |------|------|------|------| | 1 | 1 | 10 | Y | | 2 | 2 | 100 | Y | | 3 | 1 | 11 | Y | In this case no entries will be deleted, as every line table item occurs at a separate address. Compare it to this: | Addr | File | Line | Stmt | |------|------|------|------| | 1 | 1 | 10 | Y | | 1 | 2 | 100 | Y | | 2 | 1 | 11 | Y | Here, the switch to subfile 2 will cause the line item from subfile 1 (also at address 1) to be deleted. This kind of makes sense, the debug is claiming the address 1 represents both file 1, line 10 and file 2, line 100. If we stop at this address which line should GDB report? If the same situation was imagined within a single subfile, like this: | Addr | File | Line | Stmt | |------|------|------|------| | 1 | 1 | 10 | Y | | 1 | 1 | 100 | Y | | 2 | 1 | 11 | Y | GDB would report line 100 at address 1, and line 11 at address 2. By deleting the line in the two subfile case we get the same behaviour, but we protect against the empty line at the end of a subfile problem. It is for this reason, that I think this commit should not be merged with GDB. One problem that came from this commit was the test gdb.cp/step-and-next-inline.exp, which broke in several places. After looking at this test again I think that in some cases this test was only ever passing by pure luck. The debug GCC is producing for this test is pretty broken. I raised this GCC bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94474 for this and disabled one entire half of the test. There are still some cases in here that do pass, and if/when GCC is fixed it would be great to enable this test again. Also the possibility of extending GDB to handle GCC's broken debug information has been discussed. gdb/ChangeLog: * buildsym.c (buildsym_compunit::record_line): Extend header comment. Add some static assertions. Handle different end of sequence types. * buildsym.h (struct buildsym_compunit) : New constant. : New constant. * dwarf2/read.c (dwarf_finish_line): Add extra parameter, use this to decide which end of sequence marker to send through as the line number. (lnp_state_machine::record_line): Pass extra parameter to dwarf_finish_line. * symtab.c (find_pc_sect_line): The previous line is better if it was marked is-stmt, and the new possible best is not. * symtab.h (struct linetable_entry) : Extend comment. gdb/testsuite/ChangeLog: * gdb.cp/step-and-next-inline.exp (do_test): Skip all tests in the use_header case. * gdb.dwarf2/dw2-inline-header-1.exp: New file. * gdb.dwarf2/dw2-inline-header-2.exp: New file. * gdb.dwarf2/dw2-inline-header-3.exp: New file. * gdb.dwarf2/dw2-inline-header-lbls.c: New file. * gdb.dwarf2/dw2-inline-header.c: New file. * gdb.dwarf2/dw2-inline-header.h: New file. diff --git a/gdb/buildsym.c b/gdb/buildsym.c index 33bf6523e90..37fec4f53b6 100644 --- a/gdb/buildsym.c +++ b/gdb/buildsym.c @@ -663,7 +663,42 @@ buildsym_compunit::pop_subfile () } /* Add a linetable entry for line number LINE and address PC to the - line vector for SUBFILE. */ + line vector for SUBFILE. + + Pass the constant end_of_sequence for LINE when an end of sequence + marker is encountered in the original debug information. If this case + any previous line table entries already at this address will be deleted, + these lines are by definition empty, and attempting to place a + breakpoint at this address will result in a breakpoint being placed on + whatever is next in the executable, which is never going to be the + correct behaviour. + + Alternatively, pass the constant change_of_subfile for LINE to indicate + that the original debug line table switched to a different subfile. + This still results in an end of sequence marker being placed in GDB's + internal line table, but in this case we don't delete previous line + entries at this address. This case arises from two common situations, + the most common is inlined functions, in this case the switching between + subfiles occurs within a single function. If a real line entry and a + subfile switch occur at the same address we don't want to delete the + real line entry in this case as we end up loosing too much useful debug + information. + + The other situation where a subfile switch is commonly seen is when one + source file is included into another, in this case the original line + table will include information for one subfile before switching to the + second subfile. If the last line of the last function in the first + subfile is at the same address as the subfile switch then it is possible + that a breakpoint placed on this line would actually be placed in the + subsequent function by mistake. + + We could improve on this second situation by entering all end of + sequence markers here without deleting any line table entries, then + cross check the line table with the list of function blocks, we would + then delete any line table entries that occurred at an end of sequence + marker that was also at the end of a function. Right now we don't do + this, and live with the (small) risk of a breakpoint being misplaced; + the benefit of preserving the extra line table entries is worth it. */ void buildsym_compunit::record_line (struct subfile *subfile, int line, @@ -671,6 +706,13 @@ buildsym_compunit::record_line (struct subfile *subfile, int line, { struct linetable_entry *e; + /* The END_OF_SEQUENCE must be 0 as the constant 0 is used when + processing the line table as the magic end of sequence marker. The + CHANGE_OF_SUBFILE marker must be less than 0 as any value greater than + 0 is an actual line number. */ + gdb_static_assert (buildsym_compunit::end_of_sequence == 0); + gdb_static_assert (buildsym_compunit::change_of_subfile < 0); + /* Make sure line vector exists and is big enough. */ if (!subfile->line_vector) { @@ -705,7 +747,7 @@ buildsym_compunit::record_line (struct subfile *subfile, int line, end of sequence markers. All we lose is the ability to set breakpoints at some lines which contain no instructions anyway. */ - if (line == 0) + if (line == buildsym_compunit::end_of_sequence) { while (subfile->line_vector->nitems > 0) { @@ -715,8 +757,11 @@ buildsym_compunit::record_line (struct subfile *subfile, int line, subfile->line_vector->nitems--; } } + else if (line == buildsym_compunit::change_of_subfile) + line = buildsym_compunit::end_of_sequence; e = subfile->line_vector->item + subfile->line_vector->nitems++; + gdb_assert (line >= 0); e->line = line; e->is_stmt = is_stmt ? 1 : 0; e->pc = pc; diff --git a/gdb/buildsym.h b/gdb/buildsym.h index c768a4c2dae..3e22d0b4494 100644 --- a/gdb/buildsym.h +++ b/gdb/buildsym.h @@ -190,6 +190,14 @@ struct buildsym_compunit void record_line (struct subfile *subfile, int line, CORE_ADDR pc, bool is_stmt); + /* These two constants can be passed to RECORD_LINE as the value of LINE + to indicate special events in the line table. END_OF_SEQUENCE marks + an actual end of sequence marked in the original debug's line table, + while CHANGE_OF_SUBFILE indicates an end marker due to switching + between subfiles. */ + static const int end_of_sequence = 0; + static const int change_of_subfile = -1; + struct compunit_symtab *get_compunit_symtab () { return m_compunit_symtab; diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c index ec3844188ee..ed0f247b6a1 100644 --- a/gdb/dwarf2/read.c +++ b/gdb/dwarf2/read.c @@ -20067,7 +20067,7 @@ dwarf_record_line_1 (struct gdbarch *gdbarch, struct subfile *subfile, static void dwarf_finish_line (struct gdbarch *gdbarch, struct subfile *subfile, - CORE_ADDR address, struct dwarf2_cu *cu) + CORE_ADDR address, struct dwarf2_cu *cu, bool end_sequence) { if (subfile == NULL) return; @@ -20080,7 +20080,10 @@ dwarf_finish_line (struct gdbarch *gdbarch, struct subfile *subfile, paddress (gdbarch, address)); } - dwarf_record_line_1 (gdbarch, subfile, 0, address, true, cu); + int lineno = (end_sequence + ? buildsym_compunit::end_of_sequence + : buildsym_compunit::change_of_subfile); + dwarf_record_line_1 (gdbarch, subfile, lineno, address, true, cu); } void @@ -20113,7 +20116,8 @@ lnp_state_machine::record_line (bool end_sequence) || end_sequence) { dwarf_finish_line (m_gdbarch, m_last_subfile, m_address, - m_currently_recording_lines ? m_cu : nullptr); + m_currently_recording_lines ? m_cu : nullptr, + end_sequence); } if (!end_sequence) diff --git a/gdb/symtab.c b/gdb/symtab.c index 5c4e282c024..f6ebae45b27 100644 --- a/gdb/symtab.c +++ b/gdb/symtab.c @@ -3254,7 +3254,9 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent) save prev if it represents the end of a function (i.e. line number 0) instead of a real line. */ - if (prev && prev->line && (!best || prev->pc > best->pc)) + if (prev && prev->line && (!best || prev->pc > best->pc + || (prev->pc == best->pc && !best->is_stmt + && prev->is_stmt))) { best = prev; best_symtab = iter_s; diff --git a/gdb/symtab.h b/gdb/symtab.h index 9972e8125ba..62bedb45de7 100644 --- a/gdb/symtab.h +++ b/gdb/symtab.h @@ -1306,7 +1306,10 @@ struct rust_vtable_symbol : public symbol struct linetable_entry { - /* The line number for this entry. */ + /* The line number for this entry. This should be a value greater than + 0 to indicate an actual line number, or the magic value 0 is used to + indicate the end of a sequence of linetable_entry structures in a + list. */ int line; /* True if this PC is a good location to place a breakpoint for LINE. */ diff --git a/gdb/testsuite/gdb.cp/step-and-next-inline.exp b/gdb/testsuite/gdb.cp/step-and-next-inline.exp index 3733fa75570..a95e21194f9 100644 --- a/gdb/testsuite/gdb.cp/step-and-next-inline.exp +++ b/gdb/testsuite/gdb.cp/step-and-next-inline.exp @@ -24,6 +24,13 @@ if { ![supports_statement_frontiers] } { proc do_test { use_header } { global srcfile testfile + if { $use_header } { + # This test will not pass due to poor debug information + # generated by GCC (at least upto 10.x). See + # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94474 + return + } + set options {c++ debug nowarnings optimize=-O2\ -gstatement-frontiers} if { $use_header } { lappend options additional_flags=-DUSE_NEXT_INLINE_H diff --git a/gdb/testsuite/gdb.dwarf2/dw2-inline-header-1.exp b/gdb/testsuite/gdb.dwarf2/dw2-inline-header-1.exp new file mode 100644 index 00000000000..dc7ec929236 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-inline-header-1.exp @@ -0,0 +1,186 @@ +# 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 . + +# Setup a line table where: +# +# | | | | | Inline | Inline | +# | Addr | File | Line | Stmt | Rng A | Rng B | +# |------|------|------|------|--------|--------| +# | 1 | 1 | 16 | Y | | | +# | 2 | 1 | 17 | Y | | | +# | 3 | 2 | 21 | Y | X | | +# | 4 | 2 | 22 | Y | X | | +# | 4 | 1 | 18 | N | X | | +# | 5 | 2 | 23 | N | X | X | +# | 6 | 1 | 24 | Y | | | +# | 7 | 1 | END | Y | | | +# |------|------|------|------|--------|--------| +# +# Places a brekpoint at file 2, line 22. Previously GDB would discard +# the line table entry for this line due to switching files for the +# file 1, line 18 non-statement line. After patching however, GDB now +# discards the file 1, line 18 entry instead, and the breakpoint at +# line 22 should succeed. +# +# The two inlined subroutine ranges 'A' and 'B' represent two possible +# ways that a compiler might represent this siuatio in the DWARF. +# +# Range 'B' is something that has been seen in the wild using GCC 8.2. +# In this case the compilers range information is clearly wrong, but +# this shouldn't impact the main point of the test. +# +# Range 'A' is a hypothetical case of how the compiler might choose to +# represent this range, this has never been seen in the wild, but is +# an improved debug experiece over range 'B'. However, if we ever run +# in to the situation where GDB can support the range 'A' test, or +# support some real DWARF seen in the wild, then the range 'A' case +# should be dropped in favour of supporting real world cases. This is +# included here as it "just worked" once the range 'B' case was +# working. + +load_lib dwarf.exp + +# This test can only be run on targets which support DWARF-2 and use gas. +if {![dwarf2_support]} { + return 0 +} + +# The .c files use __attribute__. +if [get_compiler_info] { + return -1 +} +if !$gcc_compiled { + return 0 +} + +# Prepare and run the test. +proc do_test { start_label func_name tag } { + global srcfile srcfile2 srcfile3 srcfile4 testfile + + standard_testfile dw2-inline-header-lbls.c dw2-inline-header-${tag}.S \ + dw2-inline-header.c dw2-inline-header.h + + set build_options {nodebug optimize=-O1} + + set asm_file [standard_output_file $srcfile2] + Dwarf::assemble $asm_file { + global srcdir subdir srcfile srcfile3 srcfile4 testfile + upvar build_options build_options + upvar start_label start_label + declare_labels lines_label callee_subprog_label + + get_func_info main $build_options + + cu {} { + compile_unit { + {producer "gcc" } + {language @DW_LANG_C} + {name ${srcfile3}} + {low_pc 0 addr} + {stmt_list ${lines_label} DW_FORM_sec_offset} + } { + callee_subprog_label: subprogram { + {external 1 flag} + {name callee} + {inline 3 data1} + } + subprogram { + {external 1 flag} + {name main} + {low_pc $main_start addr} + {high_pc "$main_start + $main_len" addr} + } { + inlined_subroutine { + {abstract_origin %$callee_subprog_label} + {low_pc $start_label addr} + {high_pc line_label_6 addr} + {call_file 1 data1} + {call_line 18 data1} + } + } + } + } + + lines {version 2 default_is_stmt 1} lines_label { + include_dir "${srcdir}/${subdir}" + file_name "$srcfile3" 1 + file_name "$srcfile4" 1 + + program { + {DW_LNE_set_address line_label_1} + {DW_LNS_advance_line 15} + {DW_LNS_copy} + + {DW_LNE_set_address line_label_2} + {DW_LNS_advance_line 1} + {DW_LNS_copy} + + {DW_LNS_set_file 2} + {DW_LNE_set_address line_label_3} + {DW_LNS_advance_line 4} + {DW_LNS_copy} + + {DW_LNE_set_address line_label_4} + {DW_LNS_advance_line 1} + {DW_LNS_copy} + + {DW_LNS_advance_line -4} + {DW_LNS_set_file 1} + {DW_LNS_negate_stmt} + {DW_LNS_copy} + + {DW_LNS_set_file 2} + {DW_LNE_set_address line_label_5} + {DW_LNS_advance_line 5} + {DW_LNS_copy} + + {DW_LNS_negate_stmt} + {DW_LNS_set_file 1} + {DW_LNE_set_address line_label_6} + {DW_LNS_advance_line 1} + {DW_LNS_copy} + + {DW_LNE_set_address line_label_7} + {DW_LNE_end_sequence} + } + } + } + + if { [prepare_for_testing "failed to prepare" ${testfile}-${tag} \ + [list $srcfile $asm_file] $build_options] } { + return -1 + } + + if ![runto_main] { + return -1 + } + + # Delete all breakpoints so that the output of "info breakpoints" + # below will only contain a single breakpoint. + delete_breakpoints + + # Place a breakpoint within the function in the header file. + gdb_breakpoint "${srcfile4}:22" + + # Check that the breakpoint was placed where we expected. It should + # appear at the requested line. When the bug in GDB was present the + # breakpoint would be placed on one of the following lines instead. + gdb_test "info breakpoints" \ + ".* in $func_name at \[^\r\n\]+${srcfile4}:22\\y.*" \ + "info breakpoints, $tag" +} + +do_test line_label_3 "callee" "range-a" +do_test line_label_5 "main" "range-b" diff --git a/gdb/testsuite/gdb.dwarf2/dw2-inline-header-2.exp b/gdb/testsuite/gdb.dwarf2/dw2-inline-header-2.exp new file mode 100644 index 00000000000..9f09f353273 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-inline-header-2.exp @@ -0,0 +1,189 @@ +# 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 . + +# Setup a line table where: +# +# | Addr | File | Line | Stmt | Inline | +# |------|------|------|------|--------| +# | 1 | 1 | 16 | Y | | +# | 2 | 1 | 17 | Y | | +# | 3 | 2 | 21 | Y | X | +# | 4 | 2 | 22 | Y | X | +# | 4 | 1 | 18 | N | X | +# | 5 | 1 | 19 | Y | | +# | 6 | 1 | 20 | Y | | +# | 7 | 1 | END | Y | | +# |------|------|------|------|--------| +# +# +# Place the first brekpoint at file 2, line 22 and a second breakpoint +# at file 1, line 19. A third breakpoint is placed at file 1, line +# 18, but as this line table entry will have been discarded[1] the +# third breakpoint will actually be placed at the same location as the +# second breakpoint. +# +# This test is designed to test GDB's internal behaviour with respect +# to discarding particular line table entries. GCC and DWARF are +# starting to introduce the idea of line table views. As the views +# information becomes better supported within GDB it is likely that +# this will become out of date. This is fine, the test will have +# served its purpose by that point and can be deleted. +# +# [1] The entry for file 1, line 18 is discarded because it is at the +# same address as the previous entry, but the previous entry is-stmt, +# while line 18 is a non-stmt. + +load_lib dwarf.exp + +# This test can only be run on targets which support DWARF-2 and use gas. +if {![dwarf2_support]} { + return 0 +} + +# The .c files use __attribute__. +if [get_compiler_info] { + return -1 +} +if !$gcc_compiled { + return 0 +} + +standard_testfile dw2-inline-header-lbls.c dw2-inline-header.S \ + dw2-inline-header.c dw2-inline-header.h + +set build_options {nodebug optimize=-O1} + +set asm_file [standard_output_file $srcfile2] +Dwarf::assemble $asm_file { + global srcdir subdir srcfile srcfile3 srcfile4 + global build_options + declare_labels lines_label callee_subprog_label + + get_func_info main $build_options + + cu {} { + compile_unit { + {producer "gcc" } + {language @DW_LANG_C} + {name ${srcfile3}} + {low_pc 0 addr} + {stmt_list ${lines_label} DW_FORM_sec_offset} + } { + callee_subprog_label: subprogram { + {external 1 flag} + {name callee} + {inline 3 data1} + } + subprogram { + {external 1 flag} + {name main} + {low_pc $main_start addr} + {high_pc "$main_start + $main_len" addr} + } { + inlined_subroutine { + {abstract_origin %$callee_subprog_label} + {low_pc line_label_3 addr} + {high_pc line_label_5 addr} + {call_file 1 data1} + {call_line 18 data1} + } + } + } + } + + lines {version 2 default_is_stmt 1} lines_label { + include_dir "${srcdir}/${subdir}" + file_name "$srcfile3" 1 + file_name "$srcfile4" 1 + + program { + {DW_LNE_set_address line_label_1} + {DW_LNS_advance_line 15} + {DW_LNS_copy} + + {DW_LNE_set_address line_label_2} + {DW_LNS_advance_line 1} + {DW_LNS_copy} + + {DW_LNS_set_file 2} + {DW_LNE_set_address line_label_3} + {DW_LNS_advance_line 4} + {DW_LNS_copy} + + {DW_LNE_set_address line_label_4} + {DW_LNS_advance_line 1} + {DW_LNS_copy} + + {DW_LNS_advance_line -4} + {DW_LNS_set_file 1} + {DW_LNS_negate_stmt} + {DW_LNS_copy} + + {DW_LNE_set_address line_label_5} + {DW_LNS_advance_line 1} + {DW_LNS_negate_stmt} + {DW_LNS_copy} + + {DW_LNE_set_address line_label_6} + {DW_LNS_advance_line 1} + {DW_LNS_copy} + + {DW_LNE_set_address line_label_7} + {DW_LNE_end_sequence} + } + } +} + +if { [prepare_for_testing "failed to prepare" ${testfile} \ + [list $srcfile $asm_file] $build_options] } { + return -1 +} + +if ![runto_main] { + return -1 +} + +# Delete all breakpoints so that the output of "info breakpoints" +# below will only contain a single breakpoint. +delete_breakpoints + +# Place a breakpoint within the function in the header file. +gdb_breakpoint "${srcfile4}:22" + +# Check that the breakpoint was placed where we expected. It should +# appear at the requested line. When the bug in GDB was present the +# breakpoint would be placed on one of the following lines instead. +gdb_test "info breakpoints" \ + ".* in callee at \[^\r\n\]+${srcfile4}:22\\y.*" \ + "check for breakpoint at ${srcfile4}" + +# Delete all breakpoints so that the output of "info breakpoints" +# below will only contain a single breakpoint. +delete_breakpoints + +# Place a breakpoint within the function in the header file. +gdb_breakpoint "${srcfile3}:19" + +# Check that the breakpoint was placed where we expected. It should +# appear at the requested line. When the bug in GDB was present the +# breakpoint would be placed on one of the following lines instead. +gdb_test "info breakpoints" \ + ".* in main at \[^\r\n\]+${srcfile3}:19\\y.*" \ + "check for breakpoint at ${srcfile3}" + +# Line table entry for line 18 will have been discarded, so this +# brekpoint will be at the same location as line 19. +gdb_test "break ${srcfile3}:18" \ + "Note: breakpoint $decimal also set at pc $hex.*" diff --git a/gdb/testsuite/gdb.dwarf2/dw2-inline-header-3.exp b/gdb/testsuite/gdb.dwarf2/dw2-inline-header-3.exp new file mode 100644 index 00000000000..a3820f16d57 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-inline-header-3.exp @@ -0,0 +1,193 @@ +# 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 . + +# Setup a line table where: +# +# | Addr | File | Line | Stmt | Inline | +# |------|------|------|------|--------| +# | 1 | 1 | 16 | Y | | +# | 2 | 1 | 17 | Y | | +# | 3 | 2 | 21 | Y | X | +# | 4 | 2 | 22 | Y | X | +# | 4 | 1 | 18 | N | | +# | 5 | 1 | 19 | N | | +# | 6 | 1 | 20 | Y | | +# | 7 | 1 | END | Y | | +# |------|------|------|------|--------| +# +# Break at file 2, line 22, then single instruction step forward. We +# should pass through line 19 and then encounter line 20. +# +# Currently we don't expect GDB to see file 1, line 18, as this is a +# non-stmt line in a different file at the same address as the +# previous is-stmt line. + +load_lib dwarf.exp + +# This test can only be run on targets which support DWARF-2 and use gas. +if {![dwarf2_support]} { + return 0 +} + +# The .c files use __attribute__. +if [get_compiler_info] { + return -1 +} +if !$gcc_compiled { + return 0 +} + +standard_testfile dw2-inline-header-lbls.c dw2-inline-header.S \ + dw2-inline-header.c dw2-inline-header.h + +set build_options {nodebug optimize=-O1} + +set asm_file [standard_output_file $srcfile2] +Dwarf::assemble $asm_file { + global srcdir subdir srcfile srcfile3 srcfile4 + global build_options + declare_labels lines_label callee_subprog_label + + get_func_info main $build_options + + cu {} { + compile_unit { + {producer "gcc" } + {language @DW_LANG_C} + {name ${srcfile3}} + {low_pc 0 addr} + {stmt_list ${lines_label} DW_FORM_sec_offset} + } { + callee_subprog_label: subprogram { + {external 1 flag} + {name callee} + {inline 3 data1} + } + subprogram { + {external 1 flag} + {name main} + {low_pc $main_start addr} + {high_pc "$main_start + $main_len" addr} + } { + inlined_subroutine { + {abstract_origin %$callee_subprog_label} + {low_pc line_label_3 addr} + {high_pc line_label_5 addr} + {call_file 1 data1} + {call_line 18 data1} + } + } + } + } + + lines {version 2 default_is_stmt 1} lines_label { + include_dir "${srcdir}/${subdir}" + file_name "$srcfile3" 1 + file_name "$srcfile4" 1 + + program { + {DW_LNE_set_address line_label_1} + {DW_LNS_advance_line 15} + {DW_LNS_copy} + + {DW_LNE_set_address line_label_2} + {DW_LNS_advance_line 1} + {DW_LNS_copy} + + {DW_LNS_set_file 2} + {DW_LNE_set_address line_label_3} + {DW_LNS_advance_line 4} + {DW_LNS_copy} + + {DW_LNE_set_address line_label_4} + {DW_LNS_advance_line 1} + {DW_LNS_copy} + + {DW_LNS_advance_line -4} + {DW_LNS_set_file 1} + {DW_LNS_negate_stmt} + {DW_LNS_copy} + + {DW_LNE_set_address line_label_5} + {DW_LNS_advance_line 1} + {DW_LNS_copy} + + {DW_LNE_set_address line_label_6} + {DW_LNS_advance_line 1} + {DW_LNS_negate_stmt} + {DW_LNS_copy} + + {DW_LNE_set_address line_label_7} + {DW_LNE_end_sequence} + } + } +} + +if { [prepare_for_testing "failed to prepare" ${testfile} \ + [list $srcfile $asm_file] $build_options] } { + return -1 +} + +if ![runto_main] { + return -1 +} + +# Delete all breakpoints so that the output of "info breakpoints" +# below will only contain a single breakpoint. +delete_breakpoints + +# Place a breakpoint within the function in the header file. +gdb_breakpoint "${srcfile4}:22" + +# Check that the breakpoint was placed where we expected. It should +# appear at the requested line. When the bug in GDB was present the +# breakpoint would be placed on one of the following lines instead. +gdb_test "info breakpoints" \ + ".* in callee at \[^\r\n\]+${srcfile4}:22\\y.*" + +gdb_continue_to_breakpoint "${srcfile4}:22" \ + ".* ${srcfile4} : 22 .*" + +# Now single instruction step forward. Eventually we should hit +# ${srcfile3}:20, but before we do we should hit the non-statement +# line ${srcfile3}:19. +# +# We don't know how many instructions we'll need to step, but 100 +# should be enough for everyone (surely), and this stops us looping +# forever if something goes wrong. +set found_line_19 0 +set found_line_20 0 +set keep_going 1 +for { set i 0 } { $i < 100 && $keep_going } { incr i } { + set keep_going 0 + gdb_test_multiple "stepi" "stepi ${i}" { + -re "${srcfile3} : 19 .*${gdb_prompt} " { + set found_line_19 1 + set keep_going 1 + } + + -re "${srcfile3} : 20 .*${gdb_prompt} " { + set found_line_20 1 + } + + -re "${srcfile4} : 22 .*${gdb_prompt} " { + # Not left line 22 yet. + set keep_going 1 + } + } +} + +gdb_assert { $found_line_19 && $found_line_20 } \ + "found line 19 and 20" diff --git a/gdb/testsuite/gdb.dwarf2/dw2-inline-header-lbls.c b/gdb/testsuite/gdb.dwarf2/dw2-inline-header-lbls.c new file mode 100644 index 00000000000..a1b7b17cbeb --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-inline-header-lbls.c @@ -0,0 +1,46 @@ +/* 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 . */ + +/* Used to insert labels with which we can build a fake line table. */ +#define LL(N) asm ("line_label_" #N ": .globl line_label_" #N) + +volatile int var; +volatile int bar; + +/* Generate some code to take up some space. */ +#define FILLER do { \ + var = 99; \ +} while (0) + +int +main () +{ /* main prologue */ + asm ("main_label: .globl main_label"); + LL (1); // F1, Ln 16 + FILLER; + LL (2); // F1, Ln 17 + FILLER; + LL (3); // F2, Ln 21 + FILLER; + LL (4); // F2, Ln 22 // F1, Ln 18, !S + FILLER; + LL (5); // F1, Ln 19 !S + FILLER; + LL (6); // F1, Ln 20 + FILLER; + LL (7); + FILLER; + return 0; /* main end */ +} diff --git a/gdb/testsuite/gdb.dwarf2/dw2-inline-header.c b/gdb/testsuite/gdb.dwarf2/dw2-inline-header.c new file mode 100644 index 00000000000..a8331268a09 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-inline-header.c @@ -0,0 +1,24 @@ +/* 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 . */ + +/* dw2-inline-header.c : 16 */ +/* dw2-inline-header.c : 17 */ +/* dw2-inline-header.c : 18 */ +/* dw2-inline-header.c : 19 */ +/* dw2-inline-header.c : 20 */ +/* dw2-inline-header.c : 21 */ +/* dw2-inline-header.c : 22 */ +/* dw2-inline-header.c : 23 */ +/* dw2-inline-header.c : 24 */ diff --git a/gdb/testsuite/gdb.dwarf2/dw2-inline-header.h b/gdb/testsuite/gdb.dwarf2/dw2-inline-header.h new file mode 100644 index 00000000000..7233acbcd76 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-inline-header.h @@ -0,0 +1,24 @@ +/* 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 . */ + +/* dw2-inline-header.h : 16 */ +/* dw2-inline-header.h : 17 */ +/* dw2-inline-header.h : 18 */ +/* dw2-inline-header.h : 19 */ +/* dw2-inline-header.h : 20 */ +/* dw2-inline-header.h : 21 */ +/* dw2-inline-header.h : 22 */ +/* dw2-inline-header.h : 23 */ +/* dw2-inline-header.h : 24 */