Re: gdb support for Linux vsyscall DSO

Mark Kettenis
2003-05-11T23:14:33Z

Date: Sat, 10 May 2003 13:27:20 -0700
From: Roland McGrath <roland@redhat.com>

> The run-time dynamic linker's data structures usually are intact, but
> a fall-back mechanism wouldn't hurt I guess.

The stack is usually intact too. ;-) It would not be the end of the world
to rely on the dynamic linker's data structures. In practice, they are
intact and people don't use the vsyscall entrypoint in statically linked
programs. But I would rather consider *that* the fallback to be used in
remote situations where the kernel inquiry mechanism isn't available. If
there is a kernel inquiry mechanism, it will always be correct. If there
are dynamic linker data structures at all, they might be bogus so you don't
want to use them preferentially.

Careless thinking of me; of course one should prefer the most reliable
method. I fully agree with you here.

> Note that symbols from the vsyscall would be very helpful to the user.

Surely. But lack thereof doesn't cripple the user the way failure to
unwind the frame does, so it's not the highest priority. That's all I said.

> There is also an issue with signal trampolines. GDB needs to be able
> to recognize them in order to support stepping over functions when a
> signal arrives.

I don't think I know exactly what you mean here. Is there a special case
for signal frames aside from just knowing how to unwind them properly?
(The only other specialness I am aware of is "<signal handler called>",
which with normal unwind info would show __kernel_sigreturn instead.)

There is some special handling for signal trampolines in
infrun.c:handle_inferior_event(). Beware! Dragons can still be found
in that function. However, it seems the bit of code I'm talking about
is there for targets that don't known how to properly unwind signal
frames :-).

There is also the issue of unwinding interrupted frames vs. called
frames, where we substract 1 from the return address to get an address
in the middle of the call instruction that is in progress. But rth
has taken care of that.

> I proposed Richard Henderson to add a special DWARF CFI augmentation to
> mark __kernel_sigreturn and __kernel_rt_sigreturn as signal trampolines.
> That would allow me to recognize them without knowing their names.

The code I have seen looks at the instruction sequence to match the
expected system call (using "int $0x80"). All extant Linux kernels still
have those same exact instruction sequences (as libc's __restore and
__restore_rt). So this will continue to work, ugly as it is. Not that we
shouldn't address it more cleanly, but I don't think it's in fact breaking
anything at this very moment.

rth has added unwind info to the __kernel_{rt_,}sigreturn vsyscall code.
These describe unwinding the signal frame to restore all the registers to
the state that was interrupted by the signal (though not the processor
flags word, I dunno if i386 DWARF2 format can do that--you'd only need that
if you wanted to roll back the signal handling frame as if it had never
happened at all, not just to unwind past it or examine the frame's state).

Restoring %eflags is certainly possible. Making GDB actually pop the
signal trampoline frame should work, but could lead to "interesting"
behaviour. I mean, the kernel will still think the program has taken
a signal. Hmm, looking at both the FreeBSD and Linux kernels it seems
as if only the signal mask might be incorrect.

> Relying on the dynamic linker's data structures certainly seems
> attractive to me as an additional method since it works independently
> of the remote protocol.

Agreed. I was vaguely hoping that someone would have a brilliant idea
that is both remote-friendly and as robust as the kernel-specific
backend solutions, but I don't think there is one possible.

Well, for processes started by GDB we can read the auxiliary vector
from the pristine stack, but that doesn't work for attached-to
processes.

> To avoid kludging around one could:

These are the obvious suggestions. I am very hesitant to change
the exposed structures; frankly, those two will probably never
change again. The dynamic tag would be a convenient one, but would
require an ld change and to be sure your kernel was built by a new
enough ld; that is impractical.

Well, extending the structure shouldn't pose a problem, although there
is some risk. The origional link.h contained the following comment:

/* Structure describing...

...

This data structure might change in future, if necessary. User-level
programs must avoid defining objects of this type. */

But those last two sentences have been removed from the link.h that's
actually installed.

Exposing some way to get the l_phdr pointer is very reasonable. An
idea that doesn't raise many of the issues of changing the public
`struct link_map' layout is export an internal symbol giving
offsetof (struct link_map, l_phdr). That is still sort of a kludge
if you ask me. But it shouldn't cause many problems in practice.

Given that we know where the dynamic section is from l_ld, I think we
can figure out all we need to know from there. I used the linker
script from Linux 2.5.69 to generate a vsyscall-int80.so, and I'm
seeing the location of all relevant sections in the symbol table. Is
it possible to re-order the sections such that .dynamic comes a bit
earlier than now? In that case (l_ld & 0xfffff000) would almost
certainly be the address of the ELF header.

Mark