public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 0/2] Add support for DWARF's prologue_end flag in line-table
@ 2022-03-18 14:27 Lancelot SIX
  2022-03-18 14:27 ` [PATCH 1/2] gdb/buildsym: Line record use a record flag Lancelot SIX
  2022-03-18 14:27 ` [PATCH 2/2] gdb: Add support for DW_LNS_set_prologue_end in line-table Lancelot SIX
  0 siblings, 2 replies; 5+ messages in thread
From: Lancelot SIX @ 2022-03-18 14:27 UTC (permalink / raw)
  To: gdb-patches; +Cc: lsix, Lancelot SIX

Hi,

I came across a situation where GDB would fail to properly report a
breakpoint hit.

Lets consider the following simplified example:

    void
    foo ()
    {
      inlined_function ();
    }

In this situation, the user did place a breakpoint in foo ("break foo"),
but when the breakpoint was hit GDB reported the stop to be in
inlined_function.

In the debug information, the foo and inlined_functions have the same
low_pc, but GDB places the breakpoint at a PC higher than that $low_pc.
Therefore, when the breakpoint is hit, the effective PC seems to be
inside inlined_function.  GDB reports that the stop happened in the
inlined function which is not what the user expects.

The underlying issue is of course that the breakpoint is placed at the
wrong PC.  This comes down to an invalid detection of the end of the
prologue of the foo function, which is what this small series fixes.

The program I am interested in is compiled by a LLVM based compiler,
which includes prologue_end markers in the line table information.
Those markers (introduced in DWARF-3) indicate where breakpoints should
be placed to be at the first instruction past the prologue of a
function.  Currently, GDB does not process this information.

This series proposes to implement support for the DWARF prologue_end
flags.  The first patch in the series does some minor refactoring, and
the second patch adds support for the prologue_end flags.

As (as far as I can tell) GCC does not emit those flags, this series has
no effect to debug code produced by this compiler.

The series have been regression tested on upuntu-20.04 x86_64-linux
using:

- make check
- make check RUNTESTFLAGS="CC_FOR_TARGET=clang CXX_FOR_TARGET=clang++"

All feedbacks are welcome,
Best,
Lancelot.

Lancelot SIX (2):
  gdb/buildsym: Line record use a record flag
  gdb: Add support for DW_LNS_set_prologue_end in line-table

 gdb/NEWS                                      |  4 +
 gdb/buildsym-legacy.c                         |  2 +-
 gdb/buildsym.c                                |  5 +-
 gdb/buildsym.h                                | 12 ++-
 gdb/doc/gdb.texinfo                           | 27 ++++++
 gdb/dwarf2/read.c                             | 52 +++++++----
 gdb/symmisc.c                                 |  6 +-
 gdb/symtab.c                                  | 51 +++++++++++
 gdb/symtab.h                                  |  4 +
 .../dw2-out-of-range-end-of-seq.exp           |  4 +-
 gdb/testsuite/gdb.dwarf2/dw2-prologue-end.c   | 28 ++++++
 gdb/testsuite/gdb.dwarf2/dw2-prologue-end.exp | 91 +++++++++++++++++++
 gdb/testsuite/gdb.dwarf2/dw2-ranges-base.exp  |  2 +-
 gdb/testsuite/lib/dwarf.exp                   | 16 ++--
 14 files changed, 273 insertions(+), 31 deletions(-)
 create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-prologue-end.c
 create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-prologue-end.exp


base-commit: c4d0963383ad8ca0f0bf63c857b9462efdacff7c
-- 
2.25.1


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/2] gdb/buildsym: Line record use a record flag
  2022-03-18 14:27 [PATCH 0/2] Add support for DWARF's prologue_end flag in line-table Lancelot SIX
@ 2022-03-18 14:27 ` Lancelot SIX
  2022-03-18 14:27 ` [PATCH 2/2] gdb: Add support for DW_LNS_set_prologue_end in line-table Lancelot SIX
  1 sibling, 0 replies; 5+ messages in thread
From: Lancelot SIX @ 2022-03-18 14:27 UTC (permalink / raw)
  To: gdb-patches; +Cc: lsix, Lancelot SIX

Currently when recording a line entry (with
buildsym_compunit::record_line), a boolean argument argument is used
indicate that the is_stmt flag should be se for this particular record.
A later commit will add support for new flags to associate with line
table entries.  Instead of adding a parameter to record_line for each
possible flag, transform the current is_stmt parameter into a enum flag
which fill support all required flags.

This enum flags type is not propagated into the linetable_entry type as
this would require a lot of changes across the codebase for no practical
gain (it currently uses a bitfield where each interesting flag only
occupy 1 bit in the structure).

Tested on x86_64-linux, no regression observed.

Change-Id: I5d061fa67bdb34918742505ff983d37453839d6a
---
 gdb/buildsym-legacy.c |  2 +-
 gdb/buildsym.c        |  4 ++--
 gdb/buildsym.h        | 11 ++++++++++-
 gdb/dwarf2/read.c     | 37 ++++++++++++++++++++++---------------
 4 files changed, 35 insertions(+), 19 deletions(-)

