Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve debugging support #8538

Merged
merged 48 commits into from
Apr 16, 2020
Merged

Improve debugging support #8538

merged 48 commits into from
Apr 16, 2020

Conversation

skuznetsov
Copy link
Contributor

@skuznetsov skuznetsov commented Nov 30, 2019

Crystal debug support is here. It allows LLDB to show Crystal variables properly in C lang style.

…iables properly in C lang style. To work properly some LLDB patching is needed due to the dereferencing bug in DWARF Expression Evaluator.
Copy link
Contributor

@ysbaddaden ysbaddaden left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm afraid there is no benefit here, except disastrous performance hit by default because of a forced NoInline.

Oh, maybe LLDB is stupid and doesn't try to behave correctly with an unknown identifier, unlike GDB?

src/compiler/crystal/codegen/fun.cr Show resolved Hide resolved
@skuznetsov skuznetsov requested a review from ysbaddaden December 3, 2019 02:17
src/llvm/di_builder.cr Outdated Show resolved Hide resolved
Copy link
Member

@asterite asterite left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great!

I didn't try it, because I will need to compile LLVM with a patch to try it out, but I trust OP and in any case debugging support isn't great right now and looking at all the progress they have shown in the forums makes me think this is really good.

@ysbaddaden
Copy link
Contributor

I.e. I believe LLDB is buggy and too picky. Use GDB it will just work.

@skuznetsov
Copy link
Contributor Author

skuznetsov commented Dec 4, 2019 via email

@ysbaddaden
Copy link
Contributor

I don't use LLDB. I can't really help or provide guidance here —except for properly declaring debug type definitions, which we're lacking right now, so all debuggers would benefit.

@skuznetsov
Copy link
Contributor Author

I am looking into enrichment of DWARF info for Crystal.

@RX14
Copy link
Contributor

RX14 commented Dec 5, 2019

If we make crystal executables pretend their source code is C++ then no debug tool can ever add crystal-specific debugging support! They won't know which executable is Crystal and which is C++. This is clearly not beneficial long-term.

I too, suggest you file at LLDB and close this.

Again, a macos problem that you can't use gdb! Crystal was developed on macos and it still works far better on linux...

@skuznetsov
Copy link
Contributor Author

skuznetsov commented Dec 5, 2019

@RX14 As I said earlier this is a temporary solution to piggyback on C++ type system until proper Crystal type system will be implemented for LLDB. I also have to look how DWARF information is used in GDB to see if it useful enough for Crystal.

No one from outside of Crystal community will implement Crystal support. This is our responsibility and I am planning to implement it for LLDB, using C++ and Go Type systems as an example and boilerplate.

@RX14
Copy link
Contributor

RX14 commented Dec 5, 2019

But as soon as you want to implement proper LLDB support, you will have to revert this change. This means that all the existing LLDB versions which won't be upgraded for years after you upstream your patch will suddenly break.

I whole-heartedly support adding support to LLDB, but this is a step backwards from that. This makes adding LLDB support harder, so it cannot be accepted.

The suggestion to file upstream was to discuss treating unknown DWARF languages as C++, as gdb does, not to ask them to support crystal properly. That'd be far too much to ask.

@skuznetsov
Copy link
Contributor Author

@RX14 : It does makes sense.

We still have to get official Language ID to use for the language though and it will break versions support either as we use user defined (0x8002) (not official those are below 0x8000) Language ID.

Also at least one of the changes still needs to be accepted. The one where I replace 0 with false to do proper Optimisation setting parameter on DWARF Compile Unit.

@RX14
Copy link
Contributor

RX14 commented Dec 5, 2019

@skuznetsov the other changes are great, thanks.

Still, you cannot even develop the support without changing the language ID to something other than C++. I'm trying to understand why you're advocating for this despite making your job harder.

@ysbaddaden ysbaddaden removed their request for review December 5, 2019 14:22
@ysbaddaden
Copy link
Contributor

Now it's starting to look interesting, with proper DWARF type definitions :)

@RX14
Copy link
Contributor

RX14 commented Jan 20, 2020

FWIW, I'm happy to merge a change to the debugging type to C++ if you speak to the LLVM people and they determine that this is the best way forward. I'd really like to see a path towards getting our own official DWARF type laid out as part of that.

@RX14
Copy link
Contributor

RX14 commented Jan 20, 2020

Actually, I'll be at FOSDEM in 2 weeks and i'll try and find one of the LLDB/GDB people there and ask

@skuznetsov
Copy link
Contributor Author

FWIW, I'm happy to merge a change to the debugging type to C++ if you speak to the LLVM people and they determine that this is the best way forward. I'd really like to see a path towards getting our own official DWARF type laid out as part of that.

It is still nice to have our official DWARF Language ID but for now to keep C++ identifier until we implement LLDB and GDB plugins for Crystal language support.

@skuznetsov
Copy link
Contributor Author

Actually, I'll be at FOSDEM in 2 weeks and i'll try and find one of the LLDB/GDB people there and ask

