Patchwork Set correct source location for deallocator calls

login
register
mail settings
Submitter Dehao Chen
Date Aug. 17, 2012, 10:02 p.m.
Message ID <CAO2gOZWhueDAShNLbNcJpkHA6QqXk1LNZhEMFvfT77aTZTCH9w@mail.gmail.com>
Download mbox | patch
Permalink /patch/178401/
State New
Headers show

Comments

Dehao Chen - Aug. 17, 2012, 10:02 p.m.
Hi, Richard,

Thanks for the review. I've addressed most of the issues except the
java unittest (see comments below). The new patch is attached in the
end of this email.

Thanks,
Dehao

On Fri, Aug 17, 2012 at 8:47 AM, Richard Henderson <rth@redhat.com> wrote:
> On 2012-08-10 20:38, Dehao Chen wrote:
>> + // { dg-final { scan-assembler "1 28 0" } }
>
> This test case isn't going to work except with dwarf2, and with gas.
> You can use -dA so that you can scan for file.c:line.  There are
> other examples in the testsuite.

Done.
>
> This doesn't belong in guality.  It belongs in g++.dg/debug/.

Done.

> It would be nice if you could add a java testcase to see that it
> doesn't regress.

I spend a whole day working on this, but find it very difficult to add
such a java test because:

* First, libjava testsuits are all runtime tests, i.e., it compiles
the byte code to native code, execute it, and compares the output to
expected output. There is no way to scan the assembly.
* Though there is a way to derive the line number at runtime in java
(using Exception().getStackTrace()), this method only works on VM, and
the gcj generated native code does not get the lineno.

Any suggestions on this?

>
>> ! record_in_goto_queue_label (struct leh_tf_state *tf, treemple stmt,
>> tree label,
>> !                         location_t location)
>
> BTW, for the future, please fix your mailer to not wrap lines.

Okay, I'll try. The problem is that we have to send mail in plain txt.
And in "plain text mode" gmail wraps each line to 80 characters and
wouldn't allow you change that...

> I'll quibble with the wording here.  It reads as if we want to force
> all calls to have UNKNOWN_LOC, whereas all we want is to prevent any
> calls that already have UNKNOWN_LOC from gaining input_loc via gimplify_call_expr.

Done.

New Patch:
gcc/ChangeLog
	 * tree-eh.c (goto_queue_node): New field.
	(record_in_goto_queue): New parameter.
	(record_in_goto_queue_label): New parameter.
	(lower_try_finally_dup_block): New parameter.
	(maybe_record_in_goto_queue): Update source location.
	(lower_try_finally_copy): Likewise.
	(honor_protect_cleanup_actions): Likewise.
	* gimplify.c (gimplify_expr): Reset the location to unknown.

gcc/testsuite/ChangeLog
2012-08-07  Dehao Chen  <dehao@google.com>

	* g++.dg/debug/dwarf2/deallocator.C: New test.
Dehao Chen - Aug. 27, 2012, 11:36 p.m.
ping....

Thanks,
Dehao

