Add arithmetic operations
authora-shaurtaev <a.shaurtaev@partner.samsung.com>
Tue, 14 Sep 2021 12:46:13 +0000 (15:46 +0300)
committerAlexander Soldatov/Platform Lab /SRR/Staff Engineer/Samsung Electronics <soldatov.a@samsung.com>
Wed, 6 Oct 2021 13:05:41 +0000 (16:05 +0300)
src/managed/Evaluation.cs
src/managed/interop.cpp
src/managed/interop.h

index 0370977e1a524669edacd0713541b98a153bc4d9..68000d2291066562259b59e64487b7f2b9be3c96 100644 (file)
@@ -435,5 +435,182 @@ namespace NetCoreDbg
             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;
+        }
     }
 }
index e31ad65404ae5ebbb73aebd16493239031fa0628..a676f2959f0d64c1e4580296163d00b15df155e0 100644 (file)
@@ -69,6 +69,7 @@ typedef  RetCode (*GetAsyncMethodsSteppingInfoDelegate)(PVOID, PVOID*, int32_t*)
 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*);
@@ -104,6 +105,7 @@ CoTaskMemAllocDelegate coTaskMemAllocDelegate = nullptr;
 CoTaskMemFreeDelegate coTaskMemFreeDelegate = nullptr;
 SysAllocStringLenDelegate sysAllocStringLenDelegate = nullptr;
 SysFreeStringDelegate sysFreeStringDelegate = nullptr;
+CalculationDelegate calculationDelegate = nullptr;
 
 constexpr char ManagedPartDllName[] = "ManagedPart";
 constexpr char SymbolReaderClassName[] = "NetCoreDbg.SymbolReader";
@@ -280,6 +282,7 @@ void Init(const std::string &coreClrPath)
         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 **)&registerGetChildDelegate)) &&
+        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)) &&
@@ -315,7 +318,8 @@ void Init(const std::string &coreClrPath)
                               coTaskMemAllocDelegate &&
                               coTaskMemFreeDelegate &&
                               sysAllocStringLenDelegate &&
-                              sysFreeStringDelegate;
+                              sysFreeStringDelegate &&
+                              calculationDelegate;
 
     if (!allDelegatesInited)
         throw std::runtime_error("Some delegates nulled");
@@ -372,6 +376,7 @@ void Shutdown()
     coTaskMemFreeDelegate = nullptr;
     sysAllocStringLenDelegate = nullptr;
     sysFreeStringDelegate = nullptr;
+    calculationDelegate = nullptr;
 }
 
 HRESULT GetSequencePointByILOffset(PVOID pSymbolReaderHandle, mdMethodDef methodToken, ULONG32 ilOffset, SequencePoint *sequencePoint)
@@ -439,6 +444,33 @@ HRESULT GetNamedLocalVariableAndScope(PVOID pSymbolReaderHandle, mdMethodDef met
     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);
index ba78ad9ecc430e7ee279bb52dd7f4314a6afb6b3..664b3235bc70402282b9cb52424a6c09a55ba3a6 100644 (file)
@@ -88,6 +88,15 @@ namespace Interop
         TypeString,  //        "System.String"
     };
 
+    // Keep in sync with OperationType enum in Evaluation.cs
+    enum class OperationType
+    {
+        Addition = 1,
+        Subtraction,
+        Multiplication,
+        Division,
+        Remainder,
+    };
     struct AsyncAwaitInfoBlock
     {
         uint32_t yield_offset;
@@ -120,6 +129,7 @@ namespace Interop
     HRESULT GetAsyncMethodsSteppingInfo(PVOID pSymbolReaderHandle, std::vector<AsyncAwaitInfoBlock> &AsyncAwaitInfo);
     HRESULT GetSource(PVOID symbolReaderHandle, const std::string fileName, PVOID *data, int32_t *length);
     HRESULT ParseExpression(const std::string &expr, const std::string &typeName, std::string &data, std::string &errorText);
+    HRESULT CalculationDelegate(PVOID firstOp, int32_t firstType, PVOID secondOp, int32_t secondType, int32_t operationType, int32_t &resultType, PVOID *data, std::string &errorText);
     HRESULT EvalExpression(const std::string &expr, std::string &result, int *typeId, ICorDebugValue **ppValue, GetChildCallback cb);
     HRESULT GenerateStackMachineProgram(const std::string &expr, PVOID *ppStackProgram, std::string &textOutput);
     void ReleaseStackMachineProgram(PVOID pStackProgram);