使用VSIX

时间:2017-08-08 13:42:12

标签: visual-studio vsix

我正在使用VSIX为visual studio开发调试器插件。我的问题是我有一个地址数组但我无法将IDebugMemoryBytes2设置为特定地址。我使用DEBUG_PROPERTY_INFO并获取地址数组,并且我还能够使用IDebugMemoryContext2中的Add函数将上下文设置为数组中的特定地址。但是,我需要使用ReadAt函数从指定的地址(来自IDebugMemoryBytes2)中检索n个字节。

有没有人知道如何从内存中的任意地址检索数据?

我正在添加更多相关信息:

我正在使用Microsoft Visual Studio Extensibility包来构建我的调试器插件。在我尝试使用此插件进行调试的应用程序中,有一个双指针,我需要读取这些值以在我的插件中进一步处理它们。为此,无法在监视窗口中显示所有指针变量,因此,我无法获取指针变量指向的所有数组块的DEBUG_PROPERTY_INFO。这是我试图解决的问题。我无法读取此双指针指向的内存。

现在,对于debuggee进程中的事件,由于插件是用于调试变量,我在一个我知道这个指针被填充的地方放了一个断点,然后回到插件进行进一步的评估。

首先,我能够以某种方式获得每个阵列的起始地址。但是,我仍然无法从这些起始地址中读取x字节的内存。

即,例如,如果我有int ** ptr = //指向某个

我的地址存在于ptr [0],ptr [1],ptr [2]等中。但我需要转到每个地址并获取它们指向的内存块。

为此,经过大量搜索,我发现了这个链接:https://macropolygon.wordpress.com/2012/12/16/evaluating-debugged-process-memory-in-a-visual-studio-extension/这似乎正好解决了我的问题。

因此,为了使用表达式求值器函数,我需要一个IDebugStackFrame2对象来获取ExpressionContext。要获取此对象,我需要在debuggee进程中注册用于断点的事件。正如帖子中所说,我做了:

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;
}

我的注册就像:

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();
        }
    }
}

但是这似乎根本没有调用Event函数,因此我不知道如何获取IDebugThread2对象。

我也尝试了同一篇文章中建议的其他方式:

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();
    }
}

但是在这种方法中,我认为我遗漏了一些东西,但我不确定是什么,因为在执行该行之后

IDebuggerInternal11 debuggerServiceInternal = 
                                  (IDebuggerInternal11)debugService;

当我检查debuggerServiceInternal变量的值时,我看到CurrentThread,CurrentStackFrame有一个 System.Security.SecurityException (显然下一行会导致崩溃)。为此,我用Google搜索了错误,发现我错过了类的 ComImport属性。所以我添加了,现在,我得到一个 System.AccessViolationException:尝试读取或写入受保护的内存。这通常表明其他内存已损坏。

我也是C#编程的新手,因此,在短时间内掌握很多东西有点困难。我现在迷失了如何继续前进。

我们将非常感谢您提供相同的帮助或尝试其他方式来实现我的目标。

非常感谢,

Esash

1 个答案:

答案 0 :(得分:1)

经过多次搜索,由于时间不够,我需要一个快速的解决方案,因此,现在,似乎解决这个问题的最快方法是通过使它显示所有元素来破解.natvis文件指针,然后使用相同的旧方法,通过使用IDebug *接口方法来访问和检索每个指针元素的内存上下文。但是,在msdn论坛上发布相同的问题之后,我认为这个问题的正确答案正如Greggs所提到的: “对于读取内存,如果你想要一个快速的方法来做到这一点,你只需要原始内存,目标的调试引擎是普通的Visual Studio本机引擎(换句话说,你不是在创建自己的调试引擎),我建议引用Microsoft.VisualStudio.Debugger.Engine。然后你可以使用DkmStackFrame.ExtractFromDTEObject来获取DkmStackFrame对象。这将为你提供DkmProcess对象,你可以调用DkmProcess.ReadMemory来从目标中读取内存。“ / p>

现在,在尝试了解如何实现这一点后,我发现你可以使用以下方法完成此任务: DkmProcess.GetProcesses()并在返回的进程上执行ReadMemory。 现在有一个问题,如果返回多个进程会怎样。好吧,我尝试将许多进程附加到当前的调试过程并尝试将许多进程附加到调试对象进程,但发现DkmProcess.GetProcesses()仅获取我从中重新获得控件的进程,而不是其他进程我很依恋。我不确定这是否适用于所有情况,但对我来说,它是这样工作的,对于任何有类似要求的人来说,这也可能有效。

使用.natvis文件来实现这一点意味着,使用VS1513和先前版本的IndexListItems,并使用CustomListItems用于VS2015及更高版本,并使其看起来更漂亮,使用“no-derived”属性。没有办法使Synthetic标签只显示每个变量的基地址,因此,上述属性是最好的方法,但这在VS2013和之前的版本中不可用(基本地址可能会显示但是对于想要超越仅显示内容并访问指针元素的内存上下文的人,合成标签不是正确的事情。)

我希望这能帮助一些像我一样使用IDebug *接口的开发人员。作为参考,我还提供了msdn论坛的链接,我的问题得到了解答。

https://social.msdn.microsoft.com/Forums/en-US/030cef1c-ee79-46e9-8e40-bfc59f14cc34/how-can-i-send-a-custom-debug-event-to-my-idebugeventcallback2-handler?forum=vsdebug

感谢。