private void LoadVariablesNode(Variable theVar, CommonTools.Node parent, object[] parentNodeData) { parentNodeData[2] = theVar.ToString(); parent.SetData(parentNodeData); int i = 0; foreach (Variable aFieldVar in theVar.Fields) { CommonTools.Node newNode = new CommonTools.Node(); object[] nodeData = new object[3]; nodeData[0] = i++; nodeData[1] = aFieldVar.dbType.Signature; nodeData[2] = Utils.GetValueStr(aFieldVar.value, aFieldVar.dbType.Signature); newNode.SetData(nodeData); parent.Nodes.Add(newNode); LoadVariablesNode(aFieldVar, newNode, nodeData); } RefreshTreeViews(); }
/// <summary> /// Loads the values of the fields of this variable. /// </summary> /// <param name="debugger">The debugger to use for loading.</param> /// <param name="callback">The callback to invoke when loading is complete.</param> /// <param name="recursive">Whether to load recursively down the object tree.</param> public void LoadFields(Debugger debugger, OnLoadFieldsCompleteDelegate callback, bool recursive = false) { if (dbType.Signature == "System.String") { #region String Load StringValueLoaded = false; debugger.LoadMemoryValue(value, (uint)dbType.StackBytesSize, delegate(byte[] data, Tuple<byte[], uint, Debugger.LoadMemoryCompletedDelegate, object> state) { Variable fieldVar1 = (Variable)state.Item4; //This stuff relies entirely on how string data is compiled into the kernel uint stringLength = BitConverter.ToUInt32(data, 0); //TODO - Create a proper test condition //This was inserted because when stepping into a method, //the first two instructions set up EBP/ESP correctly //but during that time the returned values are all screwy //usually resulting in incorrect values, in this case the length //ends up insanely big! if (stringLength < 500) { Tuple<ulong, byte> fieldAddress1 = Utils.BytesToAddress(fieldVar1.value); fieldAddress1 = new Tuple<ulong, byte>(fieldAddress1.Item1 + 4, fieldAddress1.Item2); fieldVar1.value = Utils.AddressToBytes(fieldAddress1); debugger.LoadMemoryValue(fieldVar1.value, stringLength * 2, delegate(byte[] data1, Tuple<byte[], uint, Debugger.LoadMemoryCompletedDelegate, object> state1) { Variable fieldVar2 = (Variable)state1.Item4; fieldVar2.value = data1; fieldVar2.StringValueLoaded = true; callback(); }, fieldVar1); } }, this); #endregion } //If this is a reference type, it will have fields / further data to load else if (!dbType.IsValueType) { //The value bytes are in fact a reference (pointer) byte[] thisAddressBytes = value; //Convert the address to an actual number // - second value indicates the size of thr address in number of bytes (i.e. 4 for 32-bit, 8 for 64-bit) Tuple<ulong, byte> thisAddress = Utils.BytesToAddress(thisAddressBytes); //Check the address is valid if (thisAddress.Item1 != 0) { List<DB_ComplexTypeLink> children = dbType.ChildTypes.OrderBy(x => x.ParentIndex).ToList(); uint offset = 0; int fieldsLoading = children.Count; if (fieldsLoading == 0) { callback(); } else { foreach (DB_ComplexTypeLink aChild in children) { Tuple<ulong, byte> fieldAddress = new Tuple<ulong, byte>(thisAddress.Item1 + offset, thisAddress.Item2); byte[] fieldAddressBytes = Utils.AddressToBytes(fieldAddress); Variable fieldVar = new Variable() { dbType = aChild.ChildType, value = fieldAddressBytes }; Fields.Add(fieldVar); if (fieldVar.dbType.IsValueType || fieldVar.dbType.Signature == "System.String") { //Load the actual value if (fieldVar.dbType.Signature == "System.String") { #region String Load fieldVar.StringValueLoaded = false; debugger.LoadMemoryValue(fieldVar.value, (uint)fieldVar.dbType.StackBytesSize, delegate(byte[] data, Tuple<byte[], uint, Debugger.LoadMemoryCompletedDelegate, object> state) { Variable fieldVar1 = (Variable)state.Item4; //This stuff relies entirely on how string data is compiled into the kernel uint stringLength = BitConverter.ToUInt32(data, 0); //TODO - Create a proper test condition //This was inserted because when stepping into a method, //the first two instructions set up EBP/ESP correctly //but during that time the returned values are all screwy //usually resulting in incorrect values, in this case the length //ends up insanely big! if (stringLength < 500) { Tuple<ulong, byte> fieldAddress1 = Utils.BytesToAddress(fieldVar1.value); fieldAddress1 = new Tuple<ulong, byte>(fieldAddress1.Item1 + 4, fieldAddress1.Item2); fieldVar1.value = Utils.AddressToBytes(fieldAddress1); debugger.LoadMemoryValue(fieldVar1.value, stringLength * 2, delegate(byte[] data1, Tuple<byte[], uint, Debugger.LoadMemoryCompletedDelegate, object> state1) { Variable fieldVar2 = (Variable)state1.Item4; fieldVar2.value = data1; fieldsLoading--; if (fieldsLoading == 0) { callback(); } }, fieldVar1); } }, fieldVar); #endregion } else { debugger.LoadMemoryValue(fieldVar.value, (uint)fieldVar.dbType.BytesSize, delegate(byte[] data, Tuple<byte[], uint, Debugger.LoadMemoryCompletedDelegate, object> state) { Variable fieldVar1 = (Variable)state.Item4; fieldVar1.value = data; fieldVar1.StringValueLoaded = true; fieldsLoading--; if (fieldsLoading == 0) { callback(); } }, fieldVar); } } else if (recursive && dbType.Signature != "Kernel.FOS_System.Type") { //Load the field's fields - i.e. recursive debugger.LoadMemoryValue(fieldVar.value, (uint)fieldVar.dbType.StackBytesSize, delegate(byte[] data, Tuple<byte[], uint, Debugger.LoadMemoryCompletedDelegate, object> state) { Variable fieldVar1 = (Variable)state.Item4; fieldVar1.value = data; fieldVar1.LoadFields(debugger, delegate() { fieldsLoading--; if (fieldsLoading == 0) { callback(); } }, recursive); }, fieldVar); } else { fieldsLoading--; } offset += (uint)fieldVar.dbType.StackBytesSize; } } } } }