Bug#824362: glibc: Fix failure of debug/backtrace-tst on hppa
Source: glibc
Version: 2.22
Severity: normal
Tags: patch
Dear Maintainer,
The failure of the debug/backtrace-tst was introduced by the
hppa/submitted-dladdr.diff patch. The code was not prepared to handle
being passed an arbitrary address. As a result, _dl_lookup_address
generates a segmentation fault.
I believe this fixes one or two other tests as well.
This is BZ 20098:
https://sourceware.org/bugzilla/show_bug.cgi?id=20098
A patch to fix this problem in the upstream source is here:
https://sourceware.org/ml/libc-alpha/2016-05/txti8b7kcvurW.txt
Attached is a replacement for the current hppa/submitted-dladdr.diff patch.
Please update current patch.
Thanks,
Dave
-- System Information:
Debian Release: stretch/sid
APT prefers unstable
APT policy: (500, 'unstable')
Architecture: hppa (parisc64)
Kernel: Linux 3.18.29+ (SMP w/4 CPU cores)
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8) (ignored: LC_ALL set to en_CA.utf8)
Shell: /bin/sh linked to /bin/dash
Init: sysvinit (via /sbin/init)
2016-01-02 John David Anglin <danglin@gcc.gnu.org>
[BZ #19415]
* sysdeps/hppa/dl-fptr.c (_dl_fixup): Declare.
(elf_machine_resolve): New. Return address of _dl_runtime_resolve.
(_dl_lookup_address): Rewrite using function resolver trampoline.
* sysdeps/hppa/dl-lookupcfg.h (DL_LOOKUP_ADDRESS): Don't clear bottom
two bits in address.
Index: glibc-2.22/sysdeps/hppa/dl-fptr.c
===================================================================
--- glibc-2.22.orig/sysdeps/hppa/dl-fptr.c
+++ glibc-2.22/sysdeps/hppa/dl-fptr.c
@@ -321,23 +321,76 @@ _dl_unmap (struct link_map *map)
map->l_mach.fptr_table = NULL;
}
+extern ElfW(Addr) _dl_fixup (struct link_map *, ElfW(Word)) attribute_hidden;
+
+static inline Elf32_Addr
+elf_machine_resolve (void)
+{
+ Elf32_Addr addr;
+
+ asm ("b,l 1f,%0\n"
+" depi 0,31,2,%0\n"
+"1: addil L'_dl_runtime_resolve - ($PIC_pcrel$0 - 8),%0\n"
+" ldo R'_dl_runtime_resolve - ($PIC_pcrel$0 - 12)(%%r1),%0\n"
+ : "=r" (addr) : : "r1");
+
+ return addr;
+}
+
+static inline int
+_dl_read_access_allowed (unsigned int *addr)
+{
+ int result;
+
+ asm ("proberi (%1),3,%0" : "=r" (result) : "r" (addr) : );
+
+ return result;
+}
ElfW(Addr)
_dl_lookup_address (const void *address)
{
ElfW(Addr) addr = (ElfW(Addr)) address;
- struct fdesc_table *t;
- unsigned long int i;
+ unsigned int *desc, *gptr;
- for (t = local.root; t != NULL; t = t->next)
- {
- i = (struct fdesc *) addr - &t->fdesc[0];
- if (i < t->first_unused && addr == (ElfW(Addr)) &t->fdesc[i])
- {
- addr = t->fdesc[i].ip;
- break;
- }
- }
+ /* Return ADDR if the least-significant two bits of ADDR are not consistent
+ with ADDR being a linker defined function pointer. The normal value for
+ a code address in a backtrace is 3. */
+ if (((unsigned int) addr & 3) != 2)
+ return addr;
- return addr;
+ /* Handle special case where ADDR points to page 0. */
+ if ((unsigned int) addr < 4096)
+ return addr;
+
+ /* Clear least-significant two bits from descriptor address. */
+ desc = (unsigned int *) ((unsigned int) addr & ~3);
+ if (!_dl_read_access_allowed (desc))
+ return addr;
+
+ /* Load first word of candidate descriptor. It should be a pointer
+ with word alignment and point to memory that can be read. */
+ gptr = (unsigned int *) desc[0];
+ if (((unsigned int) gptr & 3) != 0
+ || !_dl_read_access_allowed (gptr))
+ return addr;
+
+ /* See if descriptor requires resolution. The following trampoline is
+ used in each global offset table for function resolution:
+
+ ldw 0(r20),r22
+ bv r0(r22)
+ ldw 4(r20),r21
+ tramp: b,l .-12,r20
+ depwi 0,31,2,r20
+ .word _dl_runtime_resolve
+ .word "_dl_runtime_resolve ltp"
+ got: .word _DYNAMIC
+ .word "struct link map address" */
+ if (gptr[0] == 0xea9f1fdd /* b,l .-12,r20 */
+ && gptr[1] == 0xd6801c1e /* depwi 0,31,2,r20 */
+ && (ElfW(Addr)) gptr[2] == elf_machine_resolve ())
+ _dl_fixup ((struct link_map *) gptr[5], (ElfW(Word)) desc[1]);
+
+ return (ElfW(Addr)) desc[0];
}
Index: glibc-2.22/sysdeps/hppa/dl-lookupcfg.h
===================================================================
--- glibc-2.22.orig/sysdeps/hppa/dl-lookupcfg.h
+++ glibc-2.22/sysdeps/hppa/dl-lookupcfg.h
@@ -31,9 +31,7 @@ rtld_hidden_proto (_dl_symbol_address)
Elf32_Addr _dl_lookup_address (const void *address);
-/* Clear the bottom two bits so generic code can find the fdesc entry */
-#define DL_LOOKUP_ADDRESS(addr) \
- (_dl_lookup_address ((void *)((unsigned long)addr & ~3)))
+#define DL_LOOKUP_ADDRESS(addr) _dl_lookup_address ((const void *) addr)
void attribute_hidden _dl_unmap (struct link_map *map);
Reply to: