Re: [DynInst_API:] inconsistent handling for non-returning functions


Date: Wed, 14 Feb 2018 13:19:50 -0600
From: Xiaozhu Meng <xmeng@xxxxxxxxxxx>
Subject: Re: [DynInst_API:] inconsistent handling for non-returning functions
Hi John,

I am able to reproduce the problem and will start to investigate it. I will let you know when I fix it.

Thanks,

--Xiaozhu

On Wed, Feb 14, 2018 at 12:50 PM, John Mellor-Crummey <johnmc@xxxxxxxx> wrote:
Non-returning functions and calls to them are not being processed properlyÂ
by Dyninst on ppc/be. As a consequence, in the analysis results producedÂ
by Dyninst for a binary for AMG 2013, two functions and a long branchÂ
trampoline are fused into a single function, which leads to confusion inÂ
HPCToolkitâs hpcstruct. Â

The problem report below refers to two binaries: one called ungetc.ppc,Â
which is a dynamic ppc/be binary for a main program that contains a single
call to ungetc and a second binary amg2013.gnu.ppc, which is a staticallyÂ
linked binary for bg/q (ppc/be).

The binaries can be found here:Â


First a case that works:
Â
The call at 0x1001cd0 in the ungetc.ppc binary at the end of ._IO_ungetc
is labeled as non-returning by the following line in Parser.C at line
1012 in my copy of Dyninst source:

 is_nonret = obj().cs()->nonReturning(target);

The function nonReturning resolves the address to a ParseAPI::FunctionÂ
and then determines that a mangled name of that functionÂ
(_Unwind_Resume) is in the table of names of non_returning_funcs
defined in ÂCodeSource.C

1001cd0:    48 07 20 71   bl   Â1073d40 <._Unwind_Resume>
1001cd4: Â Â Â 60 00 00 00 Â Â nop
_IO_ungetc():
1001cd8: Â Â Â 00 00 00 00 Â Â .long 0x0
1001cdc: Â Â Â 00 00 00 01 Â Â .long 0x1
1001ce0:    80 03 00 00   lwz   r0,0(r3)
__vmx__sigsetjmp_ent():
1001ce4: Â Â Â 60 00 00 00 Â Â nop
1001ce8: Â Â Â 60 00 00 00 Â Â nop
1001cec: Â Â Â 60 00 00 00 Â Â nop

Now a case that doesnât work:

In the amg2013.gnu.ppc binary, the branch at 0x158d6b0, which
is at the same spot in Â._IO_ungetc, goes to a ppc long_branch trampoline
that makes a tail call to _Unwind_Resume. This call is not classified as
non-returning. As a result, there is a fall through edge that joins it
to the branch trampoline for _IO_vfscanf that that follows ._IO_ungetc.

...
158d6b0:    4b ff fb 41   bl   Â158d1f0 <00008345.long_branch_r2off._Unwind_Resume+0>
158d6b4:    e8 41 00 28   ld   Âr2,40(r1)
_IO_ungetc():
158d6b8: Â Â Â 00 00 00 00 Â Â .long 0x0
158d6bc: Â Â Â 00 00 00 01 Â Â .long 0x1
158d6c0:    80 03 00 00   lwz   r0,0(r3)

000000000158d6c4 <00008368.long_branch_r2off._IO_vfscanf+0>:
00008368.long_branch_r2off._IO_vfscanf+0():
158d6c4:    f8 41 00 28   std   r2,40(r1)
158d6c8:    3c 42 00 01   addis  r2,r2,1
158d6cc:    38 42 ff f8   addi  Âr2,r2,-8
158d6d0:    48 05 a1 00   b    15e77d0 <._IO_vfscanf>
158d6d4: Â Â Â 60 00 00 00 Â Â nop
158d6d8: Â Â Â 60 00 00 00 Â Â nop
158d6dc: Â Â Â 60 00 00 00 Â Â nop

In fact, the same issue at then end of ._IO_setvbuf, which precedes
._IO_ungetc causes a fall through edge between Â._IO_setvbuf and
._IO_ungetc.

The long_branch trampoline that is the target of the call at 0x158d6b0Â
is included below:

000000000158d1f0 <00008345.long_branch_r2off._Unwind_Resume+0>:
00008345.long_branch_r2off._Unwind_Resume+0():
158d1f0:    f8 41 00 28   std   r2,40(r1)
158d1f4:    3c 42 ff ff   addis  r2,r2,-1
158d1f8:    38 42 00 08   addi  Âr2,r2,8
158d1fc:    4b fd b0 f4   b    15682f0 <._Unwind_Resume>

It seems that non-returning status isn't properly being computed forÂ
functions. When I dump dyninst parseAPI functions and print theirÂ
return status, I find that both _Unwind_Resume is listed as returning
and the long branch trampoline at 0x158d1f0 that goes to ._Unwind_ResumeÂ
is also listed as returning as well.Â

function targ158d1f0 RETURN
 [158d1f0,158d200)
  DIRECT --> 15682f0

function _Unwind_Resume RETURN
 [15682f0,15683b4)
  COND_TAKEN --> 15683b8
  COND_NOT_TAKEN --> 15683b4
 [15683b4,15683b8)
  FALLTHROUGH --> 15683b8
 [15683b8,15683d8)
  CALL --> 1567970
  CALL_FT --> 15683d8
...

It seems that the ParseAPI::Function for _Unwind_Resume should be marked
as non-returning since the name is identified as a non-returning function.
If I understand the logic and how this should propagate,Â
marking theÂparseAPI function for Â_Unwind_Resume as non-returning shouldÂ
cause the long-branch trampoline that ends in a tail call to it to be seen as non-returning,Â
which would then cause the call to the long-branch trampoline as having no CALL_FT edge.

While the branch trampolines may contribute to bad propagation ofÂ
knowledge about non-returning functions on ppc, the fact that theÂ
ParseAPI::Function for _Unwind_Resume is not marked as non-returning
seems like a problem that transcends architecture.
--
John Mellor-Crummey Professor
Dept of Computer Science Rice University
email: johnmc@xxxxxxxx phone: 713-348-5179


_______________________________________________
Dyninst-api mailing list
Dyninst-api@xxxxxxxxxxx
https://lists.cs.wisc.edu/mailman/listinfo/dyninst-api

[← Prev in Thread] Current Thread [Next in Thread→]