[LLDB] Show exit code on Windows if process can't launch (#141290)

When running a process that would exit before LLDB could stop the
target, it would try to interpret (and subsequently format) the exit
code as a Win32 error. However, processes on Windows won't return Win32
errors in that case. They will often return an
[NTSTATUS](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55).
One common case for this to occur is when a DLL is missing. In that
case, the process will start successfully, but it will exit with
`STATUS_DLL_NOT_FOUND`.
LLDB would previously return "unknown error", because it tried to
[`FormatMessage`](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-formatmessage)
`0xC0000135` which doesn't work, so it fell back to "unknown error".

This PR changes the error to be the string "Process prematurely exited
with {0:x}" and doesn't try to format the exit code. One could
`FormatMessage` an `NTSTATUS` by passing `FORMAT_MESSAGE_FROM_HMODULE`
and a handle to `ntdll.dll`, however, I don't think we can get the
required format arguments (e.g. the missing DLL name - `%hs`).
This commit is contained in:
nerix 2025-05-27 22:16:03 +02:00 committed by GitHub
parent 317f3bdcc1
commit c0a8723106
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 41 additions and 1 deletions

View File

@ -483,7 +483,8 @@ void ProcessDebugger::OnExitProcess(uint32_t exit_code) {
// of the error otherwise WaitForDebuggerConnection() will be blocked.
// An example of this issue is when a process fails to load a dependent DLL.
if (m_session_data && !m_session_data->m_initial_stop_received) {
Status error(exit_code, eErrorTypeWin32);
Status error = Status::FromErrorStringWithFormatv(
"Process prematurely exited with {0:x}", exit_code);
OnDebuggerError(error, 0);
}
}

View File

@ -0,0 +1,5 @@
C_SOURCES := main.c
DYLIB_C_SOURCES := dummy_dll.c
DYLIB_NAME := dummy_dll
include Makefile.rules

View File

@ -0,0 +1,27 @@
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
class MissingDllTestCase(TestBase):
@skipUnlessWindows
def test(self):
"""
Test that lldb reports the application's exit code (STATUS_DLL_NOT_FOUND),
rather than trying to treat it as a Win32 error number.
"""
self.build()
exe = self.getBuildArtifact("a.out")
dll = self.getBuildArtifact("dummy_dll.dll")
self.assertTrue(remove_file(dll))
target = self.dbg.CreateTarget(exe)
self.assertTrue(target, VALID_TARGET)
launch_info = lldb.SBLaunchInfo(None)
launch_info.SetWorkingDirectory(self.get_process_working_directory())
error = lldb.SBError()
target.Launch(launch_info, error)
self.assertFailure(error, "Process prematurely exited with 0xc0000135")

View File

@ -0,0 +1 @@
__declspec(dllexport) void SomeFunction(void) {}

View File

@ -0,0 +1,6 @@
__declspec(dllimport) void SomeFunction(void);
int main(void) {
SomeFunction();
return 0;
}