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  <ja...@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.

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

        Jakub

Reply via email to