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

On Windows 10, at launch of LLDB, program is unable to access stdout or stdin #309

Open
gandalfas opened this issue May 18, 2022 · 64 comments
Labels
bug Something isn't working lldb lldb or vscode-lldb issue windows Issue specific to Windows

Comments

@gandalfas
Copy link

gandalfas commented May 18, 2022

Issue Description

On Windows 10, at the launch of Swift's custom LLDB by the Swift extension for VS Code (vscode-swift), the user program's output from the 'print()' statement is nowhere to be seen, and the attempt to do 'readline()' gets an EOF result.

The issue seems most likely to be in the Swift extension for VS Code, or possibly in the CodeLLDB extension. This is based on the 'Variations' section, below.

This is in the global settings.json file, which correctly points to the Swift custom LLDB:

{
    "lldb.library": "C:\\Library\\Developer\\Toolchains\\unknown-Asserts-development.xctoolchain\\usr\\bin\\liblldb.dll"
}

Discovered during work on #301.

Let me know if you need me to provide any additional information.

Environment

OS: Windows 10
VSCode version: 1.67.1
Swift extension version: 0.5.2
CodeLLDB version: 1.7.0
Compiler: Swift 5/04/22 'latest snapshot of main': swift-DEVELOPMENT-SNAPSHOT-2022-05-04-a-windows10.exe

Test Case

md hello
cd hello
swift package init --type=executable
place these lines into main.swift:

import Foundation

print("Hello, world!")
print("enter something  ->", terminator: "")

guard let answer = readLine() else {
    print("End of File was reached - aborting...")
    exit(1)
}
print("readline() did not see EOF")

open folder with VS Code
compile with: Terminal > Build Debug hello
hello.exe is built.
set a breakpoint on 'Hello,world' line.
click Run > Start Debugging, and then step through the program.

Expected Behavior

This expectation is based on one of the 'Variations' - see below. At this point you should see the following in VS Code's lower pane > Terminal tab. When the prompt "enter something" appears, you should be able to enter text, for example "abc". Control should skip over the 'else' to the print statement at the bottom of the program. At the end of execution, the Terminal tab should show:

Hello, world!
enter something  ->abc
readline() did not see EOF

Actual Behavior

A new command prompt window is created, titled with 'hello.exe'. It remains empty throughout program execution.

The output of the print statements is nowhere to be seen - neither in the VS Code lower pane in tab 'Terminal', nor in the new empty command prompt window.

As you step over the 'readline()' statement, the program fails to wait for you to enter text, control simply falls into the 'else' part of the guard, where EOF is handled.

This output appears in the lower pane, tab 'Output', channel LLDB:

configuration: {
  type: 'lldb',
  request: 'launch',
  name: 'Debug hello',
  program: '${workspaceFolder:hello}/.build/debug/hello',
  args: [],
  cwd: '${workspaceFolder:hello}',
  preLaunchTask: 'swift: Build Debug hello',
  __configurationTarget: 5,
  relativePathBase: 'k:\\Kim Shared\\CodeLab\\SwiftTests\\hello'
}
[adapter\src\terminal.rs:104] FreeConsole() = 1
[adapter\src\terminal.rs:105] AttachConsole(pid) = 1
[adapter\src\terminal.rs:109] FreeConsole() = 1
[2022-05-17T23:49:11.082Z ERROR codelldb::debug_session] Internal debugger error: Invalid frame reference: 1001

There seems to be some variability in this error log - in another similar case, shown in #301, in the comments by me starting with "Alrighty", I had this instead:

[adapter\src\terminal.rs:104] FreeConsole() = 1
[adapter\src\terminal.rs:105] AttachConsole(pid) = 1
[adapter\src\terminal.rs:109] FreeConsole() = 1
ERROR(Python) 20:38:54 codelldb: Traceback (most recent call last):
  File "c:\Users/Kim/.vscode/extensions/vadimcn.vscode-lldb-1.7.0/adapter\codelldb.py", line 152, in evaluate
    value = evaluate_in_context(pycode, is_simple_expr, context)
  File "c:\Users/Kim/.vscode/extensions/vadimcn.vscode-lldb-1.7.0/adapter\codelldb.py", line 288, in evaluate_in_context
    return eval(code, eval_globals, eval_locals)
  File "<input>", line 1, in <module>
  File "c:\Users/Kim/.vscode/extensions/vadimcn.vscode-lldb-1.7.0/adapter\codelldb.py", line 269, in __missing__
    raise VariableNotFound(name)
codelldb.VariableNotFound: Variable 'vars' not found

[2022-05-12T01:38:54.750Z ERROR codelldb::debug_session] Variable 'vars' not found
Debug adapter exit code=0, signal=null.

Variations

When I comment out the "lldb.library" entry in settings.json, thus forcing the standard LLDB (poorly named, I meant the LLDB packaged with the CodeLLDB extension) to be used instead of the Swift custom LLDB, then do Run > Start Debugging, the print() statement output appears in the lower pane of VS Code, in the Terminal tab; likewise, for readline(), the user enters text in the same Terminal tab. That feels like the correct behavior to me, for VSCode-based debugging. This is the basis of my expected behavior, above.