diff --git a/gdb/buildsym-legacy.c b/gdb/buildsym-legacy.c
index 7659f53cbe0..53cd3bd865b 100644
--- a/gdb/buildsym-legacy.c
+++ b/gdb/buildsym-legacy.c
@@ -254,7 +254,7 @@ record_line (struct subfile *subfile, int line, CORE_ADDR pc)
   gdb_assert (buildsym_compunit != nullptr);
   /* Assume every line entry is a statement start, that is a good place to
      put a breakpoint for that line number.  */
-  buildsym_compunit->record_line (subfile, line, pc, true);
+  buildsym_compunit->record_line (subfile, line, pc, LEF_IS_STMT);
 }
 
 /* Start a new symtab for a new source file in OBJFILE.  Called, for example,
diff --git a/gdb/buildsym.c b/gdb/buildsym.c
index 999f632f401..a875eb5ce38 100644
--- a/gdb/buildsym.c
+++ b/gdb/buildsym.c
@@ -667,7 +667,7 @@ buildsym_compunit::pop_subfile ()
 
 void
 buildsym_compunit::record_line (struct subfile *subfile, int line,
-				CORE_ADDR pc, bool is_stmt)
+				CORE_ADDR pc, linetable_entry_flags flags)
 {
   struct linetable_entry *e;
 
@@ -723,7 +723,7 @@ buildsym_compunit::record_line (struct subfile *subfile, int line,
 
   e = subfile->line_vector->item + subfile->line_vector->nitems++;
   e->line = line;
-  e->is_stmt = is_stmt ? 1 : 0;
+  e->is_stmt = (flags & LEF_IS_STMT) != 0;
   e->pc = pc;
 }
 
diff --git a/gdb/buildsym.h b/gdb/buildsym.h
index 003d8a59719..09c2d563ec9 100644
--- a/gdb/buildsym.h
+++ b/gdb/buildsym.h
@@ -110,6 +110,15 @@ struct context_stack
 
   };
 
+/* Flags associated with a linetable entry.  */
+
+enum linetable_entry_flag : unsigned
+{
+  LEF_IS_STMT = 1 << 1,
+};
+DEF_ENUM_FLAGS_TYPE (enum linetable_entry_flag, linetable_entry_flags);
+
+
 /* Buildsym's counterpart to struct compunit_symtab.  */
 
 struct buildsym_compunit
@@ -188,7 +197,7 @@ struct buildsym_compunit
   const char *pop_subfile ();
 
   void record_line (struct subfile *subfile, int line, CORE_ADDR pc,
-		    bool is_stmt);
+		    linetable_entry_flags flags);
 
   struct compunit_symtab *get_compunit_symtab ()
   {
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 10550336063..e470fc6fd5d 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -20883,7 +20883,7 @@ class lnp_state_machine
   /* Handle DW_LNS_negate_stmt.  */
   void handle_negate_stmt ()
   {
-    m_is_stmt = !m_is_stmt;
+    m_flags ^= LEF_IS_STMT;
   }
 
   /* Handle DW_LNS_const_add_pc.  */
@@ -20942,7 +20942,7 @@ class lnp_state_machine
   /* These are initialized in the constructor.  */
 
   CORE_ADDR m_address;
-  bool m_is_stmt;
+  linetable_entry_flags m_flags;
   unsigned int m_discriminator;
 
   /* Additional bits of state we need to track.  */
@@ -20957,9 +20957,9 @@ class lnp_state_machine
   CORE_ADDR m_last_address;
 
   /* Set to true when a previous line at the same address (using
-     m_last_address) had m_is_stmt true.  This is reset to false when a
-     line entry at a new address (m_address different to m_last_address) is
-     processed.  */
+     m_last_address) had LEF_IS_STMT set in m_flags.  This is reset to false
+     when a line entry at a new address (m_address different to
+     m_last_address) is processed.  */
   bool m_stmt_at_address = false;
 
   /* When true, record the lines we decode.  */
