Re: time to workaround libc/13097 in fsf gdb?

Pedro Alves
2014-09-21T19:12:31Z

On 09/20/2014 10:30 PM, Jan Kratochvil wrote:
> On Fri, 19 Sep 2014 16:41:34 +0200, Pedro Alves wrote:
>> Here it is. WDYT?
> [...]
>> --- a/gdb/solib-svr4.c
>> +++ b/gdb/solib-svr4.c
> [...]
>> @@ -1478,6 +1479,42 @@ svr4_current_sos (void)
>> return svr4_current_sos_direct (info);
>> }
>>
>> +/* Implement the "current_sos" target_so_ops method. */
>> +
>> +static struct so_list *
>> +svr4_current_sos (void)
>> +{
>> + struct so_list *so_head = svr4_current_sos_1 ();
>> + struct objfile *objfile;
>> + struct obj_section *osect;
>> + CORE_ADDR vsyscall_addr = gdbarch_vsyscall_address (target_gdbarch ());
>> +
>> + /* Filter out the vDSO module, if present. Its symbol file would
>> + not be found on disk. The vDSO/vsyscall's OBJFILE is instead
>> + managed by symfile-mem.c:add_vsyscall_page. */
>> + if (vsyscall_addr != 0)
>> + {
>> + struct so_list **sop;
>> +
>> + sop = &so_head;
>> + while (*sop != NULL)
>> + {
>> + struct so_list *so = *sop;
>> +
>> + if (so->lm_info->l_addr_inferior == vsyscall_addr)
>
> This won't work as l_addr_inferior (and also l_addr) do not necessarily
> represent the real starting address of the ELF if the ELF itself is
> "prelinked". For some reason vDSOs on some kernels look like prelinked.
>
> kernel-3.16.2-200.fc20.x86_64 appears sane, vDSO is 0-based.
>
> But for example kernel-2.6.32-220.el6.x86_64 is "prelinked", see below.

Ah, didn't know that. That's the sort of thing we should have in
comments in the code, or at least in the commit log.

> That's the pain of solib-svr4.c which is OS-agnostic and so it cannot find out
> start of the ELF file just from link map. gdbserver can find it as it can
> depend on /proc/PID/{s,}maps as its linux-low.c is Linux-specific.

Is it really a pain though? We can just put things behind gdbarch hooks,
like my patch was doing. In fact, symfile-mem.c is already looking
at /proc/PID/maps to find the vdso mapping size. That's exactly done
behind a gdbarch hook:

args.size = 0;
if (gdbarch_find_memory_regions_p (target_gdbarch ()))
(void) gdbarch_find_memory_regions (target_gdbarch (),
find_vdso_size, &args);

>
> kernel-2.6.32-220.el6.x86_64
> (gdb) p *_r_debug.r_map.l_next
> $4 = {l_addr = 140737363566592, l_name = 0x3deba1ade4 "", l_ld = 0x7ffff7ffe580, l_next = 0x7ffff7ffd658, l_prev = 0x3debc21188}
> (gdb) p/x *_r_debug.r_map.l_next
> $5 = {l_addr = 0x7ffff88fe000, l_name = 0x3deba1ade4, l_ld = 0x7ffff7ffe580, l_next = 0x7ffff7ffd658, l_prev = 0x3debc21188}
> # (gdb) p/x *new.lm_info
> # $5 = {l_addr = 0x0, l_addr_inferior = 0x7ffff88fe000, l_addr_p = 0x0, lm_addr = 0x3debc21718, l_ld = 0x7ffff7ffe580, l_next = 0x7ffff7ffd658, l_prev = 0x3debc21188, l_name = 0x3deba1ade4}
> (gdb) info auxv
> 33 AT_SYSINFO_EHDR System-supplied DSO's ELF header 0x7ffff7ffe000
> (gdb) info proc mappings
> 0x7ffff7ffe000 0x7ffff7fff000 0x1000 0 [vdso]

Sounds like a predicate like this would work then?

if (vsyscall_start <= so->lm_info->l_ld && so->lm_info->l_ld < vsyscall_end)

We would move the bit that finds the vdso size to the gdbarch_vsyscall_address hook,
and make that new hook return the vsyscall's size too in addition to
the starting address. We can also cache the result somewhere instead
of constantly reopening /proc/PID/maps if necessary.

We can also add a custom linux-specific target_so_ops implementation that
extends svr4's if we want. The target_so_ops to use is also registered
in the gdbarch.

CORE_ADDR vsyscall_start;
CORE_ADDR vsyscall_end;

vsyscall_start = gdbarch_vsyscall_address (target_gdbarch (), &vsyscall_end);

/* Filter out the vDSO module, if present. Its symbol file would
not be found on disk. The vDSO/vsyscall's OBJFILE is instead
managed by symfile-mem.c:add_vsyscall_page. */
if (vsyscall_start != 0)
{
struct so_list **sop;

sop = &so_head;
while (*sop != NULL)
{
struct so_list *so = *sop;

if (vsyscall_start <= so->lm_info->l_ld
&& so->lm_info->l_ld < vsyscall_end)
{
... found vdso ...

> (gdb) dump memory vdso.bin 0x7ffff7ffe000 0x7ffff7fff000
> # readelf -Wa vdso.bin
> [...]
> Entry point address: 0xffffffffff700700
> [...]
> Section Headers:
> [Nr] Name Type Address Off Size ES Flg Lk Inf Al
> [ 0] NULL 0000000000000000 000000 000000 00 0 0 0
> [ 1] .hash HASH ffffffffff700120 000120 000038 04 A 2 0 8
> [ 2] .dynsym DYNSYM ffffffffff700158 000158 0000d8 18 A 3 2 8
> [...]
> [ 9] .dynamic DYNAMIC ffffffffff700580 000580 0000f0 10 WA 3 0 8

Thanks,
Pedro Alves