Browse Source

Rework WriteSecurityDeclarationArgument to make sure it produces output, that can be reassembled.

pull/1030/head
Siegfried Pammer 7 years ago
parent
commit
d3d7dda7e4
  1. 156
      ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs

156
ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs

@ -452,37 +452,58 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -452,37 +452,58 @@ namespace ICSharpCode.Decompiler.Disassembler
{
Primitive,
Type,
Boxed,
Enum
}
static (PrimitiveSerializationTypeCode TypeCode, TypeKind Kind, bool IsArray, string TypeName) ReadArgumentType(ref BlobReader blob)
struct TypeInfo
{
public PrimitiveSerializationTypeCode TypeCode;
public TypeKind Kind;
public bool IsArray;
public bool IsBoxed;
public string TypeName;
public TypeInfo(PrimitiveSerializationTypeCode typeCode, TypeKind kind, bool isArray, bool isBoxed, string typeName)
{
TypeCode = typeCode;
Kind = kind;
IsArray = isArray;
IsBoxed = isBoxed;
TypeName = typeName;
}
}
static TypeInfo ReadArgumentType(ref BlobReader blob)
{
var b = blob.ReadByte();
if (2 <= b && b <= 14) {
return ((PrimitiveSerializationTypeCode)b, TypeKind.Primitive, false, null);
return new TypeInfo((PrimitiveSerializationTypeCode)b, TypeKind.Primitive, false, false, null);
}
switch (b) {
case 0x1d:
var result = ReadArgumentType(ref blob);
return (result.TypeCode, result.Kind, true, result.TypeName);
return new TypeInfo(result.TypeCode, result.Kind, true, false, result.TypeName);
case 0x50:
return (0, TypeKind.Type, false, null);
case 0x51: // boxed value type
return (0, TypeKind.Boxed, false, null);
return new TypeInfo(0, TypeKind.Type, false, false, null);
case 0x51: // boxed primitive type
return new TypeInfo(0, TypeKind.Primitive, false, true, null);
case 0x55: // enum
return (0, TypeKind.Enum, false, blob.ReadSerializedString());
return new TypeInfo(0, TypeKind.Enum, false, false, blob.ReadSerializedString());
default:
throw new BadImageFormatException($"Unexpected custom attribute type 0x{b:x}.");
}
}
static object ReadSimpleArgumentValue(ref BlobReader blob, PrimitiveSerializationTypeCode typeCode, TypeKind kind, string typeName)
object ReadSimpleArgumentValue(ref BlobReader blob, PEFile module, ref TypeInfo typeInfo)
{
switch (kind) {
switch (typeInfo.Kind) {
case TypeKind.Enum:
if (typeInfo.TypeCode == 0 && typeInfo.TypeName != null) {
typeInfo.TypeCode = ResolveEnumUnderlyingType(typeInfo.TypeName, module, out _);
}
goto case TypeKind.Primitive;
case TypeKind.Primitive:
switch (typeCode) {
switch (typeInfo.TypeCode) {
case PrimitiveSerializationTypeCode.Boolean: return blob.ReadBoolean();
case PrimitiveSerializationTypeCode.Byte: return blob.ReadByte();
case PrimitiveSerializationTypeCode.SByte: return blob.ReadSByte();
@ -496,15 +517,12 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -496,15 +517,12 @@ namespace ICSharpCode.Decompiler.Disassembler
case PrimitiveSerializationTypeCode.Single: return blob.ReadSingle();
case PrimitiveSerializationTypeCode.Double: return blob.ReadDouble();
case PrimitiveSerializationTypeCode.String: return blob.ReadSerializedString();
default: throw new ArgumentOutOfRangeException(nameof(typeCode));
default: throw new ArgumentOutOfRangeException(nameof(typeInfo.TypeCode));
}
case TypeKind.Type:
return blob.ReadSerializedString();
case TypeKind.Boxed:
var typeInfo = ReadArgumentType(ref blob);
return ReadArgumentValue(ref blob, typeInfo.TypeCode, typeInfo.Kind, typeInfo.IsArray, typeInfo.TypeName);
default:
throw new ArgumentOutOfRangeException(nameof(kind));
throw new ArgumentOutOfRangeException(nameof(typeInfo.Kind));
}
}
@ -586,21 +604,29 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -586,21 +604,29 @@ namespace ICSharpCode.Decompiler.Disassembler
return this.mscorlib != null;
}
static object ReadArgumentValue(ref BlobReader blob, PrimitiveSerializationTypeCode typeCode, TypeKind kind, bool isArray, string typeName)
object ReadArgumentValue(ref BlobReader blob, PEFile module, ref TypeInfo typeInfo)
{
if (isArray) {
if (typeInfo.IsArray) {
uint elementCount = blob.ReadUInt32();
if (elementCount == 0xFFFF_FFFF) {
return null;
} else {
var array = new object[elementCount];
for (int i = 0; i < elementCount; i++) {
array[i] = ReadSimpleArgumentValue(ref blob, typeCode, kind, typeName);
array[i] = ReadSimpleArgumentValue(ref blob, module, ref typeInfo);
}
return array;
}
} else if (typeInfo.IsBoxed) {
typeInfo = ReadArgumentType(ref blob);
typeInfo.IsBoxed = true;
if (typeInfo.IsArray) {
return ReadArgumentValue(ref blob, module, ref typeInfo);
} else {
return ReadSimpleArgumentValue(ref blob, module, ref typeInfo);
}
} else {
return ReadSimpleArgumentValue(ref blob, typeCode, kind, typeName);
return ReadSimpleArgumentValue(ref blob, module, ref typeInfo);
}
}
@ -702,63 +728,88 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -702,63 +728,88 @@ namespace ICSharpCode.Decompiler.Disassembler
break;
}
var typeInfo = ReadArgumentType(ref blob);
var typeCode = typeInfo.TypeCode;
var typeDefinition = default((PEFile Module, EntityHandle Handle));
if (typeInfo.Kind == TypeKind.Enum) {
typeCode = ResolveEnumUnderlyingType(typeInfo.TypeName, module, out typeDefinition);
typeInfo.TypeCode = ResolveEnumUnderlyingType(typeInfo.TypeName, module, out typeDefinition);
}
var name = blob.ReadSerializedString();
object value = ReadArgumentValue(ref blob, typeCode, typeInfo.Kind, typeInfo.IsArray, typeInfo.TypeName);
object value = ReadArgumentValue(ref blob, module, ref typeInfo);
WriteTypeInfo(output, module, typeInfo.TypeCode, typeInfo.Kind, typeInfo.IsArray, typeInfo.TypeName, typeDefinition.Module, typeDefinition.Handle);
WriteTypeInfo(output, module, typeInfo, typeDefinition.Module, typeDefinition.Handle);
output.Write(' ');
output.Write(DisassemblerHelpers.Escape(name));
output.Write(" = ");
if (typeInfo.Kind == TypeKind.Type) {
output.Write($"type({value})");
} else if (value is string) {
// secdecls use special syntax for strings
output.Write("string('{0}')", DisassemblerHelpers.EscapeString((string)value).Replace("'", "\'"));
} else {
if (typeInfo.Kind == TypeKind.Enum || typeInfo.Kind == TypeKind.Primitive) {
WritePrimitiveTypeCode(output, typeCode);
} else if (typeInfo.Kind == TypeKind.Boxed) {
output.Write("object");
} else {
WriteTypeInfo(output, module, typeInfo.TypeCode, typeInfo.Kind, typeInfo.IsArray, typeInfo.TypeName, typeDefinition.Module, typeDefinition.Handle);
if (typeInfo.IsBoxed) {
output.Write("object(");
}
WriteTypeInfo(output, module, typeInfo, typeDefinition.Module, typeDefinition.Handle, isValue: true);
if (typeInfo.IsArray && ((object[])value).Length >= 0) {
output.Write(((object[])value).Length.ToString());
output.Write(']');
output.Write('(');
if (typeInfo.Kind == TypeKind.Boxed) {
WritePrimitiveTypeCode(output, Type.GetTypeCode(value.GetType()));
output.Write('(');
bool first = true;
foreach (var item in (object[])value) {
if (!first) output.Write(' ');
WriteValue(output, item, typeInfo);
first = false;
}
DisassemblerHelpers.WriteOperand(output, value);
if (typeInfo.Kind == TypeKind.Boxed) {
output.Write(')');
} else {
output.Write('(');
WriteValue(output, value, typeInfo);
output.Write(')');
}
if (typeInfo.IsBoxed) {
output.Write(')');
}
}
static void WriteTypeInfo(ITextOutput output, PEFile currentModule, PrimitiveSerializationTypeCode typeCode, TypeKind kind,
bool isArray, string typeName, PEFile referencedModule, EntityHandle type)
static void WriteValue(ITextOutput output, object value, TypeInfo typeInfo)
{
switch (kind) {
switch (typeInfo.Kind) {
case TypeKind.Primitive:
WritePrimitiveTypeCode(output, typeCode);
if (value is string) {
output.Write("'" + DisassemblerHelpers.EscapeString((string)value).Replace("'", "\'") + "'");
} else {
DisassemblerHelpers.WriteOperand(output, value);
}
break;
case TypeKind.Type:
output.Write("type");
output.Write(value.ToString());
break;
case TypeKind.Enum:
DisassemblerHelpers.WriteOperand(output, value);
break;
case TypeKind.Boxed:
default:
throw new ArgumentOutOfRangeException(nameof(typeInfo.Kind));
}
}
static void WriteTypeInfo(ITextOutput output, PEFile currentModule, TypeInfo typeInfo, PEFile referencedModule, EntityHandle type, bool isValue = false)
{
if (typeInfo.IsBoxed && !isValue) {
output.Write("object");
return;
}
switch (typeInfo.Kind) {
case TypeKind.Primitive:
WritePrimitiveTypeCode(output, typeInfo.TypeCode);
break;
case TypeKind.Type:
output.Write("type");
break;
case TypeKind.Enum:
if (isValue) {
WritePrimitiveTypeCode(output, typeInfo.TypeCode);
} else {
output.Write("enum ");
if (type.IsNil) {
output.Write(DisassemblerHelpers.Escape(typeName));
output.Write(DisassemblerHelpers.Escape(typeInfo.TypeName));
break;
}
if (referencedModule != currentModule) {
@ -767,17 +818,22 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -767,17 +818,22 @@ namespace ICSharpCode.Decompiler.Disassembler
output.Write(']');
output.WriteReference(referencedModule, type, type.GetFullTypeName(referencedModule.Metadata).ToString());
} else {
output.Write(DisassemblerHelpers.Escape(typeName));
output.Write(DisassemblerHelpers.Escape(typeInfo.TypeName));
}
}
break;
default:
break;
}
if (isArray) {
if (typeInfo.IsArray) {
if (isValue) {
output.Write('[');
} else {
output.Write("[]");
}
}
}
#endregion
#region WriteMarshalInfo

Loading…
Cancel
Save