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

Problems and workarounds for debugging C3 on Windows #1646

Open
heavymetalmixer opened this issue Nov 26, 2024 · 36 comments
Open

Problems and workarounds for debugging C3 on Windows #1646

heavymetalmixer opened this issue Nov 26, 2024 · 36 comments
Assignees
Labels
Additional info please Further information is requested Bug Something isn't working In Progress This task is currently being worked on
Milestone

Comments

@heavymetalmixer
Copy link

heavymetalmixer commented Nov 26, 2024

After watching the same pattern as with Zig (ziglang/zig#22039) I thought it could be an issue from LLVM, but with C3 there are other small issues added on top of it:

  1. LLDB starts debugging the line AFTER the breakpoint. Now, this doesn't mean "line number" but code line, so the if developer wrote down the next code line 4 lines below, LLDB will jump 4 lines down.

  2. Both LLDB and MSVC Debugger ignore module declarations (the thing at the top of the file) and imports. MSVC debugger jumps to the main function if there's a breakpoint on an import or module, LLDB looks for the next breakpoint and ends the debugging session if there's none.

@lerno
Copy link
Collaborator

lerno commented Nov 26, 2024

What happens with the MSVC debugger in the first case.

@heavymetalmixer
Copy link
Author

What happens with the MSVC debugger in the first case.

The MSVC debugger starts at the breakpoint unlike LLDB.

@lerno
Copy link
Collaborator

lerno commented Nov 26, 2024

Does compiling C with Clang give the right output then?

@heavymetalmixer
Copy link
Author

Does compiling C with Clang give the right output then?

Yeah, as it should on both C and C++.

@lerno
Copy link
Collaborator

lerno commented Nov 26, 2024

Could you perhaps create a small sample and dump the LLVM here for C and the corresponding C3 program? Maybe paste in a gist if it's too big.

@lerno lerno self-assigned this Nov 26, 2024
@lerno lerno added the Bug Something isn't working label Nov 26, 2024
@lerno lerno added this to the 0.6.6 milestone Nov 26, 2024
@heavymetalmixer
Copy link
Author

Could you perhaps create a small sample and dump the LLVM here for C and the corresponding C3 program? Maybe paste in a gist if it's too big.

I'm sorry if this si frustrating to you. I'm a novice and I don't know how to make an LLVM dump, so i used llvm-pdbutil dump to get info about the PDB file and I got the following:

llvm-pdbutil dump -summary main.pdb

                          Summary
============================================================
  Block Size: 4096
  Number of blocks: 1398
  Number of streams: 240
  Signature: 849705519
  Age: 1
  GUID: {32A57A2F-08C4-FC45-4C4C-44205044422E}
  Features: 0x1
  Has Debug Info: true
  Has Types: true
  Has IDs: true
  Has Globals: true
  Has Publics: true
  Is incrementally linked: false
  Has conflicting types: false
  Is stripped: false

The code is a simple Hello World:

#include <stdio.h>

int main(void) {
    printf("Hello world!\n");
    return 0;
}

If this isn't what you're looking for, let mw know what I should do.

@lerno
Copy link
Collaborator

lerno commented Nov 28, 2024

I was looking for the llvm output (-llvm-emit or something like that), but try the latest update now and see if it looks the same. Oh, and are you compiling with -gcodeview for Clang?

@lerno lerno added Additional info please Further information is requested In Progress This task is currently being worked on labels Nov 28, 2024
@heavymetalmixer
Copy link
Author

I was looking for the llvm output (-llvm-emit or something like that), but try the latest update now and see if it looks the same. Oh, and are you compiling with -gcodeview for Clang?

Ok, so after installing LLVM 19.1.4 (I used to have 19.1.0) and making a few tests I can say:

  1. Using -gcodeview makes no difference. I didn't use it before you mentioned it btw.

  2. With the environment variable LLDB_USE_NATIVE_PDB_READER set it to 1 the LLDB behavior changed for both C3 and Zig. Instead of always jumping to the next line of code, it only jumps if the breakpoint is set on top of a function name or a comment.

  3. With the environment variable LLDB_USE_NATIVE_PDB_READER set it to 0 the LLDB behavior changed for C3 but not for Zig. LLDB for C3 now starts debugging exactly where the breakpoint is set, just like the MSVC debugger.

  4. Both debuggers still avoid imports regardless of the value on LLDB_USE_NATIVE_PDB_READER as I said before. Maybe this is the intented behavior?

@lerno
Copy link
Collaborator

lerno commented Nov 30, 2024

So wait, for C you can kind of add a breakpoint on the include itself or what?

Aside from that, what else is problematic for C3?

@heavymetalmixer
Copy link
Author

So wait, for C you can kind of add a breakpoint on the include itself or what?

Aside from that, what else is problematic for C3?

  1. In C if you add a breakpoint on top of the #include line the debuggers also avoid it, so that confirms it's intentional.

  2. I've been doing several tests for C, C++, C3 and Zig it seems like the behavior is variable. Sometimes it works, sometimes it doesn't, and sometimes LLDB ignores all the breakpoints. All of those tests were made without changing the LLVM installation.

It seems that for now the only way to reliably debug C3 programs on Windows is with the MSVC debugger, same for Zig.
For C and C++ this doesn't apply if the program is compiled with GCC as it uses DWARF files instead.

So yeah, this is totally an LLVM v19.1.x issue.

@heavymetalmixer
Copy link
Author

So wait, for C you can kind of add a breakpoint on the include itself or what?

Aside from that, what else is problematic for C3?

After downgrading to LLVM 18.1.8:

  1. When LLDB_USE_NATIVE_PDB_READER is set to 1 Cand C++ binaries have no issues. For C3 and Zig when trying to "Step over" it does "Step into" instead.

  2. When LLDB_USE_NATIVE_PDB_READER is set to 0 only C and C++ binaries can be debugged without issues.

@lerno
Copy link
Collaborator

lerno commented Dec 3, 2024

Ok, so there was no improvement for C3 after the changes?

@lerno
Copy link
Collaborator

lerno commented Dec 3, 2024

Also can you compare C using Clang with -gcodeview with C3 / Zig? Because only those are comparable.

@heavymetalmixer
Copy link
Author

Also can you compare C using Clang with -gcodeview with C3 / Zig? Because only those are comparable.

After today's tests of C (-gcodeview), C3 and Zig:

The -gcodeview flag for C makes it impossible for LLDB to work.
C3 and Zig still retain the erractic behavior, it didn't change.

@lerno
Copy link
Collaborator

lerno commented Dec 4, 2024

Will you try C3 output with the very latest? I made some changes.

@heavymetalmixer
Copy link
Author

Will you try C3 output with the very latest? I made some changes.

Today (just a few minutes ago) I used the "latest" version which was release around 18 hours ago.
Now, regardless of the value on LLDB_USE_NATIVE_PDB_READER LLDB shows the same erractic behavior of "Stepping into" functions when "Step over" instead.

I also tried installing LLVM 19.1.5 (released 4 hours ago) but the result didn't change.

@lerno
Copy link
Collaborator

lerno commented Dec 4, 2024

I made mistake with the latest. Pushing something new now.

@heavymetalmixer
Copy link
Author

I made mistake with the latest. Pushing something new now.

I installed your version from a few hours ago and these are the results:

  1. With LLDB_USE_NATIVE_PDB_READER set to 0 LLDB ignores breakpoints and runs the program.

  2. With LLDB_USE_NATIVE_PDB_READER set to 1 one of two things happen:

a) If the breakpoint is on top of a function name, the LLDB sends me to a macro definition and won't let move from there. The only thing that can be done is to finish the debugging session.
Captura de pantalla 2024-12-05 134608
Captura de pantalla 2024-12-05 134634

