LLDB Ada support on Apple M2 (Could not find type system for language ada83)

Hi, I’m using macOS Ventura 13.4.1 on an Apple M2 with VSCode 8.11 and lldb-1403.0.17.67.

I’m trying to debug a basic Ada program built for x86_64:

$ file .objs/hello_world
.objs/hello_world: Mach-O 64-bit executable x86_64

I set a breakpoint in hello_world.adb and attempted to debug the program. The debugging session starts correctly, and I can step through the code. However, I’m unable to inspect the value of any variable.

Here’s the error message I receive:

Could not find type system for language ada83: typesystem for language ada83 doesn't exist

For example:

lldb -o "breakpoint set -f  hello_world.adb -l 15" -o "run" -o "e Text" /opt/adatutorial/.objs/hello_world
(lldb) target create "/opt/adatutorial/.objs/hello_world"
Current executable set to '/opt/adatutorial/.objs/hello_world' (x86_64).
(lldb) breakpoint set -f  hello_world.adb -l 15
Breakpoint 1: where = hello_world`_ada_hello_world + 115, address = 0x0000000100000e29
(lldb) run
warning: libobjc.A.dylib is being read from process memory. This indicates that LLDB could not read from the host's in-memory shared cache. This will likely reduce debugging performance.

Hello Ada World!!
warning: This version of LLDB has no plugin for the language "ada83". Inspection of frame variables will be limited.
Process 16399 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
    frame #0: 0x0000000100000e29 hello_world`_ada_hello_world at hello_world.adb:15:4
   12  	begin
   13  	   Print(Text);
   14  	   Text := "xxxxx Ada World!!";
-> 15  	   Print(Text);
   16  	end Hello_World;
Target 0: (hello_world) stopped.
Process 16399 launched: '/opt/adatutorial/.objs/hello_world' (x86_64)
(lldb) e Text
error: Could not find type system for language ada83: TypeSystem for language ada83 doesn't exist

Is there an LLDB plugin I need to install to support Ada debugging? I’ve searched extensively but haven’t found anything. Any assistance would be greatly appreciated.

We do not have any in tree support for Ada. What you are seeing is almost identical to Golang support except that you at least get an error message :slight_smile:

I do not know off the top of my head what sort of work is involved in developing a language plugin. If you were interested in doing so I guess the starting point is https://github.com/llvm/llvm-project/tree/main/lldb/source/Plugins/Language.

We also had a Go plugin in the distant past, according to Anybody using the Go/Java debugger plugins?. That might be a bit more minimum viable product to learn from, with some API churn since that time.

@JDevlieghere and colleagues have probably done significant work around the Objective C plugin, they might be able to help.

1 Like

The current hack for Rust support in lldb is to tell lldb that Rust is the same as C++, so that at least some expressions work, though many do not. Then the Rust folks have added a handful of data formatters that will get frame var to usefully present the Rust types that aren’t enough like C++ for lldb to comprehend them as C++ types.

This seems to make lldb at least somewhat useful for Rust.

If you want to support Ada for real in lldb, then you need to implement the TypeSystem interfaces for Ada, and you will likely also need a LanguageRuntime for Ada to handle things like “step across dispatch” if Ada does that and “Dynamic Type resolution” - again if that’s a thing in Ada.

You could compare the swift-enabled lldb fork to the non-swift one to get a bit of a sense of what this involves, though that implementation is somewhat more complex that the Ada job would be because of the way swift represents debug information, and because of the tight coupling between the Swift and ObjC languages.

In addition to what David and Jim have already said about adding support for Ada, I’d like to point out that you’re using lldb’s expression evaluation feature to try to get the value in a variable (The command e is just short for the expression command here). In order to do expression evaluation, lldb integrates a portion of a compiler into itself (clang for C/C++/ObjC/ObjC++ and Swift in apple’s fork). Since lldb has no explicit Ada support, this will always fail.

Instead of doing e Text to try to get the value, consider using frame variable Text command (or v Text for short). That should try to get the value based on the DWARF description of it (which I’m assuming you have because that’s the only way LLDB could know you’re dealing with Ada in the first place).

I think you have to at least tell us it’s a supported language before we’ll start parsing the DWARF, IIRC. But that’s the bit where you say “Oh, yeah, Ada is JUST LIKE C++”…

Thanks for the heads up. Yes, I tried several combinations (v, p, po…) to no avail. I have some experience using GDB from the command line, but had never used LLDB before, so I’m still learning.

I’m interested in this hack that provides support for Rust in LLDB.

I’ve searched the “handful of data formatters” and the code of the hack and I’ve found these items:

