Managed Debugger (MDbg)

MDbg is a user-mode debugger for managed applications. It does not support native or mixed-mode debugging. Because MDbg focuses on managed code, it offers a unique repertoire of debugging commands that are specific to managed code. It is also a console debugger, which supersedes the Runtime Debugger (CorDbg), the previous console debugger for managed applications.

MDbg and CorDbg share many of the same commands. This makes the transition from CorDbg to MDbg easier. However, MDbg commands are different from those of WinDbg and SOS. For developers who switch among these three tools frequently, leveraging the benefits of each, the nonstandardization of the public interface of these tools can be frustrating. For example, those three tools have three distinct commands to display a call stack. In WinDbg, you have the k commands, such as k, kb, and kp. SOS offers the !clrstack command. Of the three, MDbg has the least intuitive name for a stack trace command, which is the w (for where) command.

The following example demonstrates many of the unique features of MDbg. As mentioned, store.exe is the demonstration application used for examples throughout this chapter. In this application, you enter sales transactions. To add a transaction, enter the number of transactions in the # of Transactions text box and then click Add Transactions. The default number of transactions is 1. The Transaction dialog box, where you enter information about the transaction, appears next. When you accept the transaction, the transaction is added to the list of existing transactions. The Store application is shown in Figure 16-1. This example assumes that you have downloaded and built the MDbg project from the Microsoft download Web site.

The user interface of the Store application

Figure 16-1. The user interface of the Store application

MDbg Example

MDbg has the normal assortment of commands common to any debugger: show threads, display the call stack, list local variables, and so on. However, it also has unique commands that target managed code. For example, you can create instances of managed objects and invoke managed functions. You can seed an application with classes and functions that are used exclusively during a debugging session. Otherwise, they are not called during normal execution. The Store application has a MyDebug class that exists solely for debugging. MyDebug.Reset is a static method and is the sole member of the MyDebug class. The Reset method resets the Store application and deletes the current transactions. The MyDebug class and Reset method are a normal class and method. There are no hooks in them that are especially designed for the debugger. This is the MyDebug class:

public class MyDebug
{
    public static void Reset()
    {
        Form1.formItems.Clear();
        Form1.formListBox.Items.Clear();
        Form1.formMessage.Text = "Grand Total:";
        Form1.formSummary.Text = "Summary: No Transactions";
        Console.WriteLine("Application reset.");
    }
}

