void LoadMap(string name, ulong pointer, uint entry_count, Action <string, string> addToMap) { string entries = entry_count == 1 ? "entry" : "entries"; Log.Info($" Loading {name} map: {entry_count} {entries}, please wait..."); ulong size = 0; size += GetPaddedSize <string> (size); // from size += GetPaddedSize <string> (size); // to ulong mapSize = entry_count * size; byte[] data = ELF.GetData(pointer, mapSize); ulong offset = 0; string mapFrom; string mapTo; for (uint i = 0; i < entry_count; i++) { pointer = ReadPointer(data, ref offset); if (pointer != 0) { mapFrom = ELF.GetASCIIZ(pointer); } else { mapFrom = $"#{i}"; } pointer = ReadPointer(data, ref offset); if (pointer != 0) { mapTo = ELF.GetASCIIZ(pointer); } else { mapTo = $"#{i}"; } addToMap(mapFrom, mapTo); } }
List <TypeMapJava> LoadJavaTypes(string filePath) { ulong javaTypeCount = (ulong)ELF.GetUInt32(JavaTypeCountSymbolName); ulong javaNameWidth = (ulong)ELF.GetUInt32(JavaNameWidthSymbolName); // MUST be kept in sync with: src/monodroid/jni/xamarin-app.hh (struct TypeMapModule) ulong size = 0; size += GetPaddedSize <uint> (size); // module_index size += GetPaddedSize <uint> (size); // type_token_id size += javaNameWidth; byte[] data = ELF.GetData(MapJavaSymbolName); if (data.Length == 0) { throw new InvalidOperationException($"{filePath} doesn't have a valid '{MapJavaSymbolName}' symbol"); } ulong calculatedJavaTypeCount = (ulong)data.LongLength / size; if (calculatedJavaTypeCount != javaTypeCount) { throw new InvalidOperationException($"{filePath} has invalid '{JavaTypeCountSymbolName}' symbol value ({javaTypeCount}), '{JavaTypeCountSymbolName}' size indicates there are {calculatedJavaTypeCount} managedToJava instead"); } var ret = new List <TypeMapJava> (); ulong offset = 0; for (ulong i = 0; i < javaTypeCount; i++) { var javaEntry = new TypeMapJava { module_index = ReadUInt32(data, ref offset, packed: true), type_token_id = ReadUInt32(data, ref offset, packed: true), }; javaEntry.java_name = ELF.GetASCIIZ(data, offset); offset += javaNameWidth; ret.Add(javaEntry); } return(ret); }
bool DoLoadMaps() { // MUST be kept in sync with: src/monodroid/jni/xamarin-app.hh (struct TypeMap) ulong size = 0; size += GetPaddedSize <uint> (size); // entry_count size += GetPaddedSize <string> (size); // assembly_name (pointer) size += GetPaddedSize <string> (size); // data (pointer) size += GetPaddedSize <string> (size); // java_to_managed (pointer) size += GetPaddedSize <string> (size); // managed_to_java (pointer) string filePath = ELF.FilePath; byte[] mapData = ELF.GetData(TypeMapSymbolName); if (mapData.Length == 0) { Log.Error($"{filePath} doesn't have a valid '{TypeMapSymbolName}' symbol"); return(false); } if ((ulong)mapData.Length != size) { Log.Error($"Symbol '{TypeMapSymbolName}' in {filePath} has invalid size. Expected {size}, got {mapData.Length}"); return(false); } ulong offset = 0; uint entry_count = ReadUInt32(mapData, ref offset); ReadPointer(mapData, ref offset); // assembly_name, unused in Debug mode ReadPointer(mapData, ref offset); // data, unused in Debug mode ulong pointer = ReadPointer(mapData, ref offset); // java_to_managed LoadMap("Java to Managed", pointer, entry_count, AddJavaToManaged); pointer = ReadPointer(mapData, ref offset); // managed_to_java LoadMap("Managed to Java", pointer, entry_count, AddManagedToJava); return(true); }
List <TypeMapModule> LoadMapModules(string filePath) { ulong moduleCount = (ulong)ELF.GetUInt32(ModuleCountSymbolName); // MUST be kept in sync with: src/monodroid/jni/xamarin-app.hh (struct TypeMapModule) ulong size; size = 16; // module_uuid size += GetPaddedSize <uint> (size); // entry_count size += GetPaddedSize <uint> (size); // duplicate_count size += GetPaddedSize <string> (size); // map (pointer) size += GetPaddedSize <string> (size); // duplicate_map (pointer) size += GetPaddedSize <string> (size); // assembly_name (pointer) size += GetPaddedSize <string> (size); // image (pointer) size += GetPaddedSize <uint> (size); // java_name_width size += GetPaddedSize <string> (size); // java_map (pointer) byte[] moduleData = ELF.GetData(MapModulesSymbolName); if (moduleData.Length == 0) { throw new InvalidOperationException($"{filePath} doesn't have a valid '{MapModulesSymbolName}' symbol"); } ulong calculatedModuleCount = (ulong)moduleData.Length / size; if (calculatedModuleCount != moduleCount) { throw new InvalidOperationException($"{filePath} has invalid '{ModuleCountSymbolName}' symbol value ({moduleCount}), '{MapModulesSymbolName}' size indicates there are {calculatedModuleCount} managedToJava instead"); } var ret = new List <TypeMapModule> (); ulong offset = 0; for (ulong i = 0; i < moduleCount; i++) { Log.Debug($"Module {i + 1}"); var module = new TypeMapModule(); byte[] mvid = new byte[16]; Array.Copy(moduleData, (int)offset, mvid, 0, mvid.Length); module.module_uuid = new Guid(mvid); offset += (ulong)mvid.Length; Log.Debug($" module_uuid == {module.module_uuid}"); module.entry_count = ReadUInt32(moduleData, ref offset); Log.Debug($" entry_count == {module.entry_count}"); module.duplicate_count = ReadUInt32(moduleData, ref offset); Log.Debug($" duplicate_count == {module.duplicate_count}"); // MUST be kept in sync with: src/monodroid/jni/xamarin-app.hh (struct TypeMapModuleEntry) ulong pointer = ReadPointer(moduleData, ref offset); size = 0; size += GetPaddedSize <uint> (size); // type_token_id size += GetPaddedSize <uint> (size); // java_map_index ulong mapSize = size * module.entry_count; byte[] data = ELF.GetData(pointer, mapSize); module.map = new List <TypeMapModuleEntry> (); ReadMapEntries(module.map, data, module.entry_count); // MUST be kept in sync with: src/monodroid/jni/xamarin-app.hh (struct TypeMapModuleEntry) pointer = ReadPointer(moduleData, ref offset); if (pointer != 0) { mapSize = size * module.duplicate_count; data = ELF.GetData(pointer, mapSize); module.duplicate_map = new List <TypeMapModuleEntry> (); ReadMapEntries(module.duplicate_map, data, module.duplicate_count); } pointer = ReadPointer(moduleData, ref offset); module.assembly_name = ELF.GetASCIIZ(pointer); Log.Debug($" assembly_name == {module.assembly_name}"); Log.Debug(""); // Read the values to properly adjust the offset taking padding into account ReadPointer(moduleData, ref offset); ReadUInt32(moduleData, ref offset); ReadPointer(moduleData, ref offset); ret.Add(module); } return(ret); void ReadMapEntries(List <TypeMapModuleEntry> map, byte[] inputData, uint entryCount) { ulong mapOffset = 0; for (uint i = 0; i < entryCount; i++) { var entry = new TypeMapModuleEntry { type_token_id = ReadUInt32(inputData, ref mapOffset), java_map_index = ReadUInt32(inputData, ref mapOffset) }; map.Add(entry); } } }