Is this the hack you were referring to?

Thanks.

You can fix only so much with formatters. The language’s type system must be sufficiently close to C/C++ for LLDB to be able to parse DWARF debug info emitted by the compiler. I know next to nothing about Ada’s debug info, however I know of at least one language construct that has no analogues in C++: the discriminated unions. I would guess that trying to load Ada’s debug info as if it were C++ was broken badly enough, so LLDB devs had disabled this altogether.

BTW, Rust has a similar problem with its enums, and for a long time did not emit DW_TAG_variant (designed for exactly this purpose) in debug info, just so that debuggers would be able to parse its data structures, which would be later fixed up by type formatters. More recently, Rust support was added in mainline GDB, and there is an out-of-tree Rust type system implementation for LLDB. Current rustc does emit DW_TAG_variant. On the flip side, unmodified LLDB can no longer be used to debug Rust.

@juananpe The “hack” @jingham was referring to is probably this, which tells LLDB that it can use TypeSystemClang for Rust.

BTW, Rust has a similar problem with its enums, and for a long time did not emit DW_TAG_variant (designed for exactly this purpose) in debug info, just so that debuggers would be able to parse its data structures, which would be later fixed up by type formatters. More recently, Rust support was added in mainline GDB, and there is an out-of-tree Rust type system implementation for LLDB. Current rustc does emit DW_TAG_variant . On the flip side, unmodified LLDB can no longer be used to debug Rust.

FYI, there was a proposal recently to support DW_TAG_variant in the current C++ TypeSystem as a near-term solution to rust debugging: https://reviews.llvm.org/D149213
Looks like it was accepted but not committed yet.

1 Like

The first step to getting lldb to parse DWARF and try to construct types for a given language is to make an lldb TypeSystem for it. Rust doesn’t have a Rust specific TypeSystem in lldb, but it fakes that by saying that the current clang TypeSystem supports Rust. That’s done in TypeSystemClangSupportsLanguage. Note that D, Pascal, and Dylan are also going along for that ride. That’s the hack I was mentioning.

Once you tell lldb that is can try to ingest Ada DWARF into the Clang TypeSystem, you can start to see whether lldb can actually do that, or whether the differences in the DWARF cause that to fail.

Then, as was discussed, for types that can’t be faithfully represented by a C++ focused DWARF parser (provided they don’t cause the parser to crash…) you can improve the data presentation using formatters as the Rust examples you found show.

There’s also some code in lldb to handle the Rust demangler. If Ada uses it’s own mangling scheme you will need to add support for that as well.

1 Like

This question comes up occasionally (I remember a similar discussion about Rust). It would be nice if we could document this and make it part of the website so folks willing to add support for new languages can easily discover what the expectations (and challenges) are.

1 Like

Following the hack referred by @jingham I managed to build LLDB with “some” Ada support (usable from CLI)

Now I want to use it with VS Code, but I hit another issue.

2 Likes

That’s really cool, thanks for sharing! :smiley:

Good news! Building LLDB against the 16.x branch of a rust-enabled LLDB version did the trick! Now I can debug Ada programs in VSCode in an Apple silicon (M2) with the CodeLLDB plugin :slight_smile:

1 Like

I’m running into the same issue(s) so thank you for sharing your solution. Would you mind also sharing your build options/script?

I don’t mind playing some with config options and learning, but I’ve never built LLVM/LLDB before so definitely appreciative of any tips. Based on the the “official” build instructions for LLDB, I was going to start out with the options below and then go on from there.

cmake -G Ninja -DLLVM_ENABLE_PROJECTS="lldb" -DCMAKE_BUILD_TYPE=Release path/to/llvm-16.x-branch-project/llvm
ninja lldb

@markfrodriguez you can follow these instructions.

Hope it helps.

Thanks @juananpe, that was very helpful. It’s working!

I did get an error after applying the patch in TypeSystemClang.cpp related to undeclared identifiers for later Ada language definitions.

error: use of undeclared identifier 'eLanguageTypeAda2005'
         language == eLanguageTypeAda2005 || language == eLanguageTypeAda2012 ||
                     ^
error: use of undeclared identifier 'eLanguageTypeAda2012'
         language == eLanguageTypeAda2005 || language == eLanguageTypeAda2012 ||
                                                         ^
2 errors generated.

Removing the line and just leaving the older Ada enums worked for me.

// Use Clang for Ada until there is a proper language plugin for it
language == eLanguageTypeAda83 || language == eLanguageTypeAda95 ||
//language == eLanguageTypeAda2005 || language == eLanguageTypeAda2012 ||