Why can’t the debugger call GetFinalPathNameByHandle via .call?

There were a number of follow-up questions to my demonstration of calling the Get­Final­Path­Name­By­HandleW function from the debugger.

Mason Wheeler asks, "What debugger is this? Why doesn't it have the ability to call functions as a standard feature?"

The debugger here is the debugger that comes with the Debugging Tools for Windows. It is the core debugging engine that powers kd, cdb, ntsd, and windbg.

This debugging engine operates under very narrow constraints because it is designed to be deployed to a customer machine with minimum overhead or invasiveness. (Indeed, this debugger used to come preinstalled with Windows, but that stopped a while back, presumably to minimize attack surface, and also to give the debugging tools team control over their own release cycle.)

This means that the debugger cannot assume that there is a copy of the Windows SDK installed on the machine. Without the header files, the debugger doesn't know how to call any particular function. What's the calling convention? What is the type of each parameter? (Four-byte integers, 8-byte integers, 4-byte floating point values, 8-byte floating point values, and 128-bit SIMD values are all passed differently.) What is the function's return value? (If the return value is a structure or class, then an extra hidden parameter must be passed. And the debugger needs to know the return value in order to print the result.)

Since the debugger does not have access to a compiler or to header files, it has to make do with the symbolic information embedded in the symbol files. And that's where the "If this were a function you had written" comes from. If you had written the function, then the information about the calling convention and parameters would be found in the symbol file for the module containing the function you're trying to call. But if you didn't write the function, then you don't necessarily have full symbolic information for the function. In particular, the Windows symbol server does not provide full symbolic information for system functions. It contains only enough information to build stack traces (which basically means it has just the function name and some FPO information). That's not enough information to simulate a call to the function.

It's great to have the Visual Studio debugger or some other fancy debugger available. But if you are debugging a customer's machine via a remote connection, you have to make do with very little. Customers are understandably unhappy when you tell them, "Okay, we can try to debug your problem, but first you need to install Visual Studio onto your domain controller." Plus there's the heisenbug effect: The act of installing Visual Studio entails significant changes to the system, one of which may alter the system enough to make the bug no longer occur.

(That's also why writing a scratch program that does an Open­Process, Duplicate­Handle, Get­Final­Path­By­Handle, and then Message­Box was not considered for this problem. If you are debugging remotely, you have to be able to do everything you need from within the debugger. There is nobody sitting at the console to whom you can email your test program, ask to run it, and then have them read the results back to you.)

Comments (11)
  1. Michael says:

    So why does Microsoft not include the required information for a call into the public symbols? I can see why this would be a bad idea for undocumented functions, but why not for the official documented ones?

    1. The information is there: It’s in the SDK. But the debugger doesn’t come with the SDK.

      1. Anon says:

        Unless there’s another way to get it, the debugger *does* come with the SDK — you have to use the SDK installer to install it. It would be one more checkbox in the Windows SDK Installer. (That used to not be true, but as far as I can tell, it is no longer possible to get the debugger redists outside of downloading the SDK installer, or via some third-party kind enough to place them up for download.)

        1. morlamweb says:

          @Anon: the debuggers can be deployed separately from the SDK. The SDK installer allows you to copy the installers for the debuggers to your local disk, and those installers can then be sent to customers to install the debuggers. Defrag Tools on Channel9 took advantage of this feature to build their “lightsaber” – a USB memory stick with the debugging tools + sysinternals tools – for Win 7, 8, and 8.1.

  2. Michael says:

    Also, why not add a command to the debugger that takes the call syntax as an argument?
    .call stdcall FunctionName DWORD:123 CHAR:12 ret:INT

    1. That would be a neat extension to write. Start typing! (Functions that return structures would be more tricky.)

    2. Rosyna says:

      I wonder about that as well. For example, GDB and LLDB permit you to do typecasting to inform the debugger of the argument and return types of a function the debugger otherwise has no information about.

  3. Ben says:

    I for one enjoy the “Portability” of WinDBG/CDB and its kin.

    Missed you at //build2016 Raymond! I really want you to sign a copy of your book :)

    As to “Installing Visual Studio To Debug” at build the Visual Studio team was showing off their super slick vNext installer at //build2016, I asked the very same question (portable install), if their intel was good its getting closer, the core is ~300mb and gives you the shell, minimal syntax highlighting, and the native and managed debugger (one day we might get our CLR Debugger that shipped with .NET 2.0 back!). They were talking about the limited invasive-ness of the new installer/vNext. Still a far cry away from the ~40mb of WinDBG and its kin.

    I also had a chance to talk to the Visual Studio Debugging Tools team, I was surprised to hear that the rep had never head of the ntdebugging blog (I found them through your sidebar, those guys are simply amazing). I was also a little surprised to hear them admit WinDBG was slightly better for some operations. I know Microsoft’s a big place, but I would expected there to be some cross over. Maybe a blog post for another time that talks about the various teams (as you understand them?) or perhaps its out of scope.

    1. Anon says:

      I wouldn’t expect the VS Debug Tools team to read every other MS blog…, but I *would* expect everyone on the team to pay attention to the other Microsoft debugging tool blogs…

  4. Joshua says:

    Despite the low number of comments, this post has been particularly interesting.

  5. sense says:

    I’ve recently seen in the latest WinDbg (the windows 10 sdk version) that it can show “Source Args” for API functions in a callstack of a crash dump. This was not the case with previous versions of WinDbg.
    It seems that if public symbols contain the necessary information for the debugger to show this, it will be enough to call functions. Maybe at some point in time, the public symbols were changed and contained more information?

Comments are closed.

Skip to main content