On Sat, Aug 18, 2012 at 6:02 AM, Dehao Chen <dehao@google.com> wrote:
> Hi, Richard,
>
> Thanks for the review. I've addressed most of the issues except the
> java unittest (see comments below). The new patch is attached in the
> end of this email.
>
> Thanks,
> Dehao
>
> On Fri, Aug 17, 2012 at 8:47 AM, Richard Henderson <rth@redhat.com> wrote:
>> On 2012-08-10 20:38, Dehao Chen wrote:
>>> + // { dg-final { scan-assembler "1 28 0" } }
>>
>> This test case isn't going to work except with dwarf2, and with gas.
>> You can use -dA so that you can scan for file.c:line.  There are
>> other examples in the testsuite.
>
> Done.
>>
>> This doesn't belong in guality.  It belongs in g++.dg/debug/.
>
> Done.
>
>> It would be nice if you could add a java testcase to see that it
>> doesn't regress.
>
> I spend a whole day working on this, but find it very difficult to add
> such a java test because:
>
> * First, libjava testsuits are all runtime tests, i.e., it compiles
> the byte code to native code, execute it, and compares the output to
> expected output. There is no way to scan the assembly.
> * Though there is a way to derive the line number at runtime in java
> (using Exception().getStackTrace()), this method only works on VM, and
> the gcj generated native code does not get the lineno.
>
> Any suggestions on this?
>
>>
>>> ! record_in_goto_queue_label (struct leh_tf_state *tf, treemple stmt,
>>> tree label,
>>> !                         location_t location)
>>
>> BTW, for the future, please fix your mailer to not wrap lines.
>
> Okay, I'll try. The problem is that we have to send mail in plain txt.
> And in "plain text mode" gmail wraps each line to 80 characters and
> wouldn't allow you change that...
>
>> I'll quibble with the wording here.  It reads as if we want to force
>> all calls to have UNKNOWN_LOC, whereas all we want is to prevent any
>> calls that already have UNKNOWN_LOC from gaining input_loc via gimplify_call_expr.
>
> Done.
>
> New Patch:
> gcc/ChangeLog
>          * tree-eh.c (goto_queue_node): New field.
>         (record_in_goto_queue): New parameter.
>         (record_in_goto_queue_label): New parameter.
>         (lower_try_finally_dup_block): New parameter.
>         (maybe_record_in_goto_queue): Update source location.
>         (lower_try_finally_copy): Likewise.
>         (honor_protect_cleanup_actions): Likewise.
>         * gimplify.c (gimplify_expr): Reset the location to unknown.
>
> gcc/testsuite/ChangeLog
> 2012-08-07  Dehao Chen  <dehao@google.com>
>
>         * g++.dg/debug/dwarf2/deallocator.C: New test.
>
> Index: gcc/testsuite/g++.dg/debug/dwarf2/deallocator.C
> ===================================================================
> --- gcc/testsuite/g++.dg/debug/dwarf2/deallocator.C     (revision 0)
> +++ gcc/testsuite/g++.dg/debug/dwarf2/deallocator.C     (revision 0)
> @@ -0,0 +1,33 @@
> +// Test that debug info generated for auto-inserted deallocator is
> +// correctly attributed.
> +// This patch scans for the lineno directly from assembly, which may
> +// differ between different architectures. Because it mainly tests
> +// FE generated debug info, without losing generality, only x86
> +// assembly is scanned in this test.
> +// { dg-do compile { target { i?86-*-* x86_64-*-* } } }
> +// { dg-options "-O2 -fno-exceptions -g -dA" }
> +
> +struct t {
> +  t ();
> +  ~t ();
> +  void foo();
> +  void bar();
> +};
> +
> +int bar();
> +
> +void foo(int i)
> +{
> +  for (int j = 0; j < 10; j++)
> +    {
> +      t test;
> +      test.foo();
> +      if (i + j)
> +       {
> +         test.bar();
> +         return;
> +       }
> +    }
> +  return;
> +}
> +// { dg-final { scan-assembler "1 28 0" } }
> Index: gcc/tree-eh.c
> ===================================================================
> --- gcc/tree-eh.c       (revision 190209)
> +++ gcc/tree-eh.c       (working copy)
> @@ -321,6 +321,7 @@
>  struct goto_queue_node
>  {
>    treemple stmt;
> +  location_t location;
>    gimple_seq repl_stmt;
>    gimple cont_stmt;
>    int index;
> @@ -560,7 +561,8 @@
>  record_in_goto_queue (struct leh_tf_state *tf,
>                        treemple new_stmt,
>                        int index,
> -                      bool is_label)
> +                      bool is_label,
> +                     location_t location)
>  {
>    size_t active, size;
>    struct goto_queue_node *q;
> @@ -583,6 +585,7 @@
>    memset (q, 0, sizeof (*q));
>    q->stmt = new_stmt;
>    q->index = index;
> +  q->location = location;
>    q->is_label = is_label;
>  }
>
> @@ -590,7 +593,8 @@
>     TF is not null.  */
>
>  static void
> -record_in_goto_queue_label (struct leh_tf_state *tf, treemple stmt, tree label)
> +record_in_goto_queue_label (struct leh_tf_state *tf, treemple stmt, tree label,
> +                           location_t location)
>  {
>    int index;
>    treemple temp, new_stmt;
> @@ -629,7 +633,7 @@
>       since with a GIMPLE_COND we have an easy access to the then/else
>       labels. */
>    new_stmt = stmt;
> -  record_in_goto_queue (tf, new_stmt, index, true);
> +  record_in_goto_queue (tf, new_stmt, index, true, location);
>  }
>
>  /* For any GIMPLE_GOTO or GIMPLE_RETURN, decide whether it leaves a try_finally
> @@ -649,19 +653,22 @@
>      {
>      case GIMPLE_COND:
>        new_stmt.tp = gimple_op_ptr (stmt, 2);
> -      record_in_goto_queue_label (tf, new_stmt, gimple_cond_true_label (stmt));
> +      record_in_goto_queue_label (tf, new_stmt, gimple_cond_true_label (stmt),
> +                                 EXPR_LOCATION (*new_stmt.tp));
>        new_stmt.tp = gimple_op_ptr (stmt, 3);
> -     record_in_goto_queue_label (tf, new_stmt, gimple_cond_false_label (stmt));
> +      record_in_goto_queue_label (tf, new_stmt, gimple_cond_false_label (stmt),
> +                                 EXPR_LOCATION (*new_stmt.tp));
>        break;
>      case GIMPLE_GOTO:
>        new_stmt.g = stmt;
> -      record_in_goto_queue_label (tf, new_stmt, gimple_goto_dest (stmt));
> +      record_in_goto_queue_label (tf, new_stmt, gimple_goto_dest (stmt),
> +                                 gimple_location (stmt));
>        break;
>
>      case GIMPLE_RETURN:
>        tf->may_return = true;
>        new_stmt.g = stmt;
> -      record_in_goto_queue (tf, new_stmt, -1, false);
> +      record_in_goto_queue (tf, new_stmt, -1, false, gimple_location (stmt));
>        break;
>
>      default:
> @@ -866,13 +873,19 @@
>     Make sure to record all new labels found.  */
>
>  static gimple_seq
> -lower_try_finally_dup_block (gimple_seq seq, struct leh_state *outer_state)
> +lower_try_finally_dup_block (gimple_seq seq, struct leh_state *outer_state,
> +                            location_t loc)
>  {
>    gimple region = NULL;
>    gimple_seq new_seq;
> +  gimple_stmt_iterator gsi;
>
>    new_seq = copy_gimple_seq_and_replace_locals (seq);
>
> +  for (gsi = gsi_start (new_seq); !gsi_end_p (gsi); gsi_next (&gsi))
> +    if (gimple_location (gsi_stmt (gsi)) == UNKNOWN_LOCATION)
> +      gimple_set_location (gsi_stmt (gsi), loc);
> +
>    if (outer_state->tf)
>      region = outer_state->tf->try_finally_expr;
>    collect_finally_tree_1 (new_seq, region);
> @@ -967,7 +980,8 @@
>        gimple_try_set_cleanup (tf->top_p, gimple_eh_else_n_body (eh_else));
>      }
>    else if (this_state)
> -    finally = lower_try_finally_dup_block (finally, outer_state);
> +    finally = lower_try_finally_dup_block (finally, outer_state,
> +                                          UNKNOWN_LOCATION);
>    finally_may_fallthru = gimple_seq_may_fallthru (finally);
>
>    /* If this cleanup consists of a TRY_CATCH_EXPR with TRY_CATCH_IS_CLEANUP
> @@ -1184,7 +1198,7 @@
>
>    if (tf->may_fallthru)
>      {
> -      seq = lower_try_finally_dup_block (finally, state);
> +      seq = lower_try_finally_dup_block (finally, state, tf_loc);
>        lower_eh_constructs_1 (state, &seq);
>        gimple_seq_add_seq (&new_stmt, seq);
>
> @@ -1200,7 +1214,7 @@
>        if (eh_else)
>         seq = gimple_eh_else_e_body (eh_else);
>        else
> -       seq = lower_try_finally_dup_block (finally, state);
> +       seq = lower_try_finally_dup_block (finally, state, tf_loc);
>        lower_eh_constructs_1 (state, &seq);
>
>        emit_post_landing_pad (&eh_seq, tf->region);
> @@ -1250,7 +1264,7 @@
>           x = gimple_build_label (lab);
>            gimple_seq_add_stmt (&new_stmt, x);
>
> -         seq = lower_try_finally_dup_block (finally, state);
> +         seq = lower_try_finally_dup_block (finally, state, q->location);
>           lower_eh_constructs_1 (state, &seq);
>            gimple_seq_add_seq (&new_stmt, seq);
>
> Index: gcc/gimplify.c
> ===================================================================
> --- gcc/gimplify.c      (revision 190209)
> +++ gcc/gimplify.c      (working copy)
> @@ -7434,6 +7434,15 @@
>             gimple_seq eval, cleanup;
>             gimple try_;
>
> +           /* Calls to destructors are generated automatically in FINALL/CATCH
> +              block. They should have location as UNKNOWN_LOCATION. However,
> +              gimplify_call_expr will reset these call stmts to input_location
> +              if it finds stmt's location is unknown. To prevent resetting for
> +              destructors, we set the input_location to unknown.
> +              Note that this only affects the destructor calls in FINALL/CATCH
> +              block, and will automatically reset to its original value by the
> +              end of gimplify_expr.  */
> +           input_location = UNKNOWN_LOCATION;
>             eval = cleanup = NULL;
>             gimplify_and_add (TREE_OPERAND (*expr_p, 0), &eval);
>             gimplify_and_add (TREE_OPERAND (*expr_p, 1), &cleanup);
Richard Henderson - Aug. 30, 2012, 2:28 p.m.
On 08/17/2012 03:02 PM, Dehao Chen wrote:
> I spend a whole day working on this, but find it very difficult to add
> such a java test because:
> 
> * First, libjava testsuits are all runtime tests, i.e., it compiles
> the byte code to native code, execute it, and compares the output to
> expected output. There is no way to scan the assembly.
> * Though there is a way to derive the line number at runtime in java
> (using Exception().getStackTrace()), this method only works on VM, and
> the gcj generated native code does not get the lineno.
> 
> Any suggestions on this?

