gdb: Preserve is-stmt lines when switch between files
[deliverable/binutils-gdb.git] / gdb / dwarf2 / read.c
index 4724738363be70b296cad1ff850d6717b4ff957b..e6566f9649f8da631be48decdcabd344dc45ec39 100644 (file)
@@ -20040,6 +20040,15 @@ private:
   /* The last file a line number was recorded for.  */
   struct subfile *m_last_subfile = NULL;
 
+  /* The address of the last line entry.  */
+  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.  */
+  bool m_stmt_at_address = false;
+
   /* When true, record the lines we decode.  */
   bool m_currently_recording_lines = false;
 
@@ -20233,14 +20242,34 @@ lnp_state_machine::record_line (bool end_sequence)
       fe->included_p = 1;
       if (m_record_lines_p)
        {
-         if (m_last_subfile != m_cu->get_builder ()->get_current_subfile ()
-             || 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_is_stmt && m_stmt_at_address);
+
+         if ((file_changed && !ignore_this_line) || end_sequence)
            {
              dwarf_finish_line (m_gdbarch, m_last_subfile, m_address,
                                 m_currently_recording_lines ? m_cu : nullptr);
            }
 
-         if (!end_sequence)
+         if (!end_sequence && !ignore_this_line)
            {
              bool is_stmt = producer_is_codewarrior (m_cu) || m_is_stmt;
 
@@ -20259,6 +20288,15 @@ lnp_state_machine::record_line (bool end_sequence)
            }
        }
     }
+
+  /* Track whether we have seen any m_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;
 }
 
 lnp_state_machine::lnp_state_machine (struct dwarf2_cu *cu, gdbarch *arch,
@@ -20278,6 +20316,9 @@ lnp_state_machine::lnp_state_machine (struct dwarf2_cu *cu, gdbarch *arch,
   m_address = gdbarch_adjust_dwarf2_line (arch, 0, 0);
   m_is_stmt = lh->default_is_stmt;
   m_discriminator = 0;
+
+  m_last_address = m_address;
+  m_stmt_at_address = false;
 }
 
 void
This page took 0.029178 seconds and 4 git commands to generate.