Automating the Breakpoint and Stepping Operations

Posted by: Sankar Ramasubbu

 

I am going to show you how to automate the operation of setting and deleting breakpoints as well as various stepping operations.

The sample included here will show you how to automate the following operations:

1. Setting a breakpoint

2. Deleting all breakpoints

3. Various Stepping operations(run, step in, step over, step out)

4. Getting the current state of the debugger(run state or break state)

In a future post, I will talk about additional breakpoint operations, like deleting a specific breakpoint, disabling and enabling breakpoints.

This sample assumes that you have already downloaded an image to a device. If you haven’t done already, please refer to Automating the Download of a run-time image and Viewing process and thread data programmatically, both have complete details on downloading an image to a device. If you would like to create a Visual Studio add-in for this breakpoint and stepping sample, then please follow steps 1-7 in the post Automating the Download of a run-time image, before trying out this sample.

REFERENCES: You need to add the following refereneces:

1. System.Windows.Forms.dll

2. Interop.Microsoft.PlatformBuilder.Diagnostics.dll (found here C:\Program Files\Microsoft Platform Builder\6.00\cepb\IdeVS on my computer).

SET A BREAKPOINT: To set a breakpoint you need the Run State object, which you can get to as follows:

    diagnostics =(CCeSystemDiagnostics)dte.GetObject("Yamazaki-OM");

    runState = (CcsdRunStateControl)diagnostics.GetRunStateControl();

You need one or more of the following information to set a breakpoint:

1. Line number: Line number on which to set a breakpoint

2. Function name: Function where you want to set a breakpoint

3. File name: Source file name in which you want to set a break point

4. Module name: Execuatable or dll where you want to set a break point

The code to set a break point looks like this:

 

private static void SetBreakpoint(uint line, string function, string file, string module)

{

        csdPropertyBag breakpointPropertyBag = (csdPropertyBag)diagnostics.GetPropertyBag();

        breakpointPropertyBag.Set("LineNumber", line.ToString());

        breakpointPropertyBag.Set("FunctionName", function);

  breakpointPropertyBag.Set("SourceName", file);

  breakpointPropertyBag.Set("ProcessName", module);

  CcsdBreakpointTemplates breakpointTemplates = (CcsdBreakpointTemplates)runState.GetBreakpointTemplates();

  breakpointTemplates.NewElement((IcsdPropertyBag)breakpointPropertyBag);

    }

You don’t need all the above information to set a breakpoint. For example you can set a breakpoint with just a function name. This is what I do in the sample below. The code for setting a breakpoint at the start of a function would look like this:

private static void SetBreakpoint(string function)

{

        csdPropertyBag breakpointPropertyBag = (csdPropertyBag)diagnostics.GetPropertyBag();

        breakpointPropertyBag.Set("FunctionName", function);

        CcsdBreakpointTemplates breakpointTemplates = (CcsdBreakpointTemplates)runState.GetBreakpointTemplates();

        breakpointTemplates.NewElement((IcsdPropertyBag)breakpointPropertyBag);

    }

DELETING ALL BREAKPOINTS: Again you need to get the run state object and breakpoint template object to delete all breakpoints. The code to delete all breakpoints is pretty straight forward:

    CcsdBreakpointTemplates breakpointTemplates = (CcsdBreakpointTemplates)runState.GetBreakpointTemplates();

    breakpointTemplates.DeleteAll();

STEPPING: The run state object exposes the following methods to automate the stepping functions:

1. Run – Go command, same as pressing F5

2. StepInto – Step over the next statement, if the next statement is a function call step into it the invoked function

3. StepOver – Step over the next statement, even if it is a call statement

4. StepOut – Step out of the current function

The code for various stepping functions looks as follows:

    runState.Run(true);

    runState.StepInto(true);

    runState.StepOver(true);

    runState.StepOut(true);

All the stepping functions take a boolean parameter, which is to indicate whether you want the debugger to handle an execption or not. When you pass in the value “true” the debugger would handle any first chance exception encountered while executing the stepping operation.

DEBUGGER STATE: The last method that is used in the sample is GetCurrentRunState, which is also exposed by the run state object.This method returns whether the debugger is in break state or run state. It also returns some additional information in objects passed in as reference to this method. To keep this sample simple, I am not going into get into the details of these parameters. For this sample it is just enough to know that the method gives us the current state of the debugger. In a future post I will go into details of the other parameters.