@@ -21089,7 +21089,8 @@ dwarf_record_line_p (struct dwarf2_cu *cu,
 
 static void
 dwarf_record_line_1 (struct gdbarch *gdbarch, struct subfile *subfile,
-		     unsigned int line, CORE_ADDR address, bool is_stmt,
+		     unsigned int line, CORE_ADDR address,
+		     linetable_entry_flags flags,
 		     struct dwarf2_cu *cu)
 {
   CORE_ADDR addr = gdbarch_addr_bits_remove (gdbarch, address);
@@ -21103,7 +21104,7 @@ dwarf_record_line_1 (struct gdbarch *gdbarch, struct subfile *subfile,
     }
 
   if (cu != nullptr)
-    cu->get_builder ()->record_line (subfile, line, addr, is_stmt);
+    cu->get_builder ()->record_line (subfile, line, addr, flags);
 }
 
 /* Subroutine of dwarf_decode_lines_1 to simplify it.
@@ -21126,7 +21127,7 @@ dwarf_finish_line (struct gdbarch *gdbarch, struct subfile *subfile,
 			  paddress (gdbarch, address));
     }
 
-  dwarf_record_line_1 (gdbarch, subfile, 0, address, true, cu);
+  dwarf_record_line_1 (gdbarch, subfile, 0, address, LEF_IS_STMT, cu);
 }
 
 void
@@ -21139,7 +21140,8 @@ lnp_state_machine::record_line (bool end_sequence)
 			  " address %s, is_stmt %u, discrim %u%s\n",
 			  m_line, m_file,
 			  paddress (m_gdbarch, m_address),
-			  m_is_stmt, m_discriminator,
+			  (m_flags & LEF_IS_STMT) != 0,
+			  m_discriminator,
 			  (end_sequence ? "\t(end sequence)" : ""));
     }
 
@@ -21174,7 +21176,8 @@ lnp_state_machine::record_line (bool end_sequence)
 	    = m_last_subfile != m_cu->get_builder ()->get_current_subfile ();
 	  bool ignore_this_line
 	   = ((file_changed && !end_sequence && m_last_address == m_address
-	       && !m_is_stmt && m_stmt_at_address)
+	       && ((m_flags & LEF_IS_STMT) == 0)
+	       && m_stmt_at_address)
 	      || (!end_sequence && m_line == 0));
 
 	  if ((file_changed && !ignore_this_line) || end_sequence)
@@ -21185,7 +21188,9 @@ lnp_state_machine::record_line (bool end_sequence)
 
 	  if (!end_sequence && !ignore_this_line)
 	    {
-	      bool is_stmt = producer_is_codewarrior (m_cu) || m_is_stmt;
+	      linetable_entry_flags lte_flags = m_flags;
+	      if (producer_is_codewarrior (m_cu))
+		lte_flags |= LEF_IS_STMT;
 
 	      if (dwarf_record_line_p (m_cu, m_line, m_last_line,
 				       m_line_has_non_zero_discriminator,
@@ -21194,7 +21199,7 @@ lnp_state_machine::record_line (bool end_sequence)
 		  buildsym_compunit *builder = m_cu->get_builder ();
 		  dwarf_record_line_1 (m_gdbarch,
 				       builder->get_current_subfile (),
-				       m_line, m_address, is_stmt,
+				       m_line, m_address, m_flags,
 				       m_currently_recording_lines ? m_cu : nullptr);
 		}
 	      m_last_subfile = m_cu->get_builder ()->get_current_subfile ();
@@ -21203,14 +21208,14 @@ lnp_state_machine::record_line (bool end_sequence)
 	}
     }
 
-  /* Track whether we have seen any m_is_stmt true at m_address in case we
+  /* Track whether we have seen any IS_STMT true at m_address in case we
      have multiple line table entries all at m_address.  */
   if (m_last_address != m_address)
     {
       m_stmt_at_address = false;
       m_last_address = m_address;
     }
-  m_stmt_at_address |= m_is_stmt;
+  m_stmt_at_address |= (m_flags & LEF_IS_STMT) != 0;
 }
 
 lnp_state_machine::lnp_state_machine (struct dwarf2_cu *cu, gdbarch *arch,
@@ -21228,7 +21233,9 @@ lnp_state_machine::lnp_state_machine (struct dwarf2_cu *cu, gdbarch *arch,
      and also record it in case it needs it.  This is currently used by MIPS
      code, cf. `mips_adjust_dwarf2_line'.  */
   m_address = gdbarch_adjust_dwarf2_line (arch, 0, 0);
-  m_is_stmt = lh->default_is_stmt;
+  m_flags = 0;
+  if (lh->default_is_stmt)
+    m_flags |= LEF_IS_STMT;
   m_discriminator = 0;
 
   m_last_address = m_address;
-- 
2.25.1


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 2/2] gdb: Add support for DW_LNS_set_prologue_end in line-table
  2022-03-18 14:27 [PATCH 0/2] Add support for DWARF's prologue_end flag in line-table Lancelot SIX
  2022-03-18 14:27 ` [PATCH 1/2] gdb/buildsym: Line record use a record flag Lancelot SIX
@ 2022-03-18 14:27 ` Lancelot SIX
  2022-03-18 15:11   ` Eli Zaretskii
  1 sibling, 1 reply; 5+ messages in thread
From: Lancelot SIX @ 2022-03-18 14:27 UTC (permalink / raw)
  To: gdb-patches; +Cc: lsix, Lancelot SIX

Add support for DW_LNS_set_prologue_end when building line-tables.  This
attribute can be set by the compiler to indicate that an instruction is
an adequate place to set a breakpoint just after the prologue of a
function.

The compiler might set multiple prologue_end, but considering how
current skip_prologue_using_sal works, this commit modifies it to accept
the first instruction with this marker (if any) to be the place where to
a breakpoint should be placed to be at the end of the prologue.

The need for this support came from a problematic usecase generated by
hipcc (i.e. clang).  The problem is as follows:  There's a function
(lets call it foo) which covers PC from 0xa800 to 0xa950.  The body of
foo begins with a call to an inlined function, covering from 0xa800 to
0xa94c.   The issue is that when placing a breakpoint at 'foo', GDB
inserts the breakpoint at 0xa818.  The 0x18 offset is what GDB thinks is
foo's first address past the prologue.

Later, when hitting the breakpoint, GDB reports the stop within the
inlined function because the PC falls in its range while the user
expects to stop in FOO.

Looking at the line-table for this location, we have:

    INDEX  LINE   ADDRESS            IS-STMT
    [...]
    14     293    0x000000000000a66c Y
    15     END    0x000000000000a6e0 Y
    16     287    0x000000000000a800 Y
    17     END    0x000000000000a818 Y
    18     287    0x000000000000a824 Y
    [...]

For comparison, let's look at llvm-dwarfdump's output for this CU:

    Address            Line   Column File   ISA Discriminator Flags
    ------------------ ------ ------ ------ --- ------------- -------------
    [...]
    0x000000000000a66c    293     12      2   0             0  is_stmt
    0x000000000000a6e0     96     43     82   0             0  is_stmt
    0x000000000000a6f8    102     18     82   0             0  is_stmt
    0x000000000000a70c    102     24     82   0             0
    0x000000000000a710    102     18     82   0             0
    0x000000000000a72c    101     16     82   0             0  is_stmt
    0x000000000000a73c   2915     50     83   0             0  is_stmt
    0x000000000000a74c    110      1      1   0             0  is_stmt
    0x000000000000a750    110      1      1   0             0  is_stmt end_sequence
    0x000000000000a800    107      0      1   0             0  is_stmt
    0x000000000000a800    287     12      2   0             0  is_stmt prologue_end
    0x000000000000a818    114     59     81   0             0  is_stmt
    0x000000000000a824    287     12      2   0             0  is_stmt
    0x000000000000a828    100     58     82   0             0  is_stmt
    [...]

The main difference we are interested in here is that llvm-dwarfdump's
output tells us that 0xa800 is an adequate place to place a breakpoint
past a function prologue.  Since we know that foo starts at covers from
0xa800 to 0xa94c, 0xa800 is the address at which the breakpoint should
be placed if the user wants to break in foo.

This commit proposes to add support for the prologue_end tag in the
line-program processing.

The processing of this prologue_end flag is made in skip_prologue_sal,
before it calls gdbarch_skip_prologue_noexcept.  The intent is that if
the compiler gave information on where the prologue ends, we should use
this information before and not try to rely on architecture dependent
logic to guess it.

The testsuite have been executed using this patch on GNU/Linux x86_64.
Testcases have been combiled with both gcc/g++ and clang/clang++ since
GCC does not set the prologue_end marker.  No regression have been
observed with GCC or Clang.  Note that when using Clang, this patch
fixes a failure in gdb.opt/inline-small-func.exp.

Change-Id: I720449a8a9b2e1fb45b54c6095d3b1e9da9152f8
---
 gdb/NEWS                                      |  4 +
 gdb/buildsym.c                                |  1 +
 gdb/buildsym.h                                |  1 +
 gdb/doc/gdb.texinfo                           | 27 ++++++
 gdb/dwarf2/read.c                             | 15 ++-
 gdb/symmisc.c                                 |  6 +-
 gdb/symtab.c                                  | 51 +++++++++++
 gdb/symtab.h                                  |  4 +
 .../dw2-out-of-range-end-of-seq.exp           |  4 +-
 gdb/testsuite/gdb.dwarf2/dw2-prologue-end.c   | 28 ++++++
 gdb/testsuite/gdb.dwarf2/dw2-prologue-end.exp | 91 +++++++++++++++++++
 gdb/testsuite/gdb.dwarf2/dw2-ranges-base.exp  |  2 +-
 gdb/testsuite/lib/dwarf.exp                   | 16 ++--
 13 files changed, 238 insertions(+), 12 deletions(-)
 create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-prologue-end.c
 create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-prologue-end.exp

diff --git a/gdb/NEWS b/gdb/NEWS
index c609da7e6cf..89811219f59 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,10 @@
 
 *** Changes since GDB 11
 
+* GDB now honours the DWARF prologue_end line-table entry flag the compiler can
+  emit to indicate where a breakpoint should be placed to break in a function
+  past its prologue.
+
 * DBX mode is deprecated, and will be removed in GDB 13
 
 * GDB 12 is the last release of GDB that will support building against
diff --git a/gdb/buildsym.c b/gdb/buildsym.c
index a875eb5ce38..0b8bbe21a01 100644
--- a/gdb/buildsym.c
+++ b/gdb/buildsym.c
@@ -725,6 +725,7 @@ buildsym_compunit::record_line (struct subfile *subfile, int line,
   e->line = line;
   e->is_stmt = (flags & LEF_IS_STMT) != 0;
   e->pc = pc;
+  e->prologue_end = (flags & LEF_PROLOGUE_END) != 0;
 }
 
 \f
diff --git a/gdb/buildsym.h b/gdb/buildsym.h
index 09c2d563ec9..252bad187dc 100644
--- a/gdb/buildsym.h
+++ b/gdb/buildsym.h
@@ -115,6 +115,7 @@ struct context_stack
 enum linetable_entry_flag : unsigned
 {
   LEF_IS_STMT = 1 << 1,
+  LEF_PROLOGUE_END = 1 << 2,
 };
 DEF_ENUM_FLAGS_TYPE (enum linetable_entry_flag, linetable_entry_flags);
 
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 729f9d79a93..568ac86f6fd 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -19794,6 +19794,33 @@ line 1574.
 List the @code{struct linetable} from all @code{struct symtab}
 instances whose name matches @var{regexp}.  If @var{regexp} is not
 given, list the @code{struct linetable} from all @code{struct symtab}.
+For example:
+
+@smallexample
+(@value{GDBP}) maint info line-table
+objfile: /home/gnu/build/a.out ((struct objfile *) 0x6120000e0d40)
+compunit_symtab: simple.cpp ((struct compunit_symtab *) 0x6210000ff450)
+symtab: /home/gnu/src/simple.cpp ((struct symtab *) 0x6210000ff4d0)
+linetable: ((struct linetable *) 0x62100012b760):
+INDEX  LINE   ADDRESS            IS-STMT PROLOGUE-END
+0      3      0x0000000000401110 Y
+1      4      0x0000000000401114 Y       Y
+2      9      0x0000000000401120 Y
+3      10     0x0000000000401124 Y       Y
+4      10     0x0000000000401129
+5      15     0x0000000000401130 Y
+6      16     0x0000000000401134 Y       Y
+7      16     0x0000000000401139
+8      21     0x0000000000401140 Y
+9      22     0x000000000040114f Y       Y
+10     22     0x0000000000401154
+11     END    0x000000000040115a Y
+@end smallexample
+@noindent
+The @var{IS-STMT} column indicates if the address is a recommended breakpoint
+location to represent a line or a statement.  The @var{PROLOGUE-END} column
+indicates that a given address is an adequate to place a breakpoint at the
+first instruction following a function prologue.
 
 @kindex maint set symbol-cache-size
 @cindex symbol cache size
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index e470fc6fd5d..3905555e6d4 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -20901,6 +20901,7 @@ class lnp_state_machine
   {
     record_line (false);
     m_discriminator = 0;
+    m_flags &= ~LEF_PROLOGUE_END;
   }
 
   /* Handle DW_LNE_end_sequence.  */
@@ -20909,6 +20910,12 @@ class lnp_state_machine
     m_currently_recording_lines = true;
   }
 
+  /* Handle DW_LNS_set_prologue_end.  */
+  void handle_set_prologue_end ()
+  {
+    m_flags |= LEF_PROLOGUE_END;
+  }
+
 private:
   /* Advance the line by LINE_DELTA.  */
   void advance_line (int line_delta)
@@ -21000,6 +21007,7 @@ lnp_state_machine::handle_special_opcode (unsigned char op_code)
   advance_line (line_delta);
   record_line (false);
   m_discriminator = 0;
+  m_flags &= ~LEF_PROLOGUE_END;
 }
 
 void
