Files
UnrealEngineUWP/Engine/Source/Programs/MemoryProfiler2/IOSSymbolParser.cs

328 lines
12 KiB
C#
Raw Normal View History

// Copyright Epic Games, Inc. All Rights Reserved.
Copying //UE4/Dev-Mobile to //UE4/Dev-Main (Source: //UE4/Dev-Mobile @ 3793423) #lockdown Nick.Penwarden #rb none ============================ MAJOR FEATURES & CHANGES ============================ Change 3771581 by Chris.Babcock Add proxy support for Android #jira UE-52671 #ue4 #android Change 3771990 by Jack.Porter Fixed a crash when duplicating a landscape level in a cooked build. #jira UE-46550 Change 3772922 by Allan.Bentham Convert half float texture coordinates to float during serialize if HW does not support halfs. #jira UE-52397 Change 3772973 by Allan.Bentham Add GLES3.1 compatibility mode to mobile preview. Use -GLESCompat alongside -featureleveles31 to run windows mobile preview with android ES3.1 shaders. Change 3775585 by Cosmin.Sulea Safe zone rotation iPhoneX #jira UEMOB-52138 Change 3776702 by Peter.Sauerbrei addition of missing default icons #jira UE-52387 Change 3776775 by Peter.Sauerbrei fix for marketing icon size in the project settings #jira UE-52388 Change 3777336 by Peter.Sauerbrei properly call OnOpenURL in the main thread start if the engine hasn't been initialized previously fix courtesy of sangpan #jira UE-51133 Change 3777602 by Dmitriy.Dyomin Fxied: Project fails to package for Android with RenderDoc debugger enabled #jira UE-52758 Change 3778247 by Bogdan.Vasilache UE-50257 --> Skeletal meshes silently fail to render if they have more than 75 bones #jira UE-50257 Change 3778318 by Peter.Sauerbrei copy NSLocalizationfiles from Build/IOS/Resources/Localizations courtesty of alexchicn #jira UE-52317 Change 3778597 by Allan.Bentham Mobile support for CSM shader culling with movable lights. Add 'Support movable light CSM shader culling' option to render settings. (default on) Add new culling mode which tests against only the shadow receiving frustum, saves on CPU searching for shadow casters intersects. (default cull mode.) Add FPrimitiveSceneProxy.bReceiveMobileCSMShadows which now applies to both stationary and movable lights. (default = true) removed FPrimitiveSceneProxy.bReceiveCombinedCSMAndStaticShadowsFromStationaryLights removed 'r.AllReceiveDynamicCSM' cvar Change 3778703 by Allan.Bentham Mobile CSM distance fading. Change 3780805 by Allan.Bentham Attempt to silence CIS static analysis. Change 3781098 by Allan.Bentham Pass per project maximum shadow cascade value to mobile shader compile environment. CSM shaders no longer loop over non-existant cascades. Change 3781155 by Chris.Babcock Fix support for GL_OES_standard_derivatives on Android (contributed by jlc-innerspace) #jira UE-52872 #PR #4267 #ue4 #android Change 3785116 by Peter.Sauerbrei fix for new iOS 11 api being called on iOS 9, 10 #jia UE-52912 Change 3785240 by Chris.Babcock Updated Android SDK license agreement #jira UE-52788 #ue4 #android Change 3786652 by Cosmin.Sulea UE-50381 - Using FMallocProfiler extremely slow resolving symbols on iOS - .udebugsymbols approach #jira UE-50381 Change 3787587 by Chris.Babcock Fix oversized UMG Designed button #jira UE-53014 #ue4 Change 3772888 by Cosmin.Sulea UE-52138 - Add support to UMG safe zone to be off-center for iPhone X #jira UE-52138 [CL 3793429 by Chris Babcock in Main branch]
2017-12-06 19:54:50 -05:00
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Runtime.Serialization.Formatters.Binary;
using System.Windows.Forms;
namespace MemoryProfiler2
{
public class FIOSSymbolParser : ISymbolParser
{
private const uint PACKAGE_FILE_TAG = 0x9E2A83C1;
private const uint PACKAGE_FILE_TAG_SWAPPED = 0xC1832A9E;
private const int LOADING_COMPRESSION_CHUNK_SIZE = 131072;
protected struct FGenericPlatformSymbolInfo
{
public uint Line;
public ulong Start;
public ulong Length;
public int PathIdx;
public void Read(BinaryReader reader)
{
Line = reader.ReadUInt32();
Start = reader.ReadUInt64();
Length = reader.ReadUInt64();
PathIdx = reader.ReadInt32();
}
}
protected struct FGenericPlatformSymbolData
{
public ulong Start;
public ulong Length;
public int NameIdx;
public FGenericPlatformSymbolInfo[] SymbolInfo;
public void Read(BinaryReader reader)
{
Start = reader.ReadUInt64();
Length = reader.ReadUInt64();
NameIdx = reader.ReadInt32();
int nrSymbols = reader.ReadInt32();
SymbolInfo = new FGenericPlatformSymbolInfo[nrSymbols];
for (int i = 0; i < nrSymbols; i++)
{
SymbolInfo[i].Read(reader);
}
}
}
protected struct FGenericPlatformSymbolDatabase
{
string Signature;
string Name;
public FGenericPlatformSymbolData[] Symbols;
public string[] StringTable;
public void Read(BinaryReader reader)
{
int SignatureLen = reader.ReadInt32();
Signature = new string(reader.ReadChars(SignatureLen));
int NameLen = reader.ReadInt32();
Name = new string(reader.ReadChars(NameLen));
int nrSymbols = reader.ReadInt32();
Symbols = new FGenericPlatformSymbolData[nrSymbols];
for (int i = 0; i < nrSymbols; i++)
{
Symbols[i].Read(reader);
}
int nrStrings = reader.ReadInt32();
StringTable = new string[nrStrings];
for (int i = 0; i < nrStrings; i++)
{
int StringLen = reader.ReadInt32();
StringTable[i] = new string(reader.ReadChars(StringLen));
}
}
}
struct FCompressedChunkInfo
{
/** Holds the data's compressed size. */
public long CompressedSize;
/** Holds the data's uncompresses size. */
public long UncompressedSize;
};
public static string StaticPlatformName()
{
return "IOS";
}
protected class FIOSSymbol : IComparable<FIOSSymbol>
{
public FIOSSymbol(ulong _Address, string _OutFileName, string _OutFunction, int _OutLineNumber)
{
OutFileName = _OutFileName;
OutFunction = _OutFunction;
OutLineNumber = _OutLineNumber;
Address = _Address;
}
public int CompareTo(FIOSSymbol that)
{
if (that == null) return 1;
if (this.Address > that.Address) return 1;
if (this.Address < that.Address) return -1;
return 0;
}
public string OutFileName;
public string OutFunction;
public int OutLineNumber;
public ulong Address;
}
protected class CompareAdresses : IComparer<FIOSSymbol>
{
public int Compare(FIOSSymbol x, FIOSSymbol y)
{
if (x.Address > y.Address)
return 1;
if (x.Address < y.Address)
return -1;
return 0;
}
}
protected byte[] LoadCompressedChunk(BinaryReader reader)
{
try
{
FCompressedChunkInfo PackageFileTag = new FCompressedChunkInfo();
PackageFileTag.CompressedSize = reader.ReadInt64();
PackageFileTag.UncompressedSize = reader.ReadInt64();
FCompressedChunkInfo Summary = new FCompressedChunkInfo();
Summary.CompressedSize = reader.ReadInt64();
Summary.UncompressedSize = reader.ReadInt64();
bool bWasByteSwapped = PackageFileTag.CompressedSize != PACKAGE_FILE_TAG;
bool bHeaderWasValid = true;
if (bWasByteSwapped)
{
bHeaderWasValid = PackageFileTag.CompressedSize == PACKAGE_FILE_TAG_SWAPPED;
if (bHeaderWasValid)
{
// not supported
//Summary.CompressedSize = BYTESWAP_ORDER64(Summary.CompressedSize);
//Summary.UncompressedSize = BYTESWAP_ORDER64(Summary.UncompressedSize);
//PackageFileTag.UncompressedSize = BYTESWAP_ORDER64(PackageFileTag.UncompressedSize);
}
}
else
{
bHeaderWasValid = PackageFileTag.CompressedSize == PACKAGE_FILE_TAG;
}
// Handle change in compression chunk size in backward compatible way.
long LoadingCompressionChunkSize = PackageFileTag.UncompressedSize;
if (LoadingCompressionChunkSize == PACKAGE_FILE_TAG)
{
LoadingCompressionChunkSize = LOADING_COMPRESSION_CHUNK_SIZE;
}
// Figure out how many chunks there are going to be based on uncompressed size and compression chunk size.
long TotalChunkCount = (Summary.UncompressedSize + LoadingCompressionChunkSize - 1) / LoadingCompressionChunkSize;
// Allocate compression chunk infos and serialize them, keeping track of max size of compression chunks used.
FCompressedChunkInfo[] CompressionChunks = new FCompressedChunkInfo[TotalChunkCount];
long MaxCompressedSize = 0;
for (int ChunkIndex = 0; ChunkIndex < TotalChunkCount; ChunkIndex++)
{
CompressionChunks[ChunkIndex].CompressedSize = reader.ReadInt64();
CompressionChunks[ChunkIndex].UncompressedSize = reader.ReadInt64();
if (bWasByteSwapped)
{
// not supported
//CompressionChunks[ChunkIndex].CompressedSize = BYTESWAP_ORDER64(CompressionChunks[ChunkIndex].CompressedSize);
//CompressionChunks[ChunkIndex].UncompressedSize = BYTESWAP_ORDER64(CompressionChunks[ChunkIndex].UncompressedSize);
}
MaxCompressedSize = Math.Max(CompressionChunks[ChunkIndex].CompressedSize, MaxCompressedSize);
}
byte[] DeCompressedBuffer = new byte[Summary.UncompressedSize];
int offset = 0;
// Iterate over all chunks, serialize them into memory and decompress them directly into the destination pointer
for (long ChunkIndex = 0; ChunkIndex < TotalChunkCount; ChunkIndex++)
{
// Read compressed data.
byte[] initialSkip = reader.ReadBytes(2);
byte[] CompressedBuffer = reader.ReadBytes((int)CompressionChunks[ChunkIndex].CompressedSize - 6);
byte[] finalSkip = reader.ReadBytes(4);
MemoryStream ms = new MemoryStream(CompressedBuffer);
DeflateStream gzip = new DeflateStream(ms, CompressionMode.Decompress);
gzip.Read(DeCompressedBuffer, offset, (int)CompressionChunks[ChunkIndex].UncompressedSize);
// Decompress into dest pointer directly.
offset += (int)CompressionChunks[ChunkIndex].UncompressedSize;
}
return DeCompressedBuffer;
}
catch
{
return null;
}
}
public static void AppendAllBytes(string path, byte[] bytes)
{
using (var stream = new FileStream(path, FileMode.Append))
{
stream.Write(bytes, 0, bytes.Length);
}
}
public override bool InitializeSymbolService(string ExecutableName, FUIBroker UIBroker)
{
string FDsName = FStreamInfo.GlobalInstance.FileName;
string FAdName;
string FUcName;
string FExtension = Path.GetExtension(FDsName).ToLower();
if (FExtension == ".mprof")
{
FAdName = Path.GetDirectoryName(FDsName) + "\\" + ExecutableName + ".udebugsymbols";
FUcName = Path.GetDirectoryName(FDsName) + "\\" + ExecutableName + ".udb";
}
else
{
return false;
}
if (!File.Exists(FAdName))
{
MessageBox.Show(String.Format("Failed to look up symbol file ({0}). Please check the path and try again!", FAdName), "Memory Profiler 2", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
byte[] uncompressed = new byte[0];
bool NeedsDecompress = false;
if (!File.Exists(FUcName))
{
NeedsDecompress = true;
}
else if (File.GetCreationTimeUtc(FAdName) > File.GetCreationTimeUtc(FUcName))
{
NeedsDecompress = true;
}
if (NeedsDecompress)
{
byte[] data = File.ReadAllBytes(FAdName);
MemoryStream memory = new MemoryStream(data);
BinaryReader reader = new BinaryReader(memory);
byte[] DeCompressedBuffer = LoadCompressedChunk(reader);
while (DeCompressedBuffer != null)
{
AppendAllBytes(FUcName, DeCompressedBuffer);
DeCompressedBuffer = LoadCompressedChunk(reader);
}
}
uncompressed = File.ReadAllBytes(FUcName);
if (uncompressed != null)
{
MemoryStream memory = new MemoryStream(uncompressed);
BinaryReader reader = new BinaryReader(memory);
Database.Read(reader);
}
return true;
}
protected ulong ModuleOffset = 0;
public override void SetModuleOffset(ulong offset)
{
ModuleOffset = offset;
}
public override bool ResolveAddressToSymboInfo(ESymbolResolutionMode SymbolResolutionMode, ulong Address, out string OutFileName, out string OutFunction, out int OutLineNumber)
{
OutFileName = null;
OutFunction = null;
OutLineNumber = 0;
bool bOk = false;
foreach (var Symbol in Database.Symbols)
{
if ((Symbol.Start <= (Address - ModuleOffset)) && ((Symbol.Start + Symbol.Length) >= (Address - ModuleOffset)))
{
OutFunction = Database.StringTable[Symbol.NameIdx];
foreach(var SymbolInfo in Symbol.SymbolInfo)
{
if ((SymbolInfo.Start <= (Address - ModuleOffset)) && ((SymbolInfo.Start + SymbolInfo.Length) >= (Address - ModuleOffset)))
{
OutFileName = Database.StringTable[SymbolInfo.PathIdx];
OutLineNumber = (int)SymbolInfo.Line;
break;
}
}
bOk = true;
break;
}
}
return bOk;
}
protected FGenericPlatformSymbolDatabase Database = new FGenericPlatformSymbolDatabase();
}
}