Connecting lldb-server to GDB

Hi,
Has anyone recently tried to connect lldb-server to GDB (client)?

Please, find the output of my try below.

Target:

$ lldb-server g localhost:1234 ./m
Launched './m' as process 605331...
lldb-server-local_build
Connection established.
lldb-server exiting...

Host:

$ gdb ./m
GNU gdb (GDB) 13.0.50.20221214-git
(gdb) target remote localhost:1234
Remote debugging using localhost:1234
warning: while parsing target description (at line 1): Target description specified unknown architecture "x86_64"
warning: Could not load XML target description; ignoring
Remote register badly formatted: T13thread:93c93;name:m;00:0000000000000000;01:0000000000000000;02:0000000000000000;03:0000000000000000;04:0000000000000000;05:0000000000000000;06:0000000000000000;07:d0d6ffffff7f0000;08:0000000000000000;09:0000000000000000;0a:0000000000000000;0b:0000000000000000;0c:0000000000000000;0d:0000000000000000;0e:0000000000000000;0f:0000000000000000;10:e04fddf7ff7f0000;11:0002000000000000;12:3300000000000000;13:0000000000000000;14:0000000000000000;15:2b00000000000000;16:0000000000000000;17:0000000000000000;reason:signal;
here: 00000000;12:3300000000000000;13:0000000000000000;14:0000000000000000;15:2b00000000000000;16:0000000000000000;17:0000000000000000;reason:signal;

Although both sides comply with GDB Remote Serial Protocol, the session breaks on ‘T’ packet. The actual problem is in General Purpose Register ID numbers (regnum), order and sizes, which are not determined by standard, but LLDB and GDB have different expectations.

Please, find the table below with differences in register info.

Register GDB LLDB
$rsi bitsize=64 regnum=4 bitsize=64 regnum=5
$rdi bitsize=64 regnum=5 bitsize=64 regnum=4
$eflags ($rflags in LLDB) bitsize=32 regnum=17 bitsize=64 regnum=17
$cs bitsize=32 regnum=18 bitsize=64 regnum=18
$ss bitsize=32 regnum=19 bitsize=64 regnum=21
$ds bitsize=32 regnum=20 bitsize=64 regnum=22
$es bitsize=32 regnum=21 bitsize=64 regnum=23
$fs bitsize=32 regnum=22 bitsize=64 regnum=19
$gs bitsize=32 regnum=23 bitsize=64 regnum=20

With a workaround in lldb-server, to send registers in ‘T’ packet as GDB expects, I am able to establish communication between GDB and lldb-server, and perform a basic debugging of a simple test case (break, info registers, print vars…). On the other hand, this doesn’t break lldb-server working with lldb (client).

My question is, does anyone know, why those “regnum” and “bitsize” for GPRs are picked (different from GDB) at the first place?
I suppose there are some other incompatibilities that prevent lldb-server and GDB from working together, so does anyone have an idea, how hard it would be to make them fully compatible?

I am sorry if I retriggered already discussed matter or if I missed something, since I don’t have much experience with LLDB.

Thanks,
Nikola

The target xml file, which contains the register list, isn’t handled by gdb, so gdb is using its internal register definition instead of the one published by lldb-server. The file is specifying “x86_64” as the architecture, but gdb doesn’t like that string. To fix this you’ll either need to modify gdb to handle x86_64 as an architecture string, or modify lldb’s target xml file to be parsable by gdb.

I think the question is which description is closer to reality; what lldb defines or what gdb defines? In my opinion, lldb is a better place to modify.

Thanks for the comment @tedwoodward!
To my understanding, GDB uses target description XML to compare the info to its internal target definitions, so at the end it just selects one of the predefined architectures. It is not only target architecture string that is problematic, other parts of the XML are not matching. So, the approach could be either to add “LLDB-like x86-64” architecture definition in GDB, or to make LLDB’s x86-64 have the same description as GDB’s. I was interested in changing only LLVM part of the toolchain, so I will investigate this further. Thanks anyways!

A long time ago, gdb and the remote stub (lldb-server, here) needed to be in agreement about the register numbers and sizes (and offsets). The target.xml file was designed so that the remote stub can tell gdb/lldb what registers it can provide, what numbers it will use for them, and their sizes. The target.xml can also provide an architecture name to help set up the debugging session correctly (a starting triple, probably).

I don’t know if gdb still insists on the remote stub & its register numbers/sizes/offsets must be in agreement, or if it can use the information in the target.xml to set these. It seems like surely it would do this, but I haven’t looked. We designed lldb from the beginning to learn the register information from the remote stub and not make assumptions, because that “register set version lock” was such an annoying source of problems.

This debug session starts with

warning: while parsing target description (at line 1): Target description specified unknown architecture "x86_64"
warning: Could not load XML target description; ignoring

Did lldb-server print something like <architecture>x86_64</architecture> where gdb wants something like i386:x86-64? ProcessGDBRemote should handle the latter iirc, so lldb-server could switch to that.

As for having the same register numbers/sizes, there’s nothing special about the register number ordering that lldb-server provides. I’m sure it’s whatever random order they come up with in some register definition table in lldb. That can be reordered to fit gdb’s whims if it really can’t learn register numbers from a properly formatted target.xml file. But I’m betting if lldb-server sent a target.xml with an archtiecture name that gdb didn’t reject, the rest is going to fall into place.

I haven’t worked on intel in a while, but I think lldb-server’s register sizes here are correct for a 64-bit intel process. I’m guessing “eflags” would indicate a 32-bit intel process and you’re looking at a 64-bit intel process where rflags is passed, and the sizes of these other registers are larger as well. You might have been looking at the wrong table for gdb when you wrote up that summary.

Anyway tl;dr, I’d start by looking at what architecture name lldb-server is sending in the target.xml and what gdb wants to see. I don’t know how to get gdb to show you the packets it’s sending/receiving, but I’m sure there’s a way to do it. In lldb I’d do log enable gdb-remote packets before I start the debug session.

Hi @jasonmolenda ,
Thanks for your comments!

As I understood GDB’s implementation, it uses target description XML from debugserver to recognize one of the supported architectures. Then it just selects one of the predefined target descriptions, which, for x86-64, does not match the lldb-server’s, because of the register order, regnums and sizes. Also, to my understanding, for GDB, XML target description files are converted into C code and then built, so it seems that target description cannot be dynamically determined based on the debugserver (in the runtime).

I’ve tried to update the architecture string from “x86_64” to “i386:x86-64”, but that is just one of many fields in the target description XML that are not matching between LLDB and GDB. What I see in the generated XML target descriptions is that LLDB uses one <feature> field containing all registers, and GDB uses multiple <feature> fields for different groups of registers. Based on the 64bit-core.xml,GDB expects 32bit segment and flags registers for x86-64 architecture.

My conclusion is, at this point, that either LLDB should completely comply with GDB’s expectations, or we can create a parallel target description files in GDB for “LLDB’s configuration of x86-64”.