Follow these steps to experiment with using the MyDebug class:

  1. Start the demonstration by running the Store application in the Mdbg subfolder and adding two or more transactions.

  2. Start MDbg.

  3. Display the active processes with the pro(cessnum) command. The command lists the process identifier, executable, and domain of each process. The Store application is included in the list:

    mdbg> proc
    Active processes on current machine:
    (PID: 1232) C:mdbginDebugStore.exe
            (ID: 1) Store.exe
    (PID: 2084) C:mdbginDebugStore.vshost.exe
            (ID: 1) Store.vshost.exe
    (PID: 3788) C:Program FilesMicrosoft Visual Studio 9.0Common7IDEdevenv.exe
            (ID: 1) DefaultDomain
  4. The a(ttach) command attaches MDbg to a running application. The prompt will change to indicate that you have started a debugging session. After attaching to the Store application, the debugger immediately interrupts the program:

    mdbg> a 2812
    [p#:0, t#:0] mdbg>
  5. How is the Reset method seen in the debugger? Knowing that answer would help in calling that method. The x command can display functions in a module. The basic x command lists all the modules in an application. List the modules:

    mdbg> a 1232
    [p#:1, t#:0] mdbg> x
    Please specify module.
    Loaded Modules:
    :0      mscorlib.dll#0  (no symbols loaded)
    :1      Store.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)
    :5      System.Configuration.dll#0  (no symbols loaded)
    :6      System.Xml.dll#0  (no symbols loaded)
  6. Module ":1" is store.exe. With that knowledge, the functions in that module can be listed using the x command again, this time with the ":1" parameter. This should show the Reset method:

    [p#:1, t#:0] mdbg> x :1
    ~0. Store.Item..ctor()
    ~1. Store.Item.get_Products()
    ~2. Store.Item.set_Products(value)
    ~3. Store.Item.get_ItemId()
    ~4. Store.Item.Dispose()
    ~5. Store.Item..cctor()
    ~6. Store.Transaction.Dispose(disposing)
    ~7. Store.Transaction.InitializeComponent()
    ~8. Store.Transaction..ctor()
    ~9. Store.Transaction.btnAdd_Click(sender,e)
    ~10. Store.Transaction.chkComputer_CheckedChanged(sender,e)
    ~11. Store.Transaction.chkLaptop_CheckedChanged(sender,e)
    ~12. Store.Transaction.chkPrinter_CheckedChanged(sender,e)
    ~13. Store.Transaction.chkSoftware_CheckedChanged(sender,e)
    ~14. Store.Transaction.get_newItem()
    ~15. Store.Transaction.btnCancel_Click(sender,e)
    ~16. Store.Program.Main()
    ~17. Store.Form1..ctor()
    ~18. Store.Form1.get_formItems()
    ~19. Store.Form1.get_formMessage()
    ~20. Store.Form1.get_formSummary()
    ~21. Store.Form1.get_formListBox()
    ~22. Store.Form1.btnTransaction_Click(sender,e)
    ~23. Store.Form1.btnBad_Click(sender,e)
    ~24. Store.Form1.Dispose(disposing)
    ~25. Store.Form1.InitializeComponent()
    ~26. Store.Form1..cctor()
    ~27. Store.Properties.Resources..ctor()
    ~28. Store.Properties.Resources.get_ResourceManager()
    ~29. Store.Properties.Resources.get_Culture()
    ~30. Store.Properties.Resources.set_Culture(value)
    ~31. Store.MyDebug.Reset()
    ~32. Store.MyDebug..ctor()
    ~33. Store.Properties.Settings.get_Default()
    ~34. Store.Properties.Settings..ctor()
    ~35. Store.Properties.Settings..cctor()
    [p#:1, t#:0] mdbg>
  7. The Store.MyDebug.Reset method is found towards the bottom of the list. Store is the namespace, MyDebug is the class, and Reset is the method. The next time a transaction is added, we want to call this method to reset the application, which deletes existing transactions. The button-click handler for adding transactions is Store.Form1.btnTransaction_Click, which also is found in the preceding list. Set a breakpoint on this method and resume the Store application. The b(reakpoint) command sets breakpoints, and the g(o) command resumes an interrupted application:

    [p#:0, t#:0] mdbg> b Store.Form1.btnTransaction_Click
    Breakpoint #1 bound (Store.Form1::btnTransaction_Click(+0))
    [p#:0, t#:0] mdbg> g
  8. Click Add Transaction in the Store application. The breakpoint is hit, and the MDbg debugger interrupts the application. The source line where the program is interrupted is displayed. We no longer need this breakpoint. The b command without parameters lists all breakpoints. Using information displayed by the b command, you can delete a breakpoint with the del(ete) command:

    STOP: Breakpoint 1 Hit
    64:        {
    [p#:0, t#:0] mdbg> b
    Current breakpoints:
    Breakpoint #1 bound (Store.Form1::btnTransaction_Click(+0))
    [p#:0, t#:0] mdbg> del 1
  9. We could use the newo(bj) command to create a new instance of a class. However, Reset is a static method and does not require an instance. The method is called directly on the class. Invoke the method with the f(unceval) command:

    [p#:0, t#:0] mdbg> f Store.MyDebug.Reset
    STOP EvalComplete
  10. Resume the Store application with the g command and the application should have no transactions. Enter a new transaction in the dialog box.

Here is a second demonstration of the MDbg debugger. This example highlights exception management. When a second-chance exception is raised in a debuggee, MDbg does not intercede and the application will crash. This is contrary to the behavior of most debuggers, which would trap the second-chance exception. At your discretion, you can request that MDbg catch second-chance exceptions.

  1. Restart the Store application.

  2. Attach MDbg to the application and resume the program.

  3. Click Bad Action. As advertised, a bad action occurs, which is an unhandled exception. An error dialog box will appear for the second-chance exception. From this dialog box, terminate the application. The Bad Action button handler, shown here, is not particularly creative in generating an exception:

    private void btnBad_Click(object sender, EventArgs e)
    {
        int a = 5, b = 0;
        ++a;
        a /= 2;
        a /= b;
    }
  4. Restart the Store application.

  5. Attach the MDbg debugger.

  6. Ask the MDbg debugger to catch all second-chance exceptions with the ca(tch) ex(ception) command:

    [p#:0, t#:0] mdbg> ca ex
  7. Resume the application and then click Bad Action. This time, the exception is trapped in MDbg. In the debugger, the exception type and the properties of the current exception object are displayed, providing important information on the exception. The source code line where the exception occurred also is displayed. You now have plenty of information to debug the problem:

    [p#:0, t#:0] mdbg> g
    STOP: Exception thrown
    Exception=System.DivideByZeroException
            _className=<null>
            _exceptionMethod=<null>
            _exceptionMethodString=<null>
            _message="Attempted to divide by zero."
            _data=<null>
            _innerException=<null>
            _helpURL=<null>
            _stackTrace=array [24]
            _stackTraceString=<null>
            _remoteStackTraceString=<null>
            _remoteStackIndex=0
            _dynamicMethods=<null>
            _HResult=-2147352558
            _source=<null>
            _xptrs=1240048
            _xcode=-1073741676
    134:            a /= b;

MDbg Commands

MDbg has a full complement of commands for debugging managed applications. Some of the commands were demonstrated in the previous examples. Table 16-1 lists the MDbg commands.

Table 16-1. MDbg commands

Command

Description

? or h(elp)

Displays MDbg commands with brief descriptions.

ap(rocess)

Changes the context to another managed process, which also is being debugged. MDbg can debug multiple applications simultaneously. Without parameters, the command displays all processes in the current debugging session.

a(ttach)

Attaches the MDbg debugger to a managed process. Without parameters, the command lists the available managed processes.

b(reak)

Sets a specific breakpoint or displays all the breakpoints.

ca(tch)

Stipulates which events to catch, such as an exception. It also can display events.

conf(ig)

Sets a particular configuration or displays the configuration options.

del(ete)

Deletes a breakpoint.

de(tach)

Detaches the debugger from the current application.

d(own)

Moves the current stack frame down.

echo

Echoes text to the console.

ex(it) or q(uit)

Exits the debugger.

fo(reach)

Executes an action on all threads.

f(unceval)

Calls a method.

g(o)

Resumes execution of an interrupted application.

ig(nore)

Displays events or sets events to ignore. Complements the ca(tch) command.

int(ercept)

Intercepts exceptions at the specified stack frame.

k(ill)

Kills a process.

l(ist)

Lists loaded modules, application domains, or assemblies.

lo(ad)

Loads a debugging extension.

mo(de)

Sets a specific MDbg option or displays all the options.

newo(bj)

Creates an instance of a type.

n(ext)

Steps over the next instruction.

o(ut)

Steps out of a function.

pa(th)

Sets or displays the source path.

p(rint)

Displays the values of the local variables.

pro(cessenum)

Lists active managed processes.

re(sume)

Resumes a suspended thread.

r(un)

Runs a program and immediately attaches MDbg.

set

Sets a local variable to a new value.

setip

Moves the instruction pointer. (The move must be within the current function.)

sh(ow)

Shows the source code at the current instruction.

s(tep)

Steps into a function.

su(spend)

Suspends a running thread.

sy(mbol)

Sets or displays the symbol path.

t(hread)

Switches to a specified thread or displays all threads.

u(p)

Moves the current stack frame up.

uwgc(handle)

Displays the object referenced by the GCHandle.

when

Executes a command when a debugger event occurs.

w(here)

Displays the call stack.

x

Displays the symbols in a module or lists all the modules.

Ctrl+C

This keystroke interrupts the running application to which MDbg is attached.

Ctrl+Break

This keystroke terminates the running application and exits the debugger.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.227.9