2024-01-30 23:30:42 -06:00
|
|
|
using Humanizer;
|
2024-01-31 09:21:30 -06:00
|
|
|
using Microsoft.Iris.Asm.Models;
|
2024-01-30 23:30:42 -06:00
|
|
|
using Microsoft.Iris.Markup;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
|
|
|
|
namespace Microsoft.Iris.Asm;
|
|
|
|
|
|
|
|
|
|
public class Disassembler
|
|
|
|
|
{
|
|
|
|
|
private readonly MarkupLoadResult _loadResult;
|
|
|
|
|
|
|
|
|
|
private Disassembler(MarkupLoadResult loadResult)
|
|
|
|
|
{
|
|
|
|
|
_loadResult = loadResult;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Disassembler Load(MarkupLoadResult loadResult) => new(loadResult);
|
|
|
|
|
|
|
|
|
|
public IEnumerable<IImport> GetImports()
|
|
|
|
|
{
|
|
|
|
|
foreach (var typeImport in _loadResult.ImportTables.TypeImports)
|
|
|
|
|
{
|
|
|
|
|
var uri = typeImport.Owner.Uri;
|
|
|
|
|
|
|
|
|
|
// Skip default UIX namespace
|
|
|
|
|
if (uri == "http://schemas.microsoft.com/2007/uix")
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
string name = uri;
|
|
|
|
|
var schemeLength = uri.IndexOf("://");
|
|
|
|
|
if (schemeLength > 0)
|
|
|
|
|
{
|
|
|
|
|
var scheme = uri[..schemeLength];
|
|
|
|
|
if (scheme == "assembly")
|
|
|
|
|
{
|
|
|
|
|
// Assume the URI represents a C# namespace
|
|
|
|
|
name = uri.Split('.', '/', '\\')[^1];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Assume the URI represents a file,
|
|
|
|
|
// skip the extension
|
|
|
|
|
name = uri.Split('.', '/', '\\')[^2];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
yield return new NamespaceImport(uri, name.Camelize());
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IEnumerable<IBodyItem> GetBody()
|
|
|
|
|
{
|
|
|
|
|
var reader = _loadResult.ObjectSection;
|
|
|
|
|
|
|
|
|
|
while (reader.CurrentOffset < reader.Size)
|
|
|
|
|
{
|
|
|
|
|
var opCode = (OpCode)reader.ReadByte();
|
|
|
|
|
|
|
|
|
|
switch (opCode)
|
|
|
|
|
{
|
|
|
|
|
case OpCode.ConstructObject:
|
|
|
|
|
// COBJ <typeIndex>
|
2024-01-31 16:58:28 -06:00
|
|
|
yield return new Instruction(opCode, [new(reader.ReadUInt16())]);
|
2024-01-30 23:30:42 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OpCode.ConstructObjectIndirect:
|
|
|
|
|
// COBI <assignmentTypeIndex>
|
2024-01-31 16:58:28 -06:00
|
|
|
yield return new Instruction(opCode, [new(reader.ReadUInt16())]);
|
2024-01-30 23:30:42 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OpCode.ConstructObjectParam:
|
|
|
|
|
// COBP <targetTypeIndex> <constructorIndex>
|
2024-01-31 16:58:28 -06:00
|
|
|
yield return new Instruction(opCode, [new(reader.ReadUInt16()), new(reader.ReadUInt16())]);
|
2024-01-30 23:30:42 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OpCode.ConstructFromString:
|
|
|
|
|
// CSTR <typeIndex> <stringIndex>
|
2024-01-31 16:58:28 -06:00
|
|
|
yield return new Instruction(opCode, [new(reader.ReadUInt16()), new(reader.ReadUInt16())]);
|
2024-01-30 23:30:42 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OpCode.ConstructFromBinary:
|
|
|
|
|
// CBIN <typeIndex> <object:X>
|
|
|
|
|
var cbinTypeIndex = reader.ReadUInt16();
|
|
|
|
|
TypeSchema cbinTypeSchema = _loadResult.ImportTables.TypeImports[cbinTypeIndex];
|
|
|
|
|
object cbinObject = cbinTypeSchema.DecodeBinary(reader);
|
|
|
|
|
|
2024-01-31 16:58:28 -06:00
|
|
|
yield return new Instruction(opCode, [new(cbinTypeIndex), new(cbinObject)]);
|
2024-01-30 23:30:42 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
|
|
|
|
|
case OpCode.PropertyInitialize:
|
|
|
|
|
// PINI <propertyIndex>
|
2024-01-31 16:58:28 -06:00
|
|
|
yield return new Instruction(opCode, [new(reader.ReadUInt16())]);
|
2024-01-30 23:30:42 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OpCode.PropertyInitializeIndirect:
|
|
|
|
|
// PINII <propertyIndex>
|
2024-01-31 16:58:28 -06:00
|
|
|
yield return new Instruction(opCode, [new(reader.ReadUInt16())]);
|
2024-01-30 23:30:42 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
|
|
|
|
|
case OpCode.PushConstant:
|
|
|
|
|
// PSHC <constantIndex>
|
2024-01-31 16:58:28 -06:00
|
|
|
yield return new Instruction(opCode, [new(reader.ReadUInt16())]);
|
2024-01-30 23:30:42 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
|
|
|
|
|
case OpCode.ReturnValue:
|
|
|
|
|
// RET
|
2024-01-31 16:58:28 -06:00
|
|
|
yield return new Instruction(opCode, []);
|
2024-01-30 23:30:42 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OpCode.ReturnVoid:
|
|
|
|
|
// RETV
|
2024-01-31 16:58:28 -06:00
|
|
|
yield return new Instruction(opCode, []);
|
2024-01-30 23:30:42 -06:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
yield break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string Write()
|
|
|
|
|
{
|
|
|
|
|
_loadResult.Load(LoadPass.DeclareTypes);
|
|
|
|
|
_loadResult.Load(LoadPass.PopulatePublicModel);
|
|
|
|
|
_loadResult.Load(LoadPass.Full);
|
|
|
|
|
_loadResult.Load(LoadPass.Done);
|
|
|
|
|
|
|
|
|
|
List<IImport> imports = new(GetImports());
|
|
|
|
|
List<IBodyItem> body = new(GetBody());
|
|
|
|
|
|
|
|
|
|
Program asmProgram = new(imports, body);
|
|
|
|
|
return asmProgram.ToString();
|
|
|
|
|
}
|
|
|
|
|
}
|