1 / 40

Developing Debugger Extensions

Developing Debugger Extensions. Prasad Kakulamarri Senior Development Lead Debugging Tools for Windows PrasadK@Microsoft.com. Agenda. What are Debugger Extensions? Why create your own extension? Extension Frameworks How do they work? 64-bit support Demo. Debugger Engine.

cynara
Download Presentation

Developing Debugger Extensions

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Developing Debugger Extensions Prasad Kakulamarri Senior Development Lead Debugging Tools for Windows PrasadK@Microsoft.com

  2. Agenda • What are Debugger Extensions? • Why create your own extension? • Extension Frameworks • How do they work? • 64-bit support • Demo

  3. Debugger Engine • The debugger engine (DbgEng.dll): • Provides interfaces for examining and manipulating debugging targets in user mode and kernel mode • Can acquire targets, set breakpoints, monitor events, query symbols, read & write to memory, control threads and processes in a target • Can be used to write debugger extension libraries and stand-alone applications • Is shipped with the OS and as part of the debugger package • A debugger engine application that uses full functionality of the debugger engine is a debugger (Ex: Windbg) • A debugger extension library is an add-in to the debugger that provides additional functionality

  4. What are debugger extensions? • Extensions are plug-ins that extend the functionality of the debugger • They are DLLs that use the interfaces exposed by the debugger engine typically to get information about the state of the target (process/driver/machine) • They are loaded by the debugger and run in the context of the debugger process (Ex: windbg) • Extension command syntax ![module.]extension [arguments] • Common examples include: !Analyze – Automatic analysis of a break !Process – Displays information about a specified process or all processes

  5. Why create your own extension? • Great for automation of common debugging operations • You might want to write a command to analyze a complex data structure or get statistics of the types of operations performed by your driver • Simple structures can be dumped and analyzed using the dt debugger command; No need to write extensions for this • Complex trees and lists can be displayed, searched, and parsed to show the most commonly used information • Windows DEV team could not debug the OS without debugger extensions • We have written 100s of these: !process, !thread, !handle, !htrace, !verifier, !teb, !peb, !vad • A debugger without any extensions is like a car without any seats

  6. Getting started… • All documentation about existing debugger extensions (!pool, !thread, !process) is in the basic debugger documentation • Installed by default in the root of the debugger in debugger.chm • All documentation about debugger extension APIs and all debugger extension code samples is part of the debugger SDK • SDK is installed by default in the current external release • Docs are available in Debugger.CHM and on MSDN here: http://msdn.microsoft.com/en-us/library/cc267445.aspx • Samples are stored under the samples directory

  7. Debugger Extension Programming Model • Debugger extensions are DLLs loaded by the debugger using LoadLibrary • Debugger extensions run in the context of the debugger process (ex:WinDBG) • Debugger extensions are trusted by the debugger • A simple try/except is placed around execution of extensions to recover from AVs • Heap corruption in an extension will cause the debugger to crash

  8. Debugger Extension Programming Model (contd.) • A debugger extension can make calls to • Any Win32 API • APIs run in the context of the debugger process (ex: WinDBG) • Debugger interfaces (dbgeng.dll) • Must be careful of interactions between Win32 APIs, dbgeng and dbghelp APIs • ReadProcessMemory could return different data than calling the debugger to read memory from the target process • Calling dbghelp APIs directly can change internal state dbgeng relies on • Debugger extensions run on the host debugger • In remote debugging scenarios, input/output is sent over the wire

  9. Extensions run on the host… Target Process Host Process (Debugger) Debugger Extension No! My App Extension Interfaces My Dll 1 DbgEng My Dll 2 UserMode : I . P. C. Kernel Mode: Debug Port

  10. Remote debugging Remote Debugger Host: Debugger Process User Input Debugger Extension Extension Interfaces DbgEng DbgEng Remote Debugging Protocol: Named Pipes, TCP

  11. User Mode, Kernel Mode, Dump Files • Debugger extension can work with any type or version of target • The debugger API abstracts the “target” as much as possible • All basic extension APIs work on live sessions or dump files, user mode or kernel mode targets, and any version of the OS • Certain specific operations or data may not make sense on all targets • Examples • Breakpoints won’t work on dumps files • ReadPhysicalMemory is not supported for user mode targets • Debugger extensions must gracefully handle errors • The debugger package organizes extensions based on the targets they support • Ext.dll – extensions that work for both user mode and kernel mode (!analyze, !error, !list) • Uext.dll – user-mode only extensions (!runaway, !evlog) • Kext.dll – kernel-mode only extensions (!pci, !process)

  12. Extension Frameworks • Three types of extension frameworks • WdbgExts extensions (legacy) • DbgEng Style extensions (new) • EngExtsCpp extensions (new)

  13. Legacy (Old) Debugger Extension Interfaces (WdbgExts) • Often referred to as Old Style extensions • Continued to be fully supported by dbgeng.dll • Definitions can be found in wdbgexts.h • Expose limited functionality that enables most common features • Read and write memory • Current Process / Thread information • Expression evaluation • Basic Symbol lookup • Basic Type Lookup • Cancellation with Crtl+C/Ctrl+Break • Extension functions are called by • Asking the debugger engine for a table containing debugger extension function pointers • Making calls through these function pointers

  14. New Debugger Interfaces (DbgEng) • Often referred to as dbgengstyle extensions • Debugger engine exposes a new, complete set of interfaces • Everything that can be performed by a debugger is exposed by the interface • Referred to as the dbgeng API • WinDBG is built on top of this API • All debugging capabilities are exposed through dbgeng.dll • Can write new standalone tools that call the interface • Debugger extension DLLs are generally more convenient in most scenarios

  15. New Debugger Interfaces (DbgEng), contd. • Functionality supported by the dbgeng API • Read and write memory • Current thread and process information • Expression evaluation • Full symbol lookup and enumeration • Full type lookup and enumeration • General target information • Extension functions are called by • Creating debug interface objects • Calling the engine interfaces exposed by these objects

  16. “Legacy” or “New” interface • Legacy extensions require a little less code • Macros are available for common operations • Initialization is a little less complex • Great for very simple extensions • New extension APIs provide more flexibility and features • Many more features • Fine grained control over debugger behavior • Can still use legacy interfaces and macros for part of the code • All debugging capabilities are exposed through dbgeng.dll • Windbg is built on top of this API

  17. Selecting a Framework…

  18. Legacy Extension Initialization • Legacy extension DLLs must export the following entry points • WinDbgExtensionDllInit – Required • ExtensionApiVersion – Required • CheckVersion – Optional • The debugger finds entry points using GetProcAddress on the extension DLL • Entry Points are called at DLL initialization • No Uninitialize routine in the legacy extension model

  19. Legacy Extension Initialization typedef VOID (WDBGAPI*PWINDBG_EXTENSION_DLL_INIT)( PWINDBG_EXTENSION_APIS lpExtensionApis, USHORT MajorVersion, USHORT MinorVersion); typedef LPEXT_API_VERSION (WDBGAPI*PWINDBG_EXTENSION_API_VERSION)( VOID); typedef ULONG (WDBGAPI*PWINDBG_CHECK_VERSION)( VOID);

  20. New Extension Initialization • New extension DLL must export the following entry points • DebugExtensionInitialize - Required • DebugExtensionNotify - Optional • DebugExtensionUninitialize - Optional • An extension cannot export both new and old entry points from its DLL • The debugger finds entry points using GetProcAddress on the extension DLL • DebugExtensionNotify is called when the target is connected or disconnected

  21. DebugExtensionInitialize HRESULT CALLBACK DebugExtensionInitialize(PULONG Version, PULONG Flags) • Mandatory export • Called when the extension is loaded • Extension can use it to initialize any global variables • Should return the extension version in *Version • Should not query for debug session information • Debug session may not be active at this point

  22. DebugExtensionNotify Void CALLBACK DebugExtensionNotify(ULONG Notify, ULONG64 Argument) • DebugExtensionNotify is called when the target is connected or disconnected • Optional export • Can be used to cache debug session information without the need for registering any callbacks • Notify has the following values #define DEBUG_NOTIFY_SESSION_ACTIVE 0x00000000 #define DEBUG_NOTIFY_SESSION_INACTIVE 0x00000001 #define DEBUG_NOTIFY_SESSION_ACCESSIBLE 0x00000002 #define DEBUG_NOTIFY_SESSION_INACCESSIBLE 0x00000003

  23. DebugExtensionUninitialize • DebugExtensionUninitialize is called when the extension is unloaded • Optional export • Can perform cleanup here • Just like DebugExtensionInitialize, you cannot assume that a debug session is active at this point

  24. Anatomy of a dbgeng extension call • A debugger extension is a function with the following recommended prototype: HRESULT CALLBACK DebugExtensionCall( PDEBUG_CLIENT Client, PCSTR args) • Where "DebugExtensionCall" is an actual name of the extension being implemented, such as "stack" for a !stack extension • Can have any other prototype • The Client parameter is the pointer to the debug engine's IDebugClient interface • The args parameter is simply the command line argument string passed to the extension

  25. Anatomy of a dbgeng extension call (contd.) • A debugger extension is a function with the following recommended prototype: HRESULT CALLBACK DebugExtensionCall(PDEBUG_CLIENT Client, PCSTR args) • Can return DEBUG_EXTENSION_CONTINUE_SEARCH if the extension cannot handle the request • In this case the command is passed to the next extension DLL in the chain • Can return DEBUG_EXTENSION_RELOAD_EXTENSION to unload and reload the extension library • Allows extension to implement auto-update functionality

  26. Getting Debugger Extension APIs • Legacy debugger extensions get legacy extension interfaces (function pointers) during initialization as part of init call (param1) • Pointers must be cached in a global variable named ExtensionApis • New debugger extensions get new debugger interfaces by calling DebugCreate(__uuidof (IDebugClient), &DebugClient)) DebugClient->QueryInterface(_uuidof(Interface_you_want) • New debugger extensions can also query for the legacy extension interfaces DebugClient->QueryInterface(_uuidof(IDebugControl),&DebugControl); DebugControl->GetWindbgExtensionApis64(&ExtensionApis);

  27. Debugger input… • Debugger extensions receive arguments as one long text string • Extensions can parse parameters anyway they want • Extension will be given all input up to a ‘;’ character, unless quoted • ‘;’ is a delimiter between multiple, independent debugger commands • Debugger provides routines to help parse arguments • interface: Evaluate() • This interface does both parsing and evaluation of arguments • Strings will be treated as symbols • ‘-’ will be treated as minus

  28. Debugger output… • Standard debugger extension output is text-based • Standard output format very similar to C-runtime • %s, %d, specifiers, etc. • Special pointerspecifier%p • Always consumes 64-bit input (always use ULONG64) • Prints 32 or 64 bits based on the target OS • Interface: DebugControl->Output(Mask, Format,...); //where DebugControl is IDebugControl object

  29. Symbol Lookup • Use symbols to look up data in your driver • Always use a module qualifier when evaluating a symbol • Example: mydriver!data • Without a module qualifier, the debugger will load all symbol files until it finds a module with a symbol data • Avoid caching evaluated symbols (in global variables) • Driver can load and unload, and extensions are not notified of such events. Once a program database (PDB) is loaded, symbol lookup is not expensive. • Legacy interfaces • Get an address from a name: GetExpression() • Get a name from an address: GetSymbol() • New Interfaces • Get an address from a name: Evaluate(), GetOffsetByName() • Get a name from an address: GetNameByOffset()

  30. Reading Memory • Most code uses the built-in ReadMemory macro with legacy debugger extension interfaces for memory reading • Reading raw memory should be a rare occurrence in a debugger extension • Use more structured memory reading operations

  31. Reading Memory (contd.) • These APIs read memory on the target process / machine #define ReadMemory (ExtensionApis.lpReadProcessMemoryRoutine) Typedef ULONG (WDBGAPI*PWINDBG_READ_PROCESS_MEMORY_ROUTINE64)( ULONG64 offset, PVOID lpBuffer, ULONG cb, PULONG lpcbBytesRead); IDebugDataSpaces STDMETHOD(ReadVirtual)( THIS_ IN ULONG64 Offset, OUT PVOID Buffer, IN ULONG BufferSize, OUT OPTIONAL PULONG BytesRead);

  32. Reading Memory (contd.) • To read data that will be interpreted as pointers, use ReadPointer(ULONG64 Address, PULONG64 Pointer); • If the target uses 32-bit pointers, the pointer is sign-extended to 64 bits.

  33. Cancellation – Control+C Handling • Control+C handling is shared between the core debugger code and the extension • Generated by Ctrl+C in command line debuggers, Ctrl+Break in WinDbg • The debugger engine will: • Receive the Ctrl+C event • Store the state of this event in a global variable • Debugger extension must check this state • Only one thread in the debugger processes command. The debugger extension takes over this thread • Debugger cannot kill the extension thread • Debugger extension must call the engine to check the state and exit its processing • Very useful in cancelling long running commands

  34. Extension Functions • Most extension commands run from the debugger generate text output • Example: !pool, !process, !analyze • The debugger also supports debugger extension functions • Example: _EFN_GetPoolData • Output : ‘C’ data structure that can be consumed by the caller • Extension functions are defined in extsfns.h • Allows extensions to be built using other debugger extensions, without text parsing • Exported from a DLL, like other extension commands • _EFN_ is the convention for exporting these functions to distinguish them from normal debugger extension commands • Debugger engine automatically appends this prefix • GetExtensionFunction equivalent to GetProcAddress

  35. 64-Bit Support • Everything in the debugger and debugger extension APIs is designed around 64-bit support • All recent debugger APIs treat addresses as 64-bit values • All pointers are passed as ULONG64 • Debugger manipulates all addresses as 64-bit values • Debugger extensions should, too • 32-bit addresses read from a 32-bit target need to be SIGN-EXTENDED • #define KDEXT_64BIT required before including wdbgexts.h

  36. Some Popular Interfaces • IDebugClient • Controls the debug session • Attach/detach to a process/kernel, set/get callbacks, read/write dump files, etc. • IDebugControl • Execute debugger commands, add/remove breakpoints, get Windbg (legacy) extension APIs, etc. • IDebugSymbols • Get an address from a name: Evaluate(), GetOffsetByName() • Get a name from an address: GetNameByOffset() • Use DebugCreate to get the IDebugClient interface and go from there DebugCreate(__uuidof(IDebugClient),(void **)&DebugClient)); DebugClient->QueryInterface(__uuidof(IDebugControl), (void **)&DebugControl); DebugClient->QueryInterface(__uuidof(IDebugSymbols)( (void**)&DebugSymbols);

  37. Demo: Write a simple dbgeng style extension to execute a command from the extension (‘lm’ to list all modules loaded by the target process).Unload and reload the extension to demo auto-update feature.

  38. Call to Action • Write debugger extensions for a better debugging experience and to better understand the behavior of your driver/application • The debugger SDK ships with the debugger package • Easy to get started using the samples provided • Send any feedback to us: windbgfb@microsoft.com

  39. Resources • Debugger download site: • http://www.microsoft.com/whdc/devtools/debugging/default.mspx • Debugger e-mail – for debugger bug reports and feature requests • windbgfb@microsoft.com • This is not for general debugging support • Debugger newsgroup • Microsoft.public.windbg • Good place for general debugging issues • Debugger information on WHDC Web • http://www.microsoft.com/whdc/devtools/WDK/default.mspx • Debugger documentation in MSDN • http://msdn.microsoft.com/en-us/library/cc267445.aspx

More Related