Skip to content

Commit

Permalink
[lldb][Windows] Always call SetExecutableModule on debugger connected
Browse files Browse the repository at this point in the history
In `ProcessWindows::OnDebuggerConnected` (triggered from
`CREATE_PROCESS_DEBUG_EVENT`), we should always call
`Target::SetExecutableModule` regardless of whether LLDB has already
preloaded the executable modules. `SetExecutableModule` has the side
effect of clearing the module list of the Target, which help make sure
that module #0 is the executable module and the rest of the modules are
listed according to the DLL load order in the process (technically this
has no real consequences but it seems to make more sense anyway.) It
also fixes an issue where the modules preloaded by LLDB will be
duplicated when the debuggee process actually loads the DLL.

Reviewed By: labath

Differential Revision: https://reviews.llvm.org/D134636
  • Loading branch information
alvinhochun authored and mstorsjo committed Sep 30, 2022
1 parent 67bcf98 commit fe17e02
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 19 deletions.
36 changes: 17 additions & 19 deletions lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
Expand Up @@ -653,28 +653,26 @@ void ProcessWindows::OnDebuggerConnected(lldb::addr_t image_base) {
LLDB_LOG(log, "Debugger connected to process {0}. Image base = {1:x}",
debugger->GetProcess().GetProcessId(), image_base);

ModuleSP module = GetTarget().GetExecutableModule();
if (!module) {
// During attach, we won't have the executable module, so find it now.
const DWORD pid = debugger->GetProcess().GetProcessId();
const std::string file_name = GetProcessExecutableName(pid);
if (file_name.empty()) {
return;
}

FileSpec executable_file(file_name);
FileSystem::Instance().Resolve(executable_file);
ModuleSpec module_spec(executable_file);
Status error;
module =
GetTarget().GetOrCreateModule(module_spec, true /* notify */, &error);
if (!module) {
return;
}
ModuleSP module;
// During attach, we won't have the executable module, so find it now.
const DWORD pid = debugger->GetProcess().GetProcessId();
const std::string file_name = GetProcessExecutableName(pid);
if (file_name.empty()) {
return;
}

GetTarget().SetExecutableModule(module, eLoadDependentsNo);
FileSpec executable_file(file_name);
FileSystem::Instance().Resolve(executable_file);
ModuleSpec module_spec(executable_file);
Status error;
module =
GetTarget().GetOrCreateModule(module_spec, true /* notify */, &error);
if (!module) {
return;
}

GetTarget().SetExecutableModule(module, eLoadDependentsNo);

if (auto dyld = GetDynamicLoader())
dyld->OnLoadModule(module, ModuleSpec(), image_base);

Expand Down
2 changes: 2 additions & 0 deletions lldb/test/Shell/Target/Inputs/main.c
@@ -0,0 +1,2 @@
__declspec(dllimport) void exportFunc(void);
int main() { exportFunc(); }
1 change: 1 addition & 0 deletions lldb/test/Shell/Target/Inputs/shlib.c
@@ -0,0 +1 @@
__declspec(dllexport) void exportFunc(void) {}
24 changes: 24 additions & 0 deletions lldb/test/Shell/Target/dependent-modules-nodupe-windows.test
@@ -0,0 +1,24 @@
# REQUIRES: system-windows

# Checks that dependent modules preloaded by LLDB are not duplicated when the
# process actually loads the DLL.

# RUN: %clang_host -g0 -O0 -shared %S/Inputs/shlib.c -o %t.shlib.dll \
# RUN: %if windows-msvc %{-Wl,-implib:%t.shlib.lib%} \
# RUN: %else %{-Wl,--out-implib=%t.shlib.lib%}
# RUN: %clang_host -g0 -O0 %S/Inputs/main.c %t.shlib.lib -o %t.main.exe
# RUN: %lldb -b -o "#before" -o "target modules list" -o "b main" -o run \
# RUN: -o "#after" -o "target modules list" %t.main.exe | FileCheck %s

# CHECK-LABEL: #before
# CHECK-NEXT: target modules list
# CHECK-NEXT: .main.exe
# CHECK-NEXT: .shlib.dll

# CHECK-LABEL: #after
# CHECK-NEXT: target modules list
# CHECK-NEXT: .main.exe
# CHECK-NEXT: ntdll.dll
# CHECK-NEXT: kernel32.dll
# CHECK: .shlib.dll
# CHECK-NOT: .shlib.dll

0 comments on commit fe17e02

Please sign in to comment.