using System; using System.Collections.Generic; using System.Text; using Microsoft.VisualStudio; using Microsoft.VisualStudio.Debugger.Interop; 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; public AD7Property(DebugLocalInfo localInfo, AD7Process process, AD7StackFrame stackFrame) { m_variableInformation = localInfo; mProcess = process; mStackFrame = stackFrame; } // 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)) { // todo: add support for types of properties propertyInfo.bstrType = "System.Byte[]"; propertyInfo.dwFields |= enum_DEBUGPROP_INFO_FLAGS.DEBUGPROP_INFO_TYPE; } if (dwFields.HasFlag(enum_DEBUGPROP_INFO_FLAGS.DEBUGPROP_INFO_VALUE)) { StringBuilder sb = new StringBuilder();//m_variableInformation.m_value); // retrieve property value: // todo: corect size of data, datatypes, refactor to move to some dedicated class etc byte[] xData; if (m_variableInformation.IsLocal) { xData = mProcess.mDbgConnector.GetStackData(mStackFrame.mLocalInfos[m_variableInformation.Index].Offset, 4); } else { xData = mProcess.mDbgConnector.GetStackData(mStackFrame.mArgumentInfos[m_variableInformation.Index].Offset, 4); } // for now, dump as hex sb.Append("0x"); if (xData == null) { sb.Append("(xData == null)"); } else { for (int i = xData.Length - 1; i >= 0; i--) { sb.Append(xData[i].ToString("X2").ToUpper()); } } propertyInfo.bstrValue = sb.ToString(); 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 } }