Increasing support for other gdbservers

Hi Folks,

I would like to add better support for gdbserver from the gnu toolchain and similar legacy gdb stubs in lldb.
The work going into lldb-gdbserver is great but it is not always a possible to change the remote gdb stub, and there are so many tools and devices with older gdb stubs in them.

It seems like process gdb-remote has moved hand in hand with lldb-gdbserver away from gnu gdbservers RSP protocol.

Does anyone have an suggestions when it comes to adding lldb support for traditional gdbservers?

There seems like two obvious approaches; extend gdb-remote or create a gdb-legacy plugin.
To my mind the second approach may be cleaner, and a large amount of common code could be shared between the two.

Another approach would be to incorporate a plugin system into gdb-remote to ease the addition of new packets and handling routines.

I am interested to hear thoughts, suggestions and feedback on this topic.

Thanks,
Aidan

The problem is with GDB remote, the GDB and the GDB server must be built together and for each other. A single version of GDB is mated to a GDB server and things can't change. LLDB supports all architectures and any target, not just one at a time. And we certainly don't expect our GDB server binaries to always be in perfect sync with our LLDB. To get around this we added many packets to the GDB remote protocol to allow getting host info for what we are attaching to (triple, OS, vendor, etc), process info (architecture, pointer size, endian etc), register info (define all registers so that LLDB can dynamically figure out what registers are available and how they map to debug info and runtime info (register numbering mappings), and more.

We support GDB servers that don't support all the added LLDB specific packets by allowing users to specify a "target definition" python file in the settings:

(lldb) settings set plugin.process.gdb-remote.target-definition-file /path/to/target/defnition/foo.py

There are examples checked in:

svn cat http://llvm.org/svn/llvm-project/lldb/trunk/examples/python/x86_64_linux_target_definition.py
svn cat http://llvm.org/svn/llvm-project/lldb/trunk/examples/python/x86_64_qemu_target_definition.py
svn cat http://llvm.org/svn/llvm-project/lldb/trunk/examples/python/x86_64_target_definition.py

Then when we connect to a GDB server that doesn't support the extra packets or the register definitions, we can fall back onto the currently selected target definition file.

Typically what you want to start with is doing a:

(gdb) maint print raw-registers

In the GDB that supports hooking up to your GDB remote so you can see exactly what the register context should look like. You can then use this information to fill out a target definition file that you can use. If you do end up making any target definition files, please check the "examples/python" directory to make sure one doesn't already exists, and check it in with a very descriptive name so others can then use this. Feel free to add as many comments and you can in the python file to let people know what GDB server that your stuff will work with.

Let me know if you have any other questions.

Greg

Greg Clayton wrote:

> I would like to add better support for gdbserver from the gnu
> toolchain and similar legacy gdb stubs in lldb. The work going
> into lldb-gdbserver is great but it is not always a possible to
> change the remote gdb stub, and there are so many tools and
> devices with older gdb stubs in them.
>
> It seems like process gdb-remote has moved hand in hand with
> lldb-gdbserver away from gnu gdbservers RSP protocol.
>
> Does anyone have an suggestions when it comes to adding lldb
> support for traditional gdbservers?
>
> There seems like two obvious approaches; extend gdb-remote or
> create a gdb-legacy plugin. To my mind the second approach may be
> cleaner, and a large amount of common code could be shared between
> the two.
>
> Another approach would be to incorporate a plugin system into
> gdb-remote to ease the addition of new packets and handling
> routines.
>
> I am interested to hear thoughts, suggestions and feedback on this
> topic.

The problem is with GDB remote, the GDB and the GDB server must be
built together and for each other. A single version of GDB is mated
to a GDB server and things can't change.

Not true. Any version of GDB can work with anything that implements
the protocol. Each side indicates to the other the features it
supports, and both sides are abide by the limitations of the other.

LLDB supports all architectures and any target, not just one at a
time. And we certainly don't expect our GDB server binaries to
always be in perfect sync with our LLDB. To get around this we added
many packets to the GDB remote protocol to allow getting host info
for what we are attaching to (triple, OS, vendor, etc), process info
(architecture, pointer size, endian etc), register info (define all
registers so that LLDB can dynamically figure out what registers are
available and how they map to debug info and runtime info (register
numbering mappings), and more.

Any version of GDB can talk to anything that implements the protocol.
You can run GDB on S/390 Linux and connect to a gdbserver running on
Windows. Or vice versa. The remote side sends all these details to
GDB on request. Don't believe me? Try a simple case with protocol
debugging switched on and watch what goes over the wire:

  bash$ gdb /bin/ls
  (gdb) set debug remote 1
  (gdb) target remote | gdbserver - /bin/ls
  
You'll see something like this:

  Sending packet: $qSupported:multiprocess+;swbreak+;hwbreak+;xmlRegisters=i386;qRelocInsn+#54
  Packet received: PacketSize=3fff;QPassSignals+;QProgramSignals+;qXfer:libraries-svr4:read+;augmented-libraries-svr4-read+;qXfer:auxv:read+;qXfer:spu:read+;qXfer:spu:write+;qXfer:siginfo:read+;qXfer:siginfo:write+;qXfer:features:read+;QStartNoAckMode+;qXfer:osdata:read+;multiprocess+;QNonStop+;QDisableRandomization+;qXfer:threads:read+;ConditionalTracepoints+;TraceStateVariables+;TracepointSource+;DisconnectedTracing+;FastTracepoints+;StaticTracepoints+;InstallInTrace+;qXfer:statictrace:read+;qXfer:traceframe-info:read+;EnableDisableTracepoints+;QTBuffer:size+;tracenz+;ConditionalBreakpoints+;BreakpointCommands+;QAgent+;swbreak+;hwbreak+

That's both sides informing the other what protocol features they
support. A little further down you'll see something like this:

  Sending packet: $qXfer:features:read:target.xml:0,fff#7d...Packet received: l<?xml version="1.0"?>\n<!-- Copyright (C) 2010-2015 Free Software Foundation, Inc.\n\n Copying and distribution of this file, with or without modification,\n are permitted in any medium without royalty provided the copyright\n notice and this notice are preserved. -->\n\n<!-- AMD64 with AVX - Includes Linux-only special "register". -->\n\n<!DOCTYPE target SYSTEM "gdb-target.dtd">\n<target>\n <architecture>i386:x86-64</architecture>\n <osabi>GNU/Linux</osabi>\n <xi:include href="64bit-core.xml"/>\n <xi:include href="64bit-sse.xml"/>\n <xi:include href="64bit-linux.xml"/>\n <xi:include href="64bit-avx.xml"/>\n</target>\n
  Sending packet: $qXfer:features:read:64bit-core.xml:0,fff#75...Packet received: l<?xml version="1.0"?>\n<!-- Copyright (C) 2010-2015 Free Software Foundation, Inc.\n\n Copying and distribution of this file, with or without modification,\n are permitted in any medium without royalty provided the copyright\n notice and this notice are preserved. -->\n\n<!DOCTYPE feature SYSTEM "gdb-target.dtd">\n<feature name="org.gnu.gdb.i386.core">\n <flags id="i386_eflags" size="4">\n <field name="CF" start="0" end="0"/>\n <field name="" start="1" end="1"/>\n <field name="PF" start="2" end="2"/>\n <field name="AF" start="4" end="4"/>\n <field name="ZF" start="6" end="6"/>\n <field name="SF" start="7" end="7"/>\n <field name="TF" start="8" end="8"/>\n <field name="IF" start="9" end="9"/>\n <field name="DF" start="10" end="10"/>\n <field name="OF" start="11" end="11"/>\n <field name="NT" start="14" end="14"/>\n <field name="RF" start="16" end="16"/>\n <field name="VM" start="17" end="17"/>\n <field name="AC" start="18" end="18"/>\n <field name="VIF" start="19" end="19"/>\n <field name="VIP" start="20" end="20"/>\n <field name="ID" start="21" end="21"/>\n </flags>\n\n <reg name="rax" bitsize="64" type="int64"/>\n <reg name="rbx" bitsize="64" type="int64"/>\n <reg name="rcx" bitsize="64" type="int64"/>\n <reg name="rdx" bitsize="64" type="int64"/>...

Is something you are talking about not right there?

Cheers,
Gary

Yes I was going to point this out also. A lot of information can be obtained through the $qXfer: packets, such as register mappings via $qXfer:features:read:target.xml and associated .xml's that LLDB
currently doesn't make use of. Support for these types of features could bring gdbserver compatibility a long way, avoiding pre-canned compatibility scripts.

The reasons for originally asking is that we have had to add various degrees of gdbserver compatibility to lldb a number of times and it is something that really should be well supported upstream. The problem is doing it in such a way that fits nicely alongside existing plugins.

So GDB now supports all architectures and all OS variants in a single binary? ARM + x86_64 + i386 + MIPs + PPC for linux, darwin, Windows etc? The last time I worked with GDB, which was pre GPLv3, each GDB was compiled for a specific architecture (or closely related architectures) and a single OS. This is what I meant about LLDB handling all architectures and OS variants from the same LLDB. If GDB has changed that much since I have last looked at it I am very happy to hear that.

I know about the register numbering stuff and I would love to see support for the "$qXfer:features:" added to LLDB. The one thing this data doesn't contain is the register numbers for the ABI (DWARF register numbers (for debug info), compiler register numbers (for like .eh_frame)), but that info could be inferred from an ABI plugin that we could infer from the "osabi" of "GNU/Linux" in the target.xml:

<!DOCTYPE target SYSTEM "gdb-target.dtd">
<target>
  <architecture>i386:x86-64</architecture>
  <osabi>GNU/Linux</osabi>
  <xi:include href="64bit-core.xml"/>
  <xi:include href="64bit-sse.xml"/>
  <xi:include href="64bit-linux.xml"/>
  <xi:include href="64bit-avx.xml"/>
</target>

So please do submit patches that implement this and we will be happy to approve them.

Greg Clayton wrote:

So GDB now supports all architectures and all OS variants in a
single binary? ARM + x86_64 + i386 + MIPs + PPC for linux, darwin,
Windows etc? The last time I worked with GDB, which was pre GPLv3,
each GDB was compiled for a specific architecture (or closely
related architectures) and a single OS. This is what I meant about
LLDB handling all architectures and OS variants from the same
LLDB. If GDB has changed that much since I have last looked at it I
am very happy to hear that.

Ah, that was a while ago, some things have changed :slight_smile: Since about
seven years ago you can configure GDB with --enable-targets=all (or
some subset that you're interested in). It's not the default, it
takes longer to build, but if you do build like that it should work.

I know about the register numbering stuff and I would love to see
support for the "$qXfer:features:" added to LLDB. The one thing this
data doesn't contain is the register numbers for the ABI (DWARF
register numbers (for debug info), compiler register numbers (for
like .eh_frame)), but that info could be inferred from an ABI plugin
that we could infer from the "osabi" of "GNU/Linux" in the
target.xml:

<!DOCTYPE target SYSTEM "gdb-target.dtd">
<target>
  <architecture>i386:x86-64</architecture>
  <osabi>GNU/Linux</osabi>
  <xi:include href="64bit-core.xml"/>
  <xi:include href="64bit-sse.xml"/>
  <xi:include href="64bit-linux.xml"/>
  <xi:include href="64bit-avx.xml"/>
</target>

I see that some of GDB's features files have "regnum" fields on the
registers, maybe the ones without just count up? I have to admit that
I've not done any work on GDB at the register level and my knowledge
of DWARF is such that I know what it is and what it's for but that's
all, so I am guessing here.

So please do submit patches that implement this and we will be happy
to approve them.

I've worked on GDB, so any code I write is likely tainted from a
licensing standpoint. I can make suggestions though.

I know that the different licenses block a lot of cooperation between
the LLDB and GDB communities, but for things like the gdbserver
protocol we could perhaps cooperate through the protocol documentation
in gdb/doc/gdb.texinfo. That's licensed under GNU FDL, not GPLv3.

Cheers,
Gary

> I know about the register numbering stuff and I would love to see support for the "$qXfer:features:" added to LLDB. The one thing this data doesn't contain is the register numbers for the ABI (DWARF register numbers (for debug info), compiler register numbers (for like .eh_frame)), but that info could be inferred from an ABI plugin that we could infer from the "osabi" of "GNU/Linux" in the target.xml:

>
> So please do submit patches that implement this and we will be happy to approve them.

I am currently prototyping $qXfer:features support in LLDB with an aim to upstream it. It will require an XML parser, so I wanted to have a discussion about adding one to LLDB.

I have been using TinyXML2 in my prototype, which is open sourced under the ZLib license. Is there any policy in LLDB for handling external library dependencies?
Would there be objections to TinyXML2 making its way into the LLDB code base as an external? Writing a new XML parser from scratch in LLDB isn't ideal.

I would still like to have a discussion about adding a plugin architecture to gdb-remote making it easier to handle packets outwith the LLDB based servers. The code in gdb-remote that sends and handles packets is scattered over one or two huge classes, it would be beneficial to start looking at breaking this up and modularizing it. At least for the packets which are not supported by lldb's own RSP producers.

Hi Aidan,
+1 for this work. Please note that I did some work on making lldb understand
the xml description that came from target. Although it was not committed but
it may prove helpful to you.

http://lists.cs.uiuc.edu/pipermail/lldb-dev/2013-October/002510.html

Regards,
Abid

Thanks for the link Abid, I'll have a look over that just now.

>
> I know about the register numbering stuff and I would love to see support for the "$qXfer:features:" added to LLDB. The one thing this data doesn't contain is the register numbers for the ABI (DWARF register numbers (for debug info), compiler register numbers (for like .eh_frame)), but that info could be inferred from an ABI plugin that we could infer from the "osabi" of "GNU/Linux" in the target.xml:

>
> So please do submit patches that implement this and we will be happy to approve them.

I am currently prototyping $qXfer:features support in LLDB with an aim to upstream it. It will require an XML parser, so I wanted to have a discussion about adding one to LLDB.

Most unix variants have libxml2 that is available. I am not sure on windows though. I have CC'ed Zachary to get some input on windows XML (in case LLVM doesn't already have some support for this).

I have been using TinyXML2 in my prototype, which is open sourced under the ZLib license. Is there any policy in LLDB for handling external library dependencies?
Would there be objections to TinyXML2 making its way into the LLDB code base as an external? Writing a new XML parser from scratch in LLDB isn't ideal.

It would be great to stick with stuff that everyone has installed and hopefully that is libxml2. Windows is the biggest question. I am also not sure if llvm or clang has any XML support, but we should first look to see if llvm has XML support and if not, then look for alternatives. We definitely do not want to write our own.

I would still like to have a discussion about adding a plugin architecture to gdb-remote making it easier to handle packets outwith the LLDB based servers. The code in gdb-remote that sends and handles packets is scattered over one or two huge classes, it would be beneficial to start looking at breaking this up and modularizing it. At least for the packets which are not supported by lldb's own RSP producers.

I say just build all and any support it into GDBRemoteCommunicationClient and GDBRemoteCommunicationServer. I don't see the need to break it up.

Greg Clayton

A good rule of thumb for anything is that “Windows doesn’t have it” and that holds true for libxml2 as well. It appears that libxml2 does support Windows though (http://xmlsoft.org/downloads.html), it just isn’t something that’s there by default. It would be nice if everyone were using the same thing, could we clone this repo in our own repo and then just build it ourselves as part of the build process. The license looks very permissive, but IANAL.

There’s already some stuff in the CMake to try to find libxml, but it’s behind a Darwin specific branch in the CMake. So I think what would need to happen is that we move this into a platform agnostic codepath, and then set a define like LLDB_HAVE_LIBXML2 in the code to a value that indicates whether it is present (search clang for CLANG_HAVE_LIBXML in . to see how this is done). Then, in the code, we would need to put xml code behind a check for this define.

I noticed that use in cmake also. FWIW, my primary LLDB platform is Windows, which is why we were using TinyXML2 for ease of prototyping. If libxml2 works on all the targets we will use it - I do worry about the usual issues you get with windows prebuilts. So source may still be required. We'll look into it.

Colin

I really don’t want LLDB to embed a copy of libxml2. I think we should build it externally and reference it from LLDB. Systems with package managers can get this trivially. Windows can download and build all dependencies with one script.

As long as it’s possible to build lldb without it I’m fine with whatever, including downloading it separately, building it, and referencing it externally. But I don’t want it to be a forced dependency.

I hate ifdefs, especially the ones that we’ve added to the code. I would hate to see any others go in. It’s our plan for example to remove ifdefs that we have added .

fwiw on Mac OS X we use libxml2 over in Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp. That plugin's initialization is #ifdef __APPLE__ over in SystemInitializerFull.cpp; we don't have ifdef guard around the use of libxml2 in SymbolVendorMacOSX itself.

I hate them too. The amount of effort I spent removing them from Host (even though there’s still some there) is a testament to that. But we already have enough external dependencies on Windows as is (building Python is already a huge chore, for example), and adding more to the mix is kind of a blocking issue for me unless it’s for really critical functionality. Windows is in the unfortunate position of it being a pain to build most open source libraries. I don’t want to make it even harder for people to build LLDB on Windows just because of an xml library.

Also, it should be possible to do this in a way that doesn’t require lots of ifdefs. Just create a stub xml parser implementation that has the same interface as whatever the one in libxml2 is, and contain all the ifdefs there. have the stub return an error on creation. Then calling code can just error out if it tries to parse xml and gets an error.

I think uses of it would only need to be guarded if we plan to use it in generic code. So yea, if all the code that uses it goes into a file that isn’t compiled on windows anyway, then the problem becomes very simple