minoca / os

Minoca operating system
Other
2.71k stars 232 forks source link

evaluate debug format(s) assert() usage for necessity #115

Closed d-hoke closed 7 years ago

d-hoke commented 7 years ago

Evaluate the assert() usage within the debug format support routines for necessity.

At least in the (test?) program tdwarf, there are two fatal errors (search for 'unable to resolve') that end the program's dumping efforts, and, while those two situations may indeed be invalid, they are produced by tools currently more-or-less outside of minoca's control (gcc and family.) Avoiding the termination is reasonable, and doing so allows dumping the rest of the file.

This raised in my mind the question of whether such situations may exist within the base dwarf stuff, since I've recently had the debugger failing/exiting for various reasons, some as yet undetermined. (May also apply to other formats supported that I have not yet encountered in minoca.)

As there seem to be quite a few assert()s, I think it might be worth evaluating whether they really need to fail, or whether a check with report or avoidance would be a better approach. If trying to debug something built by tools over which user has no control, which they might be doing under a debug build (to do minoca a favor perhaps, :) ), they'd still like to be able to debug - and while the symbol information may be helpful if available and correct, the absence of entirely correct information (presumed due to errors on the language tool's part), should not prevent the user from being able to debug with what information is present and correct. (That incorrect information in some (many?) cases may not be needed by the user for their particular efforts at all.)

evangreen commented 7 years ago

Hi David, We definitely appreciate that you run debug builds, your bug reports and comments have been awesome and very helpful. So first off, thanks for that.

I realize there are varying philosophies on the subject of asserts, some people find them to be useless annoyances and some are so aggressive with them that the whole program is almost unusably slow. I try to use asserts to indicate either assumptions that I've made or conditions which the code is not well prepared to handle. I also find them to be useful indications to other programmers as a way to convey what's in my head and indicate cases that may not have been considered fully.

Usually when asserts fire it indicates that the code really is about to behave badly (except in cases like the one you just found where the bug is in the assert itself). You're right that it gets a little awkward when the code that needs to be debugged is in the debugger. (I'll add that it's even worse when it's active code in the debugger's operational path, like something in the Kd* functions).

I wrote the tdwarf program as a test of my DWARF parsing code, which I'm sure isn't perfect, especially around C++. I didn't really intend for people to use tdwarf as an actual tool for searching symbols, it was supposed to just barf at me if I got the symbol parsing wrong.

It would be easy enough to allow tdwarf to keep going. Is it really a useful tool for you, or are you using it like I was to diagnose symbol parsing issues in the debugger?

One option I thought of if you want to continue to use debug builds but don't want to debug the debugger is to do a 'make clean' in os/apps/debug, tweak minoca.mk to change -DDEBUG into -DNDEBUG, and then recompile just that directory (then revert changes to minoca.mk). That would give you a version of debug compiled without asserts. We do however appreciate the bug reports, even about the debugger.

d-hoke commented 7 years ago

this - " or are you using it like I was to diagnose symbol parsing issues in the debugger?" After I tried to hack the initial problem and was still failing, I was trying to see if there might be a quick answer as to what else was happening and found tdwarf - but no luck there. So, tdwarf was simply explored as a means to an end - a debugger that wasn't failing. :)

And I think this is a good philosophy - "Usually when asserts fire it indicates that the code really is about to behave badly".

And I bet its followed pretty strictly in the kernel - unless there's not a reasonable way to keep going, keep going, tho' likely trying to warn/alert the user somehow.

That same philosophy can also be very helpful to users of routine applications - Having your word processor or editor crash without even attempting to save the half-hour work you just performed is pretty annoying - at least to me. Maybe not to you?

Back to the debugger - not being able to debug, with whatever symbol support may be there, can be very useful. I've become somewhat convinced the particular file I'm working with may in fact have broken data in it ('unable to resolve relation'), but it's unlikely I'm going to see a fix to gcc/binutils whatever in a reasonable timeframe. But it also looks like the broken entity (based on names) probably isn't related to the specific area in which I seemed to be encountering whatever was going on...

Hence my desire to have the other tools be as tolerant as possible.

evangreen commented 7 years ago

Yes, what you said makes sense. If I had to guess I'd say GCC/binutils are probably fine, and it's just our parser that isn't parsing C++ very well. Maybe were missing or mishandling an important tag: the list of tags we process in DwarfpProcessDie is not complete.

Sounds like you'd have a better time with the quick-hack-NDEBUG version of the debugger suggested above.

Out of curiosity, what is your setup that you're using the Minoca kernel debugger on Linux to debug C++ code? Have you written a C++ kernel driver?

d-hoke commented 7 years ago

No kernel driver (although I might yet play with that.)

I was taking a (humor attempt coming) 'STAB' seeing how far I could get with LLVM/CLANG. So far, not very far.

evangreen commented 7 years ago

Who doesn't like a good debugging format pun? I do.

I have some unsolicited thoughts on your quest, hope you don't mind. When I first started porting GCC, I had no idea how any of its infrastructure worked, and so I spent a lot of time trying to directly build a compiler whose host and target was minoca using only MinGW's GCC. I actually got pretty far, but it was clear the build infrastructure wasn't prepared for this. Moral of the story is that's not at all how they want you to do it. The real way was to first build a cross compiler whose host was still your machine (linux?) and whose target was minoca (so this is a compiler that runs on Linux but produces binaries for Minoca). Only once I had that was I able to build a compiler that both runs on Minoca and produces binaries for Minoca.

Regarding actual porting changes, the only thing I've seen is this: http://wiki.osdev.org/User:MessiahAndrw/LLVM_OS_Specific_Toolchain I have no idea how helpful it is, but it might be a good start.

d-hoke commented 7 years ago

I started out with the cross compiler attempt, but when I figured out that the 'cross' approach was trying to run one of its intermediate utilities built for the target on the build host, I thought maybe it was worth a try doing it directly on the target host, since the bootstrap process was already capable of using gcc for the bootstrap.

Interestingly (perhaps as in the chinese proverb), is that the effort has been stalled at the exact same point, around the exact same utility (llvm-tblgen), although not for the exact same reason. :)