Hmm, not from me, unfortunately.  Cc'ing the java list for clues.
I won't hang up the main patch for this though.

>> BTW, for the future, please fix your mailer to not wrap lines.
> 
> Okay, I'll try. The problem is that we have to send mail in plain txt.
> And in "plain text mode" gmail wraps each line to 80 characters and
> wouldn't allow you change that...

In that case use a text/plain attachment (which, not having tried it myself,
may require you use a .txt suffix on the patch file).  Most mail readers will
show those inline.  It's certainly better than having actually corrupt data
sent to the list.

> +// { dg-options "-O2 -fno-exceptions -g -dA" }
...
> +// { dg-final { scan-assembler "1 28 0" } }

You're still scanning for the .loc line, not the "test.c:28"
comment added by -dA.

To understand the problem, go back to your build tree, edit
auto-host.h and undefine HAVE_AS_DWARF2_DEBUG_LINE.  Then
rerun the testsuite with RUNTESTFLAGS=dwarf2.exp.

> +	    /* Calls to destructors are generated automatically in FINALL/CATCH
> +	       block. They should have location as UNKNOWN_LOCATION. However,
> +	       gimplify_call_expr will reset these call stmts to input_location
> +	       if it finds stmt's location is unknown. To prevent resetting for
> +	       destructors, we set the input_location to unknown.
> +	       Note that this only affects the destructor calls in FINALL/CATCH
> +	       block, and will automatically reset to its original value by the
> +	       end of gimplify_expr.  */