@@ -21137,10 +21145,12 @@ lnp_state_machine::record_line (bool end_sequence)
     {
       fprintf_unfiltered (gdb_stdlog,
 			  "Processing actual line %u: file %u,"
-			  " address %s, is_stmt %u, discrim %u%s\n",
+			  " address %s, is_stmt %u, prologue_end %u,"
+			  " discrim %u%s\n",
 			  m_line, m_file,
 			  paddress (m_gdbarch, m_address),
 			  (m_flags & LEF_IS_STMT) != 0,
+			  (m_flags & LEF_PROLOGUE_END) != 0,
 			  m_discriminator,
 			  (end_sequence ? "\t(end sequence)" : ""));
     }
@@ -21463,6 +21473,9 @@ dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu,
 		state_machine.handle_fixed_advance_pc (addr_adj);
 	      }
 	      break;
+	    case DW_LNS_set_prologue_end:
+	      state_machine.handle_set_prologue_end ();
+	      break;
 	    default:
 	      {
 		/* Unknown standard opcode, ignore it.  */
diff --git a/gdb/symmisc.c b/gdb/symmisc.c
index 114d6bc5e53..bef477e5854 100644
--- a/gdb/symmisc.c
+++ b/gdb/symmisc.c
@@ -982,11 +982,12 @@ maintenance_print_one_line_table (struct symtab *symtab, void *data)
       /* Leave space for 6 digits of index and line number.  After that the
 	 tables will just not format as well.  */
       struct ui_out *uiout = current_uiout;
-      ui_out_emit_table table_emitter (uiout, 4, -1, "line-table");
+      ui_out_emit_table table_emitter (uiout, 5, -1, "line-table");
       uiout->table_header (6, ui_left, "index", _("INDEX"));
       uiout->table_header (6, ui_left, "line", _("LINE"));
       uiout->table_header (18, ui_left, "address", _("ADDRESS"));
-      uiout->table_header (1, ui_left, "is-stmt", _("IS-STMT"));
+      uiout->table_header (7, ui_left, "is-stmt", _("IS-STMT"));
+      uiout->table_header (12, ui_left, "prologue-end", _("PROLOGUE-END"));
       uiout->table_body ();
 
       for (int i = 0; i < linetable->nitems; ++i)
@@ -1003,6 +1004,7 @@ maintenance_print_one_line_table (struct symtab *symtab, void *data)
 	  uiout->field_core_addr ("address", objfile->arch (),
 				  item->pc);
 	  uiout->field_string ("is-stmt", item->is_stmt ? "Y" : "");
+	  uiout->field_string ("prologue-end", item->prologue_end ? "Y" : "");
 	  uiout->text ("\n");
 	}
     }
