Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* RFC: The Constructor Breakpoint Issue
@ 2004-10-14  0:30 David Lecomber
  2004-10-15 13:34 ` David Lecomber
  0 siblings, 1 reply; 7+ messages in thread
From: David Lecomber @ 2004-10-14  0:30 UTC (permalink / raw)
  To: patches

[-- Attachment #1: Type: text/plain, Size: 1409 bytes --]

Specifically, this one:
gdb/1091: Constructor breakpoints ignored
gdb/1193: g++ 3.3 creates multiple constructors: gdb 5.3 can't set
breakpoints

I see this happening in other situations.  For example, Intel's compiler
seems to produce two versions of each subroutine -- perhaps each is
optimized for a different architecture.  This means that, say, 'break
test.f:65' will usually put the breakpoint in the wrong one (c.f.
Murphy's Law).

I have implemented a fix, which works, presently I'm not too proud of
it, so I'm going to check it through before proposing the patch
formally..

However, does anyone have any problem with the approach.  

In summary, I change the linetable_entry structure to have a pointer,
'next', which will be the next linetable_entry in the table which has
the same source code and line.  

find_line_pc then actually modifies the symtab_and_line parameter to get
the linetable_entry (rather than just pulling the PC from it).

In the breakpoints code, if a symtab_and_line has several entries in the
chain of entries, it sets a new breakpoint for each one.  

This does mean that break test.f:65 will announce each breakpoint
separately.  Also, the first bpoint set is known by the line/source, the
others can be distinguished by their address.

It cures the breakpoint in the constructor issue, which is probably the
quickest way for a GNU compiler based check of the fix.

d.



[-- Attachment #2: bp.patch --]
[-- Type: text/x-patch, Size: 12181 bytes --]

Index: gdb/symtab.c
===================================================================
RCS file: /cvs/src/src/gdb/symtab.c,v
retrieving revision 1.140
diff -c -p -r1.140 symtab.c
*** gdb/symtab.c	2 Oct 2004 09:55:15 -0000	1.140
--- gdb/symtab.c	14 Oct 2004 00:22:29 -0000
*************** init_sal (struct symtab_and_line *sal)
*** 700,705 ****
--- 700,706 ----
    sal->line = 0;
    sal->pc = 0;
    sal->end = 0;
+   sal->entry = 0;
  }
  \f
  
*************** done:
*** 2307,2326 ****
     The source file is specified with a struct symtab.  */
  
  int
! find_line_pc (struct symtab *symtab, int line, CORE_ADDR *pc)
  {
    struct linetable *l;
    int ind;
! 
!   *pc = 0;
    if (symtab == 0)
      return 0;
  
!   symtab = find_line_symtab (symtab, line, &ind, NULL);
    if (symtab != NULL)
      {
        l = LINETABLE (symtab);
!       *pc = l->item[ind].pc;
        return 1;
      }
    else
--- 2308,2329 ----
     The source file is specified with a struct symtab.  */
  
  int
! find_line_pc (struct symtab_and_line *sal)
  {
    struct linetable *l;
    int ind;
!   struct symtab *symtab;
!   symtab = sal->symtab;
!   sal->pc = 0;
    if (symtab == 0)
      return 0;
  
!   symtab = find_line_symtab (sal->symtab, sal->line, &ind, NULL);
    if (symtab != NULL)
      {
        l = LINETABLE (symtab);
!       sal->pc = l->item[ind].pc;
!       sal->entry = &(l->item[ind]);
        return 1;
      }
    else
*************** find_line_pc_range (struct symtab_and_li
*** 2341,2348 ****
    struct symtab_and_line found_sal;
  
    startaddr = sal.pc;
!   if (startaddr == 0 && !find_line_pc (sal.symtab, sal.line, &startaddr))
!     return 0;
  
    /* This whole function is based on address.  For example, if line 10 has
       two parts, one from 0x100 to 0x200 and one from 0x300 to 0x400, then
--- 2344,2352 ----
    struct symtab_and_line found_sal;
  
    startaddr = sal.pc;
!   if (startaddr == 0 && !find_line_pc (&sal))
!     return 0;  
!   startaddr = sal.pc;
  
    /* This whole function is based on address.  For example, if line 10 has
       two parts, one from 0x100 to 0x200 and one from 0x300 to 0x400, then
*************** find_line_common (struct linetable *l, i
*** 2391,2396 ****
--- 2395,2402 ----
    if (l == 0)
      return -1;
  
+   *exact_match = 0;
+ 
    len = l->nitems;
    for (i = 0; i < len; i++)
      {
*************** find_line_common (struct linetable *l, i
*** 2398,2418 ****
  
        if (item->line == lineno)
  	{
! 	  /* Return the first (lowest address) entry which matches.  */
! 	  *exact_match = 1;
! 	  return i;
  	}
  
!       if (item->line > lineno && (best == 0 || item->line < best))
  	{
! 	  best = item->line;
! 	  best_index = i;
  	}
      }
- 
-   /* If we got here, we didn't get an exact match.  */
- 
-   *exact_match = 0;
    return best_index;
  }
  
--- 2404,2451 ----
  
        if (item->line == lineno)
  	{
! 	  if (*exact_match) 
! 	    {
! 	      /* create a chain of matching lines: for inlined and
! 		 default arg constructors often line number has several
! 		 PCs.
! 	       */
! 	      l->item[i].next = l->item[best_index].next;
! 	      l->item[best_index].next = &(l->item[i]);
! 	    }
! 	  else 
! 	    {
! 	      /* Return the first (lowest address) entry which matches.  */
! 	      *exact_match = 1;
! 	      best_index = i;
! 	      best = lineno;
! 	      if (l->item[i].next) 
! 		{
! 		  /* have already found this line and other matches */
! 		  return i;
! 		}
! 	    }
  	}
  
!       if (!(*exact_match) 
! 	  && item->line > lineno && (best == 0 || item->line <= best))
  	{
! 	  if (best == item->line) 
! 	    {
! 	      if (!l->item[best_index].next) 
! 		{
! 		  /* two matching 'best' lines */
! 		  l->item[i].next = l->item[best_index].next;
! 		  l->item[best_index].next = &(l->item[i]);
! 		}
! 	    }
! 	  else 
! 	    {
! 	      best = item->line;
! 	      best_index = i;
! 	    }
  	}
      }
    return best_index;
  }
  
Index: gdb/symtab.h
===================================================================
RCS file: /cvs/src/src/gdb/symtab.h,v
retrieving revision 1.92
diff -c -p -r1.92 symtab.h
*** gdb/symtab.h	10 Jun 2004 20:05:44 -0000	1.92
--- gdb/symtab.h	14 Oct 2004 00:22:29 -0000
*************** struct linetable_entry
*** 708,713 ****
--- 708,714 ----
  {
    int line;
    CORE_ADDR pc;
+   struct linetable_entry *next;
  };
  
  /* The order of entries in the linetable is significant.  They should
*************** struct symtab_and_line
*** 1198,1203 ****
--- 1199,1206 ----
  
    CORE_ADDR pc;
    CORE_ADDR end;
+ 
+   struct linetable_entry *entry;
  };
  
  extern void init_sal (struct symtab_and_line *sal);
*************** extern struct symtab_and_line find_pc_se
*** 1256,1262 ****
  
  /* Given a symtab and line number, return the pc there.  */
  
! extern int find_line_pc (struct symtab *, int, CORE_ADDR *);
  
  extern int find_line_pc_range (struct symtab_and_line, CORE_ADDR *,
  			       CORE_ADDR *);
--- 1259,1265 ----
  
  /* Given a symtab and line number, return the pc there.  */
  
! extern int find_line_pc (struct symtab_and_line *);
  
  extern int find_line_pc_range (struct symtab_and_line, CORE_ADDR *,
  			       CORE_ADDR *);
Index: gdb/buildsym.c
===================================================================
RCS file: /cvs/src/src/gdb/buildsym.c,v
retrieving revision 1.40
diff -c -p -r1.40 buildsym.c
*** gdb/buildsym.c	11 Sep 2004 10:24:45 -0000	1.40
--- gdb/buildsym.c	14 Oct 2004 00:22:32 -0000
*************** record_line (struct subfile *subfile, in
*** 733,738 ****
--- 733,739 ----
    e = subfile->line_vector->item + subfile->line_vector->nitems++;
    e->line = line;
    e->pc = ADDR_BITS_REMOVE(pc);
+   e->next = 0;
  }
  
  /* Needed in order to sort line tables from IBM xcoff files.  Sigh!  */
Index: gdb/breakpoint.c
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.c,v
retrieving revision 1.183
diff -c -p -r1.183 breakpoint.c
*** gdb/breakpoint.c	8 Oct 2004 17:30:46 -0000	1.183
--- gdb/breakpoint.c	14 Oct 2004 00:22:34 -0000
*************** struct breakpoint *
*** 4061,4073 ****
  set_raw_breakpoint (struct symtab_and_line sal, enum bptype bptype)
  {
    struct breakpoint *b, *b1;
! 
    b = (struct breakpoint *) xmalloc (sizeof (struct breakpoint));
    memset (b, 0, sizeof (*b));
    b->loc = allocate_bp_location (b, bptype);
!   b->loc->requested_address = sal.pc;
    b->loc->address = adjust_breakpoint_address (b->loc->requested_address,
!                                                bptype);
    if (sal.symtab == NULL)
      b->source_file = NULL;
    else
--- 4061,4075 ----
  set_raw_breakpoint (struct symtab_and_line sal, enum bptype bptype)
  {
    struct breakpoint *b, *b1;
!   CORE_ADDR pc;
!   pc = sal.pc;
!     
    b = (struct breakpoint *) xmalloc (sizeof (struct breakpoint));
    memset (b, 0, sizeof (*b));
    b->loc = allocate_bp_location (b, bptype);
!   b->loc->requested_address = pc;
    b->loc->address = adjust_breakpoint_address (b->loc->requested_address,
! 					       bptype);
    if (sal.symtab == NULL)
      b->source_file = NULL;
    else
*************** set_raw_breakpoint (struct symtab_and_li
*** 4105,4111 ****
  	b1 = b1->next;
        b1->next = b;
      }
! 
    check_duplicates (b);
    breakpoints_changed ();
  
--- 4107,4113 ----
  	b1 = b1->next;
        b1->next = b;
      }
!   
    check_duplicates (b);
    breakpoints_changed ();
  
*************** create_breakpoints (struct symtabs_and_l
*** 4927,4978 ****
      int i;
      for (i = 0; i < sals.nelts; i++)
        {
  	struct breakpoint *b;
  	struct symtab_and_line sal = sals.sals[i];
! 
  	if (from_tty)
  	  describe_other_breakpoints (sal.pc, sal.section);
  	
- 	b = set_raw_breakpoint (sal, type);
- 	set_breakpoint_count (breakpoint_count + 1);
- 	b->number = breakpoint_count;
- 	b->cond = cond[i];
- 	b->thread = thread;
- 	if (addr_string[i])
- 	  b->addr_string = addr_string[i];
- 	else
- 	  /* addr_string has to be used or breakpoint_re_set will delete
- 	     me.  */
- 	  b->addr_string = xstrprintf ("*0x%s", paddr (b->loc->address));
- 	b->cond_string = cond_string[i];
- 	b->ignore_count = ignore_count;
- 	b->enable_state = bp_enabled;
- 	b->disposition = disposition;
- 	/* If resolving a pending breakpoint, a check must be made to see if
- 	   the user has specified a new condition or commands for the 
- 	   breakpoint.  A new condition will override any condition that was 
- 	   initially specified with the initial breakpoint command.  */
- 	if (pending_bp)
- 	  {
- 	    char *arg;
- 	    if (pending_bp->cond_string)
- 	      {
- 		arg = pending_bp->cond_string;
- 		b->cond_string = savestring (arg, strlen (arg));
- 		b->cond = parse_exp_1 (&arg, block_for_pc (b->loc->address), 0);
- 		if (*arg)
- 		  error ("Junk at end of pending breakpoint condition expression");
- 	      }
- 	    /* If there are commands associated with the breakpoint, they should 
- 	       be copied too.  */
- 	    if (pending_bp->commands)
- 	      b->commands = copy_command_lines (pending_bp->commands);
- 	    
- 	    /* We have to copy over the ignore_count and thread as well.  */
- 	    b->ignore_count = pending_bp->ignore_count;
- 	    b->thread = pending_bp->thread;
- 	  }
- 	mention (b);
        }
    }    
  }
--- 4929,4995 ----
      int i;
      for (i = 0; i < sals.nelts; i++)
        {
+ 	char *addr_str;
+ 	struct linetable_entry *le;
  	struct breakpoint *b;
  	struct symtab_and_line sal = sals.sals[i];
! 	le = sals.sals[i].entry;
  	if (from_tty)
  	  describe_other_breakpoints (sal.pc, sal.section);
+ 
+ 	addr_str = addr_string[i];
+ 	do  {
+ 	  if (le) 
+ 	    sal.pc = le->pc;
+ 	  
+ 	  b = set_raw_breakpoint (sal, type);
+ 
+ 	  set_breakpoint_count (breakpoint_count + 1);
+ 	  b->number = breakpoint_count;
+ 	  b->cond = cond[i];
+ 	  b->thread = thread;
+ 	  if (addr_str)
+ 	    {
+ 	      b->addr_string = addr_str;
+ 	      addr_str = NULL;
+ 	    }
+ 	  else
+ 	    /* addr_string has to be used or breakpoint_re_set will delete
+ 	       me.  */
+ 	    b->addr_string = xstrprintf ("*0x%s", paddr (b->loc->address));
+ 	  b->cond_string = cond_string[i];
+ 	  b->ignore_count = ignore_count;
+ 	  b->enable_state = bp_enabled;
+ 	  b->disposition = disposition;
+ 	  /* If resolving a pending breakpoint, a check must be made to see if
+ 	     the user has specified a new condition or commands for the 
+ 	     breakpoint.  A new condition will override any condition that was 
+ 	     initially specified with the initial breakpoint command.  */
+ 	  if (pending_bp)
+ 	    {
+ 	      char *arg;
+ 	      if (pending_bp->cond_string)
+ 		{
+ 		  arg = pending_bp->cond_string;
+ 		  b->cond_string = savestring (arg, strlen (arg));
+ 		  b->cond = parse_exp_1 (&arg, block_for_pc (b->loc->address), 0);
+ 		  if (*arg)
+ 		    error ("Junk at end of pending breakpoint condition expression");
+ 		}
+ 	      /* If there are commands associated with the breakpoint, they should 
+ 		 be copied too.  */
+ 	      if (pending_bp->commands)
+ 		b->commands = copy_command_lines (pending_bp->commands);
+ 	      
+ 	      /* We have to copy over the ignore_count and thread as well.  */
+ 	      b->ignore_count = pending_bp->ignore_count;
+ 	      b->thread = pending_bp->thread;
+ 	    }
+ 	  mention (b);
+ 	  if (le) le = le->next;
+ 	} while (le);
+ 	
  	
        }
    }    
  }
*************** break_at_finish_command_1 (char *arg, in
*** 5617,5630 ****
  void
  resolve_sal_pc (struct symtab_and_line *sal)
  {
-   CORE_ADDR pc;
- 
    if (sal->pc == 0 && sal->symtab != NULL)
      {
!       if (!find_line_pc (sal->symtab, sal->line, &pc))
  	error ("No line %d in file \"%s\".",
  	       sal->line, sal->symtab->filename);
!       sal->pc = pc;
      }
  
    if (sal->section == 0 && sal->symtab != NULL)
--- 5634,5645 ----
  void
  resolve_sal_pc (struct symtab_and_line *sal)
  {
    if (sal->pc == 0 && sal->symtab != NULL)
      {
!       if (!find_line_pc (sal))
  	error ("No line %d in file \"%s\".",
  	       sal->line, sal->symtab->filename);
! 
      }
  
    if (sal->section == 0 && sal->symtab != NULL)

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

* Re: RFC: The Constructor Breakpoint Issue
  2004-10-14  0:30 RFC: The Constructor Breakpoint Issue David Lecomber
@ 2004-10-15 13:34 ` David Lecomber
  2004-10-15 14:52   ` Daniel Jacobowitz
  0 siblings, 1 reply; 7+ messages in thread
From: David Lecomber @ 2004-10-15 13:34 UTC (permalink / raw)
  To: patches

[-- Attachment #1: Type: text/plain, Size: 2553 bytes --]

Morning all,

I have reformatted this so it actually compiles - I hope...

Unfortunately this patch busts a lot of test cases (about 30..).    I
have discovered that it is being over-zealous in applying breakpoints
and need an expert to suggest solutions.

The first broken example is gdb.base/display.c - there we have a for
loop.  So, first line of the for loop (display.c:14) is at PC xxxxxx,
and also at xxxxxx + some no. which presumably is where the increment
part of the for loop occurs.  Do we want to get both these addresses for
breakpoints, or not..  because it happens..

I see the intel compiler sets the default is_stmt field to zero, and
never does anything else with it, and the GNU compilers set it to 1. 
However, dwarf2read ignores this info anyway.

I cannot see anything in the dwarf2 line info that enables us to
distinguish between the two cases - those where the lines are not really
duplicate, and those that are.  I think everyone would find fixing this
issue important..  

Opinions??

d.



On Thu, 2004-10-14 at 01:37, David Lecomber wrote:
> Specifically, this one:
> gdb/1091: Constructor breakpoints ignored
> gdb/1193: g++ 3.3 creates multiple constructors: gdb 5.3 can't set
> breakpoints
> 
> I see this happening in other situations.  For example, Intel's compiler
> seems to produce two versions of each subroutine -- perhaps each is
> optimized for a different architecture.  This means that, say, 'break
> test.f:65' will usually put the breakpoint in the wrong one (c.f.
> Murphy's Law).
> 
> I have implemented a fix, which works, presently I'm not too proud of
> it, so I'm going to check it through before proposing the patch
> formally..
> 
> However, does anyone have any problem with the approach.  
> 
> In summary, I change the linetable_entry structure to have a pointer,
> 'next', which will be the next linetable_entry in the table which has
> the same source code and line.  
> 
> find_line_pc then actually modifies the symtab_and_line parameter to get
> the linetable_entry (rather than just pulling the PC from it).
> 
> In the breakpoints code, if a symtab_and_line has several entries in the
> chain of entries, it sets a new breakpoint for each one.  
> 
> This does mean that break test.f:65 will announce each breakpoint
> separately.  Also, the first bpoint set is known by the line/source, the
> others can be distinguished by their address.
> 
> It cures the breakpoint in the constructor issue, which is probably the
> quickest way for a GNU compiler based check of the fix.
> 
> d.
> 
> 

[-- Attachment #2: bpchanges.patch --]
[-- Type: text/x-patch, Size: 17403 bytes --]

Index: gdb/breakpoint.c
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.c,v
retrieving revision 1.183
diff -c -p -r1.183 breakpoint.c
*** gdb/breakpoint.c	8 Oct 2004 17:30:46 -0000	1.183
--- gdb/breakpoint.c	15 Oct 2004 13:24:26 -0000
*************** struct breakpoint *
*** 4061,4073 ****
  set_raw_breakpoint (struct symtab_and_line sal, enum bptype bptype)
  {
    struct breakpoint *b, *b1;
! 
    b = (struct breakpoint *) xmalloc (sizeof (struct breakpoint));
    memset (b, 0, sizeof (*b));
    b->loc = allocate_bp_location (b, bptype);
!   b->loc->requested_address = sal.pc;
    b->loc->address = adjust_breakpoint_address (b->loc->requested_address,
!                                                bptype);
    if (sal.symtab == NULL)
      b->source_file = NULL;
    else
--- 4061,4075 ----
  set_raw_breakpoint (struct symtab_and_line sal, enum bptype bptype)
  {
    struct breakpoint *b, *b1;
!   CORE_ADDR pc;
!   pc = sal.pc;
!     
    b = (struct breakpoint *) xmalloc (sizeof (struct breakpoint));
    memset (b, 0, sizeof (*b));
    b->loc = allocate_bp_location (b, bptype);
!   b->loc->requested_address = pc;
    b->loc->address = adjust_breakpoint_address (b->loc->requested_address,
! 					       bptype);
    if (sal.symtab == NULL)
      b->source_file = NULL;
    else
*************** set_raw_breakpoint (struct symtab_and_li
*** 4105,4111 ****
  	b1 = b1->next;
        b1->next = b;
      }
! 
    check_duplicates (b);
    breakpoints_changed ();
  
--- 4107,4113 ----
  	b1 = b1->next;
        b1->next = b;
      }
!   
    check_duplicates (b);
    breakpoints_changed ();
  
*************** create_breakpoints (struct symtabs_and_l
*** 4927,4978 ****
      int i;
      for (i = 0; i < sals.nelts; i++)
        {
  	struct breakpoint *b;
  	struct symtab_and_line sal = sals.sals[i];
! 
  	if (from_tty)
  	  describe_other_breakpoints (sal.pc, sal.section);
  	
- 	b = set_raw_breakpoint (sal, type);
- 	set_breakpoint_count (breakpoint_count + 1);
- 	b->number = breakpoint_count;
- 	b->cond = cond[i];
- 	b->thread = thread;
- 	if (addr_string[i])
- 	  b->addr_string = addr_string[i];
- 	else
- 	  /* addr_string has to be used or breakpoint_re_set will delete
- 	     me.  */
- 	  b->addr_string = xstrprintf ("*0x%s", paddr (b->loc->address));
- 	b->cond_string = cond_string[i];
- 	b->ignore_count = ignore_count;
- 	b->enable_state = bp_enabled;
- 	b->disposition = disposition;
- 	/* If resolving a pending breakpoint, a check must be made to see if
- 	   the user has specified a new condition or commands for the 
- 	   breakpoint.  A new condition will override any condition that was 
- 	   initially specified with the initial breakpoint command.  */
- 	if (pending_bp)
- 	  {
- 	    char *arg;
- 	    if (pending_bp->cond_string)
- 	      {
- 		arg = pending_bp->cond_string;
- 		b->cond_string = savestring (arg, strlen (arg));
- 		b->cond = parse_exp_1 (&arg, block_for_pc (b->loc->address), 0);
- 		if (*arg)
- 		  error ("Junk at end of pending breakpoint condition expression");
- 	      }
- 	    /* If there are commands associated with the breakpoint, they should 
- 	       be copied too.  */
- 	    if (pending_bp->commands)
- 	      b->commands = copy_command_lines (pending_bp->commands);
- 	    
- 	    /* We have to copy over the ignore_count and thread as well.  */
- 	    b->ignore_count = pending_bp->ignore_count;
- 	    b->thread = pending_bp->thread;
- 	  }
- 	mention (b);
        }
    }    
  }
--- 4929,4995 ----
      int i;
      for (i = 0; i < sals.nelts; i++)
        {
+ 	char *addr_str;
+ 	struct linetable_entry *le;
  	struct breakpoint *b;
  	struct symtab_and_line sal = sals.sals[i];
! 	le = sals.sals[i].entry;
  	if (from_tty)
  	  describe_other_breakpoints (sal.pc, sal.section);
+ 
+ 	addr_str = addr_string[i];
+ 	do  {
+ 	  if (le) 
+ 	    sal.pc = le->pc;
+ 	  
+ 	  b = set_raw_breakpoint (sal, type);
+ 
+ 	  set_breakpoint_count (breakpoint_count + 1);
+ 	  b->number = breakpoint_count;
+ 	  b->cond = cond[i];
+ 	  b->thread = thread;
+ 	  if (addr_str)
+ 	    {
+ 	      b->addr_string = addr_str;
+ 	      addr_str = NULL;
+ 	    }
+ 	  else
+ 	    /* addr_string has to be used or breakpoint_re_set will delete
+ 	       me.  */
+ 	    b->addr_string = xstrprintf ("*0x%s", paddr (b->loc->address));
+ 	  b->cond_string = cond_string[i];
+ 	  b->ignore_count = ignore_count;
+ 	  b->enable_state = bp_enabled;
+ 	  b->disposition = disposition;
+ 	  /* If resolving a pending breakpoint, a check must be made to see if
+ 	     the user has specified a new condition or commands for the 
+ 	     breakpoint.  A new condition will override any condition that was 
+ 	     initially specified with the initial breakpoint command.  */
+ 	  if (pending_bp)
+ 	    {
+ 	      char *arg;
+ 	      if (pending_bp->cond_string)
+ 		{
+ 		  arg = pending_bp->cond_string;
+ 		  b->cond_string = savestring (arg, strlen (arg));
+ 		  b->cond = parse_exp_1 (&arg, block_for_pc (b->loc->address), 0);
+ 		  if (*arg)
+ 		    error ("Junk at end of pending breakpoint condition expression");
+ 		}
+ 	      /* If there are commands associated with the breakpoint, they should 
+ 		 be copied too.  */
+ 	      if (pending_bp->commands)
+ 		b->commands = copy_command_lines (pending_bp->commands);
+ 	      
+ 	      /* We have to copy over the ignore_count and thread as well.  */
+ 	      b->ignore_count = pending_bp->ignore_count;
+ 	      b->thread = pending_bp->thread;
+ 	    }
+ 	  mention (b);
+ 	  if (le) le = le->next;
+ 	} while (le);
+ 	
  	
        }
    }    
  }
*************** break_at_finish_command_1 (char *arg, in
*** 5617,5630 ****
  void
  resolve_sal_pc (struct symtab_and_line *sal)
  {
-   CORE_ADDR pc;
- 
    if (sal->pc == 0 && sal->symtab != NULL)
      {
!       if (!find_line_pc (sal->symtab, sal->line, &pc))
  	error ("No line %d in file \"%s\".",
  	       sal->line, sal->symtab->filename);
!       sal->pc = pc;
      }
  
    if (sal->section == 0 && sal->symtab != NULL)
--- 5634,5645 ----
  void
  resolve_sal_pc (struct symtab_and_line *sal)
  {
    if (sal->pc == 0 && sal->symtab != NULL)
      {
!       if (!find_line_pc (sal))
  	error ("No line %d in file \"%s\".",
  	       sal->line, sal->symtab->filename);
! 
      }
  
    if (sal->section == 0 && sal->symtab != NULL)
Index: gdb/buildsym.c
===================================================================
RCS file: /cvs/src/src/gdb/buildsym.c,v
retrieving revision 1.40
diff -c -p -r1.40 buildsym.c
*** gdb/buildsym.c	11 Sep 2004 10:24:45 -0000	1.40
--- gdb/buildsym.c	15 Oct 2004 13:24:26 -0000
*************** record_line (struct subfile *subfile, in
*** 733,738 ****
--- 733,739 ----
    e = subfile->line_vector->item + subfile->line_vector->nitems++;
    e->line = line;
    e->pc = ADDR_BITS_REMOVE(pc);
+   e->next = 0;
  }
  
  /* Needed in order to sort line tables from IBM xcoff files.  Sigh!  */
Index: gdb/symtab.c
===================================================================
RCS file: /cvs/src/src/gdb/symtab.c,v
retrieving revision 1.140
diff -c -p -r1.140 symtab.c
*** gdb/symtab.c	2 Oct 2004 09:55:15 -0000	1.140
--- gdb/symtab.c	15 Oct 2004 13:24:28 -0000
*************** init_sal (struct symtab_and_line *sal)
*** 700,705 ****
--- 700,706 ----
    sal->line = 0;
    sal->pc = 0;
    sal->end = 0;
+   sal->entry = 0;
  }
  \f
  
*************** done:
*** 2307,2326 ****
     The source file is specified with a struct symtab.  */
  
  int
! find_line_pc (struct symtab *symtab, int line, CORE_ADDR *pc)
  {
    struct linetable *l;
    int ind;
! 
!   *pc = 0;
    if (symtab == 0)
      return 0;
  
!   symtab = find_line_symtab (symtab, line, &ind, NULL);
    if (symtab != NULL)
      {
        l = LINETABLE (symtab);
!       *pc = l->item[ind].pc;
        return 1;
      }
    else
--- 2308,2329 ----
     The source file is specified with a struct symtab.  */
  
  int
! find_line_pc (struct symtab_and_line *sal)
  {
    struct linetable *l;
    int ind;
!   struct symtab *symtab;
!   symtab = sal->symtab;
!   sal->pc = 0;
    if (symtab == 0)
      return 0;
  
!   symtab = find_line_symtab (sal->symtab, sal->line, &ind, NULL);
    if (symtab != NULL)
      {
        l = LINETABLE (symtab);
!       sal->pc = l->item[ind].pc;
!       sal->entry = &(l->item[ind]);
        return 1;
      }
    else
*************** find_line_pc_range (struct symtab_and_li
*** 2341,2348 ****
    struct symtab_and_line found_sal;
  
    startaddr = sal.pc;
!   if (startaddr == 0 && !find_line_pc (sal.symtab, sal.line, &startaddr))
!     return 0;
  
    /* This whole function is based on address.  For example, if line 10 has
       two parts, one from 0x100 to 0x200 and one from 0x300 to 0x400, then
--- 2344,2352 ----
    struct symtab_and_line found_sal;
  
    startaddr = sal.pc;
!   if (startaddr == 0 && !find_line_pc (&sal))
!     return 0;  
!   startaddr = sal.pc;
  
    /* This whole function is based on address.  For example, if line 10 has
       two parts, one from 0x100 to 0x200 and one from 0x300 to 0x400, then
*************** find_line_common (struct linetable *l, i
*** 2391,2396 ****
--- 2395,2402 ----
    if (l == 0)
      return -1;
  
+   *exact_match = 0;
+ 
    len = l->nitems;
    for (i = 0; i < len; i++)
      {
*************** find_line_common (struct linetable *l, i
*** 2398,2418 ****
  
        if (item->line == lineno)
  	{
! 	  /* Return the first (lowest address) entry which matches.  */
! 	  *exact_match = 1;
! 	  return i;
  	}
  
!       if (item->line > lineno && (best == 0 || item->line < best))
  	{
! 	  best = item->line;
! 	  best_index = i;
  	}
      }
- 
-   /* If we got here, we didn't get an exact match.  */
- 
-   *exact_match = 0;
    return best_index;
  }
  
--- 2404,2451 ----
  
        if (item->line == lineno)
  	{
! 	  if (*exact_match) 
! 	    {
! 	      /* create a chain of matching lines: for inlined and
! 		 default arg constructors often line number has several
! 		 PCs.
! 	       */
! 	      l->item[i].next = l->item[best_index].next;
! 	      l->item[best_index].next = &(l->item[i]);
! 	    }
! 	  else 
! 	    {
! 	      /* Return the first (lowest address) entry which matches.  */
! 	      *exact_match = 1;
! 	      best_index = i;
! 	      best = lineno;
! 	      if (l->item[i].next) 
! 		{
! 		  /* have already found this line and other matches */
! 		  return i;
! 		}
! 	    }
  	}
  
!       if (!(*exact_match) 
! 	  && item->line > lineno && (best == 0 || item->line <= best))
  	{
! 	  if (best == item->line) 
! 	    {
! 	      if (!l->item[best_index].next) 
! 		{
! 		  /* two matching 'best' lines */
! 		  l->item[i].next = l->item[best_index].next;
! 		  l->item[best_index].next = &(l->item[i]);
! 		}
! 	    }
! 	  else 
! 	    {
! 	      best = item->line;
! 	      best_index = i;
! 	    }
  	}
      }
    return best_index;
  }
  
Index: gdb/symtab.h
===================================================================
RCS file: /cvs/src/src/gdb/symtab.h,v
retrieving revision 1.92
diff -c -p -r1.92 symtab.h
*** gdb/symtab.h	10 Jun 2004 20:05:44 -0000	1.92
--- gdb/symtab.h	15 Oct 2004 13:24:28 -0000
*************** struct linetable_entry
*** 708,713 ****
--- 708,714 ----
  {
    int line;
    CORE_ADDR pc;
+   struct linetable_entry *next;
  };
  
  /* The order of entries in the linetable is significant.  They should
*************** struct symtab_and_line
*** 1198,1203 ****
--- 1199,1206 ----
  
    CORE_ADDR pc;
    CORE_ADDR end;
+ 
+   struct linetable_entry *entry;
  };
  
  extern void init_sal (struct symtab_and_line *sal);
*************** extern struct symtab_and_line find_pc_se
*** 1256,1262 ****
  
  /* Given a symtab and line number, return the pc there.  */
  
! extern int find_line_pc (struct symtab *, int, CORE_ADDR *);
  
  extern int find_line_pc_range (struct symtab_and_line, CORE_ADDR *,
  			       CORE_ADDR *);
--- 1259,1265 ----
  
  /* Given a symtab and line number, return the pc there.  */
  
! extern int find_line_pc (struct symtab_and_line *);
  
  extern int find_line_pc_range (struct symtab_and_line, CORE_ADDR *,
  			       CORE_ADDR *);
Index: gdb/mi/mi-cmd-disas.c
===================================================================
RCS file: /cvs/src/src/gdb/mi/mi-cmd-disas.c,v
retrieving revision 1.20
diff -c -p -r1.20 mi-cmd-disas.c
*** gdb/mi/mi-cmd-disas.c	30 Sep 2002 15:57:26 -0000	1.20
--- gdb/mi/mi-cmd-disas.c	15 Oct 2004 13:24:29 -0000
*************** mi_cmd_disassemble (char *command, char 
*** 145,155 ****
  
    if (line_seen && file_seen)
      {
        s = lookup_symtab (file_string);
        if (s == NULL)
  	error ("mi_cmd_disassemble: Invalid filename.");
!       if (!find_line_pc (s, line_num, &start))
  	error ("mi_cmd_disassemble: Invalid line number");
        if (find_pc_partial_function (start, NULL, &low, &high) == 0)
  	error ("mi_cmd_disassemble: No function contains specified address");
      }
--- 145,162 ----
  
    if (line_seen && file_seen)
      {
+       struct symtab_and_line sal;
+       init_sal(&sal);
        s = lookup_symtab (file_string);
        if (s == NULL)
  	error ("mi_cmd_disassemble: Invalid filename.");
! 
!       sal.symtab = s;
!       sal.line = line_num;
! 
!       if (!find_line_pc (&sal))
  	error ("mi_cmd_disassemble: Invalid line number");
+       start = sal.pc;
        if (find_pc_partial_function (start, NULL, &low, &high) == 0)
  	error ("mi_cmd_disassemble: No function contains specified address");
      }
Index: gdb/tui/tui-layout.c
===================================================================
RCS file: /cvs/src/src/gdb/tui/tui-layout.c,v
retrieving revision 1.18
diff -c -p -r1.18 tui-layout.c
*** gdb/tui/tui-layout.c	13 Mar 2004 14:14:01 -0000	1.18
--- gdb/tui/tui-layout.c	15 Oct 2004 13:24:30 -0000
*************** tui_set_layout_for_display_command (cons
*** 509,514 ****
--- 509,515 ----
  static CORE_ADDR
  extract_display_start_addr (void)
  {
+   struct symtab_and_line s;
    enum tui_layout_type cur_layout = tui_current_layout ();
    CORE_ADDR addr;
    CORE_ADDR pc;
*************** extract_display_start_addr (void)
*** 518,527 ****
      {
      case SRC_COMMAND:
      case SRC_DATA_COMMAND:
!       find_line_pc (cursal.symtab,
! 		    TUI_SRC_WIN->detail.source_info.start_line_or_addr.line_no,
! 		    &pc);
!       addr = pc;
        break;
      case DISASSEM_COMMAND:
      case SRC_DISASSEM_COMMAND:
--- 519,530 ----
      {
      case SRC_COMMAND:
      case SRC_DATA_COMMAND:
! 
!       init_sal(&s);
!       s.symtab = cursal.symtab;
!       s.line = TUI_SRC_WIN->detail.source_info.start_line_or_addr.line_no;
!       find_line_pc (&s);
!       addr = s.pc;
        break;
      case DISASSEM_COMMAND:
      case SRC_DISASSEM_COMMAND:
Index: gdb/tui/tui-win.c
===================================================================
RCS file: /cvs/src/src/gdb/tui/tui-win.c,v
retrieving revision 1.20
diff -c -p -r1.20 tui-win.c
*** gdb/tui/tui-win.c	26 Jul 2004 14:53:06 -0000	1.20
--- gdb/tui/tui-win.c	15 Oct 2004 13:24:30 -0000
*************** make_visible_with_new_height (struct tui
*** 1313,1319 ****
  	    line.line_no = cursal.line;
  	  else
  	    {
! 	      find_line_pc (s, cursal.line, &line.addr);
  	    }
  	  tui_update_source_window (win_info, s, line, TRUE);
  	}
--- 1313,1325 ----
  	    line.line_no = cursal.line;
  	  else
  	    {
! 
! 	      struct symtab_and_line sal;
! 	      init_sal(&sal);
! 	      sal.symtab = s;
! 	      sal.line = cursal.line;
! 	      find_line_pc (&sal);
! 	      line.addr = sal.pc;
  	    }
  	  tui_update_source_window (win_info, s, line, TRUE);
  	}
Index: gdb/tui/tui-winsource.c
===================================================================
RCS file: /cvs/src/src/gdb/tui/tui-winsource.c,v
retrieving revision 1.15
diff -c -p -r1.15 tui-winsource.c
*** gdb/tui/tui-winsource.c	16 Feb 2004 21:05:09 -0000	1.15
--- gdb/tui/tui-winsource.c	15 Oct 2004 13:24:30 -0000
*************** void
*** 172,184 ****
  tui_update_source_windows_with_line (struct symtab *s, int line)
  {
    CORE_ADDR pc;
    union tui_line_or_address l;
!   
    switch (tui_current_layout ())
      {
      case DISASSEM_COMMAND:
      case DISASSEM_DATA_COMMAND:
!       find_line_pc (s, line, &pc);
        tui_update_source_windows_with_addr (pc);
        break;
      default:
--- 172,191 ----
  tui_update_source_windows_with_line (struct symtab *s, int line)
  {
    CORE_ADDR pc;
+ 
+   struct symtab_and_line sal;
+ 
    union tui_line_or_address l;
! 
!   init_sal(&sal);
    switch (tui_current_layout ())
      {
      case DISASSEM_COMMAND:
      case DISASSEM_DATA_COMMAND:
!       sal.symtab = s;
!       sal.line = line;
!       find_line_pc (&sal);
!       pc = sal.pc;
        tui_update_source_windows_with_addr (pc);
        break;
      default:
*************** tui_update_source_windows_with_line (str
*** 186,192 ****
        tui_show_symtab_source (s, l, FALSE);
        if (tui_current_layout () == SRC_DISASSEM_COMMAND)
  	{
! 	  find_line_pc (s, line, &pc);
  	  tui_show_disassem (pc);
  	}
        break;
--- 193,202 ----
        tui_show_symtab_source (s, l, FALSE);
        if (tui_current_layout () == SRC_DISASSEM_COMMAND)
  	{
! 	  sal.symtab = s;
! 	  sal.line = line;
! 	  find_line_pc (&sal);
! 	  pc = sal.pc;
  	  tui_show_disassem (pc);
  	}
        break;

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

* Re: RFC: The Constructor Breakpoint Issue
  2004-10-15 13:34 ` David Lecomber
