Command Line Debugging Revisited - Part 5: The X Command

In the previous installment, I talked about attaching to running processes using MDbg.  As part of that discussion, I used the X command.  Today, I'd like to spend a little time on X.  The X command is one of those great features of MDbg that I think is worth the price of admission by itself.

From MDbg's online help:

mdbg> ? xabbrev: xUsage: x [-c numSymbols] [module[!pattern]]    Displays functions matching [pattern] for a module. If numSymbols is    provided, the output is limited to the given number. If !regex is not    provided, all functions are displayed. If module is not provided either,    all loaded modules are displayed. Symbols (~#) may be used to set    breakpoints using the "break" command.Example: x mscorlib!*String*See Also:    break

I won't be going into all of the features of X here, rather I will demonstrate the ways that I most often use the command.

I'll use the Visual Studio 2005 WebCrawler sample application to show some of the cool features of X in action.  Once connected to the debuggee (via Run or Attach), we are ready to go.

When debugging using command line tools, one of the most challenging tasks is getting the fully qualified names of functions correct when setting breakpoints.  Namespaces can get long (as you will see in my examples) and the casing of names must be 100% accurate.  X makes this much much easier, as we will see.

Getting the list of loaded modules
In it's simplest form, X will display the modules loaded in your application.

[p#:0, t#:0] mdbg> xPlease specify module.Loaded Modules::0 mscorlib.dll#0 (no symbols loaded):1 webcrawler.exe#0:2 System.Windows.Forms.dll#0 (no symbols loaded):3 System.dll#0 (no symbols loaded):4 System.Drawing.dll#0 (no symbols loaded)

If you are a user of the Modules window in the Visual Studio 2005 debugger, as I am, this usage will be very familiar and handy.  The one useful thing missing from this display is the path from where the symbols were loaded, which the Visual Studio 2005 Modules window provides.

Setting a breakpoint on a function
My favorite way to use X is to help me set breakpoints on functions.  As I mentioned earlier, entering fully qualified names exactly right can be challenging, especially when they get long.  X really helps here by allowing us to search for functions by name fragments.  In the example below, I am looking for anything (methods, classes, etc) with "Crawl" as part of the name.

[p#:0, t#:0] mdbg> x webcrawler.exe!*Crawl*~0. Microsoft.Samples.NetCF.Crawler.add_CurrentPageEvent(value)~1. Microsoft.Samples.NetCF.Crawler.remove_CurrentPageEvent(value)~2. Microsoft.Samples.NetCF.Crawler.add_PageFoundEvent(value)~3. Microsoft.Samples.NetCF.Crawler.remove_PageFoundEvent(value)~4. Microsoft.Samples.NetCF.Crawler.add_CrawlFinishedEvent(value)~5. Microsoft.Samples.NetCF.Crawler.remove_CrawlFinishedEvent(value)~6. Microsoft.Samples.NetCF.Crawler..ctor(startingPage,noProxy)~7. Microsoft.Samples.NetCF.Crawler.Start()~8. Microsoft.Samples.NetCF.Crawler.Stop()~9. Microsoft.Samples.NetCF.Crawler.PageIsHtml(pageAddress,status)~10. Microsoft.Samples.NetCF.Crawler.GetPageData(pageUri,pageData)~11. Microsoft.Samples.NetCF.Crawler.GetPageLinks(pageUri,pageBody,tag,attribute,links)~12. Microsoft.Samples.NetCF.Crawler.Crawl()~13. Microsoft.Samples.NetCF.Crawler.CurrentPageEventHandler..ctor(object,method)~14. Microsoft.Samples.NetCF.Crawler.CurrentPageEventHandler.Invoke(sender,e)~15. Microsoft.Samples.NetCF.Crawler.CurrentPageEventHandler.BeginInvoke(sender,e,callback,object)~16. Microsoft.Samples.NetCF.Crawler.CurrentPageEventHandler.EndInvoke(result)~17. Microsoft.Samples.NetCF.MainForm.HandleCrawlFinishedEvent(sender,e)

When we search by a part of the name, we get a numbered list of symbols that match our fragment.  If the list contains our desired function, we can set a breakpoint very easily by specifying the index of the function within the list.  The results above returned all methods from the Crawler class as well as the event handler for the CrawlFinishedEvent within the MainForm class.  I am interested in debugging the event handler, so I'll set a breakpoint there.

[p#:0, t#:0] mdbg> b ~17Breakpoint #1 bound (:1!Microsoft.Samples.NetCF.MainForm::HandleCrawlFinishedEvent(+0))

This is much more convenient than retyping the name (Microsoft.Samples.NetCF.MainForm.HandleCrawlFinishedEvent), or using the Mark - Copy - Paste feature of the Windows Command Prompt.  It is important to be sure to use the tilde (~) when specifying the list index.  Forgetting to do so will attempt to set a breakpoint by line number within the current source file as shown in the example below.

[p#:0, t#:0] mdbg> b 17Breakpoint #2 bound (line 17 in MainForm.cs)

Enjoy!
-- DK

Disclaimer(s): This posting is provided "AS IS" with no warranties, and confers no rights.