Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get reason that LoadLibrary cannot load DLL

On Linux and Mac, when using dlopen() to load a shared library that links to another library, if linking fails because of a missing symbol, you can get the name of the missing symbol with dlerror(). It says something like

dlopen failed: cannot locate symbol "foo"

On Windows, when using LoadLibrary() to load a DLL with a missing symbol, you can only get an error code from GetLastError() which for this type of issue will always be 127. How can I figure out which symbol is missing, or a more verbose error message from LoadLibrary() that explains why the function failed?

like image 653
Vortico Avatar asked May 25 '26 21:05

Vortico


1 Answers

I figured out a way using the MSYS2 terminal. Other methods might work with GUI software.

A major caveat is that this can't be done in pure C/C++ and released for end users. It's for developers only, but it's better than nothing.

  • Install Debugging Tools for Windows by downloading the Windows SDK and unchecking everything except Debugging Tools.

    I could be wrong, but it seems that installing this software installs a hook into the Windows kernel to allow LoadLibrary() to write verbose information to stderr.

  • Open the MSYS2 Mingw64 terminal as an administrator and run:

    '/c/Program Files (x86)/Windows Kits/10/Debuggers/x64/gflags.exe' -i main.exe +sls
    

    This prints the following to the terminal to confirm that the registry has been changed:

    Current Registry Settings for main.exe executable are: 00000002
        sls - Show Loader Snaps
    

    Use -sls instead of +sls if you need to undo, since I believe that the change takes place for all programs called main.exe in Windows globally, not just for your file.

  • Then, running main.exe should print debug information to stderr, but since I'm debugging an -mwindows application, it's not working for me. But, for some reason, running the binary with MSYS2's gdb allows this debug information to be printed to stderr.

  • Install mingw-w64-x86_64-gdb with MSYS2 and run gdb ./main.exe and type run or r.

    Search for a section similar to the following:

    warning: 1ec8:43a0 @ 764081125 - LdrpNameToOrdinal - WARNING: Procedure "foo" could not be located in DLL at base 0x000000006FC40000.
    warning: 1ec8:43a0 @ 764081125 - LdrpReportError - ERROR: Locating export "foo" for DLL "C:\whatever\plugin.dll" failed with status: 0xc0000139.
    warning: 1ec8:43a0 @ 764081125 - LdrpGenericExceptionFilter - ERROR: Function LdrpSnapModule raised exception 0xc0000139
        Exception record: .exr 00000000050BE5F0
        Context record: .cxr 00000000050BE100
    warning: 1ec8:43a0 @ 764081125 - LdrpProcessWork - ERROR: Unable to load DLL: "C:\whatever\plugin.dll", Parent Module: "(null)", Status: 0xc0000139
    warning: 1ec8:43a0 @ 764081171 - LdrpLoadDllInternal - RETURN: Status: 0xc0000139
    warning: 1ec8:43a0 @ 764081171 - LdrLoadDll - RETURN: Status: 0xc0000139
    

Great! It says Procedure "foo" could not be located in DLL, so we have our missing symbol, just like in Posix/Unix's dlopen().

like image 110
Vortico Avatar answered May 27 '26 11:05

Vortico