]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
[wip] Fix range end handling of inlined subroutines users/aburgess/gdb-opt-code-debug
authorBernd Edlinger <bernd.edlinger@hotmail.de>
Mon, 2 Sep 2024 15:00:12 +0000 (17:00 +0200)
committerAndrew Burgess <aburgess@redhat.com>
Wed, 4 Dec 2024 14:03:44 +0000 (14:03 +0000)
Currently there is a problem when debugging
optimized code when the inferior stops at an inline
sub-range end PC.  It is unclear if that location
is from the inline function or from the calling
function.  Therefore the call stack is often
wrong.

This patch detects the "weak" line table entries
which are likely part of the previous inline block,
and if we have such a location, it assumes the
location belongs to the previous block.

Additionally it may happen that the infrun machinery
steps from one inline range to another inline range
of the same inline function.  That can look like
jumping back and forth from the calling program
to the inline function, while really the inline
function just jumps from a hot to a cold section
of the code, i.e. error handling.

Additionally it may happen that one inline sub-range
is empty or the inline is completely empty.  But
filtering that information away is not the right
solution, since although there is no actual code
from the inline, it is still possible that variables
from an inline function can be inspected here.

The issue with the empty ranges is also discussed here:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94474

Conceptually this patch uses a heuristic to work around
a deficiency in the dwarf-4 and dwarf-5 rnglists structure.
There should be a location view number for each inline
sub-range begin PC and end PC, similar to the DW_AT_GNU_entry_view
which is the location view for the inline entry point.

gdb/block.c
gdb/dwarf2/read.c
gdb/infcmd.c
gdb/infrun.c
gdb/symtab.c

index cf7ca6785b0c9ef4f3d809a245261d18ffaf06d8..288a3787cdb5f7d4db532e41322bba135a77ed6c 100644 (file)
@@ -196,7 +196,20 @@ blockvector_for_pc_sect (CORE_ADDR pc, struct obj_section *section,
     return NULL;
 
   if (pblock)
-    *pblock = b;
+    {
+      struct symtab_and_line sal = find_pc_sect_line (pc, section, 0);
+      if (sal.line != 0 && sal.pc == pc && sal.is_weak)
+       {
+         const struct block *b2 = find_block_in_blockvector (bl, pc - 1);
+         const struct block *b0 = b;
+         while (b0->superblock () && !b0->function ())
+           b0 = b0->superblock ();
+         if (b0->contains (b2))
+           b = b2;
+       }
+      *pblock = b;
+    }
+
   return bl;
 }
 
index 83ec2cbd6f767e58dca566bac83b71667719795f..6cd4ce8051875bebe353556a6b847e9e564c0a77 100644 (file)
@@ -18412,21 +18412,9 @@ private:
 
   /* Additional bits of state we need to track.  */
 
-  /* The last file that we called dwarf2_start_subfile for.
-     This is only used for TLLs.  */
-  unsigned int m_last_file = 0;
   /* The last file a line number was recorded for.  */
   struct subfile *m_last_subfile = NULL;
 
-  /* The address of the last line entry.  */
-  unrelocated_addr m_last_address;
-
-  /* Set to true when a previous line at the same address (using
-     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.  */
   bool m_currently_recording_lines = true;
 
@@ -18584,7 +18572,8 @@ dwarf_record_line_1 (struct gdbarch *gdbarch, struct subfile *subfile,
 
 static void
 dwarf_finish_line (struct gdbarch *gdbarch, struct subfile *subfile,
-                  unrelocated_addr address, struct dwarf2_cu *cu)
+                  unrelocated_addr address, struct dwarf2_cu *cu,
+                  bool end_sequence)
 {
   if (subfile == NULL)
     return;
@@ -18597,7 +18586,8 @@ dwarf_finish_line (struct gdbarch *gdbarch, struct subfile *subfile,
                  paddress (gdbarch, (CORE_ADDR) address));
     }
 
-  dwarf_record_line_1 (gdbarch, subfile, 0, address, LEF_IS_STMT, cu);
+  dwarf_record_line_1 (gdbarch, subfile, end_sequence ? 0 : -1, address,
+                      LEF_IS_STMT, cu);
 }
 
 void
@@ -18625,38 +18615,17 @@ lnp_state_machine::record_line (bool end_sequence)
   /* For now we ignore lines not starting on an instruction boundary.
      But not when processing end_sequence for compatibility with the
      previous version of the code.  */