Can you tell LLDB team that they have a bug in dereferencer that I pointed on the forum it will be great! Otherwise my changes will be neat but not much useful for Primitive types as they bill be shown incorrectly.
Here is the link to explanation: https://forum.crystal-lang.org/t/debugger-support/1325/34?u=computermage

Copy link
Contributor Author

@skuznetsov skuznetsov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just republishing the issue link for request of official DWARF language ID that I posted on Crystal forum: http://dwarfstd.org/ShowIssue.php?issue=200120.1

@RX14
Copy link
Contributor

RX14 commented Jan 21, 2020

Can you tell LLDB team that they have a bug in dereferencer that I pointed on the forum it will be great!

You should just submit that upstream to LLVM: https://llvm.org/docs/Contributing.html

@skuznetsov
Copy link
Contributor Author

Thanks for the link! Will patch it and will send the patch to them.

@ysbaddaden
Copy link
Contributor

Note that all the LLVMDI functions are official LLVM C API since LLVM 7. The bindings should be declared in lib_llvm.cr instead of lib_llvm_ext.cr.

It has some consequences that should be discussed: with these, Crystal will now depend on LLVM 7+ when it currently supports down to LLVM 3.x.

Maybe dropping support for anything below LLVM 7 is fine —that would really clean things up. Alternatively, we can polyfill the LLVMDI functions for a few older LLVM versions, but is it worth it? Or maybe just not enable full debug support when Crystal is built against LLVM 6 and below?

Sergey Kuznetsov and others added 3 commits April 4, 2020 14:41
Generate a lldb script from magic comments and check the output using FileCheck
@bcardiff
Copy link
Member

bcardiff commented Apr 9, 2020

Hey @skuznetsov I've been playing a bit today with this :-)
It took me a while to understand that I should use the native lldb and not the one from homebrew.

Otherwise I was getting

lldb module importing failed: This script interpreter does not support importing modules

Or

error: module importing failed: loading unimplemented

Depending on llvm version.


Either way, in mentioned before that to incorporate these changes and avoid breaking the funcionality in the future there needs to be some kind of specs.

I merged master and apply a couple of changes to start with that story in master...bcardiff:debug-specs

The interesting commit is bcardiff@3291ec8

It is inspired in rust runner and specs.

What do you think about this using this structure to show the scenarios improved by this PR?

The spec/debug/strings.cr for example will not pass if the crystal_formatters.py is not imported 😎

@skuznetsov
Copy link
Contributor Author

@bcardiff Yeah, I found it frustrating as well that Homebrew versions are not compiling it with proper Python support. Initially I built my own LLDB version with embedded python scripting so this Homebrew issue didn't hit me initially. I found that builtin Xcode version /usr/bin/lldb works just fine but it monolith version and does not have liblldb.dylib library so because of that CodeLLDB does not support scripting and my formatters as well :(
Did you try to play with it in system LLDB CLI? How do you like it so far?

I will look into your debug spec helpers. I will see what I can implement.

@bcardiff
Copy link
Member

bcardiff commented Apr 9, 2020

Using CodeLLDB with

#setting.json
    "lldb.launch.initCommands": [
        "command script import ~/path/to/crystal_formatters.py"
    ]

worked fine here

Although it seems that CodeLLDB bundles an lldb itself:

version
lldb version 10.0.0 (local revision aaae14ad1e80b489efe194b068b4b5d337ded6c8)
  clang revision aaae14ad1e80b489efe194b068b4b5d337ded6c8
  llvm revision aaae14ad1e80b489efe194b068b4b5d337ded6c8
  rust-enabled

And that does not match the native one, nor the homebrew

$ /usr/bin/lldb 
(lldb) version
lldb-1100.0.30.12

$ /usr/local/opt/llvm\@9/bin/lldb
(lldb) version
lldb version 9.0.1

$ /usr/local/opt/llvm\@10/bin/lldb
(lldb) version
lldb version 10.0.0

@RX14
Copy link
Contributor

RX14 commented Apr 9, 2020

I found it frustrating as well that Homebrew versions are not compiling it with proper Python support

Could this be noted/tweaked/fixed upstream? Might want to bug homebrew about that.

@bcardiff
Copy link
Member

Could this be noted/tweaked/fixed upstream? Might want to bug homebrew about that.

It is a known thing it seems in llvm https://lldb.llvm.org/resources/caveats.html and there are a couple of issues in homebrew-legacy related to formula options that are no longer available in homrebrew/core. I could not find a more recent issue in the core repo related to this. It seems like and old issue already settle in the current status to me.

@RX14
Copy link
Contributor

RX14 commented Apr 14, 2020

Any chance of getting a review?

Copy link
Member

@asterite asterite left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good. It seems to improve the current debugging landscape. Is it perfect or does it have all the necessary specs? No. But since debugging right now is pretty much barebones and this is a solid improvement, I think we should merge this. Tests can come later, either from @skuznetsov or from someone else.

Copy link
Member

@bcardiff bcardiff left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At least there are some specs ;-)

Without more specs for debugging, it will be really hard to accept further contributions in a confident manner.

The code changes seems fine to me regarding the existing compiler design. But the heavy part of the additions are hard to grasp whether they are still working without manually verifying.