When I run the Swift LLDB from the command prompt, the program uses stdin/stdout just fine, and that occurs in a command prompt window that lldb launches for the program.

Likewise when I run the program directly from the command prompt (no LLDB), the prog uses stdin/stdout just fine in that same command prompt window.

Taking all these variations together, these indicate that the source of the problem must be in the setup done in the Swift extension as it prepares to invoke the LLDB debug adapter, or possibly the debug adapter is mishandling something when the lldb.library is set. If no objections, we propose that we begin the investigation in the Swift extension (see #301 at the bottom).

@gandalfas gandalfas added the bug Something isn't working label May 18, 2022
@gandalfas
Copy link
Author

gandalfas commented May 18, 2022

argg, @adam-fowler , I just saw your comment of yesterday. I did check for any follow-up from you or @compnerd on #301 just before creating this issue 309, but alas, I was looking at a stale view.

So, for good or bad, I've already created this issue, so I am going to paste your reply here, and then let's continue any discussion of this issue here, in 309.

@compnerd I've had a quick look at this and sorry to pass the buck but I think this is more a Swift lldb issue. Running from the command line the standard lldb prints directly to the command line any output from the application. If you use the swift lldb it opens up a new window for the output. I'm assuming this difference is what is causing the issue inside vscode-swift as there is no output to stdout/stderr it is all redirected to the window that opens.

@compnerd
Copy link
Member

Hmm, I don't see how lldb would create a new console for the application, it does a standard process creation AFAIK. What is standard lldb here for context? Is it the lldb from llvm.org? Built at what revision?

@compnerd compnerd added the windows Issue specific to Windows label May 18, 2022
@gandalfas
Copy link
Author

gandalfas commented May 18, 2022

I am trying to reproduce Adam's case:

the standard lldb prints directly to the command line any output from the application

but I get different results. when I put the standard lldb foremost in my PATH, I get:

--> lldb hello

Fatal Python error: init_sys_streams: can't initialize sys standard streams
Python runtime state: core initialized
Traceback (most recent call last):
  File "C:\Program Files\Python\Python310\Lib\io.py", line 54, in <module>
ImportError: cannot import name 'text_encoding' from 'io' (unknown location)

my standard lldb is installed in:

c:\Users\Kim\.vscode\extensions\vadimcn.vscode-lldb-1.7.0\lldb\bin

and that is the same lldb.exe that Run > Start Debugging calls (per Process Explorer). This was installed by the LLDB extension for VS Code. That lldb\bin dir also contains its own copies of these python files: python3.dll and python39.dll. These are pulling io.py from my python 3.10 install (even when I remove that from the PATH). I won't be able to shed any light on standard lldb's behavior on my machine unless I can get it to ignore python310 folders.

@gandalfas
Copy link
Author

also, Adam said

If you use the swift lldb it opens up a new window for the output. I'm assuming this difference is what is causing the issue inside vscode-swift as there is no output to stdout/stderr it is all redirected to the window that opens.

but that differs from what I see - no output is directed to the newly opened window.

@gandalfas
Copy link
Author

gandalfas commented May 18, 2022

A thought: since commenting out the "lldb.library" entry in settings.json makes things work as expected (stdout and stdin are in VS Code's 'Terminal' pane), could we assume that whoever is processing that setting is messing up the redirecting of stdout and stdin to the Terminal pane? And would that be some component of the LLDB extension?

@adam-fowler
Copy link
Contributor

What is standard lldb here for context? Is it the lldb from llvm.org? Built at what revision?

When I say standard LLDB I mean the one that is packaged with vscode-lldb. Looking at the commit comments from vscode-lldb this would be from https://github.com/llvm/llvm-project, build id 1927 (not totally sure what build id indicates though).

but that differs from what I see - no output is directed to the newly opened window.

Sorry you are right when run via vscode-lldb no output is display to the window.

but I get different results. when I put the standard lldb foremost in my PATH

You need to resolve your python issues before you can compare the results.

As I said above the two versions of lldb when run from the command line react differently. We need to resolve this before looking at vscode-swift/lldb.

@compnerd
Copy link
Member

Thinking about this a bit: the new window might be the result of AllocConsole. There is nothing that can be done about that - it is how console applications work on windows. https://docs.microsoft.com/en-us/windows/console/allocconsole

I think that we should look at how the inferior is launched. I suspect that this might be a bug in lldb-server. One quick test would be to try a “remote” (it can be run on the same host) debug session with ds2 (https://github.com/compnerd/ds2).

@gandalfas
Copy link
Author

the new window might be the result of AllocConsole

yes, agreed, and I believe that is a valid technique to achieve clarity, i.e., when lldb is run as a CL tool, it would want the debugger commands and cmd outputs to be segregated from the program's interactions with the user, so 2 consoles is a good way to accomplish that.

You need to resolve your python issues before you can compare the results.

yes, agreed. I had updated my notes, perhaps after you read the initial notes, to indicate the same. I have a couple ideas and will report back.

@gandalfas
Copy link
Author

gandalfas commented May 19, 2022

I was able to get the standard LLDB to ignore my python310 folders, by doing:

rem PYTHONHOME=C:\Program Files\Python\Python310
rem PYTHONPATH=C:\Program Files\Python\Python310\Lib;C:\Program Files\Python\Python310\Lib\site-packages;
set PYTHONHOME=c:\Users\Kim\.vscode\extensions\vadimcn.vscode-lldb-1.7.0
set PYTHONPATH=c:\Users\Kim\.vscode\extensions\vadimcn.vscode-lldb-1.7.0\Lib;c:\Users\Kim\.vscode\extensions\vadimcn.vscode-lldb-1.7.0\Lib\site-packages;

This is in addition to the previous change to add the standard lldb foremost in my PATH, so that the one under C:\Library is not seen. With all that, the standard LLDB had the identical behavior described by Adam:

Running from the command line the standard lldb prints directly to the command line any output from the application.

I.e., the program output and input are intermingled with the LLDB command output and input:

    frame #0: 0x00007ff6146c127c hello.exe`main at main.swift:10:7
   7    
   8    
   9   
-> 10   print("Hello, world!")
   11
   12
   13   
(lldb) n
(lldb) Hello, world!                                                          ####### output from program
Process 7348 stopped                                                       ####### output from LLDB
* thread #1, stop reason = step over
    frame #0: 0x00007ff6146c1364 hello.exe`main at main.swift:15:7
   12
   13  
   14
-> 15   print("enter something  ->", terminator: "")
   16
   17   guard let answer = readLineaa() else {
   18       // EOF should NOT happen from std input.  sth is terribly wrong.
(lldb) n
enter something  ->Process 7348 stopped                      ####### output from program;  output from LLDB
* thread #1, stop reason = step over
    frame #0: 0x00007ff6146c146e hello.exe`main at main.swift:17:28
   14
   15   print("enter something  ->", terminator: "")
   16
-> 17   guard let answer = readLineaa() else {
   18       // EOF should NOT happen from std input.  sth is terribly wrong.
   19       print("\n\n\nEnd of File was reached - aborting...")
   20       exit(1)
(lldb) n                                                                          ####### user input to LLDB
(lldb) aaabbbccc                                                              ####### user input to program
Process 7348 stopped
* thread #1, stop reason = step over
    frame #0: 0x00007ff6146c15b8 hello.exe`main at main.swift:23:7
   20       exit(1)
   21   }
   22
-> 23   print("readline() did not see EOF")
   24
   25
   26   /*
(lldb) n                                                                    ####### output from LLDB
readline() did not see EOF                                                ####### output from program
Process 7348 stopped                                                  ####### output from LLDB 

So, clearly the Swift custom LLDB was changed to enable 2 separate consoles, one for LLDB and one for the program. I hope this helps.

Possibly that may have to be undone in order to get Swift custom LLDB working under VS Code. However, my own 2 cents would be that the optimal solution would be to fix the stdout/stdin redirecting while retaining the 2 separate consoles. Otherwise we are left with choosing between (A) cmd line LLDB working great with 2 consoles and VS Code-based debugging not working, or (B) the latter working and the former being degraded somewhat to 1 intermingled console. Thanks for considering.

@gandalfas
Copy link
Author

I think that we should look at how the inferior is launched. I suspect that this might be a bug in lldb-server. One quick test would be to try a “remote” (it can be run on the same host) debug session with ds2 (https://github.com/compnerd/ds2).

I will try this next.

@gandalfas
Copy link
Author

@compnerd, I see on your ds2 page that I do not have any of the many build tools listed there, and I would really prefer not to install a bunch of things and then uninstall them later, because of all the remnants that will leave.

Might you have a build that I could download and run on my Windows 10 machine?
Or, might someone else be able to attempt this?

Thanks.

@compnerd
Copy link
Member

The only bits that you should need to install is Visual Studio; Visual Studio already provides CMake + Ninja. The only other dependency is flex and bison which is part of WinFixBison (which is why it is referenced), which doesn't need any installation.

That said ... https://github.com/compnerd/ds2/suites/5881671150/artifacts/198772803 or https://github.com/compnerd/ds2/suites/5881671150/artifacts/198772802 from a recent CI run should foot the bill

@gandalfas
Copy link
Author

Thank you for that prebuilt 64-bit binary! That save a lot of time and avoided the post-uninstall crud.

I ran ds2 per the ds2 github page, and have some partial results. You didn't say exactly what you were looking for, so I'll just describe the whole session:

I ran the ds2 server in one command prompt and the lldb client in another. I had server prog crashes at first, suspected the port number, relearned about that, and found that 50000 worked. At repeated trial runs, the failed ones usually caused the port number to be made unavailable and on a subsequent re-use of that port, it caused server ds2 to crash at connection to client time. Going to the next port number worked for a while, but eventually no port number was workable (server always crashed). But one or two tries had some success, shown below.

server window - ds2

-> ds2 gdbserver localhost:50002 "K:\Kim Shared\CodeLab\SwiftTests\hello.build\debug\hello.exe"
(waited for client's 'gdb-remote' command)
Hello, world! ______ # first print stmt - did not wait at start of prog
enter something -> ______ # second print stmt
(entered 'abc')
End of File was reached - aborting... ______ # final print stmt => readline failed

Notes:

  • print to std output worked. readline from std input failed
  • only one command prompt existed - the initial one in which ds2 was launched - that was inherited by the debuggee and used for its stdio (in case you were wondering if a second command prompt would be launched)
  • obviously no command prompt was needed by lldb user cmds, since it received its commands over TCP
  • there was an oddity at end of debuggee execution, where both the debuggee and ?another process? were both reading from std input in the one command prompt. I am not sure how it got into that state, but if it is important, I can reboot and repeat the test.

client window - lldb

-> lldb "K:\Kim Shared\CodeLab\SwiftTests\hello.build\debug\hello.exe"
(lldb) target create "K:\Kim Shared\CodeLab\SwiftTests\hello\.build\debug\hello.exe" _____ # output from lldb
Current executable set to 'K:\Kim Shared\CodeLab\SwiftTests\hello.build\debug\hello.exe' (x86_64). _____ # output from lldb
(lldb) gdb-remote localhost:50002 _____ # my command, per the ds2 web page
error: Connection shut down by remote side while waiting for reply to initial handshake packet
(lldb)

Notes:

  • never really got to send any commands to the server after the gdb-remote command

So, even though I never got remote debugging fully working, was this informative enough to give you clues? If not, I can retry - would you have any thoughts on likely causes for the client error?

@gandalfas
Copy link
Author

@compnerd and @adam-fowler,

Was there anything more I can do to help gather information on this?

Or, are we thinking that we can't yet identify which project this should be submitted to? e.g.:

  • vadimcn/vscode-lldb - launcher of lldb - is it mishandling the setup of stdio when a custom LLDB is involved?
  • apple/swift-lldb - custom LLDB - is it mishandling the redirecting of stdio to the VS Code pane?

If we don't know, should I submit it to vadimcn/vscode-lldb because that component is issuing the errors above, in 'Actual Behavior'? it would at least be a place to start.

Any guidance would be much appreciated.
Thanks, Kim

@compnerd
Copy link
Member

compnerd commented Jun 6, 2022

Hmm, that is interesting. It sounds like even without lldb in the picture, the standard input is ignored? I think that this is sounding more like a Swift runtime issue rather than lldb - it seems like the stream isn't being setup. It may be interesting to a) set a breakpoint on main and see what the stdin handle is setup to b) possibly see if procmon helps see what is going on in the setup?

@compnerd
Copy link
Member

compnerd commented Jun 6, 2022

BTW, the re-start issue is related to sockets - there is a small timeout associated with sockets that needs to elapse. You can use the -R (or maybe -r?) option to open the socket with SO_REUSEADDR which would avoid that. Any port above 1024 should be available for non-Administrator use IIRC.

@gandalfas
Copy link
Author

even without lldb in the picture, the standard input is ignored?

actually, in that case, std in and std out are handled just fine by the program on its own. noted above in "Variations":

Likewise when I run the program directly from the command prompt (no LLDB), the prog uses stdin/stdout just fine in that same command prompt window.

It may be interesting to a) set a breakpoint on main and see what the stdin handle is setup to b) possibly see if procmon helps see what is going on in the setup?

Sure, I will try these.

@gandalfas
Copy link
Author

I added these statements to the top of program:

import Foundation // exit()

let myStdIn  = FileHandle.standardInput
let myStdOut = FileHandle.standardOutput
let myStdErr = FileHandle.standardError

print("myStdIn:  \(myStdIn)")
print("myStdOut: \(myStdOut)")
print("myStdErr: \(myStdErr)")

print("Hello, world!")

Running at the cmd prompt (no LLDB) gives this output:

myStdIn:  <FileHandle: 0x00000178d8bc6650>
myStdOut: <FileHandle: 0x00000178d8bcc1a0>
myStdErr: <FileHandle: 0x00000178d8bcbb50>
Hello, world!

Running via VS Code > Run > Start Debugging, and stepping through the 3 initializations, gives this, using 'v myStdIn' (gives same results as hovering over myStdIn):

(Foundation.FileHandle) myStdIn = 0x000001dc814d3f60 {
  Foundation.NSObject = {}
  _handle = 0x354
  _closeOnDealloc = false
  currentBackgroundActivityOwner = nil
  readabilitySource = nil
  writabilitySource = nil
  privateAsyncVariablesLock = 0x000001dc814cc700 {
    Foundation.NSObject = {}
    mutex = 0x1dc814f3c00 {
      pointee = {}
    }
    timeoutCond = 0x1dc814cd180 {
      pointee = {}
    }
    timeoutMutex = 0x1dc814c98d0 {
      pointee = {}
    }
    name = nil
  }
  _queue = nil
  _readabilityHandler = nil
  _writeabilityHandler = nil
}

and 'v myStdOut' gives:

(Foundation.FileHandle) myStdOut = 0x000001dc814c6dd0 {
  Foundation.NSObject = {}
  _handle = 0x364
  _closeOnDealloc = false
  currentBackgroundActivityOwner = nil
  readabilitySource = nil
  writabilitySource = nil
  privateAsyncVariablesLock = 0x000001dc814f5390 {
    Foundation.NSObject = {}
    mutex = 0x1dc814cf2a0 {
      pointee = {}
    }
    timeoutCond = 0x1dc814c3930 {
      pointee = {}
    }
    timeoutMutex = 0x1dc814f4420 {
      pointee = {}
    }
    name = nil
  }
  _queue = nil
  _readabilityHandler = nil
  _writeabilityHandler = nil
}

@compnerd
Copy link
Member

compnerd commented Jun 6, 2022

It seems reasonable - perhaps compare the value to the handle from C (GetStdHandle(STD_INPUT_HANDLE)).

@gandalfas
Copy link
Author

Will do.

Meanwhile, I ran ProcMon and after filtering out all unrelated processes, during the 9 seconds after Start Debugging, I have 15,000 lines, all from swiftc (starting the debug kicks off a quick build to ensure bld is uptodate), swift-build.exe, swift-frontend.exc, codelldb.exe, code.exe, swift.exe, conhost.exe, cmd.exe. A bit of a jungle, not sure which of them is safe to filter out.

@gandalfas
Copy link
Author

In short, the Swift handles are equal to the C handles. I added a C DLL to the Swift main prog. Code:

    HANDLE myStdInputHdlFromC = GetStdHandle(STD_INPUT_HANDLE);
    printf("myStdInputHdlFromC: %x\n", myStdInputHdlFromC);

Running the program in the debugger:

Swift:
  myStdIn = 0x0000027c1efd4b90 {    ...   _handle = 0x338       -- using 'v' cmd again
  myStdOut = 0x0000027c1efd31c0 {  ...   _handle = 0x33c

C:
   stdin handle: 0000338 (%x, hex)      -- obtained through hover over variable
   stdout handle: 000033c

I also ran the program at the cmd prompt (no LLDB), but that output was not helpful - all values were nonzero (good), but no handle values are shown in the Swift print stmt. But the above at least shows us the handles are identical in the debug environment.

@compnerd
Copy link
Member

compnerd commented Jun 6, 2022

Ugh, wait, I wonder if you are running into a "feature" of lldb. One thing that is really annoying about lldb is that it will screw up sometimes with redirection. I've noticed that on Windows, when running with lldb, you will need to switch windows to the lldb input and press the enter key before the inferior will accept any input. I think that should actually make this function properly. If that works, I don't really know how to replicate that with the VSCode setup, but that is likely something to do be done in vscode-lldb.

Note that in my experience, you will also need to do this trick after triggering a breakpoint.

@gandalfas
Copy link
Author

OK thanks, I will experiment with that tomorrow morning. But if I remember correctly, when I remove the setting that points to the custom LLDB, the normal LLDB has correct behavior in terms of stdin/stdout. I'll reverify that as well. Have a good night! (if you're in the US)

@adam-fowler
Copy link
Contributor

@Kim4444 when you run your application in lldb can you redirect stdout to a file using

process launch -e stdout.txt -- myApplication.exe

@adam-fowler
Copy link
Contributor

@Kim4444 when you run your application in lldb can you redirect stdout to a file using

process launch -e stdout.txt -- myApplication.exe

Ok I have verified this works as expected

@compnerd
Copy link
Member

compnerd commented Jun 6, 2022

@adam-fowler I believe that the issue is the input rather than the output. The input is blocked by the lldb instance (which is unblocked by the return), and the inferior will accept input subsequently. I think that the descriptor might be shared?

@adam-fowler
Copy link
Contributor

I've had a look through the vscode-lldb code and it looks like the stdio is setup here
https://github.com/vadimcn/vscode-lldb/blob/54d4fbb2dead83e98bd44d07057b67efc4305531/adapter/src/debug_session.rs#L877
From what I can work out (my Rust is rusty, bet nobody made that joke before) it sets stdin to CONIN$ and stdout to CONOUT$. The LLDB SDK docs are not particularly helpful.

@gandalfas
Copy link
Author

gandalfas commented Jun 6, 2022

lldb from 14.0.4

I have been searching for a windows build, but no luck. I'd really prefer not to get all the needed tools to build it from source (due to time, not much free disk space).

Questions:
Q1. Are there any prebuilt versions that would do?

Q2. Alternatively, (and I don't know git) is it feasible to compare the source code for the custom lldb vs the source code for vscode-lldb's version? or is that likely to produce volumes of differences with little chance of finding any stdin code changes?

@gandalfas
Copy link
Author

gandalfas commented Jun 7, 2022

Another thought:

Q3. Am I the only Windows/VS Code/CodeLLDB/custom LLDB developer to have this debugging issue? Or is this broken for all such users?

Q4. Have either of you, if you've tried to reproduce the issue, had success or failure? If this scenario does work for either of you, that shines a whole different light on it.

@gandalfas
Copy link
Author

gandalfas commented Jun 7, 2022

I thought I'd look on YouTube for uses of LLDB from the command line, to see if LLDB and the user program shared a window for stdio (like CodeLLDB's LLDB), or if they each had their own window (like the custom LLDB):

In 2 demos, one for a Mac and one for Linux, both processes shared 1 window.

Q5. Is it possible that the custom LLDB would work better under VS Code if it too allowed lldb i/o and user program i/o to share one window?

@gandalfas
Copy link
Author

@compnerd, @adam-fowler, any thoughts on Questions 1-5 above? And I'll add:

Q6. Does it seem reasonable to move this issue to the custom LLDB?

Thanks!

@compnerd
Copy link
Member

compnerd commented Jun 8, 2022

  1. I don’t know if a prebuilt version of lldb for windows
  2. I suppose it should be possible, but really, you’re better off manually dodging the code based at that point
  3. I’ve usually been using WinDBG for debugging as it gives me better information for the areas I care about - the calls into the system and the disassembly
  4. The console sharing I definitely have experienced before
  5. I don’t know how the DAP could accomplish that, it doesn’t seem like it would impact that?
  6. Moving it to the apple/llvm-project is unlikely to gain any value as I’m not aware of anyone working on lldb there other than me - and the changes that I’ve done are in llvm.org, where you don’t have swift integration.

I’m not convinced that this has anything on the lldb side and it’s more likely that the plugin has some assumptions. IIRC the Swift extensions are for the language support (integration of the compiler in the interpreter, expression evaluation) which wouldn’t impact the shell itself. Diffing the code bases might find what the difference is in the shell.

@gandalfas
Copy link
Author

  1. I’ve usually been using WinDBG for debugging

Interesting. How well does WinDbg handle the display of Swift variables (Int, String, objects)? I recall that the LLDB shipped with the CodeLLDB extension did not handle them, it displays "Unable to determine byte size".

@compnerd
Copy link
Member

Interesting. How well does WinDbg handle the display of Swift variables (Int, String, objects)? I recall that the LLDB shipped with the CodeLLDB extension did not handle them, it displays "Unable to determine byte size".

Sadly, it's about the same. However, that is due to the quality of the debug info we current generate. I think that we should be able to handle this appropriately and emit the needed debug info which would allow us to see the values rendered properly.

@gandalfas
Copy link
Author

I’m not convinced that this has anything on the lldb side and it’s more likely that the plugin has some assumptions. IIRC the Swift extensions are for the language support (integration of the compiler in the interpreter, expression evaluation) which wouldn’t impact the shell itself. Diffing the code bases might find what the difference is in the shell.

In Brief

First I tried to look at the uses of 'lldb.library' in the source for CodeLLDB extension. After a fairly quick look, nothing jumped out at me that would suggest it was handling a custom LLDB differently than the default LLDB in terms of stdio, but it was not thorough by any means.

Next, I tried to identify the source for the LLDB packaged with CodeLLDB, and the source in the Swift custom LLDB. I downloaded both, and diff'ed them, recursively. There were 29,000 lines in the diff output (wow!); 68 lines contain either stdin or stdout.

Details

1. CodeLLDB

The source I used for looking at uses of 'lldb.library'...

2a. version of LLDB used by CodeLLDB

The source I used in the comparison...

  • I have this installed: vadimcn.vscode-lldb-1.7.0 (liblldb.dll is dated 3/31/22)
  • @adam-fowler said: "When I say standard LLDB I mean the one that is packaged with vscode-lldb. Looking at the commit comments from vscode-lldb this would be from https://github.com/llvm/llvm-project, build id 1927, committed 3/05/22 (not totally sure what build id indicates though)." I found these commit comments. Since 3/05/22 was the commit date, the likely LLVM version of LLDB would be from 14.0.0-rc2, released 3/01/22 (or possibly LLVM version 14.0.0-rc1, released 2/09/22). I took rc2, since vadimcn's previous take of LLDB was build id 1831, committed 10/29/21, which was probably from LLVM version 13.0.0, released 9/30/21. Meaning, vadimcn seem to update their local copy at each major version release of LLVM.
  • Thus I took:
    https://github.com/llvm/llvm-project/releases/tag/llvmorg-14.0.0-rc2 > lldb-14.0.0rc2.src.tar.xz

2b. Swift Custom LLDB

The source I used in the comparison...

2c. diffing

diff -r lldb-14.0.0rc2.src\source lldb-llvm-project-swift-5.7-DEVELOPMENT-SNAPSHOT-2022-05-04-a\source > lldb-14.0-CodeLLDB--lldb-5.7-SwiftCustom.txt

Final Thoughts

The 68 lines of stdio diffs are perhaps due to changes made to LLVM's LLDB at some point after the Swift custom version was branched off. Or they were made to the Swift custom branch after branching from the LLVM source (and I understand you think this very unlikely). Or, undetected here, there were other changes made to CodeLLDB's copy after getting a snapshot from LLVM (is this at all likely?). Or a combination.

At any rate, to me, even without understanding the 68 lines or the context, their presence itself seems enough to warrant moving the focus to these LLDB diffs, before looking further into the CodeLLDB extension. With any luck, it might mean that the fix will be to merge some/all recent LLVM LLDB changes into the Swift custom LLDB. @compnerd, thoughts on that?

I can make my diff file available, just LMK if you want that.

@compnerd
Copy link
Member

The 14.0.0 RC release is significantly further ahead. We really should take a look at the branch point and ensure that the LLDB build at the branch point works identically from llvm.org and swift.org (that will require building LLDB at both points - a prebuilt binary won't exist for the llvm.org version).

If you really think that this was fixed recently, testing with the rebranch snapshot is a good way to get a newer LLDB (https://ci-external.swift.org/job/oss-swift-rebranch-windows-toolchain-x86_64-vs2019/353/artifact/build/artifacts/installer.exe is pretty recent).

If the diff is just 68 lines, that seems tractable to go through and figure out if it may be responsible. If there is no dependency on clang or LLVM APIs, it might even be possible to backport.

@gandalfas
Copy link
Author

Sure, I can test with that snapshot! I was too late to grab that, so I got #374. To clarify: does 'rebranch' mean this snapshot has all changes that were committed to LLVM's LLDB since the original branch point that created the custom LLDB?

@compnerd
Copy link
Member

"rebranch" is just a name, the Swift toolchain is a fork of LLVM and will merge changes periodically. This is one of this point, where it syncs up with upstream at a point and is stabilized again.

@gandalfas
Copy link
Author

If you really think that this was fixed recently, testing with the rebranch snapshot is a good way to get a newer LLDB (https://ci-external.swift.org/job/oss-swift-rebranch-windows-toolchain-x86_64-vs2019/353/artifact/build/artifacts/installer.exe is pretty recent).

I have finally tested with the rebranch snapshot (version 5.8-dev, number 374), and that failed:

  1. I ran VS Code > Start Debugging, with:
    "lldb.library": "C:\Library\Developer\Toolchains\unknown-Asserts-development.xctoolchain\usr\bin\liblldb.dll",
    set in the global settings.json.
    Unfortunately I got identical results as my prior install 5.7-dev: a new command-prompt window appears, presumably to hold stdout and receive stdin, but the print() and readLine() calls have no effect on it.

  2. I ran 'lldb' from the command line, and it also exhibits identical behavior to my prior 5.7-dev: a new command-prompt window appears, and stdout appears and receiving stdin works in there, i.e. correct behavior.

Thus, no improvement on case 1.

Note: if anyone retries this, an install of Python 3.7 is required.

Sigh.

@adam-fowler adam-fowler added the lldb lldb or vscode-lldb issue label Sep 15, 2022
@adam-fowler
Copy link
Contributor

@compnerd @Kim4444 Hi guys, I am going to disable the swift lldb setup for windows as it does not work. It will default to do the built in version of lldb. Unless someone has found a solution to the stdio being used to new terminal.

@compnerd
Copy link
Member

@adam-fowler I think that is a bad choice. Overall, the debugger currently at least provides local variables and does provide stack traces. I don't think that the stdio access issue warrants the removal of getting useful stack traces.

@gandalfas
Copy link
Author

@adam-fowler I agree with @compnerd. I have been rotating between the swift custom lldb, the lldb packaged with CodeLLDB, and using the swift custom lldb from the command prompt, all depending on the needs of whatever program I am debugging. Some progs for example do not use stdio much and in that case having good local variable display is a good thing.

Meanwhile, my next step is to contact the CodeLLDB folks to see if they had removed/modified the handling of stdio in their local fork, due to something I saw in that fork.
Unfortunately I have been detained temporarily. Hoping to pursue soon.

@adam-fowler
Copy link
Contributor

Does the broken stdio break the test explorer?

@compnerd
Copy link
Member

@adam-fowler I don't believe it does. I was able to report the failure with 5.8 and the test explorer because it stopped working, which was rather unfortunate. I had been able to use that to debug individual tests, which was rather convenient.

@adam-fowler
Copy link
Contributor

Yeah that was because of a change to SwiftPM that broke listing tests without building. I was hoping that could get fixed quickly. I'll chase it up.

@gandalfas
Copy link
Author

@compnerd and @adam-fowler, one year later: some good news!

I have upgraded to Swift 5.9 and confirmed the problem still exists, i.e.:

When debugging a command line program, at the launch of Swift's custom LLDB by the Swift extension 
for VS Code (vscode-swift), a new command prompt window is created, titled 'hello.exe', 
presumably for the user program's stdout and stdin.  But during execution, no print statement 
output ever appears in that window, and neither does any appear in the VS Code lower pane in 
tab 'Terminal'.  Also, when the program attempts to do 'readline()' to read stdin, it gets an 
EOF result - no user input is possible.

The good news is that I just found a tolerable workaround using attach:

  • first insert a readline() at the start of the user program.
  • run the user program from a command prompt - it will stop at the readline() and wait for user input.
  • in VS Code, settings.json file, enable the Swift custom LLDB with: "lldb.library": "C:\Library\Developer\Toolchains\unknown-Asserts-development.xctoolchain\usr\bin\liblldb.dll"
  • in VS Code, in launch.json, configure the debugger to attach rather than launch (details below).
  • in VS Code, hit F5 to start the debugger.
  • at that point the Swift custom LLDB will find the process and attach.
  • in VS Code, set a breakpoint at a line of interest.
  • then go to command prompt, hit Enter to satisfy the readline() and allow execution to continue after the readline().
  • the program will run until it hits the breakpoint. continue using VS Code to debug the program.
  • and most importantly, user program stdout and stdin works perfectly, using the command prompt window that the program was started in.

launch.json: (note that request = attach)

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "lldb",
            "request": "attach",
            "name": "DebugAttach",
            "program": "Hello.exe"
        }
    ]
}

Note that this workaround might well have worked on the versions of a year ago - I did not restore them and check. I.e., it may be that no fixes were made in the last year to get this workaround to work.

So, I just wanted to report this to help any users of Swift on Windows, and for maintainers in case it sheds any new light.

I am still hopeful someone might be able to isolate the problem to the Swift extension, the CodeLLDB extension, or the custom LLDB, and then to fix things so that the initial readline() and attach will not be necessary - i.e. that a launch will work.

If/when anyone thinks this should be moved to a different github repo, please LMK.

Thanks!

Environment (differs from Env at original posting)

Swift 5.9 on Windows 10
VSCode 1.80.1
Swift extension 1.5.2
CodeLLDB extension 1.10.0

@compnerd
Copy link
Member

compnerd commented Oct 4, 2023

@gandalfas I'm now thinking that this is actually related to CodeLLDB. Fortunately, this is easy to resolve: stop using CodeLLDB. We are looking to migrate to a new DAP on Windows, which is already available in the preview release. There is a bug in LLDB that will hopefully be resolved soon. There are other issues with CodeLLDB that have been noticed (e.g. print statements being discarded), and we did run into ABI breakages with the CodeLLDB implementation, so I am leaning towards just weaning ourselves off of it to a DAP that we can easily work with.

@adam-fowler
Copy link
Contributor

Hi @gandalfas
There has been some changes you might be interested in. We hit an issue on the main branch of Swift where CodeLLDB stopped completely due to an API change between different versions of LLVM. You can find the details here vadimcn/codelldb#976

The LLVM codebase actually has a debug adapter (DAP) for VSCode. This is not included in the macOS or Linux toolchains, but is in the Windows Swift toolchain. I have done a pre-release of the Swift extension that uses this DAP. You can use this by installing the swift extension pre-release and then go to the settings and select Swift.Debugger.UseDebugAdapterFromToolchain.

I would be interested in your experiences with running this instead of CodeLLDB

@adam-fowler
Copy link
Contributor

haha @compnerd beat me to it

@gandalfas
Copy link
Author

Thanks for your work on this!!

I'm not seeing any improvement. From ProcessExplorer I can see that codelldb.exe from my vscode\extensions\vadmcn.vscode folder is still invoked when I hit F5 (and that is bad, right?).

Details:
I uninstalled the Swift extension, then installed the pre-release.
Tried to uninstall CodeLLDB, but that failed because the Swift extension depends on it, per VS Code.
I set the checkbox for that setting you mention. (FYI above you have capital S, D, U, but those are lowercase when the .json entry is created by the checkbox. but neither spelling seems to improve things.)

I must be missing a step?

@adam-fowler
Copy link
Contributor

Did you set the settings? Have you got custom launch.json entries? Open launch.json and change "type": "lldb" to "type": "swift-lldb"

@gandalfas
Copy link
Author

gandalfas commented Oct 5, 2023

Yes, I have a launch entry. I made the change you gave, but I still have been unsuccessful. I've deleted the swift extension and codelldb extension subfolders after uninstalling them in VSCode. Then installed the preview swift extension. Then at start-debugger time, still getting no output in the blank cmd prompt.

Here is my launch config:

        {
            "type": "swift-lldb",
            "request": "launch",
            "name": "Debug",
            "program": "${workspaceFolder}\\objdbg\\Hello.exe",
            "args": ["testarg"],
            "cwd": "${workspaceFolder}",
            "env": {
                "Path": "${env:Path};K:\\KimsLib\\bin"
            }
        }

I suspect that since I did not initially have "type" set to "swift-lldb", there may be other entries that I am missing? I noticed many other debugger-oriented settings are displayed by a dropdown when I am editing the launch.json file. Perhaps their default values are not working?

@adam-fowler
Copy link
Contributor

@compnerd This is still an issue. See #700. Have you any new ideas why Windows LLDB would be spawning a new console window for its stdio and not outputting directly to the console?

@compnerd
Copy link
Member

compnerd commented Mar 1, 2024

No, I don't know off hand why it would do that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working lldb lldb or vscode-lldb issue windows Issue specific to Windows
Projects
None yet
Development

No branches or pull requests

3 participants