none
Access process memory within Visual Studio debugger extension

    Question

  • A bit of background. I develop a VS Extension that allows users to plot the contents of arrays whilst debugging. The user specifies an expression that should evaluate to the array start address, and an expression that evaluates to the length of the array. The extensions retrieves and formats the raw memory, then plots it in a graph.

    The method that the current released version uses to obtain the array contents is summarised as:

    1. DTE2::Debugger::GetExpression() to get the array start address and length
    2. Get current process from DTE2::Debugger::CurrentProcess
    3. OpenProcess() on current process (from kernel32.dll)
    4. Get raw memory byte array from ReadProcessMemory() (from kernel32.dll)

    This method is simple and efficient and has worked for all of my own needs. BUT… others attempting to debug any process that isn’t running in native memory, or utilising a third party debugger (ie visual GDB) have found, understandably, that it does not work in this scenario. The address is correctly determined, but it is unable to access the memory. However, the built-in debugging environment, ie Memory Window works as expected.

    I expected that there had to exist some Visual Studio Framework that would allow me to query / access the debugger in the same manner as Visual Studio. Some searching led me to a MacroPolygon post (http://macropolygon.wordpress.com/2012/12/16/evaluating-debugged-process-memory-in-a-visual-studio-extension/).

    I implemented the above approach, which worked fine for my use cases with local debugging. The steps are summarised as:

    1. Get current stack frame as IDebugStackFrame2 (from DTE2::Debugger.CurrentStackFrame)
    2. Evaluate address / length expressions:
    3.   Get IDebugExpressionContext2 from IDebugStackFrame2::GetExpressionContext()
    4.   Get IDebugExpression2 from IDebugExpressionContext2::ParseText(expression, …)
    5.   Get IDebugProperty2 from IDebugExpression2::EvaluateSync
    6. Get IDebugMemoryContext2 from address IDebugProperty2::GetMemoryContext()
    7. Get IDebugMemoryBytes2 from IDebugMemoryContext2::GetMemoryBytes()
    8. Read raw memory bytes using IDebugMemoryBytes2::ReadAt(memoryContext)

    I then installed WSL and made a test project deploying C++ to Linux (on WSL). My revised extension does NOT work with this test project.

    The failing step was the call to GetMemoryContext(). A System.InvalidCastException was thrown: “Unable to cast object of type ‘Microsoft.MIDebugEngine.AD7MemoryAddress’ to type ‘Microsoft.VisualStudio.Debugger.Interop.IDebugMemoryContext2’”

    A search brought me to https://github.com/Microsoft/MIEngine, where comments AD7MemoryAddress.cs suggests that the AD7MemoryAddress class IS a IDebugMemoryContext2, and the source shows that the class IS a IDebugCodeContext2 which IS a IDebugMemoryContext2.

    So I’m now wondering why the AD7MemoryAddress couldn’t be casted to a IDebugMemoryContext2?

    Alternatively, does anyone know by what method the Memory Window retrieves it’s memory?


    Sunday, June 17, 2018 1:27 PM

All replies

  • Note I also attempted to use the method as per the DumpMemory extension (https://github.com/yifanlu/DumpMemory), which obtains the IDebugStackFrame2 slightly differently. No luck. It still failed attempting to cast the memory context
    Sunday, June 24, 2018 1:50 PM
  • Also, according to https://msdn.microsoft.com/en-us/library/bb161954.aspx:

    Visual Studio's Memory View calls GetMemoryBytes to retrieve an IDebugMemoryBytes2 interface for accessing system memory. The address to be accessed is obtained by parsing the expression entered as an address into the Memory View and then evaluating the parsed expression using EvaluateSync to get an IDebugProperty2interface. A call to GetMemoryContext returns the IDebugMemoryContext2 that describes the memory address. This memory context is then passed to ReadAt and WriteAt

    Monday, November 26, 2018 11:17 AM