Docs: How to extract function argument and return value??

Created on 30 Jul 2018  Â·  6Comments  Â·  Source: dotnet/docs

It is a very helpful article for understanding. I would like to know, how we can extract function parameter name, value and also function return value.


Document Details

⚠ Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.

Area - .NET Framework Guide Area - API Reference product-question

Most helpful comment

My team owns it.

1) To get parameter names you would want to use metadata...
a) ICorProfilerInfo::GetFunctionInfo() converts from FunctionID -> ModuleID and mdToken (MethodDef token)
b) ICorProfilerInfo::GetModuleMetaData() get an IMetadataImport interface for the ModuleID
c) IMetadataImport::GetParamForMethodInfex() gets a ParamDef token for the n'th parameter given the MethodDef token for the method
d) IMetaDataImport::GetParamProps() gets the name of the parameter given the ParamDef token

2) To get values you need to inspect the memory that is pointed to by the argument info
a) FunctionEnter2 has an argumentInfo structure passed to you as an argument
b) COR_PRF_FUNCTION_ARGUMENT_INFO describes a set of memory ranges where are all the arguments are stored in left to right order
c) You can use metadata to understand the types of the arguments (IMetadataImport::GetMethodProps to get the signature blob, which then can be parsed according to ECMA CLI specification for a LocalVarSignature)
d) Once you know the types of the arguments, you can infer their sizes and how to interpret the bytes you are reading from memory. For example an int is going to be 4 bytes of the memory range or any reference type is going to be a pointer sized piece of memory that points at the object contents. Methods such as ICorProfilerInfo2::GetClassLayout, ICorProfiler2::GetArrayObjectInfo, and ICorProfiler2::GetBoxClassLayout can assist in understanding the layout of complex types that might appear in these arguments

3) Return value is similar to arguments, except use the retvalRange parameter in FunctionLeave2.

Sorry this is just a quick overview as the full details can get fairly involved. I hunted around to see if I could find a sample but unforetunately I didn't locate one. Hope this helps though.

All 6 comments

Thanks @Ashutosh-K-Singh. @noahfalk do you own profiling or knows who own that could help with this question?

My team owns it.

1) To get parameter names you would want to use metadata...
a) ICorProfilerInfo::GetFunctionInfo() converts from FunctionID -> ModuleID and mdToken (MethodDef token)
b) ICorProfilerInfo::GetModuleMetaData() get an IMetadataImport interface for the ModuleID
c) IMetadataImport::GetParamForMethodInfex() gets a ParamDef token for the n'th parameter given the MethodDef token for the method
d) IMetaDataImport::GetParamProps() gets the name of the parameter given the ParamDef token

2) To get values you need to inspect the memory that is pointed to by the argument info
a) FunctionEnter2 has an argumentInfo structure passed to you as an argument
b) COR_PRF_FUNCTION_ARGUMENT_INFO describes a set of memory ranges where are all the arguments are stored in left to right order
c) You can use metadata to understand the types of the arguments (IMetadataImport::GetMethodProps to get the signature blob, which then can be parsed according to ECMA CLI specification for a LocalVarSignature)
d) Once you know the types of the arguments, you can infer their sizes and how to interpret the bytes you are reading from memory. For example an int is going to be 4 bytes of the memory range or any reference type is going to be a pointer sized piece of memory that points at the object contents. Methods such as ICorProfilerInfo2::GetClassLayout, ICorProfiler2::GetArrayObjectInfo, and ICorProfiler2::GetBoxClassLayout can assist in understanding the layout of complex types that might appear in these arguments

3) Return value is similar to arguments, except use the retvalRange parameter in FunctionLeave2.

Sorry this is just a quick overview as the full details can get fairly involved. I hunted around to see if I could find a sample but unforetunately I didn't locate one. Hope this helps though.

Thanks @noahfalk! Closing this issue then.

Thanks @mairaw and @noahfalk for super fast response!

I was trying from couple of days to extract the function input and return parameter of a function. Although @noahfalk mentioned here a straightforward approach to extract the information but it still seems me hard to find parameter here. There are so many cases and searching at byte and memory level seems a bit tedious here.

In my case am trying to capture a property value as below -
output.Result.RequestMessage.RequestUri

Sample .NET code for which i am profiling.
public void FatDateNow()
{
DateTime dt = DateTime.Now;

        HttpClient http = new HttpClient();
        http.BaseAddress = new Uri("http://dev-api-csplugin.crosscode.io");
        http.DefaultRequestHeaders.Accept.Clear();
        http.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));


        AccountAPIInputParam input = new AccountAPIInputParam();
        input.AccountId = string.IsNullOrWhiteSpace(null) ? "d2b5ec99-8123-3d20-866a-3d7d203b5479" : null;
        var d = JsonConvert.SerializeObject(input);
        var content = new StringContent(d, Encoding.UTF8, "application/json");
        try
        {
            var output = http.PostAsync("api/v1.0/getAccountLibrary", new StringContent("test"));
            var url = output.Result.RequestMessage.RequestUri;

            //InterceptLib.DebugLogger.Log(http.BaseAddress + http.)
        }
        catch (Exception ex)
        {

        }

        System.Console.Write("AKS -DateTime.Now : ");
        System.Console.WriteLine(dt.ToString("HH:mm"));
    }

