Debugger support

Representation of some unions might change. They could have different representation depending if they are closured or not and compiled with multi-threading. There is nothing settle yet.

You probably know already that nillable reference type unions are a void* at the end of the day. Since the type id is the prefix of the instance representation. A union of value types have a type id as first component. The type id of known types are not guaranteed between compilations.

@bcardiff Yes, I figured it out. As of type ids I am planning to store them as enum types in DWARF so I will be able to match them this way for debugging purposes.

Ok. debugger is mostly working. I still having some issues with unions in some cases when it shows type_id when it not needed, I suspect it is when it uses it as struct instead of pointer.
I am still investigating. I am using llvm_typer.cr and unions.cr files for AST type memory layout examples.

Soon I will publish some more screen shots like this:

5 Likes

Ok. minor glitches remained. If someone feeling adventurous you can look at my changes at this branch: https://github.com/skuznetsov/crystal/tree/debug

It is not ready for proper PR yet but it is workable.

I see some references to “variant” types in DWARF, would they be more suitable for crystal’s unions?

See for example: https://github.com/rust-lang/rust/blob/master/src/test/debuginfo/unique-enum.rs

I will check. It depends if debugger supports it.

Some versions of gdb and lldb must support it, since the rust debuginfo specs use them.

I will check LLDB code for Rust and will check what LanguageID Rust uses.

Rust has it’s own LanguageID I think.

I just checked rust source code and I found that they do have their own LangID (0x1C) they have some kludges in the code (check the comment):

debug!("compile_unit_metadata: {:?}", name_in_debuginfo);
let rustc_producer =
    format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION"),);
// FIXME(#41252) Remove "clang LLVM" if we can get GDB and LLVM to play nice.
let producer = format!("clang LLVM ({})", rustc_producer);

I tried to use the same kludge in Crystal with 0x8002 Lang ID and it didn’t do any trick (no variables was exposed). Will try with 0x1C to see if it will be different

Just use GDB, it works fine.

If LLDB is broken, dont use it.

By some reason GDB does not work on MacBook. I was reinstalling it multiple times and it always hangs badly when I start Crystal debugging, so I have to kill both GDB and target (which becomes zombie)

At least LLDB works for me and I have debug version compiled by me so I can tweak it for myself if needed.

:(

I’d rather you edit LLDB to accept unknown type IDs as the same as C++ for now…

After I visit fosdem I’ll hopefully have some human answers for what the best way to approach this is.

I can do it. It has something like 0x0 LangID that can be treated as general LLVM catch-all LanguageID for all LLVM based languages and will be mapped to clang. I think it is just one check at the same location where it check if it is C/C++ flavour. or may be some lldb config option that will allow to map specified language id to specific LLDB language plugin.

If that patch can be accepted then it will be cool and will buy us some time.

Looks like it used to be behaviour for earlier LLDB version but not anymore :frowning:

I just checked. RustID works because it is hardcoded in LLDB check for types that are suitable for CLang AST context:

static inline bool
ClangASTContextSupportsLanguage(lldb::LanguageType language) {
return language == eLanguageTypeUnknown || // Clang is the default type system
Language::LanguageIsC(language) ||
Language::LanguageIsCPlusPlus(language) ||
Language::LanguageIsObjC(language) ||
Language::LanguageIsPascal(language) ||
// Use Clang for Rust until there is a proper language plugin for it
language == eLanguageTypeRust ||
language == eLanguageTypeExtRenderScript ||
// Use Clang for D until there is a proper language plugin for it
language == eLanguageTypeD ||
// Open Dylan compiler debug info is designed to be Clang-compatible
language == eLanguageTypeDylan;
}

If we will have our own LanguageID assigned to us we can do the same trick for now.
Can you ask LLDB devs (if you will see them) how to receive official DWARD Language ID and hardcode it for now?

This was what I was going to ask.

1 Like

I just sent email to the email that was on dwarfstd.org with this question so we will see if he will be able to answer.

2 Likes

In LLDB code I see the following:

eLanguageTypeD = 0x0013, ///< D.
eLanguageTypePython = 0x0014, ///< Python.
// NOTE: The below are DWARF5 constants, subject to change upon
// completion of the DWARF5 specification
eLanguageTypeOpenCL = 0x0015, ///< OpenCL.
eLanguageTypeGo = 0x0016, ///< Go.
eLanguageTypeModula3 = 0x0017, ///< Modula 3.
eLanguageTypeHaskell = 0x0018, ///< Haskell.
eLanguageTypeC_plus_plus_03 = 0x0019, ///< ISO C++:2003.
eLanguageTypeC_plus_plus_11 = 0x001a, ///< ISO C++:2011.
eLanguageTypeOCaml = 0x001b, ///< OCaml.
eLanguageTypeRust = 0x001c, ///< Rust.
eLanguageTypeC11 = 0x001d, ///< ISO C:2011.
eLanguageTypeSwift = 0x001e, ///< Swift.
eLanguageTypeJulia = 0x001f, ///< Julia.
eLanguageTypeDylan = 0x0020, ///< Dylan.
eLanguageTypeC_plus_plus_14 = 0x0021, ///< ISO C++:2014.
eLanguageTypeFortran03 = 0x0022, ///< ISO Fortran 2003.
eLanguageTypeFortran08 = 0x0023, ///< ISO Fortran 2008.
// Vendor Extensions
// Note: Language::GetNameForLanguageType
// assumes these can be used as indexes into array language_names, and
// Language::SetLanguageFromCString and Language::AsCString assume these can
// be used as indexes into array g_languages.
eLanguageTypeMipsAssembler = 0x0024, ///< Mips_Assembler.
eLanguageTypeExtRenderScript = 0x0025, ///< RenderScript.

Look at this clause:

// NOTE: The below are DWARF5 constants, subject to change upon
// completion of the DWARF5 specification

it means that all IDs below 0x14 were self-acquired.
That means that we can safely assign 0x26 to me a semi-official language ID then and it will be reassigned during next version standardisation then.

I just got answer from Michael Eager (who is supporting dwarfstd.org):

Hi Sergey –

Using a user-extension value is a good thing to do, but there is a small amount of work to be done when a language ID value is assigned. Obsolete temporary values tend to have over long lifetimes.

I recommend that you submit an issue on the DWARF website and request a specific ID value. When the standard is updated, this value is almost guaranteed to be accepted, unless another language requests the same value.

1 Like