@ 2004-10-15 14:52   ` Daniel Jacobowitz
  2004-10-20 13:12     ` David Lecomber
  0 siblings, 1 reply; 7+ messages in thread
From: Daniel Jacobowitz @ 2004-10-15 14:52 UTC (permalink / raw)
  To: David Lecomber; +Cc: patches

On Fri, Oct 15, 2004 at 02:41:39PM +0100, David Lecomber wrote:
> Morning all,
> 
> I have reformatted this so it actually compiles - I hope...
> 
> Unfortunately this patch busts a lot of test cases (about 30..).    I
> have discovered that it is being over-zealous in applying breakpoints
> and need an expert to suggest solutions.
> 
> The first broken example is gdb.base/display.c - there we have a for
> loop.  So, first line of the for loop (display.c:14) is at PC xxxxxx,
> and also at xxxxxx + some no. which presumably is where the increment
> part of the for loop occurs.  Do we want to get both these addresses for
> breakpoints, or not..  because it happens..
> 
> I see the intel compiler sets the default is_stmt field to zero, and
> never does anything else with it, and the GNU compilers set it to 1. 
> However, dwarf2read ignores this info anyway.

Yes; I've been thinking on and off about fixing this for the GNU
compilers.

> I cannot see anything in the dwarf2 line info that enables us to
> distinguish between the two cases - those where the lines are not really
> duplicate, and those that are.  I think everyone would find fixing this
> issue important..  
> 
> Opinions??