diff --git a/gdb/symtab.c b/gdb/symtab.c
index a867e1db9fd..2f0884b7b31 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -3818,6 +3818,42 @@ skip_prologue_using_lineinfo (CORE_ADDR func_addr, struct symtab *symtab)
   return func_addr;
 }
 
+/* Try to locate the address where a breakpoint should be placed past the
+   prologue of function starting at FUNC_ADDR using the line table.
+
+   Return the address associated with the first entry in the line-table for
+   the function starting at FUNC_ADDR which has prologue_end set to true if
+   such entry exist, otherwise return an empty optional.  */
+
+static gdb::optional<CORE_ADDR>
+skip_prologue_using_linetable (CORE_ADDR func_addr)
+{
+  CORE_ADDR start_pc, end_pc;
+
+  if (!find_pc_partial_function (func_addr, nullptr, &start_pc, &end_pc))
+    return {};
+
+  const struct symtab_and_line prologue_sal = find_pc_line (start_pc, 0);
+  if (prologue_sal.symtab != nullptr
+      && prologue_sal.symtab->language () != language_asm)
+    {
+      struct linetable *linetable = prologue_sal.symtab->linetable ();
+
+      auto it = std::lower_bound
+	(linetable->item, linetable->item + linetable->nitems, start_pc,
+	 [] (const linetable_entry &lte, CORE_ADDR pc) -> bool
+	 { return lte.pc < pc; });
+
+      for (;
+	   it < linetable->item + linetable->nitems && it->pc <= end_pc ;
+	   it++)
+	if (it->prologue_end)
+	  return {it->pc};
+    }
+
+  return {};
+}
+
 /* Adjust SAL to the first instruction past the function prologue.
    If the PC was explicitly specified, the SAL is not changed.
    If the line number was explicitly specified then the SAL can still be
@@ -3901,6 +3937,21 @@ skip_prologue_sal (struct symtab_and_line *sal)
     {
       pc = saved_pc;
 
+      /* Check if the compiler explicitely indicated where a breakpoint should
+         be placed to skip the prologue.  */
+      if (skip)
+	{
+	  gdb::optional<CORE_ADDR> linetable_pc
+	    = skip_prologue_using_linetable (pc);
+	  if (linetable_pc)
+	    {
+	      pc = *linetable_pc;
+	      start_sal = find_pc_sect_line (pc, section, 0);
+	      force_skip = 1;
+	      continue;
+	    }
+	}
+
       /* If the function is in an unmapped overlay, use its unmapped LMA address,
 	 so that gdbarch_skip_prologue has something unique to work on.  */
       if (section_is_overlay (section) && !section_is_mapped (section))
