diff options
Diffstat (limited to 'src/vm/sigformat.cpp')
-rw-r--r-- | src/vm/sigformat.cpp | 653 |
1 files changed, 653 insertions, 0 deletions
diff --git a/src/vm/sigformat.cpp b/src/vm/sigformat.cpp new file mode 100644 index 0000000000..69e818a39c --- /dev/null +++ b/src/vm/sigformat.cpp @@ -0,0 +1,653 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + + + +#include "common.h" +#include "sigformat.h" +#include "typedesc.h" + +SigFormat::SigFormat() +{ + WRAPPER_NO_CONTRACT; // THROWS;GC_TRIGGERS;INJECT_FAULT(ThrowOM) + _size = SIG_INC; + _pos = 0; + _fmtSig = new char[_size]; +} + +SigFormat::SigFormat(MetaSig &metaSig, LPCUTF8 szMemberName, LPCUTF8 szClassName, LPCUTF8 szNameSpace) +{ + WRAPPER_NO_CONTRACT; + FormatSig(metaSig, szMemberName, szClassName, szNameSpace); +} + + +// SigFormat::SigFormat() +// This constructor will create the string representation of a +// method. +SigFormat::SigFormat(MethodDesc* pMeth, TypeHandle owner, BOOL fIgnoreMethodName) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + INJECT_FAULT(COMPlusThrowOM()); + } + CONTRACTL_END + + // Explicitly use MethodDesc::LoadMethodInstantiation so that we can succesfully format + // non-typical generic method definitions. + MetaSig sig(pMeth, pMeth->GetExactClassInstantiation(owner), pMeth->LoadMethodInstantiation()); + + if (fIgnoreMethodName) + { + FormatSig(sig, NULL); + } + else + { + FormatSig(sig, pMeth->GetName()); + } +} + + +SigFormat::~SigFormat() +{ + LIMITED_METHOD_CONTRACT; + + if (_fmtSig) + delete [] _fmtSig; +} + +const char * SigFormat::GetCString() +{ + LIMITED_METHOD_CONTRACT; + return _fmtSig; +} + +const char * SigFormat::GetCStringParmsOnly() +{ + LIMITED_METHOD_CONTRACT; + // _fmtSig looks like: "void Put (byte[], int, int)". + // Skip to the '('. + int skip; + for(skip=0; _fmtSig[skip]!='('; skip++) + ; + return _fmtSig + skip; +} + +void SigFormat::AddString(LPCUTF8 s) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + INJECT_FAULT(COMPlusThrowOM()); + } + CONTRACTL_END + + size_t len = strlen(s); + // Allocate on overflow + size_t requiredSize = _pos + len + 1; + + if (requiredSize <= _pos) { // check for integer overflow in previous calc + #ifndef DACCESS_COMPILE + COMPlusThrowOM(); + #else + DacError(E_OUTOFMEMORY); + #endif + } + + if (requiredSize > _size) { + size_t newSize = (_size+SIG_INC > requiredSize) ? _size+SIG_INC : requiredSize+SIG_INC; + char* temp = new char[newSize]; + memcpy(temp,_fmtSig,_size); + delete [] _fmtSig; + _fmtSig = temp; + _size=newSize; + } + strcpy_s(&_fmtSig[_pos],_size - (&_fmtSig[_pos] - _fmtSig), s); + _pos += len; +} + + +//------------------------------------------------------------------------ +// Replacement for SigFormat::AddType that avoids class loading +// and copes with formal type parameters +//------------------------------------------------------------------------ +void SigFormat::AddTypeString(Module* pModule, SigPointer sig, const SigTypeContext *pTypeContext) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + INJECT_FAULT(COMPlusThrowOM()); + } + CONTRACTL_END + + LPCUTF8 szcName; + LPCUTF8 szcNameSpace; + /* + ULONG cArgs; + VOID *pEnum; + ULONG i; + */ + + CorElementType type; + IfFailThrow(sig.GetElemType(&type)); + + // Format the output + switch (type) + { +// @Todo: Should these be ilasm-style types? + case ELEMENT_TYPE_VOID: AddString("Void"); break; + case ELEMENT_TYPE_BOOLEAN: AddString("Boolean"); break; + case ELEMENT_TYPE_I1: AddString("SByte"); break; + case ELEMENT_TYPE_U1: AddString("Byte"); break; + case ELEMENT_TYPE_I2: AddString("Int16"); break; + case ELEMENT_TYPE_U2: AddString("UInt16"); break; + case ELEMENT_TYPE_CHAR: AddString("Char"); break; + case ELEMENT_TYPE_I: AddString("IntPtr"); break; + case ELEMENT_TYPE_U: AddString("UIntPtr"); break; + case ELEMENT_TYPE_I4: AddString("Int32"); break; + case ELEMENT_TYPE_U4: AddString("UInt32"); break; + case ELEMENT_TYPE_I8: AddString("Int64"); break; + case ELEMENT_TYPE_U8: AddString("UInt64"); break; + case ELEMENT_TYPE_R4: AddString("Single"); break; + case ELEMENT_TYPE_R8: AddString("Double"); break; + case ELEMENT_TYPE_OBJECT: AddString(g_ObjectClassName); break; + case ELEMENT_TYPE_STRING: AddString(g_StringClassName); break; + + // For Value Classes we fall through unless the pVMC is an Array Class, + // If its an array class we need to get the name of the underlying type from + // it. + case ELEMENT_TYPE_VALUETYPE: + case ELEMENT_TYPE_CLASS: + { + IMDInternalImport *pInternalImport = pModule->GetMDImport(); + mdToken token; + IfFailThrow(sig.GetToken(&token)); + + if (TypeFromToken(token) == mdtTypeDef) + { + IfFailThrow(pInternalImport->GetNameOfTypeDef(token, &szcName, &szcNameSpace)); + } + else if (TypeFromToken(token) == mdtTypeRef) + { + IfFailThrow(pInternalImport->GetNameOfTypeRef(token, &szcNameSpace, &szcName)); + } + else + break; + + if (*szcNameSpace) + { + AddString(szcNameSpace); + AddString("."); + } + AddString(szcName); + break; + } + case ELEMENT_TYPE_INTERNAL: + { + TypeHandle hType; + + // this check is not functional in DAC and provides no security against a malicious dump + // the DAC is prepared to receive an invalid type handle +#ifndef DACCESS_COMPILE + if (pModule->IsSigInIL(sig.GetPtr())) + THROW_BAD_FORMAT(BFA_BAD_COMPLUS_SIG, pModule); +#endif + + CorSigUncompressPointer(sig.GetPtr(), (void**)&hType); + _ASSERTE(!hType.IsNull()); + MethodTable *pMT = hType.GetMethodTable(); + _ASSERTE(pMT); + mdToken token = pMT->GetCl(); + IfFailThrow(pMT->GetMDImport()->GetNameOfTypeDef(token, &szcName, &szcNameSpace)); + if (*szcNameSpace) + { + AddString(szcNameSpace); + AddString("."); + } + AddString(szcName); + break; + } + case ELEMENT_TYPE_TYPEDBYREF: + { + AddString("TypedReference"); + break; + } + + case ELEMENT_TYPE_BYREF: + { + AddTypeString(pModule, sig, pTypeContext); + AddString(" ByRef"); + } + break; + + case ELEMENT_TYPE_MVAR : + { + DWORD ix; + IfFailThrow(sig.GetData(&ix)); + if (pTypeContext && !pTypeContext->m_methodInst.IsEmpty() && ix >= 0 && ix < pTypeContext->m_methodInst.GetNumArgs()) + { + AddType(pTypeContext->m_methodInst[ix]); + } + else + { + char smallbuf[20]; + sprintf_s(smallbuf, COUNTOF(smallbuf), "!!%d", ix); + AddString(smallbuf); + } + } + break; + + case ELEMENT_TYPE_VAR : + { + DWORD ix; + IfFailThrow(sig.GetData(&ix)); + + if (pTypeContext && !pTypeContext->m_classInst.IsEmpty() && ix >= 0 && ix < pTypeContext->m_classInst.GetNumArgs()) + { + AddType(pTypeContext->m_classInst[ix]); + } + else + { + char smallbuf[20]; + sprintf_s(smallbuf, COUNTOF(smallbuf), "!%d", ix); + AddString(smallbuf); + } + } + break; + + case ELEMENT_TYPE_GENERICINST : + { + AddTypeString(pModule, sig, pTypeContext); + + IfFailThrow(sig.SkipExactlyOne()); + DWORD n; + IfFailThrow(sig.GetData(&n)); + + AddString("<"); + for (DWORD i = 0; i < n; i++) + { + if (i > 0) + AddString(","); + AddTypeString(pModule,sig, pTypeContext); + IfFailThrow(sig.SkipExactlyOne()); + } + AddString(">"); + + break; + } + + case ELEMENT_TYPE_SZARRAY: // Single Dim, Zero + case ELEMENT_TYPE_ARRAY: // General Array + { + AddTypeString(pModule, sig, pTypeContext); + IfFailThrow(sig.SkipExactlyOne()); + if (type == ELEMENT_TYPE_ARRAY) + { + AddString("["); + ULONG len; + IfFailThrow(sig.GetData(&len)); + + for (ULONG i=1;i<len;i++) + AddString(","); + + AddString("]"); + } + else + { + AddString("[]"); + } + } + break; + + case ELEMENT_TYPE_PTR: + { + // This will pop up on methods that take a pointer to a block of unmanaged memory. + AddTypeString(pModule, sig, pTypeContext); + AddString("*"); + break; + } + + case ELEMENT_TYPE_FNPTR: + { + DWORD callConv; + IfFailThrow(sig.GetData(&callConv)); + + ULONG cArgs; + IfFailThrow(sig.GetData(&cArgs)); + + AddTypeString(pModule, sig, pTypeContext); + IfFailThrow(sig.SkipExactlyOne()); + AddString(" ("); + ULONG i; + for (i = 0; i < cArgs; i++) { + AddTypeString(pModule, sig, pTypeContext); + IfFailThrow(sig.SkipExactlyOne()); + if (i != (cArgs - 1)) + AddString(", "); + } + if ((callConv & IMAGE_CEE_CS_CALLCONV_MASK) == IMAGE_CEE_CS_CALLCONV_VARARG) + { + if (cArgs) + AddString(", "); + AddString("..."); + } + AddString(")"); + break; + } + + default: + AddString("**UNKNOWN TYPE**"); + + } +} + +void SigFormat::FormatSig(MetaSig &sig, LPCUTF8 szMemberName, LPCUTF8 szClassName, LPCUTF8 szNameSpace) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + INJECT_FAULT(COMPlusThrowOM()); + } + CONTRACTL_END + + UINT cArgs; + + _size = SIG_INC; + _pos = 0; + _fmtSig = new char[_size]; + + AddTypeString(sig.GetModule(), sig.GetReturnProps(), sig.GetSigTypeContext()); + + AddString(" "); + if (szNameSpace != NULL) + { + AddString(szNameSpace); + AddString("."); + } + if (szClassName != NULL) + { + AddString(szClassName); + AddString("."); + } + if (szMemberName != NULL) + { + AddString(szMemberName); + } + + cArgs = sig.NumFixedArgs(); + sig.Reset(); + + AddString("("); + + // Loop through all of the args + for (UINT i=0;i<cArgs;i++) { + sig.NextArg(); + AddTypeString(sig.GetModule(), sig.GetArgProps(), sig.GetSigTypeContext()); + if (i != cArgs-1) + AddString(", "); + } + + // Display vararg signature at end + if (sig.IsVarArg()) + { + if (cArgs) + AddString(", "); + AddString("..."); + } + + AddString(")"); +} + +void SigFormat::AddType(TypeHandle th) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + INJECT_FAULT(COMPlusThrowOM()); + } + CONTRACTL_END + + LPCUTF8 szcName; + LPCUTF8 szcNameSpace; + ULONG cArgs; + ULONG i; + + if (th.IsNull()) + { + AddString("**UNKNOWN TYPE**"); + return; + } + + CorElementType type = th.GetSignatureCorElementType(); + + // Format the output + switch (type) + { +// <TODO>@Todo: Should these be ilasm-style types?</TODO> + case ELEMENT_TYPE_VOID: AddString("Void"); break; + case ELEMENT_TYPE_BOOLEAN: AddString("Boolean"); break; + case ELEMENT_TYPE_I1: AddString("SByte"); break; + case ELEMENT_TYPE_U1: AddString("Byte"); break; + case ELEMENT_TYPE_I2: AddString("Int16"); break; + case ELEMENT_TYPE_U2: AddString("UInt16"); break; + case ELEMENT_TYPE_CHAR: AddString("Char"); break; + case ELEMENT_TYPE_I: AddString("IntPtr"); break; + case ELEMENT_TYPE_U: AddString("UIntPtr"); break; + case ELEMENT_TYPE_I4: AddString("Int32"); break; + case ELEMENT_TYPE_U4: AddString("UInt32"); break; + case ELEMENT_TYPE_I8: AddString("Int64"); break; + case ELEMENT_TYPE_U8: AddString("UInt64"); break; + case ELEMENT_TYPE_R4: AddString("Single"); break; + case ELEMENT_TYPE_R8: AddString("Double"); break; + case ELEMENT_TYPE_OBJECT: AddString(g_ObjectClassName); break; + case ELEMENT_TYPE_STRING: AddString(g_StringClassName); break; + + // For Value Classes we fall through unless the pVMC is an Array Class, + // If its an array class we need to get the name of the underlying type from + // it. + case ELEMENT_TYPE_VALUETYPE: + case ELEMENT_TYPE_CLASS: + { + if (FAILED(th.GetMethodTable()->GetMDImport()->GetNameOfTypeDef(th.GetCl(), &szcName, &szcNameSpace))) + { + szcName = szcNameSpace = "Invalid TypeDef record"; + } + + if (*szcNameSpace != 0) + { + AddString(szcNameSpace); + AddString("."); + } + AddString(szcName); + + if (th.HasInstantiation()) + { + Instantiation inst = th.GetInstantiation(); + + if(!inst.IsEmpty()) + { + AddString("<"); + for (DWORD j = 0; j < th.GetNumGenericArgs(); j++) + { + if (j > 0) + AddString(","); + + AddType(inst[j]); + } + AddString(">"); + } + } + + break; + } + case ELEMENT_TYPE_TYPEDBYREF: + { + AddString("TypedReference"); + break; + } + + case ELEMENT_TYPE_BYREF: + { + TypeHandle h = th.AsTypeDesc()->GetTypeParam(); + AddType(h); + AddString(" ByRef"); + } + break; + + case ELEMENT_TYPE_SZARRAY: // Single Dim, Zero + case ELEMENT_TYPE_ARRAY: // General Array + { + ArrayTypeDesc* aTD = th.AsArray(); + AddType(aTD->GetArrayElementTypeHandle()); + + if (type == ELEMENT_TYPE_ARRAY) + { + AddString("["); + int len = aTD->GetRank(); + + for (int j=0;j<len-1;j++) + + AddString(","); + AddString("]"); + } + else + { + AddString("[]"); + } + } + break; + + case ELEMENT_TYPE_PTR: + { + // This will pop up on methods that take a pointer to a block of unmanaged memory. + TypeHandle h = th.AsTypeDesc()->GetTypeParam(); + AddType(h); + AddString("*"); + break; + } + case ELEMENT_TYPE_FNPTR: + { + FnPtrTypeDesc* pTD = th.AsFnPtrType(); + + TypeHandle *pRetAndArgTypes = pTD->GetRetAndArgTypes(); + AddType(pRetAndArgTypes[0]); + AddString(" ("); + + cArgs = pTD->GetNumArgs(); + + for (i = 0; i < cArgs; i++) + { + AddType(pRetAndArgTypes[i+1]); + + if (i != (cArgs - 1)) + AddString(", "); + } + if ((pTD->GetCallConv() & IMAGE_CEE_CS_CALLCONV_MASK) == IMAGE_CEE_CS_CALLCONV_VARARG) + { + AddString(", "); + + AddString("..."); + } + AddString(")"); + + break; + } + + case ELEMENT_TYPE_VAR: + case ELEMENT_TYPE_MVAR: + { + StackScratchBuffer scratch; + StackSString name; + th.GetName(name); + + AddString(name.GetANSI(scratch)); + + break; + } + + default: + AddString("**UNKNOWN TYPE**"); + } +} + +// +// Legacy debug-only string formatting pretty printer +// + +#ifdef _DEBUG +#ifndef DACCESS_COMPILE + +#include <formattype.h> + +/*******************************************************************/ +const char* FormatSigHelper(MethodDesc* pMD, CQuickBytes *out, LoaderHeap *pHeap, AllocMemTracker *pamTracker) +{ + PCCOR_SIGNATURE pSig; + ULONG cSig; + const char *ret = NULL; + + pMD->GetSig(&pSig, &cSig); + + if (pSig == NULL) + { + return "<null>"; + } + + EX_TRY + { + const char* sigStr = PrettyPrintSig(pSig, cSig, "*", out, pMD->GetMDImport(), 0); + + S_SIZE_T len = S_SIZE_T(strlen(sigStr))+S_SIZE_T(1); + if(len.IsOverflow()) COMPlusThrowHR(COR_E_OVERFLOW); + + char* mem = (char*) pamTracker->Track(pHeap->AllocMem(len)); + + if (mem != NULL) + { + strcpy_s(mem, len.Value(), sigStr); + ret = mem; + } + } + EX_CATCH + { + } + EX_END_CATCH(RethrowTerminalExceptions); + + return ret; +} + +/*******************************************************************/ +const char* FormatSig(MethodDesc * pMD, LoaderHeap * pHeap, AllocMemTracker * pamTracker) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + } + CONTRACTL_END; + + CQuickBytes out; + return FormatSigHelper(pMD, &out, pHeap, pamTracker); +} + +/*******************************************************************/ +const char* FormatSig(MethodDesc* pMD, AppDomain *pDomain, AllocMemTracker *pamTracker) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + } + CONTRACTL_END; + + return FormatSig(pMD,pDomain->GetLowFrequencyHeap(),pamTracker); +} +#endif +#endif |