none
How can I send a custom Debug event to my IDebugEventCallback2 handler?

    Question

  • Hello,

    I have installed an IDebugEventCallback2 handler, which is happily receiving events. I would like to allow the code which is being debugged to send a custom IDebugEvent2 object. Please can someone show me how?

    Thanks,
    Charlie.

    Wednesday, March 15, 2017 7:02 PM

All replies

  • The code that is trying to send events is the target app?

    What kind of code are you debugging? (ex: C#, C++, etc) 

    What are you trying to do?

    Gregg


    Visual Studio Debugger Dev

    Thursday, March 16, 2017 11:16 PM
    Moderator
  • Hello Charlie & Gregg,

    I am new to programming with event registration and callback. Could you please help me  about how to receive events using IDebugEventCallback2 (to get the CurrentThread) ? I basically am using VSIX to develop a debugger plugin and I need to get the stackframe (IDebugStackFrame2) using Expression Evaluators for which I need a IDebugProperty2 object. I can get this from the IDebugStackFrame2 object but to get to this point, I first need to register to IDebugEventCallback2 to receive events from my debuggee program. I am not sure how to do this.

    I am currently following https://macropolygon.wordpress.com/2012/12/16/evaluating-debugged-process-memory-in-a-visual-studio-extension/ tutorial. Though it really explains all concepts well, since I am a newbie to this concept, I am finding it hard to understand.

    So, this is what I am not able to work out: I need the CurrentThread (IDebugThread2) from the IDebugEventCallback2 to read the EnumFrameInfo. How do I do this? 

    Please help.

    Thursday, August 10, 2017 2:48 PM
  • esash28,

    Can you tell me a bit more about what you are trying to do? --

    1. Are you trying to do this with your own engine, or one of the built in Microsoft engines?

    2. Are you trying to immediately evaluate something when a stopping event comes in? Or is this more like the user hits some sort of button (or something) and then do do some evaluations?

    3. What behavior do you want if the user switches frames or threads?

    4. Do you just need to scrape the string results that come back from the evaluation? Or are you trying to do something more complicated?

    5. Are you trying to evaluate functions or read variables?


    Visual Studio Debugger Dev

    Thursday, August 10, 2017 4:31 PM
    Moderator
  • Hello Gregg,

    Thanks a lot for the reply. I am using the Microsoft Visual Studio Extensibility package to build my debugger plugin. In the application I am trying to debug using this plugin, there is a double pointer and I need to read those values to process them further in my plugin. For this, there is no way to display all the pointer variables in the watch window and hence, I am not able to get the DEBUG_PROPERTY_INFO for all the block of arrays which the pointer variable is pointing to. This is my problem which I am trying to address. There is no way for me to read the memory pointed to by this double pointer.

    Now as for the events in the debuggee process, since the plugin is for debugging variables, I put a breakpoint at a place where I know this pointer is populated and then come back to the plugin for further evaluation. 

    As a start, I was somehow able to get the starting addresses of each of the array. But still, I am not able to read x bytes of memory from each of these starting addresses. 

    ie., for example, if I have int **ptr = // pointing to something

    I have the addresses present in ptr[0], ptr[1], ptr[2], etc. But I need to go to each of these addresses and fetch the memory block they are pointing to. 

    For this, after much search, I found this link: https://macropolygon.wordpress.com/2012/12/16/evaluating-debugged-process-memory-in-a-visual-studio-extension/  which seems to address exactly my issue. 

    So to use expression evaluator functions, I need an IDebugStackFrame2 object to get the ExpressionContext. To get this object, I need to register to events in the debuggee process which is for breakpoint. As said in the post, I did:

    public int Event(IDebugEngine2 engine, IDebugProcess2 process, IDebugProgram2 program,
                         IDebugThread2 thread, IDebugEvent2 debugEvent, ref Guid riidEvent, uint attributes)
            {
                if (debugEvent is IDebugBreakpointEvent2)
                {
                    this.thread = thread;

                }
                return VSConstants.S_OK;
            }

    And my registration is like:

    private void GetCurrentThread()
            {
                uint cookie;
                DBGMODE[] modeArray = new DBGMODE[1];
                // Get the Debugger service. 

                debugService = Package.GetGlobalService(typeof(SVsShellDebugger)) as IVsDebugger;
                if (debugService != null)
                {
                    // Register for debug events.
                    // Assumes the current class implements IDebugEventCallback2.
                    debugService.AdviseDebuggerEvents(this, out cookie);
                    debugService.AdviseDebugEventCallback(this);
                    debugService.GetMode(modeArray);

                    modeArray[0] = modeArray[0] & ~DBGMODE.DBGMODE_EncMask;

                    if (modeArray[0] == DBGMODE.DBGMODE_Break)
                    {
                           GetCurrentStackFrame();
                    }
                }
            }

    But this doesn't seem to invoke the Event function at all and hence, I am not sure how to get the IDebugThread2 object. 

    I also tried the other way suggested in the same post:

    namespace Microsoft.VisualStudio.Debugger.Interop.Internal
    {
        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("1DA40549-8CCC-48CF-B99B-FC22FE3AFEDF")]
        public interface IDebuggerInternal11 {
            [DispId(0x6001001f)]
            IDebugThread2 CurrentThread { [return: MarshalAs(UnmanagedType.Interface)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 
            get; [param: In, MarshalAs(UnmanagedType.Interface)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] set; }
        }
    }

    private void GetCurrentThread()
            {
                debugService = Package.GetGlobalService(typeof(SVsShellDebugger)) as IVsDebugger;
                if (debugService != null)
                {
                    IDebuggerInternal11 debuggerServiceInternal = (IDebuggerInternal11)debugService;
                    thread = debuggerServiceInternal.CurrentThread;

                    GetCurrentStackFrame();
                }

           }

    But in this method, I think I am missing something but I am not sure what, because after the execution of the line  

     IDebuggerInternal11 debuggerServiceInternal = (IDebuggerInternal11)debugService;

    when I check the values of the debuggerServiceInternal  variable, I see there is a System.Security.SecurityException for CurrentThread, CurrentStackFrame (and so obviously the next line causes a crash). I am new to C# programming as well and hence, it is a bit difficult to grasp many things in short duration. 

    Please help. Also, if there is any other simpler method to achieve my objective, I will be glad to opt that option.

    Any suggestions would be greatly appreciated.

    Thanks a lot,

    Esash


    • Edited by esash28 Friday, August 11, 2017 10:14 AM
    Friday, August 11, 2017 9:54 AM
  • Okay. Latest update is, I googled the error and it said I was missing the ComImport attribute to the class. So I add that and now, I get a System.AccessViolationException : Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

    I am lost as to how to proceed further. :(

    Thanks,

    Esash

    Friday, August 11, 2017 10:27 AM
  • Hi Esash,

    As you have seen, there are a bunch of challenges from trying to use the 'IDebug*' interfaces from an external debugger UI component.

    The easier way to try and get access to the current stack frame, get events when it changes and evaluate expressions is to use the EnvDTE.Debugger (see MSDN) interfaces instead.

    For reading memory, if you want a fast way to do this, you just want the raw memory, and the debug engine of the target is the normal Visual Studio native engine (in other words, you aren't creating your own debug engine), I would recommend referencing Microsoft.VisualStudio.Debugger.Engine. You can then use DkmStackFrame.ExtractFromDTEObject to get the DkmStackFrame object. This will give you the DkmProcess object and you can call DkmProcess.ReadMemory to read memory from the target.

    Gregg


    Visual Studio Debugger Dev

    Sunday, August 13, 2017 5:22 PM
    Moderator
  • Hello Gregg,

    Thanks a lot for the wonderful reply. The suggestion for reading memory using Microsoft.VisualStudio.Debugger.Engine sounds promising. I am going to give it a try today and check out how far I progress. 

    Will keep you posted about my progress. 

    Regards,

    Esash

    Monday, August 14, 2017 9:23 AM
  • Hello Gregg,

    Sorry again, is there an example which I can refer to for using the Microsoft.VisualStudio.Debugger.Engine and DkmProcess.ReadMemory as you have suggested? I am not able to understand the usage completely ( I saw the Concord Extensibility Example but I think I am lost).

    Please help. 

    Regards,

    Esash


    Monday, August 14, 2017 1:22 PM
  • Hello Gregg,

    Thanks a lot to you, I was able to retrieve the memory bytes using the Microsoft.VisualStudio.Debugger.Engine  and it is really fast too. But I am puzzled over my implementation. I am debugging only one process and I only used DkmProcess.GetProcesses() to see what all processes are there and obviously, I got the process I was debugging. Next, I read memory of n bytes from a starting address. I did not use any DTE object or stackFrame as suggested by you and looks like it is working fine. 

    So, my question is, how is this working fine and when do I need to use the stackFrame? Am I missing something? 

    Please advice. 

    Thanks,

    Esash

    Tuesday, August 15, 2017 10:39 AM
  • This was very helpful! Thanks a lot!
    Sunday, July 1, 2018 4:36 PM