Fix uprobes on powerpc64 (#2032)
* 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: Sandipan 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: Sandipan Das <sandipan@linux.ibm.com>
Showing
Please register or sign in to comment