s/FINALL/FINALLY/g


r~
Bryce McKinlay - Aug. 30, 2012, 2:45 p.m.
On Thu, Aug 30, 2012 at 3:28 PM, Richard Henderson <rth@redhat.com> wrote:
> On 08/17/2012 03:02 PM, Dehao Chen wrote:
>> I spend a whole day working on this, but find it very difficult to add
>> such a java test because:
>>
>> * First, libjava testsuits are all runtime tests, i.e., it compiles
>> the byte code to native code, execute it, and compares the output to
>> expected output. There is no way to scan the assembly.
>> * Though there is a way to derive the line number at runtime in java
>> (using Exception().getStackTrace()), this method only works on VM, and
>> the gcj generated native code does not get the lineno.
>>
>> Any suggestions on this?
>
> Hmm, not from me, unfortunately.  Cc'ing the java list for clues.
> I won't hang up the main patch for this though.

libjava calls out to addr2line to get the line number and source file
name for stack traces. As long as it can find addr2line you should get
a line number - but some platforms don't have it.

Ref: libjava/stacktrace.cc and libjava/gnu/gcj/runtime/NameFinder.java
Andrew Haley - Aug. 30, 2012, 3:20 p.m.
On 08/30/2012 03:28 PM, Richard Henderson wrote:
> On 08/17/2012 03:02 PM, Dehao Chen wrote:
>> I spend a whole day working on this, but find it very difficult to add
>> such a java test because:
>>
>> * First, libjava testsuits are all runtime tests, i.e., it compiles
>> the byte code to native code, execute it, and compares the output to
>> expected output. There is no way to scan the assembly.
>> * Though there is a way to derive the line number at runtime in java
>> (using Exception().getStackTrace()), this method only works on VM, and
>> the gcj generated native code does not get the lineno.
>>
>> Any suggestions on this?
> 
> Hmm, not from me, unfortunately.  Cc'ing the java list for clues.
> I won't hang up the main patch for this though.

Fair enough.  As Bryce said, line numbers should work if you have
addr2line installed.

Can't we scan the assembly?  Is the problem simply that the logic to
scan the assembly code isn't present in the libgcj testsuite?

Andrew.
Richard Henderson - Aug. 30, 2012, 4:33 p.m.
On 08/30/2012 08:20 AM, Andrew Haley wrote:
> Is the problem simply that the logic to
> scan the assembly code isn't present in the libgcj testsuite?

Yes, exactly.


r~
Dehao Chen - Sept. 4, 2012, 4:07 p.m.
On Thu, Aug 30, 2012 at 9:33 AM, Richard Henderson <rth@redhat.com> wrote:
> On 08/30/2012 08:20 AM, Andrew Haley wrote:
>> Is the problem simply that the logic to
>> scan the assembly code isn't present in the libgcj testsuite?
>
> Yes, exactly.

For this case, I don't think that we want a testcase to rely on
addr2line in the system. So how about that that we add a test when
assembly scan is available in libgcj testsuit?

Thanks,
Dehao

>
>
> r~
Andrew Haley - Sept. 4, 2012, 4:22 p.m.
On 09/04/2012 05:07 PM, Dehao Chen wrote:
> On Thu, Aug 30, 2012 at 9:33 AM, Richard Henderson <rth@redhat.com> wrote:
>> On 08/30/2012 08:20 AM, Andrew Haley wrote:
>>> Is the problem simply that the logic to
>>> scan the assembly code isn't present in the libgcj testsuite?
>>
>> Yes, exactly.
> 
> For this case, I don't think that we want a testcase to rely on
> addr2line in the system. So how about that that we add a test when
> assembly scan is available in libgcj testsuit?

Fine by me.  I guess you can just copy the scanning code from the gcc
testsuite.

Andrew.
Bryce McKinlay - Sept. 4, 2012, 4:32 p.m.
On Tue, Sep 4, 2012 at 5:07 PM, Dehao Chen <dehao@google.com> wrote:
> On Thu, Aug 30, 2012 at 9:33 AM, Richard Henderson <rth@redhat.com> wrote:
>> On 08/30/2012 08:20 AM, Andrew Haley wrote:
>>> Is the problem simply that the logic to
>>> scan the assembly code isn't present in the libgcj testsuite?
>>
>> Yes, exactly.
>
> For this case, I don't think that we want a testcase to rely on
> addr2line in the system. So how about that that we add a test when
> assembly scan is available in libgcj testsuit?

Once Ian Lance Taylor's libbacktrace patch is integrated (see:
http://gcc.gnu.org/ml/gcc/2012-08/msg00317.html), we'll be able to get
rid of the code that calls addr2line from libgcj.

So, I think it would be fine to write a Java test case using
Throwable.getStackTrace(). Whichever approach is easiest for you is
fine.

Bryce
Andrew Haley - Sept. 4, 2012, 4:39 p.m.
On 09/04/2012 05:32 PM, Bryce McKinlay wrote:
> On Tue, Sep 4, 2012 at 5:07 PM, Dehao Chen <dehao@google.com> wrote:
>> On Thu, Aug 30, 2012 at 9:33 AM, Richard Henderson <rth@redhat.com> wrote:
>>> On 08/30/2012 08:20 AM, Andrew Haley wrote:
>>>> Is the problem simply that the logic to
>>>> scan the assembly code isn't present in the libgcj testsuite?
>>>
>>> Yes, exactly.
>>
>> For this case, I don't think that we want a testcase to rely on
>> addr2line in the system. So how about that that we add a test when
>> assembly scan is available in libgcj testsuit?
> 
> Once Ian Lance Taylor's libbacktrace patch is integrated (see:
> http://gcc.gnu.org/ml/gcc/2012-08/msg00317.html), we'll be able to get
> rid of the code that calls addr2line from libgcj.