b) If the breakpoint is inside the function, LLDB will jump to whatever the last line was at the moment of compiling the code. If I press enter to put that line way further below LLDB will still jump to the line number it was before just right after compiling.
Captura de pantalla 2024-12-05 134654
Captura de pantalla 2024-12-05 134720
Captura de pantalla 2024-12-05 135116

@lerno
Copy link
Collaborator

lerno commented Dec 5, 2024

Main is special since it has some implicit macro expansions, can you try stopping in some other regular function and see what happens? If the problem is the same or if it works properly there at least.

@heavymetalmixer
Copy link
Author

Main is special since it has some implicit macro expansions, can you try stopping in some other regular function and see what happens? If the problem is the same or if it works properly there at least.

This change I added two simple functions to test the debuggin:

module c3test;
import std::io;

fn int sumA() {
	return 5 + 6;
}

fn int sumB(int va, int vb) {
	int sum = va + vb;
	return sum;
}

fn int main(String[] args) {
	int a = 1;
	io::printn("Hello, World!\n");
	int b = 2;
	int c = sumA();
	int d = sumB(b, c);

	io::printfn("sumA = %d\n", c);


	io::printfn("sumB = %d\n", d);

	return 0;
}

So:
a) When I set a breakpoint on top of the sumA) function name, the debugger jumps to the next line.
When I set the breakpoit inside the funtion (the return line), the debugger starts right there.

