Package: dlltracer
dlltracerThedlltracertool is an assistive tool for diagnosing import errors in
CPython when they are caused by DLL resolution failures on Windows.In general, any DLL load error is reported as anImportErrorof the top-level
extension module. No more specific information is available for CPython to
display, which can make it difficult to diagnose.This tool uses not-quite-documented performance events to report on the
intermediate steps of importing an extension module. These events are
undocumented and unsupported, so the format has been inferred by example and may
change, but until it does it will report on the loads thatactually occur.
However, because it can't report on loads thatneveroccur, you'll still need
to do some work to diagnose the root cause of the failure.The most useful static analysis tool isdumpbin,
which is included with Visual Studio. When passed a DLL or PYD file and the/importsoption, it will list all dependencies thatshould beloaded. It
shows them by name, that is, before path resolution occurs.dlltracerperforms dynamic analysis, which shows the DLLs that are loaded at
runtime with their full paths. Combined with understanding the dependency
graph of your module, it is easier to diagnose why the overall import fails.Installpip install dlltracerWhere thepipcommand may be replaced by a more appropriate command for your
environment, such aspython -m piporpip3.9.UseNote:Regardless of how output is collected, this toolmust be run as
Administrator. Otherwise, starting a trace will fail with aPermissionError.
Only one thread may be tracing across your entire machine. Because the state
of traces is not well managed by Windows, this tool will attempt to stop any
other running traces.A basic trace that prints messages to standard output is:importdlltracerimportsyswithdlltracer.Trace(out=sys.stdout):importmodule_to_traceThe output may look like this (forimport ssl):LoadLibrary \Device\HarddiskVolume3\Windows\System32\kernel.appcore.dll
LoadLibrary \Device\HarddiskVolume3\Program Files\Python39\DLLs\_ssl.pyd
LoadLibrary \Device\HarddiskVolume3\Windows\System32\crypt32.dll
LoadLibrary \Device\HarddiskVolume3\Program Files\Python39\DLLs\libcrypto-1_1.dll
LoadLibrary \Device\HarddiskVolume3\Program Files\Python39\DLLs\libssl-1_1.dll
LoadLibrary \Device\HarddiskVolume3\Windows\System32\user32.dll
LoadLibrary \Device\HarddiskVolume3\Windows\System32\win32u.dll
LoadLibrary \Device\HarddiskVolume3\Windows\System32\gdi32.dll
LoadLibrary \Device\HarddiskVolume3\Windows\System32\gdi32full.dll
LoadLibrary \Device\HarddiskVolume3\Windows\System32\msvcp_win.dll
LoadLibrary \Device\HarddiskVolume3\Windows\System32\imm32.dll
LoadLibrary \Device\HarddiskVolume3\Program Files\Python39\DLLs\_socket.pyd
LoadLibrary \Device\HarddiskVolume3\Program Files\Python39\DLLs\select.pydA failed import may look like this (forimport sslbut withlibcrypto-1_1.dllmissing):LoadLibrary \Device\HarddiskVolume3\Windows\System32\kernel.appcore.dll
LoadLibrary \Device\HarddiskVolume3\Program Files\Python39\DLLs\_ssl.pyd
LoadLibrary \Device\HarddiskVolume3\Windows\System32\crypt32.dll
LoadLibrary \Device\HarddiskVolume3\Program Files\Python39\DLLs\libssl-1_1.dll
Failed \Device\HarddiskVolume3\Windows\System32\crypt32.dll
Failed \Device\HarddiskVolume3\Program Files\Python39\DLLs\libssl-1_1.dll
Failed \Device\HarddiskVolume3\Program Files\Python39\DLLs\_ssl.pyd
Traceback (most recent call last):
  File "C:\Projects\test-script.py", line 28, in <module>
    import ssl
  File "C:\Program Files\Python39\lib\ssl.py", line 98, in <module>
    import _ssl             # if we can't import it, let the error propagate
ImportError: DLL load failed while importing _ssl: The specified module could not be found.Notice that the missing DLL is never mentioned, and so human analysis is
necessary to diagnose the root cause.Write to fileTo write output to a file-like object (anything that can be passed to thefile=argument ofprint), pass it as theout=argument ofTrace.importdlltracerwithopen("log.txt","w")aslog:withdlltracer.Trace(out=log):importmodule_to_traceCollect to listTo collect events to an iterable object, passcollect=TruetoTraceand
bind the context manager. The result will be a list containing event objects,
typicallydlltracer.LoadEventanddlltracer.LoadFailedEvent.importdlltracerwithdlltracer.Trace(collect=True)asevents:try:importmodule_to_traceexceptImportError:# If we don't handle the error, program will exit before# we get to inspect the events.pass# Inspect the events after ending the traceall_loaded={e.pathforeineventsifisinstance(e,dlltracer.LoadEvent)}all_failed={e.pathforeineventsifisinstance(e,dlltracer.LoadFailedEvent)}Raise audit eventsTo raise audit events for DLL loads, passaudit=TruetoTrace. The events
raised aredlltracer.loadanddlltracer.failed, and both only include the
path as an argument.importdlltracerimportsysdefhook(event,args):ifevent=="dlltracer.load":# args = (path,)print("Loaded",args[0])elifevent=="dlltracer.failed":# args = (path,)print("Failed",args[0])sys.add_audit_hook(hook)withdlltracer.Trace(audit=True):importmodule_to_traceAdditional eventsNote:This is mainly intended for development ofdlltracer.Because event formats may change, and additional events may be of interest but
are not yet handled, passing thedebug=Trueoption toTraceenables all
events to be collected, written, or audited. Regular events are suppressed.importdlltracerimportsysdefhook(event,args):ifevent!="dlltracer.debug":return# args schema:#   provider is a UUID representing the event source#   opcode is an int representing the operation#   header is bytes taken directly from the event header#   data is bytes taken directly from the event dataprovider,opcode,header,data=argssys.add_audit_hook(hook)withdlltracer.Trace(debug=True,audit=True,collect=True,out=sys.stderr)asevents:try:importmodule_to_traceexceptImportError:passforeinevents:assertisinstance(e,dlltracer.DebugEvent)# DebugEvent contains provider, opcode, header and data as for the audit eventContributeThis project welcomes contributions and suggestions.  Most contributions require you to agree to a
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
the rights to use your contribution. For details, visithttps://cla.opensource.microsoft.com.When you submit a pull request, a CLA bot will automatically determine whether you need to provide
a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions
provided by the bot. You will only need to do this once across all repos using our CLA.This project has adopted theMicrosoft Open Source Code of Conduct.
For more information see theCode of Conduct FAQor
contactopencode@microsoft.comwith any additional questions or comments.TrademarksThis project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft
trademarks or logos is subject to and must followMicrosoft's Trademark & Brand Guidelines.
Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship.
Any use of third-party trademarks or logos are subject to those third-party's policies.