You can't tell from the line table.  You can tell if you have both a
line table and a .debug_info section; in the case that is interesting
to you, the two PCs will be in different DW_TAG_subprogram trees.
Given the order in which we parse things I'm not sure if you'll be able
to check that easily.

I don't much like the idea of your hack.  However, since no one has
had the time for a thorough fix _still_, if you can get it to work, it
may be a good idea.

I haven't looked at your implementation yet, though.

-- 
Daniel Jacobowitz


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

* Re: RFC: The Constructor Breakpoint Issue
  2004-10-15 14:52   ` Daniel Jacobowitz
@ 2004-10-20 13:12     ` David Lecomber
  2004-10-20 16:02       ` Jim Blandy
  0 siblings, 1 reply; 7+ messages in thread
From: David Lecomber @ 2004-10-20 13:12 UTC (permalink / raw)
  To: Daniel Jacobowitz; +Cc: patches

Hi Dan
> You can't tell from the line table.  You can tell if you have both a
> line table and a .debug_info section; in the case that is interesting
> to you, the two PCs will be in different DW_TAG_subprogram trees.
> Given the order in which we parse things I'm not sure if you'll be able
> to check that easily.

How about this idea.. Getting into the dwarf2 area looks like quite a
major set of mods, which ultimately will be supported only by the
dwarves, which is not good.  However, inspection of the result of
find_pc_function() suggests it is different on the occasions when it
needs to be, such as in C++ constructors, and the same when we want it
to be - such as the start and end of for loops.

Cheers
d.


d.


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

* Re: RFC: The Constructor Breakpoint Issue
  2004-10-20 13:12     ` David Lecomber