diff --git a/gdb/symtab.h b/gdb/symtab.h
index d12eee6e9d8..25b4f7d2704 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -1398,6 +1398,10 @@ struct linetable_entry
   /* True if this PC is a good location to place a breakpoint for LINE.  */
   unsigned is_stmt : 1;
 
+  /* True if this location is a good location to place a breakpoint after a
+     function prologue.  */
+  bool prologue_end : 1;
+
   /* The address for this entry.  */
   CORE_ADDR pc;
 };
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-out-of-range-end-of-seq.exp b/gdb/testsuite/gdb.dwarf2/dw2-out-of-range-end-of-seq.exp
index f60f622067e..23df111e73a 100644
--- a/gdb/testsuite/gdb.dwarf2/dw2-out-of-range-end-of-seq.exp
+++ b/gdb/testsuite/gdb.dwarf2/dw2-out-of-range-end-of-seq.exp
@@ -86,10 +86,10 @@ if ![runto_main] {
 
 set test "END with address 1 eliminated"
 gdb_test_multiple "maint info line-table $srcfile$" $test {
-    -re -wrap "END *0x0*1 *Y \r\n.*" {
+    -re -wrap "END *0x0*1 *Y *\r\n.*" {
 	fail $gdb_test_name
     }
-    -re -wrap "END *$hex *Y " {
+    -re -wrap "END *$hex *Y *" {
 	pass $gdb_test_name
     }
 }
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-prologue-end.c b/gdb/testsuite/gdb.dwarf2/dw2-prologue-end.c
new file mode 100644
index 00000000000..d166540d9b3
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-prologue-end.c
@@ -0,0 +1,28 @@
+/* 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/>.  */
+
+
+int
+main (void)
+{							/* main prologue */
+  asm ("main_label: .global main_label");
+  int m = 42;						/* main assign m */
+  asm ("main_assign_n: .global main_assign_n");
+  int n = 54;						/* main assign n */
+  asm ("main_end_prologue: .global main_end_prologue");
+  int o = 96;						/* main assign o */
+  asm ("main_end: .global main_end");			/* main end */
+  return m + n - o;
+}
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-prologue-end.exp b/gdb/testsuite/gdb.dwarf2/dw2-prologue-end.exp
new file mode 100644
index 00000000000..0de13ae680d
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-prologue-end.exp
@@ -0,0 +1,91 @@
+# 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/>.
+
+# Check that GDB can honor the prologue_end flag the compiler can place
+# in the line-table data.
+
+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 .c .S
+
+set asm_file [standard_output_file $srcfile2]
+Dwarf::assemble $asm_file {
+    global srcdir subdir srcfile srcfile2
+    declare_labels lines_label
+
+    get_func_info main
+
+    cu {} {
+	compile_unit {
+	    {language @DW_LANG_C}
+	    {name dw2-prologue-end.c}
+	    {stmt_list ${lines_label} DW_FORM_sec_offset}
+	} {
+	    subprogram {
+		{external 1 flag}
+		{name main}
+		{low_pc $main_start addr}
+		{high_pc "$main_start + $main_len" addr}
+	    }
+	}
+    }
+
+    lines {version 5} lines_label {
+	include_dir "${srcdir}/${subdir}"
+	file_name "$srcfile" 1
+
+	program {
+	    {DW_LNE_set_address $main_start}
+	    {line [gdb_get_line_number "main prologue"]}
+	    {DW_LNS_copy}
+
+	    {DW_LNE_set_address main_label}
+	    {line [gdb_get_line_number "main assign m"]}
+	    {DW_LNS_copy}
+
+	    {DW_LNE_set_address main_assign_n}
+	    {line [gdb_get_line_number "main assign n"]}
+	    {DW_LNS_copy}
+
+	    {DW_LNE_set_address main_end_prologue}
+	    {line [gdb_get_line_number "main assign o"]}
+	    {DW_LNS_set_prologue_end}
+	    {DW_LNS_copy}
+
+	    {DW_LNE_set_address main_end}
+	    {line [gdb_get_line_number "main end"]}
+	    {DW_LNS_copy}
+
+	    {DW_LNE_end_sequence}
+	}
+    }
+}
+
+if { [prepare_for_testing "failed to prepare" ${testfile} \
+	  [list $srcfile $asm_file] {nodebug}] } {
+    return -1
+}
+
+if ![runto_main] {
+    return -1
+}
+
+set prologue_end_line [gdb_get_line_number "main assign o"]
+gdb_test "frame" ".*main \\\(\\\) at \[^\r\n\]*:$prologue_end_line\r\n.*"
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-ranges-base.exp b/gdb/testsuite/gdb.dwarf2/dw2-ranges-base.exp
index ae44dc49329..ec31f1f9d23 100644
--- a/gdb/testsuite/gdb.dwarf2/dw2-ranges-base.exp
+++ b/gdb/testsuite/gdb.dwarf2/dw2-ranges-base.exp
@@ -183,7 +183,7 @@ gdb_test_multiple "maint info line-table gdb.dwarf2/dw2-ranges-base.c" \
 	-re ".*linetable: \\(\\(struct linetable \\*\\) 0x0\\):\r\nNo line table.\r\n" {
 	    exp_continue
 	}
-	-re ".*linetable: \\(\\(struct linetable \\*\\) $hex\\):\r\nINDEX\[ \t\]+LINE\[ \t\]+ADDRESS\[ \t\]+IS-STMT *\r\n" {
+	-re ".*linetable: \\(\\(struct linetable \\*\\) $hex\\):\r\nINDEX\[ \t\]+LINE\[ \t\]+ADDRESS\[ \t\]+IS-STMT\[ \t\]PROLOGUE-END *\r\n" {
 	    exp_continue
 	}
     }
diff --git a/gdb/testsuite/lib/dwarf.exp b/gdb/testsuite/lib/dwarf.exp
index 6e8b1ccbe7f..ed7ad383180 100644
--- a/gdb/testsuite/lib/dwarf.exp
+++ b/gdb/testsuite/lib/dwarf.exp
@@ -2269,14 +2269,13 @@ namespace eval Dwarf {
 	_op .byte $_default_is_stmt "default_is_stmt"
 	_op .byte 1 "line_base"
 	_op .byte 1 "line_range"
-	_op .byte 10 "opcode_base"
+	_op .byte 11 "opcode_base"
 
 	# The standard_opcode_lengths table.  The number of arguments
-	# for each of the standard opcodes.  Generating 9 entries here
-	# matches the use of 10 in the opcode_base above.  These 9
-	# entries match the 9 standard opcodes for DWARF2, making use
-	# of only 9 should be fine, even if we are generating DWARF3
-	# or DWARF4.
+	# for each of the standard opcodes.  Generating 10 entries here
+	# matches the use of 11 in the opcode_base above.  These 10
+	# entries match the 9 standard opcodes for DWARF2 plus
+	# DW_LNS_prologue_end from DWARF3.
 	_op .byte 0 "standard opcode 1"
 	_op .byte 1 "standard opcode 2"
 	_op .byte 1 "standard opcode 3"
@@ -2286,6 +2285,7 @@ namespace eval Dwarf {
 	_op .byte 0 "standard opcode 7"
 	_op .byte 0 "standard opcode 8"
 	_op .byte 1 "standard opcode 9"
+	_op .byte 0 "standard opcode 10"
 
 	proc include_dir {dirname} {
 	    variable _line_include_dirs
@@ -2481,6 +2481,10 @@ namespace eval Dwarf {
 		_op .byte 6
 	    }
 
+	    proc DW_LNS_set_prologue_end {} {
+		_op .byte 0x0a
+	    }
+
 	    proc DW_LNS_advance_pc {offset} {
 		_op .byte 2
 		_op .uleb128 ${offset}
-- 
2.25.1


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 2/2] gdb: Add support for DW_LNS_set_prologue_end in line-table
  2022-03-18 14:27 ` [PATCH 2/2] gdb: Add support for DW_LNS_set_prologue_end in line-table Lancelot SIX
@ 2022-03-18 15:11   ` Eli Zaretskii
  2022-03-18 16:35     ` Lancelot SIX
  0 siblings, 1 reply; 5+ messages in thread
From: Eli Zaretskii @ 2022-03-18 15:11 UTC (permalink / raw)
  To: Lancelot SIX; +Cc: gdb-patches, lsix

> Date: Fri, 18 Mar 2022 14:27:33 +0000
> From: Lancelot SIX via Gdb-patches <gdb-patches@sourceware.org>
> Cc: lsix@lancelotsix.com, Lancelot SIX <lancelot.six@amd.com>
> 
> diff --git a/gdb/NEWS b/gdb/NEWS
> index c609da7e6cf..89811219f59 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -3,6 +3,10 @@
>  
>  *** Changes since GDB 11
>  
> +* GDB now honours the DWARF prologue_end line-table entry flag the compiler can
> +  emit to indicate where a breakpoint should be placed to break in a function
> +  past its prologue.

Should we tell what user-visible effects will this have?

> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index 729f9d79a93..568ac86f6fd 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -19794,6 +19794,33 @@ line 1574.
>  List the @code{struct linetable} from all @code{struct symtab}
>  instances whose name matches @var{regexp}.  If @var{regexp} is not
>  given, list the @code{struct linetable} from all @code{struct symtab}.
> +For example:
> +
> +@smallexample
> +(@value{GDBP}) maint info line-table
> +objfile: /home/gnu/build/a.out ((struct objfile *) 0x6120000e0d40)
> +compunit_symtab: simple.cpp ((struct compunit_symtab *) 0x6210000ff450)
> +symtab: /home/gnu/src/simple.cpp ((struct symtab *) 0x6210000ff4d0)
> +linetable: ((struct linetable *) 0x62100012b760):
> +INDEX  LINE   ADDRESS            IS-STMT PROLOGUE-END
> +0      3      0x0000000000401110 Y
> +1      4      0x0000000000401114 Y       Y
> +2      9      0x0000000000401120 Y
> +3      10     0x0000000000401124 Y       Y
> +4      10     0x0000000000401129
> +5      15     0x0000000000401130 Y
> +6      16     0x0000000000401134 Y       Y
> +7      16     0x0000000000401139
> +8      21     0x0000000000401140 Y
> +9      22     0x000000000040114f Y       Y
> +10     22     0x0000000000401154
> +11     END    0x000000000040115a Y
> +@end smallexample
> +@noindent
> +The @var{IS-STMT} column indicates if the address is a recommended breakpoint
> +location to represent a line or a statement.  The @var{PROLOGUE-END} column
> +indicates that a given address is an adequate to place a breakpoint at the
> +first instruction following a function prologue.

IS-STMT and PROLOGUE-END should be in @samp, not @var.  Those are
literal headings of the columns, so @var is inappropriate for them.

Thanks.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 2/2] gdb: Add support for DW_LNS_set_prologue_end in line-table
  2022-03-18 15:11   ` Eli Zaretskii
@ 2022-03-18 16:35     ` Lancelot SIX
  0 siblings, 0 replies; 5+ messages in thread
From: Lancelot SIX @ 2022-03-18 16:35 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches, lsix

Hi,

Thanks for the feedbacks.  I have done the changes locally (see below).

>>
>> +* GDB now honours the DWARF prologue_end line-table entry flag the compiler can
>> +  emit to indicate where a breakpoint should be placed to break in a function
>> +  past its prologue.
> 
> Should we tell what user-visible effects will this have?

Yes, probably.  Sorry, I am usually unsure to what extent maint commands 
are documented / mentioned in NEWS entries.

I have added the following locally on top of the original patch:

diff --git a/gdb/NEWS b/gdb/NEWS 

index 89811219f59..ca3c2d13629 100644 

--- a/gdb/NEWS 

+++ b/gdb/NEWS 

@@ -127,6 +127,11 @@ show ada source-charset 

    values for this follow the values that can be passed to the GNAT 

    compiler via the '-gnati' option.  The default is ISO-8859-1. 

 

+maintenance info line-table 

+  Add a PROLOGUE-END column to the output which indicates that an 

+  entry corresponds to an address where a breakpoint should be placed 

+  to be at the first instruction past a function's prologue. 

+ 

  * Changed commands 

 

  print 



> 
> IS-STMT and PROLOGUE-END should be in @samp, not @var.  Those are
> literal headings of the columns, so @var is inappropriate for them.
> 
> Thanks

I did the changes locally.

I'll include those change in a V2, but will wait for other reviews on 
the patches before sending it.

Thanks,
Lancelot.

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2022-03-18 16:35 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-18 14:27 [PATCH 0/2] Add support for DWARF's prologue_end flag in line-table Lancelot SIX
2022-03-18 14:27 ` [PATCH 1/2] gdb/buildsym: Line record use a record flag Lancelot SIX
2022-03-18 14:27 ` [PATCH 2/2] gdb: Add support for DW_LNS_set_prologue_end in line-table Lancelot SIX
2022-03-18 15:11   ` Eli Zaretskii
2022-03-18 16:35     ` Lancelot SIX

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).