As I understand it, Ian Taylor's backtrace patch is intended for use in
gcc development, and as he puts it "Since its use in GCC would
be purely for GCC developers, it's not essential that it be fully
portable."  Not for gcj runtime.

Andrew.
Bryce McKinlay - Sept. 4, 2012, 5:08 p.m.
On Tue, Sep 4, 2012 at 5:39 PM, Andrew Haley <aph@redhat.com> wrote:
> On 09/04/2012 05:32 PM, Bryce McKinlay wrote:
>> On Tue, Sep 4, 2012 at 5:07 PM, Dehao Chen <dehao@google.com> wrote:
>>> On Thu, Aug 30, 2012 at 9:33 AM, Richard Henderson <rth@redhat.com> wrote:
>>>> On 08/30/2012 08:20 AM, Andrew Haley wrote:
>>>>> Is the problem simply that the logic to
>>>>> scan the assembly code isn't present in the libgcj testsuite?
>>>>
>>>> Yes, exactly.
>>>
>>> For this case, I don't think that we want a testcase to rely on
>>> addr2line in the system. So how about that that we add a test when
>>> assembly scan is available in libgcj testsuit?
>>
>> Once Ian Lance Taylor's libbacktrace patch is integrated (see:
>> http://gcc.gnu.org/ml/gcc/2012-08/msg00317.html), we'll be able to get
>> rid of the code that calls addr2line from libgcj.
>
> As I understand it, Ian Taylor's backtrace patch is intended for use in
> gcc development, and as he puts it "Since its use in GCC would
> be purely for GCC developers, it's not essential that it be fully
> portable."  Not for gcj runtime.

He's also planning to use it for libgo, and other gcc runtime libs
have indicated interest. It doesn't have to work on all platforms, and
I can't see how it would be any less portable than addr2line!

Bryce
Andrew Haley - Sept. 4, 2012, 5:12 p.m.
On 09/04/2012 06:08 PM, Bryce McKinlay wrote:
> On Tue, Sep 4, 2012 at 5:39 PM, Andrew Haley <aph@redhat.com> wrote:
>> On 09/04/2012 05:32 PM, Bryce McKinlay wrote:
>>> On Tue, Sep 4, 2012 at 5:07 PM, Dehao Chen <dehao@google.com> wrote:
>>>> On Thu, Aug 30, 2012 at 9:33 AM, Richard Henderson <rth@redhat.com> wrote:
>>>>> On 08/30/2012 08:20 AM, Andrew Haley wrote:
>>>>>> Is the problem simply that the logic to
>>>>>> scan the assembly code isn't present in the libgcj testsuite?
>>>>>
>>>>> Yes, exactly.
>>>>
>>>> For this case, I don't think that we want a testcase to rely on
>>>> addr2line in the system. So how about that that we add a test when
>>>> assembly scan is available in libgcj testsuit?
>>>
>>> Once Ian Lance Taylor's libbacktrace patch is integrated (see:
>>> http://gcc.gnu.org/ml/gcc/2012-08/msg00317.html), we'll be able to get
>>> rid of the code that calls addr2line from libgcj.
>>
>> As I understand it, Ian Taylor's backtrace patch is intended for use in
>> gcc development, and as he puts it "Since its use in GCC would
>> be purely for GCC developers, it's not essential that it be fully
>> portable."  Not for gcj runtime.
> 
> He's also planning to use it for libgo, and other gcc runtime libs
> have indicated interest. It doesn't have to work on all platforms, and
> I can't see how it would be any less portable than addr2line!

I certainly can.  Maybe once it's shaken-down so it's at least as
robust as what we have now it'll be OK.  I suspect it hasn't had much
testing with, for example, unwinding through signal handlers.

Andrew.
Bryce McKinlay - Sept. 4, 2012, 5:17 p.m.
On Tue, Sep 4, 2012 at 6:12 PM, Andrew Haley <aph@redhat.com> wrote:

>> He's also planning to use it for libgo, and other gcc runtime libs
>> have indicated interest. It doesn't have to work on all platforms, and
>> I can't see how it would be any less portable than addr2line!
>
> I certainly can.  Maybe once it's shaken-down so it's at least as
> robust as what we have now it'll be OK.  I suspect it hasn't had much
> testing with, for example, unwinding through signal handlers.

libgcj wouldn't actually use it for unwinding, we already have all
that. We'd just use it to read DWARF debug info and give us the source
code line numbers.
Andrew Haley - Sept. 4, 2012, 5:20 p.m.
On 09/04/2012 06:17 PM, Bryce McKinlay wrote:
> On Tue, Sep 4, 2012 at 6:12 PM, Andrew Haley <aph@redhat.com> wrote:
> 
>>> He's also planning to use it for libgo, and other gcc runtime libs
>>> have indicated interest. It doesn't have to work on all platforms, and
>>> I can't see how it would be any less portable than addr2line!
>>
>> I certainly can.  Maybe once it's shaken-down so it's at least as
>> robust as what we have now it'll be OK.  I suspect it hasn't had much
>> testing with, for example, unwinding through signal handlers.
> 
> libgcj wouldn't actually use it for unwinding, we already have all
> that. We'd just use it to read DWARF debug info and give us the source
> code line numbers.