b) For the sumB function if I set a breakpoint on top of its function name, the debugger does start right there. The same goes for the first line of the function which is a variable definition.
When I set the breakpoint on the last line (the return line), the debugger ignores it and just runs the program.

@lerno
Copy link
Collaborator

lerno commented Dec 6, 2024

Thank you, I'll inspect the LLVM output

@lerno
Copy link
Collaborator

lerno commented Dec 6, 2024

The LLVM output (for Clang) surprised me. Basically it's the normal output but just without column information. You can see if the latest update yields a better result.

@heavymetalmixer
Copy link
Author

The LLVM output (for Clang) surprised me. Basically it's the normal output but just without column information. You can see if the latest update yields a better result.

Changes from the same code:

  1. sumB shows the same behavior as sumA for LLDB.

  2. As you can see inside the main functions there are three calls to io::printfn, the first one is a "Hello world!" while the others show numbers.
    The first one is ignored by LLDB if I set a breakpoint on top of it but not the other 2.

@lerno
Copy link
Collaborator

lerno commented Dec 6, 2024

Is this with native pdb reader? So what are the remaining issues to fix? Just so I understand correctly? Doesn't stop correctly in when placing the breakpoint on the function? How does main behave now?

@heavymetalmixer
Copy link
Author

heavymetalmixer commented Dec 6, 2024

Is this with native pdb reader? So what are the remaining issues to fix? Just so I understand correctly? Doesn't stop correctly in when placing the breakpoint on the function? How does main behave now?

  1. The tests were done with LLDB_USE_NATIVE_PDB_READER set to 1, AKA not the native PDB reader but the one from LLVM. When LLDB_USE_NATIVE_PDB_READER is set to 0 (native PDB reader) LLDB ignores all breakpoints and simply runs the program.

  2. From what I've tested the user-made functions now work as intented. The main function name and its return statement still force you to see the calls to macros and the standard library. Also, setting the breakpoint on the main funtion name makes it ignore the first 2 lines, which in this case are int a = 1; and io::printn("Hello, World!\n");.

  3. One more thing I noticed which seems like a bug: Pressing "Step out" on top of a variable definition (regardless if it has a breakpoint or not) sends me to a macro but "Step into" doesn't. It's not the same macro as the one showed when the breakpoint is set on top of the main function's name.

a) If I press Step Out and then Step Over until it ends:

1
2
3
4
5

b) If I press Step Out until it ends:
1
2
6

@heavymetalmixer
Copy link
Author