Here is the sample of code which i am trying to find the function parameter in return parameter.

I have created a common function as below, which i am using in FunctionEnter2 and FunctionLeave2:

Sample Profiler code which i am trying-
void ILRewriteProfilerImpl::WriteMethodInfo(FunctionID functionId, COR_PRF_FUNCTION_ARGUMENT_INFO *pArgInfo)
{

IMetaDataImport *pMetaDataImport;
PCCOR_SIGNATURE pSig, p, pParamStart;
WCHAR szName[256], szType[256], szValue[256], szBuf[1024];
ULONG i,sequence;
CorElementType type;
mdMethodDef methodDef;
mdTypeDef typeDef;
BOOL bArray, bRef;
LPVOID *lplpValue;
mdParamDef paramDef;
LPWSTR szParamNAme;

g_debugLogger << "WriteMethodInfo" << std::endl;

m_corProfilerInfo2->GetTokenAndMetaDataFromFunction(functionId, IID_IMetaDataImport, (IUnknown **)&pMetaDataImport, &methodDef);
pMetaDataImport->GetMethodProps(methodDef, NULL, szName, 256, NULL, NULL, &pSig, NULL, NULL, NULL);

//pMetaDataImport->GetParamForMethodIndex(methodDef, sequence, &paramDef);
//pMetaDataImport->GetParamProps(paramDef,methodDef)

p = &pSig[2]; 
pParamStart = p;

g_debugLogger << "WriteMethodInfo - function Name" << szName << std::endl;
g_debugLogger << "numRanges = " << pArgInfo->numRanges <<"totalArgumentsize " <<pArgInfo->totalArgumentSize << std::endl;
g_debugLogger << "WriteLogFile(szBuf);" <<std::endl;

p = pParamStart;

for (i = 0; i < pArgInfo->numRanges; i++) {
    lplpValue = (LPVOID *)pArgInfo->ranges[i].startAddress;

    type = GetElementType(&p, &typeDef, &bRef, &bArray);
    GetElementTypeName(pMetaDataImport, type, typeDef, bRef, bArray, szType);

    g_debugLogger << "GetElementTypeName called" << std::endl;

    if (bArray) {

        g_debugLogger << "bArray = true " <<  std::endl;
        GetArray(lplpValue, type, szValue);
        wsprintfW(szBuf, L"%s = %s", szType, szValue);
        g_debugLogger << "bArray " << szType <<" "<< szValue << std::endl;
        //WriteLogFile(szBuf);
    }
    else if (type == ELEMENT_TYPE_CLASS) {
        g_debugLogger << "bArray = ELEMENT_TYPE_CLASS " << std::endl;

        ClassID  classId;
        g_debugLogger << "Going to convert in objectID" << std::endl;
        **ObjectID oid = *(ObjectID *)(lplpValue);**  //breaks the programe

        g_debugLogger << "ObjectID oid = *(ObjectID *)(lplpValue); " << std::endl;
        m_corProfilerInfo2->GetClassFromObject(oid, &classId);
        g_debugLogger << "_corProfilerInfo2->GetClassFromObject(oid, &classId) " << std::endl;

        GetClass(pMetaDataImport, classId, szType, *lplpValue);

        g_debugLogger << "GetClass finished" << szType << " " << classId << std::endl;

    }
    else if (type == ELEMENT_TYPE_VALUETYPE) {

        g_debugLogger << "bArray = ELEMENT_TYPE_VALUETYPE " << std::endl;
        ClassID  classId;
        ModuleID moduleId;

        m_corProfilerInfo2->GetFunctionInfo(functionId, 0, &moduleId, 0);
        m_corProfilerInfo2->GetClassFromToken(moduleId, typeDef, &classId);

        GetClass(pMetaDataImport, classId, szType, lplpValue);

    }
    else {

        g_debugLogger << "bArray = else  " << std::endl;

        GetValue(bRef ? *lplpValue : lplpValue, type, szValue);
        //wsprintfW(szBuf, L"%s = %s", szType, szValue);

        g_debugLogger << "wsprintfW(szBuf, L, szType, szValue);" << szType<< "  "<<szValue <<std::endl;

        //WriteLogFile(szBuf);
    }
}

g_debugLogger << "pMetaDataImport->Release();" << std::endl;

pMetaDataImport->Release();

}
It gives us class structure but still breaking while converting in objectId as highlighted in above code. I dont know what i am missing or what should be write approach or code here. Please have a look and help me out.

Thanks
Ashutosh

Hi, @mairaw and @noahfalk , can you guys have look and provide me some solution? It would be highly appreciable.
Thanks

You might want to check out https://github.com/dotnet/coreclr/issues/18977. It doesn't have an answer for you yet, but I think its going in that direction.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

sdmaclea picture sdmaclea  Â·  3Comments

gmatv picture gmatv  Â·  3Comments

stanuku picture stanuku  Â·  3Comments

Eilon picture Eilon  Â·  3Comments

ite-klass picture ite-klass  Â·  3Comments