OK, as long as that's all it does.  I think I was perhaps a bit
misled by its description of "a stack backtrace library".  It
certainly looks like a nicer approach than addr2line, but is
going to be much less well-ported.  I guess we'll see how it goes.

Andrew.
Dehao Chen - Sept. 4, 2012, 8:31 p.m.
Looks like even with addr2line properly installed, the gcj generated
code cannot get the correct source file/lineno. Do I need to pass in
anything to gcj to let it know where addr2line is?

Thanks,
Dehao

#javac stacktrace.java
#java stacktrace
stacktrace.e(stacktrace.java:42)
stacktrace.d(stacktrace.java:38)
stacktrace.c(stacktrace.java:31)
stacktrace.b(stacktrace.java:26)
stacktrace.a(stacktrace.java:19)
stacktrace.main(stacktrace.java:12)
#gcj *.class -o stacktrace.exe
#./stacktrace.exe
stacktrace.e(stacktrace.exe:-1)
stacktrace.d(stacktrace.exe:-1)
stacktrace.c(stacktrace.exe:-1)
stacktrace.b(stacktrace.exe:-1)
stacktrace.a(stacktrace.exe:-1)
stacktrace.main(stacktrace.exe:-1)

The java code is shown below:
stacktrace.java
/* This test should test the stacktrace functionality.
   We only print ClassName and MethName since the other information
   like FileName and LineNumber are not consistent while building
   native or interpreted and we want to test the output inside the dejagnu
   test environment.
   Also, we have to make the methods public since they might be optimized away
   with inline's and then the -O3/-O2 execution might fail.
*/
public class stacktrace {
  public static void main(String args[]) {
    try {
      new stacktrace().a();
    } catch (TopException e) {
    }
  }

  public void a() throws TopException {
    try {
      b();
    } catch (MiddleException e) {
      throw new TopException(e);
    }
  }

  public void b() throws MiddleException {
    c();
  }

  public void c() throws MiddleException {
    try {
      d();
    } catch (BottomException e) {
      throw new MiddleException(e);
    }
  }

  public void d() throws BottomException {
    e();
  }

  public void e() throws BottomException {
    throw new BottomException();
  }
}

class TopException extends Exception {
  TopException(Throwable cause) {
    super(cause);
  }
}

class MiddleException extends Exception {
  MiddleException(Throwable cause) {
    super(cause);
  }
}

class BottomException extends Exception {
  BottomException() {
    StackTraceElement stack[] = this.getStackTrace();
    for (int i = 0; i < stack.length; i++) {
      String className = stack[i].getClassName();
      String methodName = stack[i].getMethodName();
      System.out.println(className + "." + methodName + "(" +
                         stack[i].getFileName() + ":" +
                         stack[i].getLineNumber() +  ")");
    }
  }
}
Dehao Chen - Sept. 4, 2012, 8:40 p.m.
On Tue, Sep 4, 2012 at 9:22 AM, Andrew Haley <aph@redhat.com> wrote:
> On 09/04/2012 05:07 PM, Dehao Chen wrote:
>> On Thu, Aug 30, 2012 at 9:33 AM, Richard Henderson <rth@redhat.com> wrote:
>>> On 08/30/2012 08:20 AM, Andrew Haley wrote:
>>>> Is the problem simply that the logic to
>>>> scan the assembly code isn't present in the libgcj testsuite?
>>>
>>> Yes, exactly.
>>
>> For this case, I don't think that we want a testcase to rely on
>> addr2line in the system. So how about that that we add a test when
>> assembly scan is available in libgcj testsuit?
>
> Fine by me.  I guess you can just copy the scanning code from the gcc
> testsuite.

I tried that, but it is not trivial, and simply copying "proc
scan-assembler" to libjava seems ugly. Do libjava people really think
it's worth to add scan-assembler and other premitives in gcc testsuite
into libjava testsuite? If yes, I'll leave it to the TODO list.

Thanks,
Dehao
>
> Andrew.
>
Andrew Haley - Sept. 5, 2012, 7:29 a.m.
On 09/04/2012 09:31 PM, Dehao Chen wrote:
> Looks like even with addr2line properly installed, the gcj generated
> code cannot get the correct source file/lineno. Do I need to pass in
> 
> #javac stacktrace.java
> #java stacktrace
> stacktrace.e(stacktrace.java:42)
> stacktrace.d(stacktrace.java:38)
> stacktrace.c(stacktrace.java:31)
> stacktrace.b(stacktrace.java:26)
> stacktrace.a(stacktrace.java:19)
> stacktrace.main(stacktrace.java:12)
> #gcj *.class -o stacktrace.exe
> #./stacktrace.exe
> stacktrace.e(stacktrace.exe:-1)
> stacktrace.d(stacktrace.exe:-1)
> stacktrace.c(stacktrace.exe:-1)
> stacktrace.b(stacktrace.exe:-1)
> stacktrace.a(stacktrace.exe:-1)
> stacktrace.main(stacktrace.exe:-1)

