Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
468 lines (399 sloc) 15 KB
// Copyright (c) 2012 DotNetAnywhere
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "Compat.h"
#include "Sys.h"
#include "MetaData.h"
#include "CLIFile.h"
#include "Type.h"
#include "Types.h"
U32 MetaData_CompareNameAndSig(STRING name, BLOB_ sigBlob, tMetaData *pSigMetaData, tMD_TypeDef **ppSigClassTypeArgs, tMD_TypeDef **ppSigMethodTypeArgs, tMD_MethodDef *pMethod, tMD_TypeDef **ppMethodClassTypeArgs, tMD_TypeDef **ppMethodMethodTypeArgs) {
if (strcmp(name, pMethod->name) == 0) {
SIG sig, thisSig;
U32 e, thisE, paramCount, i;
sig = MetaData_GetBlob(sigBlob, NULL);
thisSig = MetaData_GetBlob(pMethod->signature, NULL);
e = MetaData_DecodeSigEntry(&sig);
thisE = MetaData_DecodeSigEntry(&thisSig);
// Check method call type (static, etc...)
if (e != thisE) {
return 0;
}
// If method has generic arguments, check the generic type argument count
if (e & SIG_METHODDEF_GENERIC) {
e = MetaData_DecodeSigEntry(&sig);
thisE = MetaData_DecodeSigEntry(&thisSig);
// Generic argument count
if (e != thisE) {
return 0;
}
}
e = MetaData_DecodeSigEntry(&sig);
thisE = MetaData_DecodeSigEntry(&thisSig);
// check parameter count
if (e != thisE) {
return 0;
}
paramCount = e + 1; // +1 to include the return type
// check all parameters
for (i=0; i<paramCount; i++) {
tMD_TypeDef *pParamType, *pThisParamType;
pParamType = Type_GetTypeFromSig(pSigMetaData, &sig, ppSigClassTypeArgs, ppSigMethodTypeArgs);
pThisParamType = Type_GetTypeFromSig(pMethod->pMetaData, &thisSig, ppMethodClassTypeArgs, ppMethodMethodTypeArgs);
if (pParamType != pThisParamType) {
return 0;
}
}
// All parameters the same, so found the right method
return 1;
}
return 0;
}
static tMD_MethodDef* FindMethodInType(tMD_TypeDef *pTypeDef, STRING name, tMetaData *pSigMetaData, BLOB_ sigBlob, tMD_TypeDef **ppClassTypeArgs, tMD_TypeDef **ppMethodTypeArgs) {
U32 i;
tMD_TypeDef *pLookInType = pTypeDef;
do {
for (i=0; i<pLookInType->numMethods; i++) {
if (MetaData_CompareNameAndSig(name, sigBlob, pSigMetaData, ppClassTypeArgs, ppMethodTypeArgs, pLookInType->ppMethods[i], pLookInType->ppClassTypeArgs, NULL)) {
return pLookInType->ppMethods[i];
}
}
pLookInType = pLookInType->pParent;
} while (pLookInType != NULL);
{
// Error reporting!!
U32 entry, numParams, i;
SIG sig;
char *pMsg;
tMD_TypeDef *pParamTypeDef;
pMsg = (char*)malloc(2048);
*pMsg = 0;
sig = MetaData_GetBlob(sigBlob, &i);
entry = MetaData_DecodeSigEntry(&sig);
if ((entry & SIG_METHODDEF_HASTHIS) == 0) {
sprintf(strchr(pMsg, 0), "static ");
}
if (entry & SIG_METHODDEF_GENERIC) {
// read number of generic type args - don't care what it is
MetaData_DecodeSigEntry(&sig);
}
numParams = MetaData_DecodeSigEntry(&sig);
pParamTypeDef = Type_GetTypeFromSig(pSigMetaData, &sig, ppClassTypeArgs, ppMethodTypeArgs); // return type
if (pParamTypeDef != NULL) {
sprintf(strchr(pMsg, 0), "%s ", pParamTypeDef->name);
}
sprintf(strchr(pMsg, 0), "%s.%s.%s(", pTypeDef->nameSpace, pTypeDef->name, name);
for (i=0; i<numParams; i++) {
pParamTypeDef = Type_GetTypeFromSig(pSigMetaData, &sig, ppClassTypeArgs, ppMethodTypeArgs);
if (i > 0) {
sprintf(strchr(pMsg, 0), ",");
}
if (pParamTypeDef != NULL) {
sprintf(strchr(pMsg, 0), pParamTypeDef->name);
} else {
sprintf(strchr(pMsg, 0), "???");
}
}
Crash("FindMethodInType(): Cannot find method %s)", pMsg);
}
FAKE_RETURN;
}
static tMD_FieldDef* FindFieldInType(tMD_TypeDef *pTypeDef, STRING name) {
U32 i;
MetaData_Fill_TypeDef(pTypeDef, NULL, NULL);
for (i=0; i<pTypeDef->numFields; i++) {
if (strcmp(pTypeDef->ppFields[i]->name, name) == 0) {
return pTypeDef->ppFields[i];
}
}
Crash("FindFieldInType(): Cannot find field '%s' in type %s.%s", name, pTypeDef->nameSpace, pTypeDef->name);
FAKE_RETURN;
}
tMetaData* MetaData_GetResolutionScopeMetaData(tMetaData *pMetaData, IDX_TABLE resolutionScopeToken, tMD_TypeDef **ppInNestedType) {
switch (TABLE_ID(resolutionScopeToken)) {
case MD_TABLE_ASSEMBLYREF:
{
tMD_AssemblyRef *pAssemblyRef;
pAssemblyRef = (tMD_AssemblyRef*)MetaData_GetTableRow(pMetaData, resolutionScopeToken);
*ppInNestedType = NULL;
return CLIFile_GetMetaDataForAssembly(pAssemblyRef->name);
}
case MD_TABLE_TYPEREF:
{
tMD_TypeDef *pTypeDef;
pTypeDef = MetaData_GetTypeDefFromDefRefOrSpec(pMetaData, resolutionScopeToken, NULL, NULL);
*ppInNestedType = pTypeDef;
return pTypeDef->pMetaData;
}
default:
Crash("MetaData_GetResolutionScopeMetaData(): Cannot resolve token: 0x%08x", resolutionScopeToken);
FAKE_RETURN;
}
}
tMD_TypeDef* MetaData_GetTypeDefFromName(tMetaData *pMetaData, STRING nameSpace, STRING name, tMD_TypeDef *pInNestedClass) {
U32 i;
for (i=1; i<=pMetaData->tables.numRows[MD_TABLE_TYPEDEF]; i++) {
tMD_TypeDef *pTypeDef;
pTypeDef = (tMD_TypeDef*)MetaData_GetTableRow(pMetaData, MAKE_TABLE_INDEX(MD_TABLE_TYPEDEF, i));
if (pInNestedClass == pTypeDef->pNestedIn &&
strcmp(name, pTypeDef->name) == 0 &&
(pInNestedClass != NULL || strcmp(nameSpace, pTypeDef->nameSpace) == 0)) {
return pTypeDef;
}
}
Crash("MetaData_GetTypeDefFromName(): Cannot find type %s.%s", nameSpace, name);
FAKE_RETURN;
}
tMD_TypeDef* MetaData_GetTypeDefFromFullName(STRING assemblyName, STRING nameSpace, STRING name) {
tMetaData *pTypeMetaData;
pTypeMetaData = CLIFile_GetMetaDataForAssembly(assemblyName);
// Note that this cannot get a nested class, as this final parameter is always NULL
return MetaData_GetTypeDefFromName(pTypeMetaData, nameSpace, name, NULL);
}
tMD_TypeDef* MetaData_GetTypeDefFromDefRefOrSpec(tMetaData *pMetaData, IDX_TABLE token, tMD_TypeDef **ppClassTypeArgs, tMD_TypeDef **ppMethodTypeArgs) {
void *pTableEntry;
pTableEntry = MetaData_GetTableRow(pMetaData, token);
if (pTableEntry == NULL) {
return NULL;
}
if (((tMDC_ToTypeDef*)pTableEntry)->pTypeDef != NULL) {
return ((tMDC_ToTypeDef*)pTableEntry)->pTypeDef;
}
switch (TABLE_ID(token)) {
case MD_TABLE_TYPEDEF:
((tMDC_ToTypeDef*)pTableEntry)->pTypeDef = (tMD_TypeDef*)pTableEntry;
return (tMD_TypeDef*)pTableEntry;
case MD_TABLE_TYPEREF:
{
tMetaData *pTypeDefMetaData;
tMD_TypeRef *pTypeRef;
tMD_TypeDef *pTypeDef;
tMD_TypeDef *pInNestedClass;
pTypeRef = (tMD_TypeRef*)pTableEntry;
pTypeDefMetaData = MetaData_GetResolutionScopeMetaData(pMetaData, pTypeRef->resolutionScope, &pInNestedClass);
pTypeDef = MetaData_GetTypeDefFromName(pTypeDefMetaData, pTypeRef->nameSpace, pTypeRef->name, pInNestedClass);
pTypeRef->pTypeDef = pTypeDef;
return pTypeDef;
}
case MD_TABLE_TYPESPEC:
{
tMD_TypeSpec *pTypeSpec;
tMD_TypeDef *pTypeDef;
SIG sig;
pTypeSpec = (tMD_TypeSpec*)pTableEntry;
sig = MetaData_GetBlob(pTypeSpec->signature, NULL);
pTypeDef = Type_GetTypeFromSig(pTypeSpec->pMetaData, &sig, ppClassTypeArgs, ppMethodTypeArgs);
// Note: Cannot cache the TypeDef for this TypeSpec because it
// can change depending on class arguemnts given.
return pTypeDef;
}
return NULL;
default:
Crash("MetaData_GetTypeDefFromDefRefOrSpec(): Cannot handle token: 0x%08x", token);
FAKE_RETURN;
}
}
tMD_TypeDef* MetaData_GetTypeDefFromMethodDef(tMD_MethodDef *pMethodDef) {
tMetaData *pMetaData;
U32 i;
pMetaData = pMethodDef->pMetaData;
for (i=pMetaData->tables.numRows[MD_TABLE_TYPEDEF]; i>0; i--) {
tMD_TypeDef *pTypeDef;
pTypeDef = (tMD_TypeDef*)MetaData_GetTableRow(pMetaData, MAKE_TABLE_INDEX(MD_TABLE_TYPEDEF, i));
if (pTypeDef->methodList <= pMethodDef->tableIndex) {
return pTypeDef;
}
}
Crash("MetaData_GetTypeDefFromMethodDef(): Cannot find type for method: %s", pMethodDef->name);
FAKE_RETURN;
}
tMD_TypeDef* MetaData_GetTypeDefFromFieldDef(tMD_FieldDef *pFieldDef) {
tMetaData *pMetaData;
U32 i;
pMetaData = pFieldDef->pMetaData;
for (i=pMetaData->tables.numRows[MD_TABLE_TYPEDEF]; i>0; i--) {
tMD_TypeDef *pTypeDef;
pTypeDef = (tMD_TypeDef*)MetaData_GetTableRow(pMetaData, MAKE_TABLE_INDEX(MD_TABLE_TYPEDEF, i));
if (pTypeDef->fieldList <= pFieldDef->tableIndex) {
return pTypeDef;
}
}
Crash("MetaData_GetTypeDefFromFieldDef(): Cannot find type for field: %s", pFieldDef->name);
FAKE_RETURN;
}
tMD_MethodDef* MetaData_GetMethodDefFromDefRefOrSpec(tMetaData *pMetaData, IDX_TABLE token, tMD_TypeDef **ppClassTypeArgs, tMD_TypeDef **ppMethodTypeArgs) {
void *pTableEntry;
pTableEntry = MetaData_GetTableRow(pMetaData, token);
if (((tMDC_ToMethodDef*)pTableEntry)->pMethodDef != NULL) {
return ((tMDC_ToMethodDef*)pTableEntry)->pMethodDef;
}
switch (TABLE_ID(token)) {
case MD_TABLE_METHODDEF:
((tMDC_ToMethodDef*)pTableEntry)->pMethodDef = (tMD_MethodDef*)pTableEntry;
return (tMD_MethodDef*)pTableEntry;
case MD_TABLE_MEMBERREF:
{
tMD_MemberRef *pMemberRef;
pMemberRef = (tMD_MemberRef*)pTableEntry;
switch (TABLE_ID(pMemberRef->class_))
{
case MD_TABLE_TYPEREF:
case MD_TABLE_TYPESPEC:
{
tMD_TypeDef *pTypeDef;
tMD_MethodDef *pMethodDef;
pTypeDef = MetaData_GetTypeDefFromDefRefOrSpec(pMetaData, pMemberRef->class_, ppClassTypeArgs, ppMethodTypeArgs);
MetaData_Fill_TypeDef(pTypeDef, NULL, NULL);
pMethodDef = FindMethodInType(pTypeDef, pMemberRef->name, pMetaData, pMemberRef->signature, pTypeDef->ppClassTypeArgs, ppMethodTypeArgs);
//pMethodDef->pMethodDef = pMethodDef;
return pMethodDef;
}
default:
Crash("MetaData_GetMethodDefFromMethodDefOrRef(): Cannot handle pMemberRef->class_=0x%08x", pMemberRef->class_);
}
}
case MD_TABLE_METHODSPEC:
{
tMD_MethodSpec *pMethodSpec;
tMD_MethodDef *pMethodDef;
pMethodSpec = (tMD_MethodSpec*)pTableEntry;
pMethodDef = Generics_GetMethodDefFromSpec(pMethodSpec, ppClassTypeArgs, ppMethodTypeArgs);
// Note: Cannot cache the MethodDef from the MethodSpec, as class generic arguments
// may be different.
return pMethodDef;
}
}
Crash("MetaData_GetMethodDefFromMethodDefOrRef(): Cannot handle token: 0x%08x", token);
FAKE_RETURN;
}
tMD_FieldDef* MetaData_GetFieldDefFromDefOrRef(tMetaData *pMetaData, IDX_TABLE token, tMD_TypeDef **ppClassTypeArgs, tMD_TypeDef **ppMethodTypeArgs) {
void *pTableEntry;
pTableEntry = MetaData_GetTableRow(pMetaData, token);
if (((tMDC_ToFieldDef*)pTableEntry)->pFieldDef != NULL) {
return ((tMDC_ToFieldDef*)pTableEntry)->pFieldDef;
}
switch (TABLE_ID(token)) {
case MD_TABLE_FIELDDEF:
((tMDC_ToFieldDef*)pTableEntry)->pFieldDef = (tMD_FieldDef*)pTableEntry;
return (tMD_FieldDef*)pTableEntry;
case MD_TABLE_MEMBERREF:
{
tMD_MemberRef *pMemberRef;
pMemberRef = (tMD_MemberRef*)pTableEntry;
switch (TABLE_ID(pMemberRef->class_))
{
case MD_TABLE_TYPEREF:
case MD_TABLE_TYPESPEC:
{
tMD_TypeDef *pTypeDef;
tMD_FieldDef *pFieldDef;
pTypeDef = MetaData_GetTypeDefFromDefRefOrSpec(pMetaData, pMemberRef->class_, ppClassTypeArgs, ppMethodTypeArgs);
pFieldDef = FindFieldInType(pTypeDef, pMemberRef->name);
if (TABLE_ID(pMemberRef->class_) == MD_TABLE_TYPEREF) {
// Can't do this for TypeSpec because the resulting TypeDef will change
// depending on what the class type arguments are.
((tMDC_ToFieldDef*)pTableEntry)->pFieldDef = pFieldDef;
}
return pFieldDef;
}
default:
Crash("MetaData_GetMethodDefFromMethodDefOrRef(): Cannot handle pMemberRef->class_=0x%08x", pMemberRef->class_);
}
}
}
Crash("MetaData_GetFieldDefFromDefOrRef(): Cannot handle token: 0x%08x", token);
FAKE_RETURN;
}
// Return pointer to the relevant Def structure.
// pObjectType returns:
// 0 - tMD_TypeDef
// 1 - tMD_MethodDef
// 2 - tMD_FieldDef
// (These link up with the JIT_LOADTOKEN_* opcodes)
PTR MetaData_GetTypeMethodField(tMetaData *pMetaData, IDX_TABLE token, U32 *pObjectType, tMD_TypeDef **ppClassTypeArgs, tMD_TypeDef **ppMethodTypeArgs) {
switch (TABLE_ID(token)) {
case MD_TABLE_TYPEDEF:
case MD_TABLE_TYPEREF:
case MD_TABLE_TYPESPEC:
{
tMD_TypeDef *pTypeDef;
pTypeDef = MetaData_GetTypeDefFromDefRefOrSpec(pMetaData, token, ppClassTypeArgs, ppMethodTypeArgs);
MetaData_Fill_TypeDef(pTypeDef, NULL, NULL);
*pObjectType = 0;
return (PTR)pTypeDef;
}
case MD_TABLE_METHODDEF:
method:
{
tMD_MethodDef *pMethodDef;
pMethodDef = MetaData_GetMethodDefFromDefRefOrSpec(pMetaData, token, ppClassTypeArgs, ppMethodTypeArgs);
if (pMethodDef->isFilled == 0) {
tMD_TypeDef *pTypeDef;
pTypeDef = MetaData_GetTypeDefFromMethodDef(pMethodDef);
MetaData_Fill_TypeDef(pTypeDef, NULL, NULL);
}
*pObjectType = 1;
return (PTR)pMethodDef;
}
case MD_TABLE_FIELDDEF:
field:
{
tMD_FieldDef *pFieldDef;
pFieldDef = MetaData_GetFieldDefFromDefOrRef(pMetaData, token, ppClassTypeArgs, ppMethodTypeArgs);
if (pFieldDef->pParentType == NULL) {
tMD_TypeDef *pTypeDef;
pTypeDef = MetaData_GetTypeDefFromFieldDef(pFieldDef);
MetaData_Fill_TypeDef(pTypeDef, NULL, NULL);
}
*pObjectType = 2;
return (PTR)pFieldDef;
}
case MD_TABLE_MEMBERREF:
{
tMD_MemberRef *pMemberRef;
SIG sig;
pMemberRef = (tMD_MemberRef*)MetaData_GetTableRow(pMetaData, token);
sig = MetaData_GetBlob(pMemberRef->signature, NULL);
if (*(U8*)sig == 0x06) {
// Field
goto field;
} else {
// Method
goto method;
}
}
}
Crash("MetaData_GetTypeMethodField(): Cannot handle token: 0x%08x", token);
FAKE_RETURN;
}
tMD_ImplMap* MetaData_GetImplMap(tMetaData *pMetaData, IDX_TABLE memberForwardedToken) {
U32 i;
for (i=pMetaData->tables.numRows[MD_TABLE_IMPLMAP]; i >= 1; i--) {
tMD_ImplMap *pImplMap = (tMD_ImplMap*)MetaData_GetTableRow(pMetaData, MAKE_TABLE_INDEX(MD_TABLE_IMPLMAP, i));
if (pImplMap->memberForwarded == memberForwardedToken) {
return pImplMap;
}
}
Crash("MetaData_GetImplMap() Cannot find mapping for token: 0x%08x", memberForwardedToken);
FAKE_RETURN;
}
STRING MetaData_GetModuleRefName(tMetaData *pMetaData, IDX_TABLE memberRefToken) {
tMD_ModuleRef *pModRef = (tMD_ModuleRef*)MetaData_GetTableRow(pMetaData, memberRefToken);
return pModRef->name;
}