I started working on implementing a DynamicLoader plugin.
While it's indeed quite simple, I still have some questions about why it's necessary to make shared library load/unloading work.
I do understand the use case for other platforms, because there is a non-trivial amount of work required to detect shared library loading / unloading. On Windows however, there is no work involved because the OS tells us at every occurrence of a shared library load or unload. As a result, my DynamicLoader implementation basically boils down to some code like this in my process plugin
if (event is a module load)
else if (event is a module unload)
In each of these two methods, all I do is construct an empty ModuleList, add a single item to it, set the load address, and call GetTarget().ModulesDidLoad() or GetTarget().ModulesDidUnload().
So either way I'm calling ModulesDidLoad() / ModulesDidUnload() directly, it's just am I having the Process plugin tell the DynamicLoader to do it, or am I having the process do it itself. Whichever one does it though, it's the same few lines of code to prepare the call to ModulesDidLoad().
That is indeed simple and if you have all the info you need in the message that is sent to the data to the handle, then it doesn't make sense to do this in the dynamic loader. For us, we can use the same dynamic loader plug-in with different Process subclasses since it just uses the process to find a symbol and read data via memory reads. So our dynamic loader will work on core files with ProcessMachCore and it also works with ProcessGDBRemote. In your case, you are getting messages straight from your process runner via the OS which is quite different than any other platform, so don't change anything, but you can continue to do what you do by directly doing the load/unload from the process plug-in and have your DynamicLoaderWindows just not do anything.
One thing you might actually need to do in the DynamicLoaderWindows is find out all the shared libraries that are loaded when you attach to a process. When you attach to a running process in windows, does it give you a bunch of callbacks for each shared library that is already loaded? Just like when you are running and a shared library loads/unloads? Or must you discover them in a different way?
One more question: You said this: "the MacOSX version finds the global list of shared libraries that are loaded, iterates through them, seaches for any modules that are in the target, removes any images from the target that aren't loaded, then sets the section load address for all sections in all modules to the correct value".
Just to clarify some terminology, are "shared library", "module", and "image" here the same thing?
Why would you have a shared library that is loaded but not in the target?
You wouldn't, but you might have said "file a.out" on the command line, and from just inspecting the "a.out" mach-o file it added a bunch of modules to your target. Before you run you would have:
(lldb) image list
But when you run you specified DYLD_LIBRARY_PATH=/tmp/my_dylibs in the environement so when you actually attach to "a.out" you really have a different set of shared libraries:
(lldb) image list
We we start out with a target that contains the first three images, but when we run and get our first batch of shared library loaded notifications we look for "/tmp/a.out" and leave it because it is correct and set its load location, we remove the "/tmp/lib/libc.dylib" from the image list in the target and add the "/tmp/my_dylibs/libc.dylib" and then set its load address, and then we look for "/usr/lib/libxml2.dylib" and keep it because it is correct and set its load addresses.
Where else would it be?
As for setting the section load address for all sections, it sounds like this is the same as just calling module->SetModuleLoadAddress() to the load address of the entire shared library. Is this correct?
If your system always loads all sections by sliding them all by constant amounts, then yes. On MacOSX, all shared libraries in the shared cache will have all their sections moved separately. So we need to load add sections to completely different addresses (we don't just add a constant slide to all of them like module->SetModuleLoadAddress() does). Some sections aren't loaded sometimes (like the "__LINKEDIT" section isn't always loaded for our kernel). So you need to do what you need to do to load things correctly on your system.