Works for me:

[aph@nighthawk ~]$ gcj stacktrace.java --main=stacktrace -g
[aph@nighthawk ~]$ ./a.out
stacktrace.e(stacktrace.java:42)
stacktrace.d(stacktrace.java:38)
stacktrace.c(stacktrace.java:31)
stacktrace.b(stacktrace.java:26)
stacktrace.a(stacktrace.java:19)
stacktrace.main(stacktrace.java:12)

Aren't you just compiling without -g ?  There is no debuginfo.

Andrew.
Andrew Pinski - Sept. 5, 2012, 7:30 a.m.
On Wed, Sep 5, 2012 at 12:29 AM, Andrew Haley <aph@redhat.com> wrote:
> On 09/04/2012 09:31 PM, Dehao Chen wrote:
>> Looks like even with addr2line properly installed, the gcj generated
>> code cannot get the correct source file/lineno. Do I need to pass in
>>
>> #javac stacktrace.java
>> #java stacktrace
>> stacktrace.e(stacktrace.java:42)
>> stacktrace.d(stacktrace.java:38)
>> stacktrace.c(stacktrace.java:31)
>> stacktrace.b(stacktrace.java:26)
>> stacktrace.a(stacktrace.java:19)
>> stacktrace.main(stacktrace.java:12)
>> #gcj *.class -o stacktrace.exe
>> #./stacktrace.exe
>> stacktrace.e(stacktrace.exe:-1)
>> stacktrace.d(stacktrace.exe:-1)
>> stacktrace.c(stacktrace.exe:-1)
>> stacktrace.b(stacktrace.exe:-1)
>> stacktrace.a(stacktrace.exe:-1)
>> stacktrace.main(stacktrace.exe:-1)
>
> Works for me:
>
> [aph@nighthawk ~]$ gcj stacktrace.java --main=stacktrace -g
> [aph@nighthawk ~]$ ./a.out
> stacktrace.e(stacktrace.java:42)
> stacktrace.d(stacktrace.java:38)
> stacktrace.c(stacktrace.java:31)
> stacktrace.b(stacktrace.java:26)
> stacktrace.a(stacktrace.java:19)
> stacktrace.main(stacktrace.java:12)
>
> Aren't you just compiling without -g ?  There is no debuginfo.

The other thing that might be needed is a newer addr2line which works
correctly with the dwarf2(4) that GCC outputs.

Thanks,
Andrew
Mark Wielaard - Sept. 5, 2012, 9:58 a.m.
On Tue, 2012-09-04 at 18:17 +0100, Bryce McKinlay wrote:
> libgcj wouldn't actually use it for unwinding, we already have all
> that. We'd just use it to read DWARF debug info and give us the source
> code line numbers.

Casey Marshell did also write that part some time ago, but it was never
finished/integrated.
http://gcc.gnu.org/ml/java-patches/2004-q3/msg00350.html

Cheers,

Mark

Patch

Index: gcc/testsuite/g++.dg/debug/dwarf2/deallocator.C
===================================================================
--- gcc/testsuite/g++.dg/debug/dwarf2/deallocator.C	(revision 0)
+++ gcc/testsuite/g++.dg/debug/dwarf2/deallocator.C	(revision 0)
@@ -0,0 +1,33 @@ 
+// Test that debug info generated for auto-inserted deallocator is
+// correctly attributed.
+// This patch scans for the lineno directly from assembly, which may
+// differ between different architectures. Because it mainly tests
+// FE generated debug info, without losing generality, only x86
+// assembly is scanned in this test.
+// { dg-do compile { target { i?86-*-* x86_64-*-* } } }
+// { dg-options "-O2 -fno-exceptions -g -dA" }
+
+struct t {
+  t ();
+  ~t ();
+  void foo();
+  void bar();
+};
+
+int bar();
+
+void foo(int i)
+{
+  for (int j = 0; j < 10; j++)
+    {
+      t test;
+      test.foo();
+      if (i + j)
+	{
+	  test.bar();
+	  return;
+	}
+    }
+  return;
+}
+// { dg-final { scan-assembler "1 28 0" } }
Index: gcc/tree-eh.c
===================================================================
--- gcc/tree-eh.c	(revision 190209)
+++ gcc/tree-eh.c	(working copy)
@@ -321,6 +321,7 @@ 
 struct goto_queue_node
 {
   treemple stmt;
+  location_t location;
   gimple_seq repl_stmt;
   gimple cont_stmt;
   int index;
@@ -560,7 +561,8 @@ 
 record_in_goto_queue (struct leh_tf_state *tf,
                       treemple new_stmt,
                       int index,
-                      bool is_label)
+                      bool is_label,
+		      location_t location)
 {
   size_t active, size;
   struct goto_queue_node *q;
@@ -583,6 +585,7 @@ 
   memset (q, 0, sizeof (*q));
   q->stmt = new_stmt;
   q->index = index;
+  q->location = location;
   q->is_label = is_label;
 }

@@ -590,7 +593,8 @@ 
    TF is not null.  */

 static void
