diff mbox

Ensure incoming location is available in debug info for parameters (PR debug/49382)

Message ID 20110614155101.GD17079@tyan-ft48-01.lab.bos.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek June 14, 2011, 3:51 p.m. UTC
Hi!

As detailed in the PR, when gdb attempts to print originally passed
values to parameters instead of current values using call site info,
if the parameter is modified already before the first real instruction
in the function, it will find there already the modified value.
E.g. void foo (int x) { x++; }
or the larger testcase in the PR where first insn in the function
is call (x++); and x is unused afterwards.
In this case we say x lives in DW_OP_breg5 1 DW_OP_stack_value
from the beginning of the function till the end (in the first case)
or middle of the call (in the PR testcase).
Unfortunately that means GDB doesn't know where x has been originally
passed and thus can't look up in call site info what was passed to it.

This patch special cases the parameters, such that the very first
location in VAR_LOCATION note will be emitted even as empty range
and won't be optimized away even if before the first real insn
is some other VAR_LOCATION note for the parameter.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2011-06-14  Jakub Jelinek  <jakub@redhat.com>

	PR debug/49382
	* dwarf2out.c (dw_loc_list_node): Add force field.
	(add_var_loc_to_decl): For PARM_DECL, attempt to keep
	the incoming location in the list, even if it is modified
	before first real insn.
	(output_loc_list): Emit empty ranges with force flag set.
	(dw_loc_list): If first range of a PARM_DECL is empty,
	set force flag.


	Jakub

Comments

Jeff Law June 14, 2011, 4:27 p.m. UTC | #1
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 06/14/11 09:51, Jakub Jelinek wrote:
> Hi!
> 
> As detailed in the PR, when gdb attempts to print originally passed
> values to parameters instead of current values using call site info,
> if the parameter is modified already before the first real instruction
> in the function, it will find there already the modified value.
> E.g. void foo (int x) { x++; }
> or the larger testcase in the PR where first insn in the function
> is call (x++); and x is unused afterwards.
> In this case we say x lives in DW_OP_breg5 1 DW_OP_stack_value
> from the beginning of the function till the end (in the first case)
> or middle of the call (in the PR testcase).
> Unfortunately that means GDB doesn't know where x has been originally
> passed and thus can't look up in call site info what was passed to it.
> 
> This patch special cases the parameters, such that the very first
> location in VAR_LOCATION note will be emitted even as empty range
> and won't be optimized away even if before the first real insn
> is some other VAR_LOCATION note for the parameter.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
> 
> 2011-06-14  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR debug/49382
> 	* dwarf2out.c (dw_loc_list_node): Add force field.
> 	(add_var_loc_to_decl): For PARM_DECL, attempt to keep
> 	the incoming location in the list, even if it is modified
> 	before first real insn.
> 	(output_loc_list): Emit empty ranges with force flag set.
> 	(dw_loc_list): If first range of a PARM_DECL is empty,
> 	set force flag.
OK.
Jeff
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJN94wFAAoJEBRtltQi2kC7UcsIAJZNzCJqYUB0/axMZlooxpBq
OCZZTM1m/GRH0NZMTOx5gebvfXyJazcbM2z/tQAaYvKNfFiQNus9W3shzSDW3jzP
vIFKnc4mMZIJnulrtZ1zCrxN6ahyCj3LPgOOhoIr/FJqCjetLDIeLexlbQPST2fo
UOIscpkfL8e9QztBivkcMCMc7EDsmiwAyZeHzzUrO+WUK6vnWUpqXR0cCFwOewyv
76c+ce+7/LW6BG50PmmdvuvaDOoyz1jrj4PUNxlNTdnuYm0IwL7FA43iE0I2Vk/0
TUgBHJgYxMTijk+TeXWknRO1b0WgBMZQTIvWYknxOUyeO3P7XUIfxGmykGYr5vw=
=0NBt
-----END PGP SIGNATURE-----
diff mbox

Patch

--- gcc/dwarf2out.c.jj	2011-06-09 19:15:26.000000000 +0200
+++ gcc/dwarf2out.c	2011-06-14 12:04:39.000000000 +0200
@@ -4466,6 +4466,9 @@  typedef struct GTY(()) dw_loc_list_struc
   /* True if this list has been replaced by dw_loc_next.  */
   bool replaced;
   bool emitted;
+  /* True if the range should be emitted even if begin and end
+     are the same.  */
+  bool force;
 } dw_loc_list_node;
 
 static dw_loc_descr_ref int_loc_descriptor (HOST_WIDE_INT);
@@ -8619,7 +8622,30 @@  add_var_loc_to_decl (tree decl, rtx loc_
   else
     temp = (var_loc_list *) *slot;
 
-  if (temp->last)
+  /* For PARM_DECLs try to keep around the original incoming value,
+     even if that means we'll emit a zero-range .debug_loc entry.  */
+  if (temp->last
+      && temp->first == temp->last
+      && TREE_CODE (decl) == PARM_DECL
+      && GET_CODE (temp->first->loc) == NOTE
+      && NOTE_VAR_LOCATION_DECL (temp->first->loc) == decl
+      && DECL_INCOMING_RTL (decl)
+      && NOTE_VAR_LOCATION_LOC (temp->first->loc)
+      && GET_CODE (NOTE_VAR_LOCATION_LOC (temp->first->loc))
+	 == GET_CODE (DECL_INCOMING_RTL (decl))
+      && prev_real_insn (temp->first->loc) == NULL_RTX
+      && (bitsize != -1
+	  || !rtx_equal_p (NOTE_VAR_LOCATION_LOC (temp->first->loc),
+			   NOTE_VAR_LOCATION_LOC (loc_note))
+	  || (NOTE_VAR_LOCATION_STATUS (temp->first->loc)
+	      != NOTE_VAR_LOCATION_STATUS (loc_note))))
+    {
+      loc = ggc_alloc_cleared_var_loc_node ();
+      temp->first->next = loc;
+      temp->last = loc;
+      loc->loc = construct_piece_list (loc_note, bitpos, bitsize);
+    }
+  else if (temp->last)
     {
       struct var_loc_node *last = temp->last, *unused = NULL;
       rtx *piece_loc = NULL, last_loc_note;
@@ -8665,7 +8691,9 @@  add_var_loc_to_decl (tree decl, rtx loc_
 	    }
 	  else
 	    {
-	      gcc_assert (temp->first == temp->last);
+	      gcc_assert (temp->first == temp->last
+			  || (temp->first->next == temp->last
+			      && TREE_CODE (decl) == PARM_DECL));
 	      memset (temp->last, '\0', sizeof (*temp->last));
 	      temp->last->loc = construct_piece_list (loc_note, bitpos, bitsize);
 	      return temp->last;
@@ -11392,7 +11420,7 @@  output_loc_list (dw_loc_list_ref list_he
     {
       unsigned long size;
       /* Don't output an entry that starts and ends at the same address.  */
-      if (strcmp (curr->begin, curr->end) == 0)
+      if (strcmp (curr->begin, curr->end) == 0 && !curr->force)
 	continue;
       if (!have_multiple_function_sections)
 	{
@@ -16087,6 +16115,11 @@  dw_loc_list (var_loc_list *loc_list, tre
 	      }
 
 	    *listp = new_loc_list (descr, node->label, endname, secname);
+	    if (TREE_CODE (decl) == PARM_DECL
+		&& node == loc_list->first
+		&& GET_CODE (node->loc) == NOTE
+		&& strcmp (node->label, endname) == 0)
+	      (*listp)->force = true;
 	    listp = &(*listp)->dw_loc_next;
 
 	    if (range_across_switch)