SAMPLE: I am going to briefly explain what the sample is doing. Once again I want to remind you that you need to download an image to the device before executing this sample. To start, I make the debugger go to break state before setting a breakpoint. This is to make sure that the breakpoint is instantiated immediately when it is set. Currently the Windows CE 6.0 platform builder debugger doesn’t immediately instantiate a breakpoint in run state. When you set a breakpoint in run state, it is instantiated during the next break or module load/unload operation. When debugger reaches the break state, you might get a “Find Source” dialog, just cancel it. Once in break state, I set a breakpoint at the start of the function “DoHelp”. This function is defined in shell.exe. After setting the breakpoint, execute the run command to go back to run state. Now you need to open the target control window and type the command “?”. A message box reminding you to do this will apprear. Once you type “?” in the target control window click OK to close the message box. The breakpoint will be hit. If you don’t have access to shell.exe source code, the breakpoint will be hit in disassembly. After the breakpoint is hit, I execute the stepping functions, step into, step over and step out in order. Finally I delete all breakpoints and make the debugger go back to run state. You should see the output of “?” command in the target control window. You would have noticed that I have used functions “WaitForBreak” and “WaitForRun” in the sample. This is to make sure that the debugger is in the correct state to execute an operation. Sometime stepping operations will fail if the debugger is not in the correct state, or if the stepping functions are called before the debugger has reached the correct state. That’s it we are done. Here is the complete code for the sample:

namespace BreakpointsSteppingSample

{

    // Standard namespaces

    using System;

    using System.Collections.Generic;

    using System.Text;

    using System.Windows.Forms;

    // PlatformBuilder and Visual Studio namespaces

    using EnvDTE;

    using EnvDTE80;

    using Interop.Microsoft.PlatformBuilder.Diagnostics;

    internal static class BreakpointSteppingSample

    {

        /// <summary>

        /// The caption to use in message boxes.

        /// </summary>

        private const string Caption = "PB - Breakpoint Stepping Sample";

        /// <summary>

        /// Debugger object.

        /// </summary>

        private static CCeSystemDiagnostics diagnostics;

        /// <summary>

        /// Run state Object

        /// </summary>

        private static CcsdRunStateControl runState;

        /// <summary>

        /// Set a breakpoint

        /// </summary>

        /// <param name="line">Line number</param>

        /// <param name="function">Function name</param>

        /// <param name="file">File name</param>

        /// <param name="module">Executable or dll</param>

        private static void SetBreakpoint(uint line, string function, string file, string module)

  {

            try

            {

                // Get the break point property object and give values to the properties needed to set a breakpoint

                csdPropertyBag breakpointPropertyBag = (csdPropertyBag)diagnostics.GetPropertyBag();

                breakpointPropertyBag.Set("LineNumber", line.ToString());

                breakpointPropertyBag.Set("FunctionName", function);

                breakpointPropertyBag.Set("SourceName", file);

                breakpointPropertyBag.Set("ProcessName", module);

                // Get the breakpoint template object and add a new breakpoint

                CcsdBreakpointTemplates breakpointTemplates = (CcsdBreakpointTemplates)runState.GetBreakpointTemplates();

             breakpointTemplates.NewElement((IcsdPropertyBag)breakpointPropertyBag);

            }

            catch (Exception e)

            {

                MessageBox.Show(e.Message, Caption, MessageBoxButtons.OK, MessageBoxIcon.Error);

            }

            return;

        }

        /// <summary>

        /// Set a breakpoint

        /// </summary>

        /// <param name="function">Function name</param>

        private static void SetBreakpoint(string function)

        {

            try

            {

                // Get the break point property object and set the Function Name property to where you want the breakpoint

                csdPropertyBag breakpointPropertyBag = (csdPropertyBag)diagnostics.GetPropertyBag();

                breakpointPropertyBag.Set("FunctionName", function);

                // Get the breakpoint template object and add a new breakpoint

                CcsdBreakpointTemplates breakpointTemplates = (CcsdBreakpointTemplates)runState.GetBreakpointTemplates();

                breakpointTemplates.NewElement((IcsdPropertyBag)breakpointPropertyBag);

            }

            catch (Exception e)

            {

                MessageBox.Show(e.Message, Caption, MessageBoxButtons.OK, MessageBoxIcon.Error);

            }

            return;

        }

        /// <summary>

        /// Wait for the debugger to reach break state

        /// </summary>

        /// <param name="run"></param>

        static void WaitForBreak(int timeOut)

        {

            try

            {

                for (int i = 0; i < timeOut; i++)

                {

                    csdHaltReason haltReason = csdHaltReason.csdHaltReasonStepComplete;

                    object breakpoint = null;

                    object exception = null;

                    byte phase = 0;

                    csdTriState state;

                    System.Threading.Thread.Sleep(1000);

   // get the current state of the debugger

                    state = runState.GetCurrentRunState(ref haltReason, ref breakpoint, ref exception, ref phase);

                    // return if the debugger is in break state

                 if (state == csdTriState.csdTriStateTrue)

                        return;

                }

                MessageBox.Show("ERROR: Debugger did not reach break state in 60 seconds", Caption, MessageBoxButtons.OK, MessageBoxIcon.Error);

            }

            catch (Exception e)

            {

                MessageBox.Show(e.Message, Caption, MessageBoxButtons.OK, MessageBoxIcon.Error);

            }

        }

        /// <summary>

        /// Wait for the debugger to reach run state

        /// </summary>

        /// <param name="run"></param>

        static void WaitForRun(int timeOut)

        {

            try

            {

                for (int i = 0; i < timeOut; i++)

                {

                    csdHaltReason haltReason = csdHaltReason.csdHaltReasonStepComplete;

                    object breakpoint = null;

                    object exception = null;

                    byte phase = 0;

                    csdTriState state;

                    System.Threading.Thread.Sleep(1000);

                    // get the current state of the debugger

                    state = runState.GetCurrentRunState(ref haltReason, ref breakpoint, ref exception, ref phase);

                    // return if the debugger is in run state

                    if (state == csdTriState.csdTriStateFalse)

                        return;

                }

                MessageBox MessageBox.Show("ERROR: Debugger did not reach run state in 60 seconds", Caption, MessageBoxButtons.OK, MessageBoxIcon.Error);

            }

            catch (Exception e)

            {

                MessageBox.Show(e.Message, Caption, MessageBoxButtons.OK, MessageBoxIcon.Error);

            }

        }

        /// <summary>

        /// Sample that illustrates break, set breakpoint, run, hit breakpoint, step into, step over and step out, delete all breakpoints

        /// </summary>

        public static void BreakpointSteppingSample()

        {

            // Get the debugger object model

            diagnostics = (CCeSystemDiagnostics)dte.GetObject("Yamazaki-OM");

           

            // Get the runState Control

            runState = (CcsdRunStateControl)diagnostics.GetRunStateControl();

            // Go to break state, to ensure that the breatpoint we set is instantiated immediately

            runState.Break();

            // Wait until debugger reaches break state

            WaitForBreak(60);

            // Set a breakpoint on the function named DoHelp; which is defined in the module shell.exe

            SetBreakpoint("DoHelp");

           

            // Go back to run state as we have set a breakpoint

            runState.Run(true);

            // Wait until debugger reaches run state

            WaitForRun(60);

   

            // TO DO:

            // - Add code to run the command "?" in the target control window

  // - Or use this message box as a reminder to manually open target control window and type "?"

            MessageBox.Show("Open the target control window and type - ?", Caption, MessageBoxButtons.OK, MessageBoxIcon.Information);

            // Wait until the breakpoint is hit and debugger is in break state

            WaitForBreak(60);

           

            // Step over the next statement, if the next statement is a call statement then step into the function invoked

            runState.StepInto(true);

            WaitForBreak(60);

            // Step over the next statement, even if it is a call statement

            runState.StepOver(true);

            WaitForBreak(60);

            // Step out of the current function

            runState.StepOut(true);

            WaitForBreak(60);

            // Delete all breakpoints

            CcsdBreakpointTemplates breakpointTemplates = (CcsdBreakpointTemplates)runState.GetBreakpointTemplates();

            breakpointTemplates.DeleteAll();

            // Run so that the "?" command is compeleted in the target control window

            runState.Run(true);

        }

    }

}