Cosmos/source2/Debug/Cosmos.Debug.VSDebugEngine/AD7.Impl/AD7Property.cs

280 lines
No EOL
14 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Debugger.Interop;
using Cosmos.Debug.Common;
namespace Cosmos.Debug.VSDebugEngine
{
// An implementation of IDebugProperty2
// This interface represents a stack frame property, a program document property, or some other property.
// The property is usually the result of an expression evaluation.
//
// The sample engine only supports locals and parameters for functions that have symbols loaded.
class AD7Property : IDebugProperty2
{
private DebugLocalInfo m_variableInformation;
private AD7Process mProcess;
private AD7StackFrame mStackFrame;
private DebugInfo.Local_Argument_Info mDebugInfo;
public AD7Property(DebugLocalInfo localInfo, AD7Process process, AD7StackFrame stackFrame)
{
m_variableInformation = localInfo;
mProcess = process;
mStackFrame = stackFrame;
if (localInfo.IsLocal)
{
mDebugInfo = mStackFrame.mLocalInfos[m_variableInformation.Index];
}
else
{
mDebugInfo = mStackFrame.mArgumentInfos[m_variableInformation.Index];
}
}
// Construct a DEBUG_PROPERTY_INFO representing this local or parameter.
public DEBUG_PROPERTY_INFO ConstructDebugPropertyInfo(enum_DEBUGPROP_INFO_FLAGS dwFields)
{
DEBUG_PROPERTY_INFO propertyInfo = new DEBUG_PROPERTY_INFO();
if (dwFields.HasFlag(enum_DEBUGPROP_INFO_FLAGS.DEBUGPROP_INFO_FULLNAME))
{
propertyInfo.bstrFullName = m_variableInformation.Name;
propertyInfo.dwFields |= enum_DEBUGPROP_INFO_FLAGS.DEBUGPROP_INFO_FULLNAME;
}
if (dwFields.HasFlag(enum_DEBUGPROP_INFO_FLAGS.DEBUGPROP_INFO_NAME))
{
propertyInfo.bstrName = m_variableInformation.Name;
propertyInfo.dwFields |= enum_DEBUGPROP_INFO_FLAGS.DEBUGPROP_INFO_NAME;
}
if (dwFields.HasFlag(enum_DEBUGPROP_INFO_FLAGS.DEBUGPROP_INFO_TYPE))
{
propertyInfo.bstrType = mDebugInfo.Type;
propertyInfo.dwFields |= enum_DEBUGPROP_INFO_FLAGS.DEBUGPROP_INFO_TYPE;
}
if (dwFields.HasFlag(enum_DEBUGPROP_INFO_FLAGS.DEBUGPROP_INFO_VALUE))
{
byte[] xData;
if (mDebugInfo.Type == typeof(string).AssemblyQualifiedName)
{
const uint xStringLengthOffset = 16;
const uint xStringFirstCharPtrOffset = 20;
xData = mProcess.mDbgConnector.GetStackData(mDebugInfo.Offset, 4);
uint xStrPointer = BitConverter.ToUInt32(xData, 0);
if (xStrPointer == 0)
{
propertyInfo.bstrValue = "(null)";
}
else
{
xData = mProcess.mDbgConnector.GetMemoryData(xStrPointer + xStringLengthOffset, 4, 4);
uint xStringLength = BitConverter.ToUInt32(xData, 0);
if (xStringLength > 100)
{
propertyInfo.bstrValue = "For now, strings larger than 100 chars are not supported..";
}
else
{
xData = mProcess.mDbgConnector.GetMemoryData(xStrPointer + xStringFirstCharPtrOffset, 4, 4);
uint xFirstCharPtr = BitConverter.ToUInt32(xData, 0);
xData = mProcess.mDbgConnector.GetMemoryData(xFirstCharPtr, xStringLength * 2, 2);
propertyInfo.bstrValue = "\"" + Encoding.Unicode.GetString(xData) + "\"";
}
//propertyInfo.bstrValue = Encoding.Unicode.GetString(xData);
//propertyInfo.bstrValue = String.Format("String at 0x{0}, Length at 0x{1}, Length Value = {2}", xLocation, (xStrPointer + xStringLengthOffset).ToString("X8").ToUpper(), xStringLength);
//propertyInfo.bstrValue = "String of length: " + xStringLength;
}
}
else if (mDebugInfo.Type == typeof(char).AssemblyQualifiedName)
{
xData = mProcess.mDbgConnector.GetStackData(mDebugInfo.Offset, 2);
var xTypedCharValue = BitConverter.ToChar(xData, 0);
propertyInfo.bstrValue = String.Format("{0} '{1}'", (ushort)xTypedCharValue, xTypedCharValue);
}
else if (mDebugInfo.Type == typeof(int).AssemblyQualifiedName)
{
xData = mProcess.mDbgConnector.GetStackData(mDebugInfo.Offset, 4);
var xTypedIntValue = BitConverter.ToInt32(xData, 0);
propertyInfo.bstrValue = String.Format("{0} (0x{1})", xTypedIntValue, xTypedIntValue.ToString("X").ToUpper());
}
else if (mDebugInfo.Type == typeof(long).AssemblyQualifiedName)
{
#if DEBUGGERFIXED
//didnt work, think because SendMethodContext didnt check the size, but sure
// for now, hack long/ulong support: stack values are stored in reverse order (dword-wise)
xData = mProcess.mDbgConnector.GetStackData(mDebugInfo.Offset, 8);
if (xData.Length != 8)
{
throw new Exception("Length should have been 8, but is " + xData.Length);
}
#else
byte[] xData1 = mProcess.mDbgConnector.GetStackData(mDebugInfo.Offset, 4);
byte[] xData2 = mProcess.mDbgConnector.GetStackData(mDebugInfo.Offset - 4, 4);
if (xData1.Length + xData2.Length != 8)
{
throw new Exception("Length should have been 8, but is " + (xData1.Length + xData2.Length));
}
xData = new byte[8];
Array.Copy(xData2, 0, xData, 0, 4);
Array.Copy(xData1, 0, xData, 4, 4);
#endif
var xTypedLongValue = BitConverter.ToInt64(xData, 0);
propertyInfo.bstrValue = String.Format("{0} (0x{1})", xTypedLongValue, xTypedLongValue.ToString("X").ToUpper());
}
else if (mDebugInfo.Type == typeof(ulong).AssemblyQualifiedName)
{
#if DEBUGGERFIXED
xData = mProcess.mDbgConnector.GetStackData(mDebugInfo.Offset, 8);
if (xData.Length != 8)
{
throw new Exception("Length should have been 8, but is " + xData.Length);
}
#else
byte[] xData1 = mProcess.mDbgConnector.GetStackData(mDebugInfo.Offset, 4);
byte[] xData2 = mProcess.mDbgConnector.GetStackData(mDebugInfo.Offset - 4, 4);
if (xData1.Length + xData2.Length != 8)
{
throw new Exception("Length should have been 8, but is " + (xData1.Length + xData2.Length));
}
xData = new byte[8];
Array.Copy(xData2, 0, xData, 0, 4);
Array.Copy(xData1, 0, xData, 4, 4);
#endif
var xTypedULongValue = BitConverter.ToUInt64(xData, 0);
propertyInfo.bstrValue = String.Format("{0} (0x{1})", xTypedULongValue, xTypedULongValue.ToString("X").ToUpper());
}
else
{
xData = mProcess.mDbgConnector.GetStackData(mDebugInfo.Offset, 4);
var xTypedUIntValue = BitConverter.ToUInt32(xData, 0);
propertyInfo.bstrValue = String.Format("{0} (0x{1})", xTypedUIntValue, xTypedUIntValue.ToString("X").ToUpper());
}
propertyInfo.dwFields |= enum_DEBUGPROP_INFO_FLAGS.DEBUGPROP_INFO_VALUE;
}
if (dwFields.HasFlag(enum_DEBUGPROP_INFO_FLAGS.DEBUGPROP_INFO_ATTRIB))
{
// The sample does not support writing of values displayed in the debugger, so mark them all as read-only.
propertyInfo.dwAttrib = enum_DBG_ATTRIB_FLAGS.DBG_ATTRIB_VALUE_READONLY;
//if (this.m_variableInformation.child != null)
{
//propertyInfo.dwAttrib |= DBG_ATTRIB_FLAGS.DBG_ATTRIB_OBJ_IS_EXPANDABLE;
}
}
// If the debugger has asked for the property, or the property has children (meaning it is a pointer in the sample)
// then set the pProperty field so the debugger can call back when the chilren are enumerated.
//if (((dwFields & (uint)enum_DEBUGPROP_INFO_FLAGS.DEBUGPROP_INFO_PROP) != 0)
//|| (this.m_variableInformation.child != null))
{
//propertyInfo.pProperty = (IDebugProperty2)this;
//propertyInfo.dwFields |= (uint)(DEBUGPROP_INFO_FLAGS.DEBUGPROP_INFO_PROP);
}
return propertyInfo;
}
#region IDebugProperty2 Members
// Enumerates the children of a property. This provides support for dereferencing pointers, displaying members of an array, or fields of a class or struct.
// The sample debugger only supports pointer dereferencing as children. This means there is only ever one child.
public int EnumChildren(enum_DEBUGPROP_INFO_FLAGS dwFields, uint dwRadix, ref System.Guid guidFilter, enum_DBG_ATTRIB_FLAGS dwAttribFilter, string pszNameFilter, uint dwTimeout, out IEnumDebugPropertyInfo2 ppEnum)
{
ppEnum = null;
//if (this.m_variableInformation.child != null)
//{
// DEBUG_PROPERTY_INFO[] properties = new DEBUG_PROPERTY_INFO[1];
// properties[0] = (new AD7Property(this.m_variableInformation.child)).ConstructDebugPropertyInfo(dwFields);
// ppEnum = new AD7PropertyEnum(properties);
// return VSConstants.S_OK;
//}
return VSConstants.S_FALSE;
}
// Returns the property that describes the most-derived property of a property
// This is called to support object oriented languages. It allows the debug engine to return an IDebugProperty2 for the most-derived
// object in a hierarchy. This engine does not support this.
public int GetDerivedMostProperty(out IDebugProperty2 ppDerivedMost)
{
throw new Exception("The method or operation is not implemented.");
}
// This method exists for the purpose of retrieving information that does not lend itself to being retrieved by calling the IDebugProperty2::GetPropertyInfo
// method. This includes information about custom viewers, managed type slots and other information.
// The sample engine does not support this.
public int GetExtendedInfo(ref System.Guid guidExtendedInfo, out object pExtendedInfo)
{
throw new Exception("The method or operation is not implemented.");
}
// Returns the memory bytes for a property value.
public int GetMemoryBytes(out IDebugMemoryBytes2 ppMemoryBytes)
{
throw new Exception("The method or operation is not implemented.");
}
// Returns the memory context for a property value.
public int GetMemoryContext(out IDebugMemoryContext2 ppMemory)
{
throw new Exception("The method or operation is not implemented.");
}
// Returns the parent of a property.
// The sample engine does not support obtaining the parent of properties.
public int GetParent(out IDebugProperty2 ppParent)
{
throw new Exception("The method or operation is not implemented.");
}
// Fills in a DEBUG_PROPERTY_INFO structure that describes a property.
public int GetPropertyInfo(enum_DEBUGPROP_INFO_FLAGS dwFields, uint dwRadix, uint dwTimeout, IDebugReference2[] rgpArgs, uint dwArgCount, DEBUG_PROPERTY_INFO[] pPropertyInfo)
{
pPropertyInfo[0] = new DEBUG_PROPERTY_INFO();
rgpArgs = null;
pPropertyInfo[0] = ConstructDebugPropertyInfo(dwFields);
return VSConstants.S_OK;
}
// Return an IDebugReference2 for this property. An IDebugReference2 can be thought of as a type and an address.
public int GetReference(out IDebugReference2 ppReference)
{
throw new Exception("The method or operation is not implemented.");
}
// Returns the size, in bytes, of the property value.
public int GetSize(out uint pdwSize)
{
throw new Exception("The method or operation is not implemented.");
}
// The debugger will call this when the user tries to edit the property's values
// the sample has set the read-only flag on its properties, so this should not be called.
public int SetValueAsReference(IDebugReference2[] rgpArgs, uint dwArgCount, IDebugReference2 pValue, uint dwTimeout)
{
throw new Exception("The method or operation is not implemented.");
}
// The debugger will call this when the user tries to edit the property's values in one of the debugger windows.
// the sample has set the read-only flag on its properties, so this should not be called.
public int SetValueAsString(string pszValue, uint dwRadix, uint dwTimeout)
{
throw new Exception("The method or operation is not implemented.");
}
#endregion
}
}