--- /dev/null
+LEVEL := ../../make
+
+LD_EXTRAS := -ldllfunc
+C_SOURCES := main.c
+
+include $(LEVEL)/Makefile.rules
+
+a.out: dllfunc
+
+dllfunc:
+ $(MAKE) VERBOSE=1 VPATH=$(SRCDIR) -I $(SRCDIR) -f $(SRCDIR)/dllfunc.mk
+
+clean::
+ $(MAKE) -f $(SRCDIR)/dllfunc.mk clean
--- /dev/null
+"""
+Test that breakpoints work in a DLL
+"""
+
+from __future__ import print_function
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+@skipUnlessWindows
+class WindowsDLLTestCase(TestBase):
+ def setUP(self):
+ TestBase.setUp(self)
+ self.build()
+
+ def test_dll_linking(self):
+ """test that the debugger works with DLLs"""
+
+ exe = self.getBuildArtifact("a.out")
+ target = self.dbg.CreateTarget(exe)
+ self.assertTrue(target and target.IsValid(), "Target is valid")
+
+ self.runCmd("breakpoint set --file main.c --line 16")
+ self.runCmd("breakpoint set --file dllfunc.c --line 18")
+
+ process = target.LaunchSimple(None, None, self.get_process_working_directory())
+
+ self.expect("p x", "16")
+ self.runCmd("thread step-out")
+ self.expect("p x", "16")
+ self.expect("thread step-in")
+ self.expect("thread step-in")
+ self.expect("p n", "8")
+ self.runCmd("c")
+ self.expect("p x", "64")
+ self.runCmd("breakpoint delete 2")
+ self.runCmd("c")
+
+ self.assertEqual(process.GetExitStatus(), 336, PROCESS_EXITED)
--- /dev/null
+//===-- a.c -----------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <windows.h>
+
+BOOL WINAPI DllMain(HINSTANCE h, DWORD reason, void* reserved) {
+ return TRUE;
+}
+
+int __declspec(dllexport) DllFunc(int n) {
+ int x = n * n;
+ return x; // set breakpoint here
+}
--- /dev/null
+LEVEL := ../../make
+
+DYLIB_NAME := dllfunc
+DYLIB_C_SOURCES := dllfunc.c
+DYLIB_ONLY := YES
+
+include $(LEVEL)/Makefile.rules
--- /dev/null
+//===-- main.c --------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <windows.h>
+
+int __declspec(dllimport) DllFunc(int n);
+
+int main(int argc, char ** argv) {
+ int x = DllFunc(4);
+ int y = DllFunc(8); // set breakpoint here
+ int z = DllFunc(16);
+ return x + y + z;
+}
endif
else
$(EXE) : $(OBJECTS) $(ARCHIVE_NAME)
- $(LD) $(OBJECTS) $(LDFLAGS) $(ARCHIVE_NAME) -o "$(EXE)"
+ "$(LD)" $(OBJECTS) $(LDFLAGS) $(ARCHIVE_NAME) -o "$(EXE)"
ifneq "$(CODESIGN)" ""
$(CODESIGN) -s - "$(EXE)"
endif
endif
endif
else
- $(LD) $(DYLIB_OBJECTS) $(LDFLAGS) -shared -o "$(DYLIB_FILENAME)"
+ "$(LD)" $(DYLIB_OBJECTS) $(LDFLAGS) -shared -o "$(DYLIB_FILENAME)"
ifeq "$(SPLIT_DEBUG_SYMBOLS)" "YES"
$(OBJCOPY) --only-keep-debug "$(DYLIB_FILENAME)" "$(DYLIB_FILENAME).debug"
$(OBJCOPY) --strip-debug --add-gnu-debuglink="$(DYLIB_FILENAME).debug" "$(DYLIB_FILENAME)" "$(DYLIB_FILENAME)"
#include "DynamicLoaderWindowsDYLD.h"
+#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/ThreadPlanStepInstruction.h"
+#include "lldb/Utility/Log.h"
#include "llvm/ADT/Triple.h"
return nullptr;
}
-void DynamicLoaderWindowsDYLD::DidAttach() {}
+void DynamicLoaderWindowsDYLD::DidAttach() {
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+ if (log)
+ log->Printf("DynamicLoaderWindowsDYLD::%s()", __FUNCTION__);
-void DynamicLoaderWindowsDYLD::DidLaunch() {}
+ DidLaunch();
+
+ m_process->LoadModules();
+}
+
+void DynamicLoaderWindowsDYLD::DidLaunch() {
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+ if (log)
+ log->Printf("DynamicLoaderWindowsDYLD::%s()", __FUNCTION__);
+
+ ModuleSP executable = GetTargetExecutable();
+
+ if (!executable.get())
+ return;
+
+ // Try to fetch the load address of the file from the process, since there
+ // could be randomization of the load address.
+
+ // It might happen that the remote has a different dir for the file, so we
+ // only send the basename of the executable in the query. I think this is safe
+ // because I doubt that two executables with the same basenames are loaded in
+ // memory...
+ FileSpec file_spec(
+ executable->GetPlatformFileSpec().GetFilename().GetCString());
+ bool is_loaded;
+ addr_t base_addr = 0;
+ lldb::addr_t load_addr;
+ Status error = m_process->GetFileLoadAddress(file_spec, is_loaded, load_addr);
+ if (error.Success() && is_loaded) {
+ base_addr = load_addr;
+ }
+
+ UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, base_addr, false);
+
+ ModuleList module_list;
+ module_list.Append(executable);
+ m_process->GetTarget().ModulesDidLoad(module_list);
+}
Status DynamicLoaderWindowsDYLD::CanLoadImage() { return Status(); }