• Sandipan Das's avatar
    Fix uprobes on powerpc64 (#2032) · bbd4180c
    Sandipan Das authored
    * Use correct entry point for uprobes on powerpc64
    
    For powerpc64 (big endian), the address of a function is the
    address of the corresponding function descriptor. While the
    actual functions reside in the ".text" section, the function
    descriptors are present in the ".opd" section. According to
    the ABI, each descriptor is a tri-doubleword data structure
    where the first doubleword is the actual entry point address.
    
    The symbol table entries do not list actual entry points but
    instead provide the location of the function descriptor. So,
    when attaching a probe, the location should be changed to the
    actual entry point by peeking into the function descriptor.
    
    This has been verified as shown below.
    
      $ readelf -S /usr/lib64/power8/libc-2.26.so | grep -A1 ".opd"
        [30] .opd              PROGBITS         0000000000213648  00203648
             000000000000bcb8  0000000000000000  WA       0     0     8
    
    The first column shows the index of the ".opd" section.
    
      $ readelf -s /usr/lib64/power8/libc-2.26.so | grep "inet_pton$"
        3405: 000000000021d168    96 FUNC    LOCAL  DEFAULT   30 __inet_pton
        3990: 000000000021d168    96 FUNC    LOCAL  DEFAULT   30 __GI___inet_pton
        5167: 000000000021d168    96 FUNC    LOCAL  DEFAULT   30 __GI_inet_pton
        6514: 000000000021d168    96 FUNC    WEAK   DEFAULT   30 inet_pton
    
    The seventh column shows the index of the section to which the
    symbols belong. This implies that all of these symbols are from
    the ".opd" section.
    
      $ objdump -d --section=.opd /usr/lib64/power8/libc-2.26.so | grep -A5 "inet_pton>:"
      000000000021d168 <inet_pton>:
        21d168:       00 00 00 00     .long 0x0
        21d16c:       00 17 2b 40     .long 0x172b40
        21d170:       00 00 00 00     .long 0x0
        21d174:       00 22 73 00     .long 0x227300
    
      $ objdump -d /usr/lib64/power8/libc-2.26.so | grep -A5 "inet_pton>:"
      0000000000172b40 <.__inet_pton>:
        172b40:       7c 08 02 a6     mflr    r0
        172b44:       fb c1 ff f0     std     r30,-16(r1)
        172b48:       fb e1 ff f8     std     r31,-8(r1)
        172b4c:       7c 7f 1b 78     mr      r31,r3
        172b50:       7c 83 23 78     mr      r3,r4
    
    The first doubleword in the descriptor of "inet_pton" gives the
    actual entry point address i.e. 0x172b40. So, the probe must be
    attached here and not 0x21d168.
    
      $ sudo trace "c:inet_pton" -U
      PID     TID     COMM            FUNC
      40769   40769   ping            inet_pton
              __GI___inet_pton+0x0 [libc-2.26.so]
              gaih_inet.constprop.7+0xf4c [libc-2.26.so]
              __GI_getaddrinfo+0x15c [libc-2.26.so]
              [unknown] [ping]
              generic_start_main.isra.0+0x150 [libc-2.26.so]
              __libc_start_main+0xbc [libc-2.26.so]
    
      $ ping -6 ::1
      PING ::1(::1) 56 data bytes
      64 bytes from ::1: icmp_seq=1 ttl=64 time=0.271 ms
      64 bytes from ::1: icmp_seq=2 ttl=64 time=0.039 ms
      ^C
      --- ::1 ping statistics ---
      2 packets transmitted, 2 received, 0% packet loss, time 1058ms
      rtt min/avg/max/mdev = 0.039/0.155/0.271/0.116 ms
    
    Previously, the event was not triggered upon running ping.
    Signed-off-by: default avatarSandipan Das <sandipan@linux.ibm.com>
    
    * Use correct entry point for uprobes on powerpc64le
    
    For powerpc64le, functions have a Global Entry Point (GEP)
    and a Local Entry Point (LEP). When using the GEP, there
    are some additional instructions at the beginning of the
    function that setup the TOC pointer. However, for all local
    calls, the TOC pointer is not required and a function can
    be called into directly via the LEP.
    
    While placing a uprobe, we should always prefer the LEP as
    the probe location since this will be encountered for any
    call through either the GEP or the LEP. Currently, the GEP
    is used as the probe location and hence the corresponding
    event is never triggered when the function is called via
    it's LEP.
    
    Information about the LEP can be obtained from the st_other
    field of an Elf symbol. While this field typically provides
    visibility information, the three most significant bits can
    provide additional information about the offset of the Local
    Entry Point (LEP) from the Global Entry Point (GEP) for any
    symbol in case of powerpc64le.
    
    This has been verified as shown below.
    
      $ readelf -s /usr/lib64/libc-2.27.so | grep "inet_pton "
      3522: 0000000000164610   104 FUNC    LOCAL  DEFAULT   11 __inet_pton  [<localentry>: 8]
      4188: 0000000000164610   104 FUNC    LOCAL  DEFAULT   11 __GI___inet_pton     [<localentry>: 8]
      5528: 0000000000164610   104 FUNC    LOCAL  DEFAULT   11 __GI_inet_pton       [<localentry>: 8]
      6925: 0000000000164610   104 FUNC    WEAK   DEFAULT   11 inet_pton    [<localentry>: 8]
    
      $ sudo trace "c:inet_pton" -U
      PID     TID     COMM            FUNC
      25383   25383   ping            inet_pton
              __GI___inet_pton+0x8 [libc-2.27.so]
              gaih_inet.constprop.7+0x1040 [libc-2.27.so]
              getaddrinfo+0x164 [libc-2.27.so]
              [unknown] [ping]
              generic_start_main.isra.0+0x138 [libc-2.27.so]
              __libc_start_main+0xc4 [libc-2.27.so]
    
      $ ping -6 ::1
      PING ::1(::1) 56 data bytes
      64 bytes from ::1: icmp_seq=1 ttl=64 time=0.140 ms
      64 bytes from ::1: icmp_seq=2 ttl=64 time=0.029 ms
      ^C
      --- ::1 ping statistics ---
      2 packets transmitted, 2 received, 0% packet loss, time 1022ms
      rtt min/avg/max/mdev = 0.029/0.084/0.140/0.056 ms
    
    Previously, the event was not triggered upon running ping.
    Signed-off-by: default avatarSandipan Das <sandipan@linux.ibm.com>
    bbd4180c
bcc_elf.c 20.9 KB