diff mbox

Don't ICE on >= 64KB expressions in dwarf2out (PR debug/51695)

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

Commit Message

Jakub Jelinek Jan. 4, 2012, 6:09 p.m. UTC
Hi!

.debug_loc section format only uses 2 byte long size field for expressions,
therefore we can't emit >= 64KB expressions.
Unfortunately from time to time we do generate them, I hope Alex will look
at how to prevent that from happening at var-tracking time, but still
this isn't something we should assert on.  The following patch drops them
on the floor, it is questionable how much useful would they be compared to
their huge size, another alternative would be to create
DW_TAG_dwarf_procedure for them or for portions thereof (for subexpressions
it would be even a potential nice debug info shrinking method, but would
mean a lot of work and gdb support isn't there yet).
So, for the time being I'm suggesting to just don't emit anything.

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

2012-01-04  Jakub Jelinek  <jakub@redhat.com>

	PR debug/51695
	* dwarf2out.c (output_loc_list): For now drop >= 64KB expressions
	in .debug_loc on the floor.

	* gcc.dg/pr51695.c: New test.


	Jakub

Comments

Jason Merrill Jan. 4, 2012, 6:23 p.m. UTC | #1
OK.

Jason
Tom Tromey Jan. 4, 2012, 7:11 p.m. UTC | #2
>>>>> "Jakub" == Jakub Jelinek <jakub@redhat.com> writes:

Jakub> another alternative would be to create DW_TAG_dwarf_procedure for
Jakub> them or for portions thereof (for subexpressions it would be even
Jakub> a potential nice debug info shrinking method, but would mean a
Jakub> lot of work and gdb support isn't there yet).

AFAIK, gdb supports DW_OP_call2 and DW_OP_call4 correctly.
If you know otherwise, please file a bug + reproducer.

gdb doesn't support DW_OP_call_ref yet.  I'm not sure why.
If it is important, we can add it.

Tom
Jakub Jelinek Jan. 4, 2012, 7:13 p.m. UTC | #3
On Wed, Jan 04, 2012 at 12:11:29PM -0700, Tom Tromey wrote:
> >>>>> "Jakub" == Jakub Jelinek <jakub@redhat.com> writes:
> 
> Jakub> another alternative would be to create DW_TAG_dwarf_procedure for
> Jakub> them or for portions thereof (for subexpressions it would be even
> Jakub> a potential nice debug info shrinking method, but would mean a
> Jakub> lot of work and gdb support isn't there yet).
> 
> AFAIK, gdb supports DW_OP_call2 and DW_OP_call4 correctly.
> If you know otherwise, please file a bug + reproducer.
> 
> gdb doesn't support DW_OP_call_ref yet.  I'm not sure why.
> If it is important, we can add it.

Honza said that GDB doesn't support DW_TAG_dwarf_procedure though.
We'd need to represent it as nameless artificial DW_TAG_variable
or something similar.

	Jakub
Tom Tromey Jan. 4, 2012, 7:27 p.m. UTC | #4
>>>>> "Jakub" == Jakub Jelinek <jakub@redhat.com> writes:

Jakub> Honza said that GDB doesn't support DW_TAG_dwarf_procedure though.
Jakub> We'd need to represent it as nameless artificial DW_TAG_variable
Jakub> or something similar.

I think gdb will issue a complaint if it sees one.  I'm not sure, I
don't think I've ever seen a program using this DWARF feature.

IIUC, the DW_OP_call* includes the needed DIE offset.  So, I think gdb
doesn't need to do anything for DW_TAG_dwarf_procedure except ignore it.

Doing this and eliminating the complaint is trivial.
I'm reluctant to do it without a way to test the change, though.
(And the complaint itself is harmless and not visible to users by
default anyway.)

Tom
Alexandre Oliva Jan. 10, 2012, 4:57 p.m. UTC | #5
On Jan  4, 2012, Jakub Jelinek <jakub@redhat.com> wrote:

> Unfortunately from time to time we do generate them, I hope Alex will
> look at how to prevent that from happening at var-tracking time, but
> still this isn't something we should assert on.

I've spent some time looking into this.  I could avoid the huge
expression by reducing the default max-vartrack-expr-depth from 12 to 8,
and AFAICT this didn't change at all the debug info generated for any of
the host parts of GCC, so we could do that.  I haven't regtested that,
though, for I'm not convinced that's the way to go.

FWIW, that wouldn't solve the underlying problem, which is that
expressions may get arbitrarily large, and debug info formats may not be
able to deal with that.  I think cutting them off within the debug info
format logic is the best we can do for now.  Using dwarf procedures is a
longer-term project that, if done in var-tracking where IMHO it belogs,
will require some additional interfaces between var-tracking and debug
info formats (are procedures supported, what's the expr size limit,
what's the size of a certain expr, etc).

One shorter-term way to avoid too-big expressions is to change the expr
depth computation logic.  Currently, if we find something like (op
(value) (const_int)) we don't regard it as any deeper than value by
itself.  Only operations with two or more value operands increase the
depth.  E.g., in the testcase for this bug, we only increase the depth
of the expression for the already-dead variable o at the if_then_else
expressions, for everything else (ands, xors, etc) involve constants.  I
don't think that'd be a positive change overall, though.
diff mbox

Patch

--- gcc/dwarf2out.c.jj	2012-01-03 16:22:48.000000000 +0100
+++ gcc/dwarf2out.c	2012-01-04 16:01:19.522191886 +0100
@@ -8166,6 +8166,13 @@  output_loc_list (dw_loc_list_ref list_he
       /* Don't output an entry that starts and ends at the same address.  */
       if (strcmp (curr->begin, curr->end) == 0 && !curr->force)
 	continue;
+      size = size_of_locs (curr->expr);
+      /* If the expression is too large, drop it on the floor.  We could
+	 perhaps put it into DW_TAG_dwarf_procedure and refer to that
+	 in the expression, but >= 64KB expressions for a single value
+	 in a single range are unlikely very useful.  */
+      if (size > 0xffff)
+	continue;
       if (!have_multiple_function_sections)
 	{
 	  dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->begin, curr->section,
@@ -8184,7 +8191,6 @@  output_loc_list (dw_loc_list_ref list_he
 			       "Location list end address (%s)",
 			       list_head->ll_symbol);
 	}
-      size = size_of_locs (curr->expr);
 
       /* Output the block length for this list of location operations.  */
       gcc_assert (size <= 0xffff);
--- gcc/testsuite/gcc.dg/pr51695.c.jj	2012-01-04 16:04:51.990964287 +0100
+++ gcc/testsuite/gcc.dg/pr51695.c	2012-01-04 16:03:16.000000000 +0100
@@ -0,0 +1,52 @@ 
+/* PR debug/51695 */
+/* { dg-do compile { target { int32plus } } } */
+/* { dg-options "-O2 -g" } */
+
+typedef struct
+{
+  struct { unsigned int t1, t2, t3, t4, t5, t6; } t;
+  int p;
+  struct { double X, Y, Z; } r;
+} T;
+typedef struct { T *h; } S;
+
+static unsigned int v = 0x12345678;
+
+int
+foo (void)
+{
+  v = (v & 0x80000000) ? ((v << 1) ^ 0xa398655d) : (v << 1);
+  return 0;
+}
+
+double
+bar (void)
+{
+  unsigned int o;
+  v = (v & 0x80000000) ? ((v << 1) ^ 0xa398655d) : (v << 1);
+  o = v & 0xffff;
+  return (double) o / 32768.0;
+}
+
+int
+baz (void)
+{
+  foo ();
+  return 0;
+}
+
+void
+test (S *x)
+{
+  T *t = x->h;
+  t->t.t1 = foo ();
+  t->t.t2 = foo ();
+  t->t.t3 = foo ();
+  t->t.t4 = foo ();
+  t->t.t5 = foo ();
+  t->t.t6 = foo ();
+  t->p = baz ();
+  t->r.X = bar ();
+  t->r.Y = bar ();
+  t->r.Z = bar ();
+}