#include "il2cpp-config.h" #include #include #include #include "os/Mutex.h" #include "utils/StringUtils.h" #include "vm/Class.h" #include "vm/Image.h" #include "vm/MetadataCache.h" #include "vm/StackTrace.h" #include "vm/Type.h" #include "utils/HashUtils.h" #include "utils/Il2CppHashMap.h" #include "utils/MemoryMappedFile.h" #include "utils/StringUtils.h" #include "vm-utils/VmStringUtils.h" #include "os/Atomic.h" #include "hybridclr/metadata/Image.h" struct NamespaceAndNamePairHash { size_t operator()(const std::pair& pair) const { return il2cpp::utils::HashUtils::Combine(il2cpp::utils::StringUtils::Hash(pair.first), il2cpp::utils::StringUtils::Hash(pair.second)); } }; struct NamespaceAndNamePairEquals { bool operator()(const std::pair& p1, const std::pair& p2) const { return !strcmp(p1.first, p2.first) && !strcmp(p1.second, p2.second); } }; struct NamespaceAndNamePairLess { bool operator()(const std::pair& p1, const std::pair& p2) const { int namespaceCompare = strcmp(p1.first, p2.first); if (namespaceCompare < 0) return true; if (namespaceCompare > 0) return false; return strcmp(p1.second, p2.second) < 0; } }; struct Il2CppNameToTypeDefinitionIndexHashTable : public Il2CppHashMap, TypeDefinitionIndex, NamespaceAndNamePairHash, NamespaceAndNamePairEquals> { typedef Il2CppHashMap, TypeDefinitionIndex, NamespaceAndNamePairHash, NamespaceAndNamePairEquals> Base; Il2CppNameToTypeDefinitionIndexHashTable() : Base() { } }; namespace il2cpp { namespace vm { const Il2CppAssembly* Image::GetAssembly(const Il2CppImage* image) { return image->assembly; } typedef il2cpp::vm::StackFrames::const_reverse_iterator StackReverseIterator; static bool IsSystemType(Il2CppClass* klass) { return strcmp(klass->namespaze, "System") == 0 && strcmp(klass->name, "Type") == 0; } static bool IsSystemReflectionAssembly(Il2CppClass* klass) { return strcmp(klass->namespaze, "System.Reflection") == 0 && strcmp(klass->name, "Assembly") == 0; } static StackReverseIterator GetNextImageFromStack(StackReverseIterator first, StackReverseIterator last) { for (StackReverseIterator it = first; it != last; it++) { Il2CppClass* klass = it->method->klass; if (klass->image != NULL && !IsSystemType(klass) && !IsSystemReflectionAssembly(klass)) { return it; } } return last; } const Il2CppImage* Image::GetExecutingImage() { const il2cpp::vm::StackFrames& stack = *StackTrace::GetStackFrames(); StackReverseIterator imageIt = GetNextImageFromStack(stack.rbegin(), stack.rend()); if (imageIt != stack.rend()) { return imageIt->method->klass->image; } // Fallback to corlib if no image is found return const_cast(Image::GetCorlib()); } const Il2CppImage* Image::GetCallingImage() { const il2cpp::vm::StackFrames& stack = *StackTrace::GetStackFrames(); StackReverseIterator imageIt = GetNextImageFromStack(stack.rbegin(), stack.rend()); if (imageIt != stack.rend()) { imageIt = GetNextImageFromStack(++imageIt, stack.rend()); if (imageIt != stack.rend()) { return imageIt->method->klass->image; } } // Fallback to corlib if no image is found return const_cast(Image::GetCorlib()); } const char * Image::GetName(const Il2CppImage* image) { return image->name; } const char * Image::GetFileName(const Il2CppImage* image) { return image->name; } const MethodInfo* Image::GetEntryPoint(const Il2CppImage* image) { if (image->entryPointIndex == -1) return NULL; return MetadataCache::GetMethodInfoFromMethodDefinitionIndex(image->entryPointIndex); } Il2CppImage* Image::GetCorlib() { return il2cpp_defaults.corlib; } static os::FastMutex s_ClassFromNameMutex; static void AddNestedTypesToNametoClassHashTable(const Il2CppImage* image, Il2CppNameToTypeDefinitionIndexHashTable* hashTable, const char *namespaze, const std::string& parentName, Il2CppClass *klass) { std::string name = parentName + "/" + klass->name; char *pName = (char*)IL2CPP_CALLOC(name.size() + 1, sizeof(char)); strcpy(pName, name.c_str()); hashTable->insert(std::make_pair(std::make_pair(namespaze, (const char*)pName), MetadataCache::GetIndexForTypeDefinition(klass))); void *iter = NULL; while (Il2CppClass *nestedClass = Class::GetNestedTypes(klass, &iter)) AddNestedTypesToNametoClassHashTable(image, hashTable, namespaze, name, nestedClass); } static void AddNestedTypesToNametoClassHashTable(const Il2CppImage* image, Il2CppNameToTypeDefinitionIndexHashTable* table, const Il2CppTypeDefinition* typeDefinition) { for (int i = 0; i < typeDefinition->nested_type_count; ++i) { Il2CppClass *klass = MetadataCache::GetNestedTypeFromOffset(typeDefinition, i); AddNestedTypesToNametoClassHashTable(image, image->nameToClassHashTable, MetadataCache::GetStringFromIndex(typeDefinition->namespaceIndex), MetadataCache::GetStringFromIndex(typeDefinition->nameIndex), klass); } } // This must be called when the s_ClassFromNameMutex is held. static void AddTypeToNametoClassHashTable(const Il2CppImage* image, Il2CppNameToTypeDefinitionIndexHashTable* table, TypeDefinitionIndex typeIndex) { const Il2CppTypeDefinition* typeDefinition = MetadataCache::GetTypeDefinitionFromIndex(typeIndex); // don't add nested types if (typeDefinition->declaringTypeIndex != kTypeIndexInvalid) return; if (image != il2cpp_defaults.corlib) AddNestedTypesToNametoClassHashTable(image, table, typeDefinition); //table->insert(std::make_pair(MetadataCache::GetTypeNamespaceAndName(typeHandle), typeHandle)); table->insert(std::make_pair(std::make_pair(MetadataCache::GetStringFromIndex(typeDefinition->namespaceIndex), MetadataCache::GetStringFromIndex(typeDefinition->nameIndex)), typeIndex)); } void Image::InitNestedTypes(const Il2CppImage *image) { for (uint32_t index = 0; index < image->typeCount; index++) { TypeDefinitionIndex typeIndex = image->typeStart + index; const Il2CppTypeDefinition* typeDefinition = MetadataCache::GetTypeDefinitionFromIndex(typeIndex); // don't add nested types if (typeDefinition->declaringTypeIndex != kTypeIndexInvalid) return; AddNestedTypesToNametoClassHashTable(image, image->nameToClassHashTable, typeDefinition); } for (uint32_t index = 0; index < image->exportedTypeCount; index++) { TypeDefinitionIndex typeIndex = MetadataCache::GetExportedTypeFromIndex(image->exportedTypeStart + index); if (typeIndex != kTypeIndexInvalid) { const Il2CppTypeDefinition* typeDefinition = MetadataCache::GetTypeDefinitionFromIndex(typeIndex); // don't add nested types if (typeDefinition->declaringTypeIndex != kTypeIndexInvalid) return; AddNestedTypesToNametoClassHashTable(image, image->nameToClassHashTable, typeDefinition); } } } static void InitImageNameToTypeHandleHashTable(const Il2CppImage* image) { os::FastAutoLock lock(&s_ClassFromNameMutex); if (!image->nameToClassHashTable) { auto nameToClassHashTable = new Il2CppNameToTypeDefinitionIndexHashTable(); image->nameToClassHashTable = nameToClassHashTable; for (uint32_t index = 0; index < image->typeCount; index++) { TypeDefinitionIndex typeIndex = image->typeStart + index; AddTypeToNametoClassHashTable(image, nameToClassHashTable, typeIndex); } for (uint32_t index = 0; index < image->exportedTypeCount; index++) { TypeDefinitionIndex typeIndex = MetadataCache::GetExportedTypeFromIndex(image->exportedTypeStart + index); if (typeIndex != kTypeIndexInvalid) AddTypeToNametoClassHashTable(image, nameToClassHashTable, typeIndex); } } } Il2CppClass* Image::ClassFromName(const Il2CppImage* image, const char* namespaze, const char *name) { if (!image->nameToClassHashTable) { InitImageNameToTypeHandleHashTable(image); } Il2CppNameToTypeDefinitionIndexHashTable::const_iterator iter = image->nameToClassHashTable->find(std::make_pair(namespaze, name)); if (iter != image->nameToClassHashTable->end()) return MetadataCache::GetTypeInfoFromTypeDefinitionIndex(iter->second); return NULL; } Il2CppMetadataTypeHandle Image::TypeHandleFromName(const Il2CppImage* image, const char* namespaze, const char* name) { if (!image->nameToClassHashTable) { InitImageNameToTypeHandleHashTable(image); } Il2CppNameToTypeDefinitionIndexHashTable::const_iterator iter = image->nameToClassHashTable->find(std::make_pair(namespaze, name)); if (iter != image->nameToClassHashTable->end()) return MetadataCache::GetTypeDefinitionFromIndex(iter->second); return NULL; } void Image::GetTypes(const Il2CppImage* image, bool exportedOnly, TypeVector* target) { size_t typeCount = Image::GetNumTypes(image); for (size_t sourceIndex = 0; sourceIndex < typeCount; sourceIndex++) { const Il2CppClass* type = Image::GetType(image, sourceIndex); if (strcmp(type->name, "") == 0) { continue; } target->push_back(type); } } size_t Image::GetNumTypes(const Il2CppImage* image) { return image->typeCount; } const Il2CppClass* Image::GetType(const Il2CppImage* image, size_t index) { size_t typeDefinitionIndex = image->typeStart + index; IL2CPP_ASSERT(typeDefinitionIndex <= static_cast(std::numeric_limits::max())); return MetadataCache::GetTypeInfoFromTypeDefinitionIndex(static_cast(typeDefinitionIndex)); } static bool StringsMatch(const char* left, const char* right, bool ignoreCase) { if (!ignoreCase) { return strcmp(left, right) == 0; } else { utils::VmStringUtils::CaseInsensitiveComparer comparer; return comparer(left, right); } } static Il2CppClass* FindClassMatching(const Il2CppImage* image, const char* namespaze, const char *name, Il2CppClass* declaringType, bool ignoreCase) { for (uint32_t i = 0; i < image->typeCount; i++) { Il2CppClass* type = MetadataCache::GetTypeInfoFromTypeDefinitionIndex(image->typeStart + i); if (type->declaringType == declaringType && StringsMatch(namespaze, type->namespaze, ignoreCase) && StringsMatch(name, type->name, ignoreCase)) { return type; } } return NULL; } static Il2CppClass* FindExportedClassMatching(const Il2CppImage* image, const char* namespaze, const char *name, Il2CppClass* declaringType, bool ignoreCase) { for (uint32_t i = 0; i < image->exportedTypeCount; i++) { TypeDefinitionIndex typeIndex = MetadataCache::GetExportedTypeFromIndex(image->exportedTypeStart + i); if (typeIndex != kTypeIndexInvalid) { Il2CppClass* type = MetadataCache::GetTypeInfoFromTypeDefinitionIndex(typeIndex); if (type->declaringType == declaringType && StringsMatch(namespaze, type->namespaze, ignoreCase) && StringsMatch(name, type->name, ignoreCase)) { return type; } } } return NULL; } static Il2CppClass* FindNestedType(Il2CppClass* klass, const char* name) { void* iter = NULL; while (Il2CppClass* nestedType = Class::GetNestedTypes(klass, &iter)) { if (!strcmp(name, nestedType->name)) return nestedType; } return NULL; } Il2CppClass* Image::FromTypeNameParseInfo(const Il2CppImage* image, const TypeNameParseInfo &info, bool ignoreCase) { const char* ns = info.ns().c_str(); const char* name = info.name().c_str(); Il2CppClass *parent_class = FindClassMatching(image, ns, name, NULL, ignoreCase); if (parent_class == NULL) { parent_class = FindExportedClassMatching(image, ns, name, NULL, ignoreCase); if (parent_class == NULL) return NULL; } std::vector::const_iterator it = info.nested().begin(); while (it != info.nested().end()) { parent_class = FindNestedType(parent_class, (*it).c_str()); if (parent_class == NULL) return NULL; ++it; } return parent_class; } static os::FastMutex s_Mutex; static std::vector s_CachedResourceData; static std::map s_CachedMemoryMappedResourceFiles; void Image::CacheMemoryMappedResourceFile(Il2CppReflectionAssembly* assembly, void* memoryMappedFile) { os::FastAutoLock lock(&s_Mutex); s_CachedMemoryMappedResourceFiles[assembly] = memoryMappedFile; } void* Image::GetCachedMemoryMappedResourceFile(Il2CppReflectionAssembly* assembly) { os::FastAutoLock lock(&s_Mutex); std::map::iterator entry = s_CachedMemoryMappedResourceFiles.find(assembly); if (entry != s_CachedMemoryMappedResourceFiles.end()) return entry->second; return NULL; } void Image::CacheResourceData(EmbeddedResourceRecord record, void* data) { os::FastAutoLock lock(&s_Mutex); s_CachedResourceData.push_back(EmbeddedResourceData(record, data)); } void* Image::GetCachedResourceData(const Il2CppImage* image, const std::string& name) { os::FastAutoLock lock(&s_Mutex); for (std::vector::iterator it = s_CachedResourceData.begin(); it != s_CachedResourceData.end(); ++it) { if (it->record.image == image && it->record.name == name) return it->data; } return NULL; } void Image::ClearCachedResourceData() { os::FastAutoLock lock(&s_Mutex); for (std::map::iterator i = s_CachedMemoryMappedResourceFiles.begin(); i != s_CachedMemoryMappedResourceFiles.end(); ++i) utils::MemoryMappedFile::Unmap(i->second); s_CachedMemoryMappedResourceFiles.clear(); s_CachedResourceData.clear(); } } /* namespace vm */ } /* namespace il2cpp */