-  else if (m_op_index == 0 || end_sequence)
-    {
-      /* When we switch files we insert an end maker in the first file,
-        switch to the second file and add a new line entry.  The
-        problem is that the end marker inserted in the first file will
-        discard any previous line entries at the same address.  If the
-        line entries in the first file are marked as is-stmt, while
-        the new line in the second file is non-stmt, then this means
-        the end marker will discard is-stmt lines so we can have a
-        non-stmt line.  This means that there are less addresses at
-        which the user can insert a breakpoint.
-
-        To improve this we track the last address in m_last_address,
-        and whether we have seen an is-stmt at this address.  Then
-        when switching files, if we have seen a stmt at the current
-        address, and we are switching to create a non-stmt line, then
-        discard the new line.  */
-      bool file_changed
-       = m_last_subfile != m_cu->get_builder ()->get_current_subfile ();
-      bool ignore_this_line
-       = ((file_changed && !end_sequence && m_last_address == m_address
-           && ((m_flags & LEF_IS_STMT) == 0)
-           && m_stmt_at_address)
-          || (!end_sequence && m_line == 0));
-
-      if ((file_changed && !ignore_this_line) || end_sequence)
+  else if ((m_op_index == 0 && m_line != 0) || end_sequence)
+    {
+      if (m_last_subfile != m_cu->get_builder ()->get_current_subfile ()
+         || 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 || (m_flags & LEF_IS_STMT) != 0);
        }
 
-      if (!end_sequence && !ignore_this_line)
+      if (!end_sequence)
        {
          linetable_entry_flags lte_flags = m_flags;
          if (producer_is_codewarrior (m_cu))
@@ -18676,15 +18645,6 @@ lnp_state_machine::record_line (bool end_sequence)
          m_last_line = m_line;
        }
     }
-
-  /* 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_flags & LEF_IS_STMT) != 0;
 }
 
 lnp_state_machine::lnp_state_machine (struct dwarf2_cu *cu, gdbarch *arch,
@@ -18698,8 +18658,7 @@ lnp_state_machine::lnp_state_machine (struct dwarf2_cu *cu, gdbarch *arch,
        This is currently used by MIPS code,
        cf. `mips_adjust_dwarf2_line'.  */
     m_address ((unrelocated_addr) gdbarch_adjust_dwarf2_line (arch, 0, 0)),
-    m_flags (lh->default_is_stmt ? LEF_IS_STMT : (linetable_entry_flags) 0),
-    m_last_address (m_address)
+    m_flags (lh->default_is_stmt ? LEF_IS_STMT : (linetable_entry_flags) 0)
 {
 }
 
index 5c0e3f51162803d2aa4e4ca0b41475d616deda29..0580fc67ba173a239bbb07cf98c5e265690eef3c 100644 (file)
@@ -996,7 +996,8 @@ prepare_one_step (thread_info *tp, struct step_command_fsm *sm)
              if (sym->aclass () == LOC_BLOCK)
                {
                  const block *block = sym->value_block ();
-                 if (block->end () < tp->control.step_range_end)
+                 if (block->end () < tp->control.step_range_end
+                     && block->end () > tp->control.step_range_start)
                    tp->control.step_range_end = block->end ();
                }
            }
index 43eca814e296e9cd300bdc73a3388af1f2dc0113..65ac9f3b8ab0df59c4f722ea8534dd77ace568e9 100644 (file)
@@ -8200,6 +8200,8 @@ process_event_stop_test (struct execution_control_state *ecs)
       infrun_debug_printf ("stepping through inlined function");
 
       if (ecs->event_thread->control.step_over_calls == STEP_OVER_ALL
+         || ecs->event_thread->stop_pc () != stop_pc_sal.pc
+         || !stop_pc_sal.is_stmt
          || inline_frame_is_marked_for_skip (false, ecs->event_thread))
        keep_going (ecs);
       else
@@ -8248,7 +8250,8 @@ process_event_stop_test (struct execution_control_state *ecs)
          end_stepping_range (ecs);
          return;
        }
-      else if (*curr_frame_id == original_frame_id)
+      else if (get_stack_frame_id (frame)
+              == ecs->event_thread->control.step_stack_frame_id)
        {
          /* We are not at the start of a statement, and we have not changed
             frame.
index f2e357d144973cbf611faf56c7e8db23a2ee1635..5abd4b83a35419e8a45253f1c67bd80dac66b483 100644 (file)
@@ -3294,7 +3294,10 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent)
         0) instead of a real line.  */
 
       if (prev && prev->line
-         && (!best || prev->unrelocated_pc () > best->unrelocated_pc ()))
+         && (!best || prev->unrelocated_pc () > best->unrelocated_pc ()
+                   || (prev->unrelocated_pc () == best->unrelocated_pc ()
+                       && (best->pc (objfile) == pc
+                           ? !best->is_stmt : best->is_weak))))
        {
          best = prev;
          best_symtab = iter_s;
@@ -3322,7 +3325,7 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent)
                     && (tmp - 1)->unrelocated_pc () == tmp->unrelocated_pc ()
                     && (tmp - 1)->line != 0 && !tmp->is_stmt)
                --tmp;
-             if (tmp->is_stmt)
+             if (tmp->is_stmt && (tmp->pc (objfile) == pc || !tmp->is_weak))
                best = tmp;
            }
 
@@ -3346,18 +3349,14 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent)
         We used to return alt->line - 1 here, but that could be
         anywhere; if we don't have line number info for this PC,
         don't make some up.  */
-      val.pc = pc;
-    }
-  else if (best->line == 0)
-    {
-      /* If our best fit is in a range of PC's for which no line
-        number info is available (line number is zero) then we didn't
-        find any valid line information.  */
+      if (notcurrent)
+       pc++;
       val.pc = pc;
     }
   else
     {
       val.is_stmt = best->is_stmt;
+      val.is_weak = best->is_weak;
       val.symtab = best_symtab;
       val.line = best->line;
       val.pc = best->pc (objfile);