@ 2004-10-20 16:02       ` Jim Blandy
  2004-10-20 16:04         ` Daniel Jacobowitz
  0 siblings, 1 reply; 7+ messages in thread
From: Jim Blandy @ 2004-10-20 16:02 UTC (permalink / raw)
  To: David Lecomber; +Cc: Daniel Jacobowitz, patches


David Lecomber <david@streamline-computing.com> writes:
> > You can't tell from the line table.  You can tell if you have both a
> > line table and a .debug_info section; in the case that is interesting
> > to you, the two PCs will be in different DW_TAG_subprogram trees.
> > Given the order in which we parse things I'm not sure if you'll be able
> > to check that easily.
> 
> How about this idea.. Getting into the dwarf2 area looks like quite a
> major set of mods, which ultimately will be supported only by the
> dwarves, which is not good.  However, inspection of the result of
> find_pc_function() suggests it is different on the occasions when it
> needs to be, such as in C++ constructors, and the same when we want it
> to be - such as the start and end of for loops.

What you're suggesting here, if I understand, is to take all the
occurrences of a given source line in the line table (and there may be
many, due not just to things like 'for' loops, but also due to
instruction scheduling and other sorts of optimizations), look to see
which function each falls in, and report the first occurrence from
each function.

Sounds good to me (although note that I don't approve symtab changes
any more, so this is just advice).  Some thoughts:

The line number lookup code actually looks for "best" matches, not
just exact matches; see symtab.c:find_line_common.  Preserving that
behavior will require a bit of care.

The downside that comes to mind is that this approach requires GDB to
always traverse the full linetable, instead of stopping as soon as it
finds an exact match, as it does now.

It'll be a substantial change to the line lookup machinery, since
those functions are not designed, at present, to return multiple
values.  But it's not that hairy in the aerial view.

There are some opportunities for optimization.  A symtab's linetable
and its blockvector's blocks are both sorted in order of increasing
addresses.  So one could traverse the blockvector and linetable in
parallel (skipping blocks that don't represent functions), and avoid
doing a full symbol lookup by pc for each plausible line.


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

* Re: RFC: The Constructor Breakpoint Issue
  2004-10-20 16:02       ` Jim Blandy
@ 2004-10-20 16:04         ` Daniel Jacobowitz
  2004-10-20 18:24           ` Jim Blandy
  0 siblings, 1 reply; 7+ messages in thread
From: Daniel Jacobowitz @ 2004-10-20 16:04 UTC (permalink / raw)
  To: Jim Blandy; +Cc: David Lecomber, patches

On Wed, Oct 20, 2004 at 11:00:25AM -0500, Jim Blandy wrote:
> The line number lookup code actually looks for "best" matches, not
> just exact matches; see symtab.c:find_line_common.  Preserving that
> behavior will require a bit of care.
> 
> The downside that comes to mind is that this approach requires GDB to
> always traverse the full linetable, instead of stopping as soon as it
> finds an exact match, as it does now.

I think the data structures involved will have to change to do this, or
it will just be too painful.

-- 
Daniel Jacobowitz


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

* Re: RFC: The Constructor Breakpoint Issue
  2004-10-20 16:04         ` Daniel Jacobowitz
@ 2004-10-20 18:24           ` Jim Blandy
  0 siblings, 0 replies; 7+ messages in thread
From: Jim Blandy @ 2004-10-20 18:24 UTC (permalink / raw)
  To: Daniel Jacobowitz; +Cc: David Lecomber, patches

Daniel Jacobowitz <drow@false.org> writes:

> On Wed, Oct 20, 2004 at 11:00:25AM -0500, Jim Blandy wrote:
> > The line number lookup code actually looks for "best" matches, not
> > just exact matches; see symtab.c:find_line_common.  Preserving that
> > behavior will require a bit of care.
> > 
> > The downside that comes to mind is that this approach requires GDB to
> > always traverse the full linetable, instead of stopping as soon as it
> > finds an exact match, as it does now.
> 
> I think the data structures involved will have to change to do this, or
> it will just be too painful.

Will it be such a big change?  It seems reasonable to assume that line
number queries are evenly distributed across the line tables.  So on
average, every query traverses half the line table now.  This change
would double the number of entries we examine for a single query.  So
you've doubled your search time, and doubled your working set for the
query.

Unlike queries by address, I can't think offhand of a situation where
queries by line occur that are not in response to user input.  This
doesn't seem like a show-stopper to me.


If the data structures do need to change, let me throw an idea out
there:

Our current structures are ordered by address, not by source location.
But adding a new structure indexed by source location could be a big
memory hit.

One way to reduce the size of that structure is to record the
information inexactly.  That is, instead of a table mapping line
numbers to lists of address ranges, we could have a table mapping
*ranges* of line numbers to lists of address ranges.  Or, ranges of
line numbers to lists of blocks, since blocks have start and end
addresses.  Then we could then use this information to narrow down the
range of PC values we need to search; since the line table is already
sorted by PC (I don't know why we don't use a binary search there),
that would cut down the amount of linear searching needed to something
acceptable.


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

end of thread, other threads:[~2004-10-20 18:24 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-10-14  0:30 RFC: The Constructor Breakpoint Issue David Lecomber
2004-10-15 13:34 ` David Lecomber
2004-10-15 14:52   ` Daniel Jacobowitz
2004-10-20 13:12     ` David Lecomber
2004-10-20 16:02       ` Jim Blandy
2004-10-20 16:04         ` Daniel Jacobowitz
2004-10-20 18:24           ` Jim Blandy

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox