Browse Source

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

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

184
ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs

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

Loading…
Cancel
Save