Page MenuHomePhabricator

[pecoff] Implement ObjectFilePECOFF::GetDependedModules()

Authored by asmith on Oct 10 2018, 10:23 AM.



This parses entries in pecoff import tables for imported DLLs and
is intended as the first step to allow LLDB to load a PE's shared
modules when creating a target on the LLDB console.

Diff Detail

Event Timeline

asmith created this revision.Oct 10 2018, 10:23 AM

If you plan to invest in more substantial changes in ObjectFilePECOFF, it might worth considering a complete re-write in terms of llvm::object::coff. It has pretty comprehensive support for the PE/COFF spec, so it's just a matter of implementing ObjectFilePECOFF on top of it.


Does this actually need to be a recursive_mutex?

Hui added a subscriber: Hui.Oct 10 2018, 6:38 PM
Hui added inline comments.

I think there is access to the member 'm_filespec_ap'.


Given no valid UUID for PECOFF for now, you can't get a valid image based on a filename only.
So if the exe target is filed on LLDB, its shared modules probably can't be appended to the target's image list until the process is launched. This makes it impossible for developers to lookup any symbol from the shared libraries or set any breakpoint by name to the shared libraries.

For example,

$ ldd main.exe
        ntdll.dll => /c/WINDOWS/SYSTEM32/ntdll.dll (0x7ffc5e070000)
        KERNEL32.DLL => /c/WINDOWS/System32/KERNEL32.DLL (0x7ffc5ddb0000)
        KERNELBASE.dll => /c/WINDOWS/System32/KERNELBASE.dll (0x7ffc5ad00000)
        DllB.dll => /c/DllB.dll (0x7ffc31450000)
        DllA.dll => /c/DllA.dll (0x7ffc2f7b0000)
./lldb.exe main.exe
(lldb) image list
[  0]                                                         C:\main.exe

However we expect 3 images at the moment (excluding windows system libraries)

./lldb.exe main.exe
(lldb) image list
[  0]                                                         C:\main.exe
[  1]                                                         C:\DllA.dll
[  2]                                                         C:\DllB.dll

So it will be better to have full path of the imported modules here.


I'm afraid of a race condition here. It seems we can occur here in different threads simultaneously (due to the mutex lock at the line 810), but it is not thread-safe to change and read same unique_ptr in different threads simultaneously. It is safe to move it between threads, but it's not the case. I would guard all actions on unique_ptr with the mutex.


Also consider the following scenario:

Thread A: GetDependentModules -> ParseDependentModules -> e.g. line 837, idx is greater than 0, but less than num_entries;
Thread B: GetDependentModules (or DumpDependentModules) -> ParseDependentModules -> ParseDependentModules returns num_modules less than actual;
Thread A: continues to write into m_filespec_ap;
Thread B: reads m_filespec_ap which is modified at the time by Thread A.


The same situation as I've described above.

asmith updated this revision to Diff 170781.Oct 23 2018, 4:32 PM

I think this addresses all the previous comments.

I think this addresses all the previous comments.

Still didn't get a clear answer if the mutex being used needs to be recursive. If it doesn't, perhaps std::mutex can be used instead of std::recursive_mutex? Not everyone agrees with me, but I often prefer to be too strict rather than too relaxed.

asmith marked 6 inline comments as done.Oct 23 2018, 4:38 PM

Zach: yes the module mutex needs to be recursive. Plenty of places where the symbol file stuff can call other symbol file APIs. To avoid A/B locking issues, the lldb_private::Module, lldb_private::ObjectFile and lldb_private::SymbolVendor and lldb_private::SymbolFile all use the module mutex.

lemo added a subscriber: lemo.Oct 24 2018, 11:39 AM

drive by CR notes:

  1. does this handle forwarding imports? (it doesn't seem to from a quick glance at the code)
  2. can you please add, or extend the existing test to cover the transitive case? A simple dag would suffice (ex. make both dllA and dllB implicitly import dllC)

nit: either explicitly assign values to all or none

labath added a subscriber: labath.Oct 29 2018, 3:27 AM

It sounds like at least part of this could be tested by adding the ability to dump dependent modules to lldb-test object-file (which I think would fit very nicely within the current information printed by that command). I seem to recall seeing code like that in some patch but it seems to be missing here now.

asmith added a comment.Nov 6 2018, 5:22 AM

The ability to dump dependent modules is in another review that is waiting on this one.

Could we reverse the dependencies between the two? I.e., first add the necessary functionality to lldb-test and then write the test using that? Or just merge that into a single patch?

Some of the information tested here is already available there (list of sections) other can be added easily (list of symbols).

asmith updated this revision to Diff 176259.Dec 1 2018, 9:39 AM

Add changes from D53096 as requested.

labath accepted this revision.Dec 3 2018, 1:01 AM

Thanks for adding the test. looks good to me.


Consider using Optional<T> instead of unique_ptr to reduce pointer chasing.

Also, do these have to be mutable? I was expecting that you needed to lazy-initialize them from some const member, but I couldn't find any evidence of that...

This revision is now accepted and ready to land.Dec 3 2018, 1:01 AM
asmith updated this revision to Diff 177036.Dec 6 2018, 1:30 PM
asmith accepted this revision.Dec 6 2018, 1:34 PM
asmith updated this revision to Diff 177038.
asmith marked 2 inline comments as done.
asmith closed this revision.Dec 6 2018, 1:39 PM


This PR broke the green dragon bots, see the following log file:

I was about to revert it but it looks @stella.stamenova landed a fix that looks good:

Please watch the bots after you land a change.