So, after my small testing and contribution for the specs I'm fine merging this, but I would prefer if there were some more specs to ensure we don't go backward. Maybe merging this can encourage others to script their own lldb sessions, but I am not very confident (#ProveMeWrongPlease).

# Naked functions must not have debug info associated with them
false
else
declare_variable(var.name, var.type, pointer, var.location)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other invocations of declare_variable occur only if if @debug.variables?. With than in mind there are some refactor that can be applied since that method now does a noop unless @debug.variables?

@bcardiff bcardiff added this to the 0.35.0 milestone Apr 16, 2020
@bcardiff bcardiff merged commit 642ae96 into crystal-lang:master Apr 16, 2020
@bcardiff
Copy link
Member

Thanks @skuznetsov and others for this.

Let's keep in mind the need for some specs in order to move forward and don't lose support for debugging upon compiler/codegen changes.

@jkthorne
Copy link
Contributor

thank you @skuznetsov !!

@RX14
Copy link
Contributor

RX14 commented Apr 16, 2020

Thank you so much!!

@bcardiff
Copy link
Member

For those interested in trying this with VSCode I drop the configuration I've been using at https://dev.to/bcardiff/debug-crystal-in-vscode-via-codelldb-3lf

@skuznetsov
Copy link
Contributor Author

For those interested in trying this with VSCode I drop the configuration I've been using at https://dev.to/bcardiff/debug-crystal-in-vscode-via-codelldb-3lf

Sometimes Debugger values dereferencing is become too burdensome as it is gooing too deep on the parsed tree. In that case I recommend to disable "Dereference Pointers" feature:
image

It solves occasional hangups when LLDB is going way too deep.

carlhoerberg pushed a commit to carlhoerberg/crystal that referenced this pull request Apr 29, 2020
* Rudimentary debug support is here. It allows LLDB to show Crystal variables properly in C lang style. To work properly some LLDB patching is needed due to the dereferencing bug in DWARF Expression Evaluator.

* Rolled back enforced NoInline in debug mode.

* Added comment to explain why we have to use C++ Language ID

* Added debug information for union and nullable types.

* Fixed some of the debug type glitches (MixedUnionType notoriously) as well as fixed line linfo for blocks.

* Refactored debug information logging as per bcardiff comments

* Added array types debugging with DWARF support.

* Some extra features was added to llvm module so now it is possible to access to any block or any instruction in the LLVM function.
Also some refactoring as done to show properly locations of block variables.

* Added debug support for Tuples, NamedTuples, TypeDefs and partial support for Symbols.

* Removed unnecessary debug logs and did some format tidy up.

* More of code tidy up.

* Moving LLVM functions to the class they belong to.

* Neating up the code as per comments of reviewers.

* Code cleanup as per Sija's comments.

* Moved lldb crystal formatter into etc/lldb
Added get_or_create_array_subrange_variable method to LLVM module.

* Rolled back previously  set_current_debug_location as they are breaking unit tests and not really beneficial.

* Fixes as per Sija's suggestions as well as fix for failed unit test due to the missed filename of the unit test

* autoformated source code

* Removed location code that is not needed and was redundant and also was breaking the unit tests.

* Code clean up as per Sija's comments.

* Typo fix! Thanks a lot, Sija!

* Some clean up to trigger the build to re-test Alpine Linux.

* Re-trigger build wth comment commit.

* Fixed formatting issues (who knew that ### is not allowed! )

* initial refactor to use proper debug alloca

* fixing of alloca to be on alloca block

* formatted code

* Bug fixing for proper debug implementation. It should work properly now for most of variables and "self" variable.

* Fix of code formatting.

* Code fixes and avoid generating debug info for naked functions

* Fixed function name typo that @Sija found

* Addressed PR comments and refactored back to Type for debug_type_hash.

* changed the order of 'if' branch execution for setup_fun when --debug flag is used as per PR comments from @RX14

* Removed method attributes irrelevant for debugging as per @RX14

* Refactored code as per suggestions from @Asterlite and @Sija

* Code refactoring as per @Sija suggestions

* Removed all unused methods that were implemented during debug support implementeation.

* Initial debug specs

Generate a lldb script from magic comments and check the output using FileCheck

* Cherrypicked debug driver from @bcardiff

Co-authored-by: Sergey Kuznetsov <[email protected]>
Co-authored-by: Brian J. Cardiff <[email protected]>
@dinkopehar
Copy link

@skuznetsov

Is there a way, when dereferencing is disabled, to see values of variables ?

For example, in a simple program I see all values of variables, but in larger ones, when that option is disabled, I only get hex values which I don't understand...

@skuznetsov
Copy link
Contributor Author

skuznetsov commented May 13, 2021

@skuznetsov

Is there a way, when dereferencing is disabled, to see values of variables ?

For example, in a simple program I see all values of variables, but in larger ones, when that option is disabled, I only get hex values which I don't understand...

Usually, you have to add * before dereferencing it (or use -> if it is inside of a structure) as it uses C referencing model.

@dinkopehar
Copy link

Yes, I'm aware of that. But mostly with nested structures, it states "can not read memory at"... But CodeLLDB reads it normally sometimes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.