A question: Internally what level of optimization (-Ox) and debug info (-gx) uses LLVM for C3 when building?

@lerno
Copy link
Collaborator

lerno commented Dec 8, 2024

Do you mean what is passed to LLVM in these cases?

@heavymetalmixer
Copy link
Author

Do you mean what is passed to LLVM in these cases?

Sorry for taking so long to reply, my ISP gave me a broken router a few days ago.

On topic: Yeah, to LLVM. I wasn't able to find info about the debug info and optimization levels in the documentation for C3.

@lerno
Copy link
Collaborator

lerno commented Dec 9, 2024

-g is equivalent to Clang's -g and -g0 to Clang's -g0.

For optimization options: C3
-O0 is Clang -O0
-O1 corresponds to Clang -O2
-O2 is like the previous level but safety off
-O3 is like previous level but single module
-O4 is like Clang -O3 and relaxed maths
-O5 is like Clang -O3 and fast math
-Os is like Clang -Os
-Oz is like Clang -Oz

@heavymetalmixer
Copy link
Author

-g is equivalent to Clang's -g and -g0 to Clang's -g0.

For optimization options: C3 -O0 is Clang -O0 -O1 corresponds to Clang -O2 -O2 is like the previous level but safety off -O3 is like previous level but single module -O4 is like Clang -O3 and relaxed maths -O5 is like Clang -O3 and fast math -Os is like Clang -Os -Oz is like Clang -Oz

Ok, so: The only "real" issue right now is that for some reason LLDB ignores io::print variations if they only have a string literal as argument, if that function call has a breakpoint on top of it.

I used -g and O0 to compile this time.

@lerno
Copy link
Collaborator

lerno commented Dec 15, 2024

io::print is macro, so maybe that is the reason.

@heavymetalmixer
Copy link
Author

io::print is macro, so maybe that is the reason.

MSVC debugger doesn't avoid them, but still gets buggy if I try to get into their code. Maybe C3 macros. right now are difficult to get proper debug info for.

@lerno
Copy link
Collaborator

lerno commented Dec 18, 2024

No, it should be possible to get it to work. A "fake" function is created for macros so that they can be entered. What's the behaviour you see?

@heavymetalmixer
Copy link
Author

To examine the interior of the io::printn also with LLDB call I set the breakpoint in the instruction before it. These are the results:

  1. With LLDB when I try to Step in it throws an Exception 0x80000003 encountered at adress 0x7ff75daa8d33. If I press Step in again it takes me to the fn File* stdout() function and then to the macro void printn(x = "") function. This seems to be just a small issue. If I press Step out it returns to the main function code as expected.

  2. With LLDB again I pressed Step out this time on the io::printn call and it took me to the macro int @wmain_to_int_main_args(#m, int argc, Char16** argv) function and then to a bunch of assembly code until the program ends after pressing Step over a few times.

  3. With MSVC debugger when I start with Step in it took me straight into the fn File* stdout() function and then to the macro void printn(x = "") function and goes as expected.

  4. If I press Step out with MSVC debugger instead I'm sent to the macro int @wmain_to_int_main_args(#m, int argc, Char16** argv) function and then to a file called "exe_common.inl" and the program ends after I presse Step out or Step over a few times.

@lerno
Copy link
Collaborator

lerno commented Dec 19, 2024

So MSVC looks fine, or was there still something unexpected? @heavymetalmixer I'm thinking we could add a -gdwarf flag to make it output DWARF only for LLDB.

@heavymetalmixer
Copy link
Author

So MSVC looks fine, or was there still something unexpected? @heavymetalmixer I'm thinking we could add a -gdwarf flag to make it output DWARF only for LLDB.

That could be a good option tbh, as long as the making PDB files doesn't get removed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Additional info please Further information is requested Bug Something isn't working In Progress This task is currently being worked on
Projects
None yet
Development

No branches or pull requests

2 participants