Page MenuHomePhabricator

[lldb/gdb-remote] Add support for the qOffsets packet
Needs ReviewPublic

Authored by labath on Fri, Feb 14, 2:39 AM.

Details

Summary

This packet is necessary to make lldb work with the remote-gdb stub in
user mode qemu when running position-independent binaries. It reports
the relative position (load bias) of the loaded executable wrt. the
addresses in the file itself.

Lldb needs to know this information in order to correctly set the load
address of the executable. Normally, lldb would be able to find this out
on its own by following the breadcrumbs in the process auxiliary vector,
but we can't do this here because qemu does not support the
qXfer:auxv:read packet.

This patch does not implement full scope of the qOffsets packet (which
supports having different biases for code, data and bss sections). This
is because the relevant lldb interfaces (e.g., Module::SetLoadAddress)
do not support passing different values for different sections, and it's
not clear how would such a thing apply to typicall object files. And
qemu will always
(https://github.com/qemu/qemu/blob/master/linux-user/elfload.c#L2436)
return the same value for code and data offsets. In fact, even gdb
ignores the offset for the bss sections, and uses the "data" offset
instead. So, until the we need more of this packet, I think it's best
to stick to the simplest solution possible. This patch simply rejects
replies with non-uniform offsets.

Event Timeline

labath created this revision.Fri, Feb 14, 2:39 AM
Herald added a project: Restricted Project. · View Herald TranscriptFri, Feb 14, 2:39 AM

This patch does not implement full scope of the qOffsets packet (which supports having different biases for code, data and bss sections). This is because the relevant lldb interfaces (e.g., Module::SetLoadAddress) do not support passing different values for different sections, and it's not clear how would such a thing apply to typical object files.

While Module::SetLoadAddress doesn't, the Target interfaces do in fact support this fully. You specify the section and the section load address. Look at the macOS dynamic loader, it does this. All shared libraries in the macOS dyld shared cache have all the the TEXT segments put next to each other so that the OS can load one large read + execute mapping, all the modifiable data sections in DATA are relocated as well along with other segments. The Module::SetLoadAddress() interface was put in Module to make it easy to slide full binaries.

lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
3552

Too a bit to understand what this was doing. Might be worth a comment here or in the header that says something like:

We only handle offsets where all sections in a file are offset by the same amount. If any sections is slid by a different amount, we return no value.
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
428

Might be nice to document that we only handle when a binary has all its sections slid by the same amount somewhere.

429

It would be nice to have two functions here:
1 - "llvm::SmallVector<llvm::StringRef> GetQOffsets();" which will return raw qOffsets calls results
2 - "llvm::Optional<lldb::addr_t> GetExecutableOffset();" which calls above function and then does it thing where it tries to get a single rigid slide for the entire executable binary or fails.

lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
1116

We could fall back eventually to try and parse the full results of qOffsets directly here and try to slide. Doesn't need to be done now, but a TODO comment might be nice.