-record_in_goto_queue_label (struct leh_tf_state *tf, treemple stmt, tree label)
+record_in_goto_queue_label (struct leh_tf_state *tf, treemple stmt, tree label,
+			    location_t location)
 {
   int index;
   treemple temp, new_stmt;
@@ -629,7 +633,7 @@ 
      since with a GIMPLE_COND we have an easy access to the then/else
      labels. */
   new_stmt = stmt;
-  record_in_goto_queue (tf, new_stmt, index, true);
+  record_in_goto_queue (tf, new_stmt, index, true, location);
 }

 /* For any GIMPLE_GOTO or GIMPLE_RETURN, decide whether it leaves a try_finally
@@ -649,19 +653,22 @@ 
     {
     case GIMPLE_COND:
       new_stmt.tp = gimple_op_ptr (stmt, 2);
-      record_in_goto_queue_label (tf, new_stmt, gimple_cond_true_label (stmt));
+      record_in_goto_queue_label (tf, new_stmt, gimple_cond_true_label (stmt),
+				  EXPR_LOCATION (*new_stmt.tp));
       new_stmt.tp = gimple_op_ptr (stmt, 3);
-     record_in_goto_queue_label (tf, new_stmt, gimple_cond_false_label (stmt));
+      record_in_goto_queue_label (tf, new_stmt, gimple_cond_false_label (stmt),
+				  EXPR_LOCATION (*new_stmt.tp));
       break;
     case GIMPLE_GOTO:
       new_stmt.g = stmt;
-      record_in_goto_queue_label (tf, new_stmt, gimple_goto_dest (stmt));
+      record_in_goto_queue_label (tf, new_stmt, gimple_goto_dest (stmt),
+				  gimple_location (stmt));
       break;

     case GIMPLE_RETURN:
       tf->may_return = true;
       new_stmt.g = stmt;
-      record_in_goto_queue (tf, new_stmt, -1, false);
+      record_in_goto_queue (tf, new_stmt, -1, false, gimple_location (stmt));
       break;

     default:
@@ -866,13 +873,19 @@ 
    Make sure to record all new labels found.  */

 static gimple_seq
-lower_try_finally_dup_block (gimple_seq seq, struct leh_state *outer_state)
+lower_try_finally_dup_block (gimple_seq seq, struct leh_state *outer_state,
+			     location_t loc)
 {
   gimple region = NULL;
   gimple_seq new_seq;
+  gimple_stmt_iterator gsi;

   new_seq = copy_gimple_seq_and_replace_locals (seq);

+  for (gsi = gsi_start (new_seq); !gsi_end_p (gsi); gsi_next (&gsi))
+    if (gimple_location (gsi_stmt (gsi)) == UNKNOWN_LOCATION)
+      gimple_set_location (gsi_stmt (gsi), loc);
+
   if (outer_state->tf)
     region = outer_state->tf->try_finally_expr;
   collect_finally_tree_1 (new_seq, region);
@@ -967,7 +980,8 @@ 
       gimple_try_set_cleanup (tf->top_p, gimple_eh_else_n_body (eh_else));
     }
   else if (this_state)
-    finally = lower_try_finally_dup_block (finally, outer_state);
+    finally = lower_try_finally_dup_block (finally, outer_state,
+					   UNKNOWN_LOCATION);
   finally_may_fallthru = gimple_seq_may_fallthru (finally);

   /* If this cleanup consists of a TRY_CATCH_EXPR with TRY_CATCH_IS_CLEANUP
@@ -1184,7 +1198,7 @@ 

   if (tf->may_fallthru)
     {
-      seq = lower_try_finally_dup_block (finally, state);
+      seq = lower_try_finally_dup_block (finally, state, tf_loc);
       lower_eh_constructs_1 (state, &seq);
       gimple_seq_add_seq (&new_stmt, seq);

@@ -1200,7 +1214,7 @@ 
       if (eh_else)
 	seq = gimple_eh_else_e_body (eh_else);
       else
-	seq = lower_try_finally_dup_block (finally, state);
+	seq = lower_try_finally_dup_block (finally, state, tf_loc);
       lower_eh_constructs_1 (state, &seq);

       emit_post_landing_pad (&eh_seq, tf->region);
@@ -1250,7 +1264,7 @@ 
 	  x = gimple_build_label (lab);
           gimple_seq_add_stmt (&new_stmt, x);

-	  seq = lower_try_finally_dup_block (finally, state);
+	  seq = lower_try_finally_dup_block (finally, state, q->location);
 	  lower_eh_constructs_1 (state, &seq);
           gimple_seq_add_seq (&new_stmt, seq);

Index: gcc/gimplify.c
===================================================================
--- gcc/gimplify.c	(revision 190209)
+++ gcc/gimplify.c	(working copy)
@@ -7434,6 +7434,15 @@ 
 	    gimple_seq eval, cleanup;
 	    gimple try_;

+	    /* Calls to destructors are generated automatically in FINALL/CATCH
+	       block. They should have location as UNKNOWN_LOCATION. However,
+	       gimplify_call_expr will reset these call stmts to input_location
+	       if it finds stmt's location is unknown. To prevent resetting for
+	       destructors, we set the input_location to unknown.
+	       Note that this only affects the destructor calls in FINALL/CATCH
+	       block, and will automatically reset to its original value by the
+	       end of gimplify_expr.  */
+	    input_location = UNKNOWN_LOCATION;
 	    eval = cleanup = NULL;
 	    gimplify_and_add (TREE_OPERAND (*expr_p, 0), &eval);
 	    gimplify_and_add (TREE_OPERAND (*expr_p, 1), &cleanup);