MarshalValue(value, out size, out data);
return RetCode.OK;
}
+
+ //BasicTypes enum must be sync with enum from native part
+ internal enum BasicTypes
+ {
+ TypeCorValue = -1,
+ TypeObject = 0,
+ TypeBoolean,
+ TypeByte,
+ TypeSByte,
+ TypeChar,
+ TypeDouble,
+ TypeSingle,
+ TypeInt32,
+ TypeUInt32,
+ TypeInt64,
+ TypeUInt64,
+ TypeInt16,
+ TypeUInt16,
+ TypeIntPtr,
+ TypeUIntPtr,
+ TypeDecimal,
+ TypeString,
+ };
+
+ //OperationType enum must be sync with enum from native part
+ internal enum OperationType
+ {
+ Addition = 1,
+ Subtraction,
+ Multiplication,
+ Division,
+ Remainder,
+ Compound
+ };
+
+ internal static Dictionary<OperationType, Func<object, object, object>> operationTypesMap = new Dictionary<OperationType, Func<object, object, object>>
+ {
+ { OperationType.Addition, (object firstOp, object secondOp) => { return Addition(firstOp, secondOp); }},
+ { OperationType.Division, (object firstOp, object secondOp) => { return Division(firstOp, secondOp); }},
+ { OperationType.Multiplication, (object firstOp, object secondOp) => { return Multiplication(firstOp, secondOp); }},
+ { OperationType.Remainder, (object firstOp, object secondOp) => { return Remainder(firstOp, secondOp); }},
+ { OperationType.Subtraction, (object firstOp, object secondOp) => { return Subtraction(firstOp, secondOp); }}
+ };
+
+ internal static Dictionary<BasicTypes, Func<byte[], object>> typesMap = new Dictionary<BasicTypes, Func<byte[], object>>
+ {
+ { BasicTypes.TypeBoolean, (byte[] values) => {return BitConverter.ToBoolean(values,0);}},
+ { BasicTypes.TypeByte, (byte[] values) => {return values[0];}},
+ { BasicTypes.TypeChar, (byte[] values) => {return BitConverter.ToChar(values,0);}},
+ { BasicTypes.TypeDouble, (byte[] values) => {return BitConverter.ToDouble(values,0);}},
+ { BasicTypes.TypeInt16, (byte[] values) => {return BitConverter.ToInt16(values,0);}},
+ { BasicTypes.TypeInt32, (byte[] values) => {return BitConverter.ToInt32(values,0);}},
+ { BasicTypes.TypeInt64, (byte[] values) => {return BitConverter.ToInt64(values,0);}},
+ { BasicTypes.TypeSByte, (byte[] values) => {return (sbyte)values[0];}},
+ { BasicTypes.TypeSingle, (byte[] values) => {return BitConverter.ToSingle(values,0);}},
+ { BasicTypes.TypeUInt16, (byte[] values) => {return BitConverter.ToUInt16(values,0);}},
+ { BasicTypes.TypeUInt32, (byte[] values) => {return BitConverter.ToUInt32(values,0);}},
+ { BasicTypes.TypeUInt64, (byte[] values) => {return BitConverter.ToUInt64(values,0);}}
+ };
+
+ internal static Dictionary<Type, BasicTypes> basicTypesMap = new Dictionary<Type, BasicTypes>
+ {
+ { typeof(Boolean), BasicTypes.TypeBoolean },
+ { typeof(Byte), BasicTypes.TypeByte },
+ { typeof(Char), BasicTypes.TypeChar },
+ { typeof(Double), BasicTypes.TypeDouble },
+ { typeof(Int16), BasicTypes.TypeInt16 },
+ { typeof(Int32), BasicTypes.TypeInt32 },
+ { typeof(Int64), BasicTypes.TypeInt64 },
+ { typeof(SByte), BasicTypes.TypeSByte },
+ { typeof(Single), BasicTypes.TypeSingle },
+ { typeof(UInt16), BasicTypes.TypeUInt16 },
+ { typeof(UInt32), BasicTypes.TypeUInt32 },
+ { typeof(UInt64), BasicTypes.TypeUInt64 }
+ };
+
+ /// <summary>
+ /// Convert Single(float) type to Int32
+ /// </summary>
+ /// <param name="value">float value</param>
+ /// <returns></returns>
+ private static unsafe int floatToInt32Bits(float value)
+ {
+ return *((int*)&value);
+ }
+
+ /// <summary>
+ /// Converts value to a IntPtr to IntPtr
+ /// </summary>
+ /// <param name="value">source value</param>
+ /// <returns></returns>
+ private static IntPtr valueToPtr(object value)
+ {
+ IntPtr result = IntPtr.Zero;
+ IntPtr ptr = IntPtr.Zero;
+ Int64 newValue = 0;
+ if (value.GetType() == typeof(string))
+ {
+ result = Marshal.AllocHGlobal(Marshal.SizeOf(newValue));
+ ptr = Marshal.StringToBSTR(value as string);
+ }
+ else
+ {
+ if (value.GetType() == typeof(float) || value.GetType() == typeof(double))
+ newValue = value.GetType() == typeof(float) ? Convert.ToInt64(floatToInt32Bits(Convert.ToSingle(value))) : BitConverter.DoubleToInt64Bits(Convert.ToDouble(value));
+ else
+ newValue = Convert.ToInt64(value);
+ var size = Marshal.SizeOf(newValue);
+ result = Marshal.AllocHGlobal(Marshal.SizeOf(newValue));
+ ptr = Marshal.AllocHGlobal(size);
+ Marshal.WriteInt64(ptr, newValue);
+ }
+ Marshal.WriteIntPtr(result, ptr);
+ return result;
+ }
+
+ private static object ptrToValue(IntPtr ptr, int type)
+ {
+ if ((BasicTypes)type == BasicTypes.TypeString)
+ return Marshal.PtrToStringAuto(ptr);
+
+ var intValue = Marshal.ReadInt64(ptr);
+ var bytesArray = BitConverter.GetBytes(intValue);
+ return typesMap[(BasicTypes)type](bytesArray);
+ }
+
+ internal static RetCode CalculationDelegate(IntPtr firstOpPtr, int firstType, IntPtr secondOpPtr, int secondType, int operation, int resultType, out IntPtr result, out IntPtr errorText)
+ {
+ result = IntPtr.Zero;
+ errorText = IntPtr.Zero;
+
+ try
+ {
+ var firstOp = ptrToValue(firstOpPtr, firstType);
+ var secondOp = ptrToValue(secondOpPtr, secondType);
+ object operationResult = operationTypesMap[(OperationType)operation](firstOp, secondOp);
+ resultType = (int)basicTypesMap[operationResult.GetType()];
+ result = valueToPtr(operationResult);
+ }
+ catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException ex)
+ {
+ errorText = Marshal.StringToBSTR(ex.ToString());
+ return RetCode.Exception;
+ }
+ catch (System.Exception ex)
+ {
+ errorText = Marshal.StringToBSTR(ex.ToString());
+ return RetCode.Exception;
+ }
+
+ return RetCode.OK;
+ }
+
+ private static object Addition(dynamic first, dynamic second)
+ {
+ return first + second;
+ }
+
+ private static object Subtraction(dynamic first, dynamic second)
+ {
+ return first - second;
+ }
+
+ private static object Multiplication(dynamic first, dynamic second)
+ {
+ return first * second;
+ }
+
+ private static object Division(dynamic first, dynamic second)
+ {
+ return first / second;
+ }
+
+ private static object Remainder(dynamic first, dynamic second)
+ {
+ return first % second;
+ }
}
}
typedef RetCode (*GetSourceDelegate)(PVOID, const WCHAR*, int32_t*, PVOID*);
typedef RetCode (*ParseExpressionDelegate)(const WCHAR*, const WCHAR*, PVOID*, int32_t*, BSTR*);
typedef RetCode (*EvalExpressionDelegate)(const WCHAR*, PVOID, BSTR*, int32_t*, int32_t*, PVOID*);
+typedef RetCode (*CalculationDelegate)(PVOID, int32_t, PVOID, int32_t, int32_t, int32_t*, PVOID*, BSTR*);
typedef BOOL (*GetChildDelegate)(PVOID, PVOID, const WCHAR*, int32_t*, PVOID*);
typedef BOOL (*RegisterGetChildDelegate)(GetChildDelegate);
typedef int (*GenerateStackMachineProgramDelegate)(const WCHAR*, PVOID*, BSTR*);
CoTaskMemFreeDelegate coTaskMemFreeDelegate = nullptr;
SysAllocStringLenDelegate sysAllocStringLenDelegate = nullptr;
SysFreeStringDelegate sysFreeStringDelegate = nullptr;
+CalculationDelegate calculationDelegate = nullptr;
constexpr char ManagedPartDllName[] = "ManagedPart";
constexpr char SymbolReaderClassName[] = "NetCoreDbg.SymbolReader";
SUCCEEDED(Status = createDelegate(hostHandle, domainId, ManagedPartDllName, EvaluationClassName, "ParseExpression", (void **)&parseExpressionDelegate)) &&
SUCCEEDED(Status = createDelegate(hostHandle, domainId, ManagedPartDllName, EvaluationClassName, "EvalExpression", (void **)&evalExpressionDelegate)) &&
SUCCEEDED(Status = createDelegate(hostHandle, domainId, ManagedPartDllName, EvaluationClassName, "RegisterGetChild", (void **)®isterGetChildDelegate)) &&
+ SUCCEEDED(Status = createDelegate(hostHandle, domainId, ManagedPartDllName, EvaluationClassName, "CalculationDelegate", (void **)&calculationDelegate)) &&
SUCCEEDED(Status = createDelegate(hostHandle, domainId, ManagedPartDllName, EvaluationClassName, "GenerateStackMachineProgram", (void **)&generateStackMachineProgramDelegate)) &&
SUCCEEDED(Status = createDelegate(hostHandle, domainId, ManagedPartDllName, EvaluationClassName, "ReleaseStackMachineProgram", (void **)&releaseStackMachineProgramDelegate)) &&
SUCCEEDED(Status = createDelegate(hostHandle, domainId, ManagedPartDllName, EvaluationClassName, "NextStackCommand", (void **)&nextStackCommandDelegate)) &&
coTaskMemAllocDelegate &&
coTaskMemFreeDelegate &&
sysAllocStringLenDelegate &&
- sysFreeStringDelegate;
+ sysFreeStringDelegate &&
+ calculationDelegate;
if (!allDelegatesInited)
throw std::runtime_error("Some delegates nulled");
coTaskMemFreeDelegate = nullptr;
sysAllocStringLenDelegate = nullptr;
sysFreeStringDelegate = nullptr;
+ calculationDelegate = nullptr;
}
HRESULT GetSequencePointByILOffset(PVOID pSymbolReaderHandle, mdMethodDef methodToken, ULONG32 ilOffset, SequencePoint *sequencePoint)
return S_OK;
}
+HRESULT CalculationDelegate(PVOID firstOp, int32_t firstType, PVOID secondOp, int32_t secondType, int32_t operationType, int32_t &resultType, PVOID *data, std::string &errorText)
+{
+ std::unique_lock<Utility::RWLock::Reader> read_lock(CLRrwlock.reader);
+ if (!calculationDelegate)
+ return E_FAIL;
+
+ BSTR werrorText;
+ RetCode retCode = calculationDelegate(firstOp, firstType, secondOp, secondType, operationType, &resultType, data, &werrorText);
+ read_lock.unlock();
+ BasicTypes resType = static_cast<BasicTypes>(resultType);
+
+ if (retCode != RetCode::OK)
+ {
+ errorText = to_utf8(werrorText);
+ Interop::SysFreeString(werrorText);
+ return E_FAIL;
+ }
+
+ if (resType == BasicTypes::TypeString)
+ {
+ auto dataStr = to_utf8((BSTR)(data));
+ Interop::SysFreeString((BSTR)&dataStr);
+ }
+
+ return (retCode == RetCode::OK) ? S_OK : E_FAIL;
+}
+
HRESULT GetMethodLastIlOffset(PVOID pSymbolReaderHandle, mdMethodDef methodToken, ULONG32 *ilOffset)
{
std::unique_lock<Utility::RWLock::Reader> read_lock(CLRrwlock.reader);