From 5b526cfeac9dfa84771c2b75cb64d7dcb02a150d Mon Sep 17 00:00:00 2001 From: ElektroKill Date: Tue, 7 Nov 2023 21:39:16 +0100 Subject: [PATCH 1/5] Read and use tuple element names and dynamic type information from PDBs --- .../DebugInfo/IDebugInfoProvider.cs | 1 + .../ICSharpCode.Decompiler.csproj | 1 + .../IL/ApplyPdbLocalTypeInfoTypeVisitor.cs | 151 ++++++++++++++++++ ICSharpCode.Decompiler/IL/ILReader.cs | 10 +- .../PdbProvider/MonoCecilDebugInfoProvider.cs | 12 +- .../PdbProvider/PortableDebugInfoProvider.cs | 73 ++++++++- 6 files changed, 245 insertions(+), 3 deletions(-) create mode 100644 ICSharpCode.Decompiler/IL/ApplyPdbLocalTypeInfoTypeVisitor.cs diff --git a/ICSharpCode.Decompiler/DebugInfo/IDebugInfoProvider.cs b/ICSharpCode.Decompiler/DebugInfo/IDebugInfoProvider.cs index 5c148df258..bab259b26b 100644 --- a/ICSharpCode.Decompiler/DebugInfo/IDebugInfoProvider.cs +++ b/ICSharpCode.Decompiler/DebugInfo/IDebugInfoProvider.cs @@ -23,6 +23,7 @@ public interface IDebugInfoProvider IList GetSequencePoints(MethodDefinitionHandle method); IList GetVariables(MethodDefinitionHandle method); bool TryGetName(MethodDefinitionHandle method, int index, out string name); + bool TryGetExtraTypeInfo(MethodDefinitionHandle method, int index, out string[] tupleElementNames, out bool[] dynamicFlags); string SourceFileName { get; } } } diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj index a742391f72..0a897cfa2a 100644 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj +++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj @@ -95,6 +95,7 @@ + diff --git a/ICSharpCode.Decompiler/IL/ApplyPdbLocalTypeInfoTypeVisitor.cs b/ICSharpCode.Decompiler/IL/ApplyPdbLocalTypeInfoTypeVisitor.cs new file mode 100644 index 0000000000..a6b629f876 --- /dev/null +++ b/ICSharpCode.Decompiler/IL/ApplyPdbLocalTypeInfoTypeVisitor.cs @@ -0,0 +1,151 @@ +using System; +using System.Collections.Immutable; + +using ICSharpCode.Decompiler.TypeSystem; +using ICSharpCode.Decompiler.TypeSystem.Implementation; + +namespace ICSharpCode.Decompiler.IL +{ + /// + /// Heavily based on + /// + sealed class ApplyPdbLocalTypeInfoTypeVisitor : TypeVisitor + { + private readonly bool[] dynamicData; + private readonly string[] tupleElementNames; + private int dynamicTypeIndex = 0; + private int tupleTypeIndex = 0; + + public ApplyPdbLocalTypeInfoTypeVisitor(bool[] dynamicData, string[] tupleElementNames) + { + this.dynamicData = dynamicData; + this.tupleElementNames = tupleElementNames; + } + + public override IType VisitModOpt(ModifiedType type) + { + dynamicTypeIndex++; + return base.VisitModOpt(type); + } + + public override IType VisitModReq(ModifiedType type) + { + dynamicTypeIndex++; + return base.VisitModReq(type); + } + + public override IType VisitPointerType(PointerType type) + { + dynamicTypeIndex++; + return base.VisitPointerType(type); + } + + public override IType VisitArrayType(ArrayType type) + { + dynamicTypeIndex++; + return base.VisitArrayType(type); + } + + public override IType VisitByReferenceType(ByReferenceType type) + { + dynamicTypeIndex++; + return base.VisitByReferenceType(type); + } + + public override IType VisitTupleType(TupleType type) + { + if (tupleElementNames != null && tupleTypeIndex < tupleElementNames.Length) + { + int tupleCardinality = type.Cardinality; + string[] extractedValues = new string[tupleCardinality]; + Array.Copy(tupleElementNames, tupleTypeIndex, extractedValues, 0, + Math.Min(tupleCardinality, tupleElementNames.Length - tupleTypeIndex)); + var elementNames = ImmutableArray.CreateRange(extractedValues); + tupleTypeIndex += tupleCardinality; + + int level = 0; + var elementTypes = new IType[type.ElementTypes.Length]; + for (int i = 0; i < type.ElementTypes.Length; i++) + { + dynamicTypeIndex++; + IType elementType = type.ElementTypes[i]; + if (i != 0 && (i - level) % TupleType.RestPosition == 0 && elementType is TupleType tuple) + { + tupleTypeIndex += tuple.Cardinality; + level++; + } + elementTypes[i] = elementType.AcceptVisitor(this); + } + + return new TupleType( + type.Compilation, + elementTypes.ToImmutableArray(), + elementNames, + type.GetDefinition()?.ParentModule + ); + } + return base.VisitTupleType(type); + } + + public override IType VisitParameterizedType(ParameterizedType type) + { + if (TupleType.IsTupleCompatible(type, out var tupleCardinality)) + tupleTypeIndex += tupleCardinality; + // Visit generic type and type arguments. + // Like base implementation, except that it increments dynamicTypeIndex. + var genericType = type.GenericType.AcceptVisitor(this); + bool changed = type.GenericType != genericType; + var arguments = new IType[type.TypeArguments.Count]; + for (int i = 0; i < type.TypeArguments.Count; i++) + { + dynamicTypeIndex++; + arguments[i] = type.TypeArguments[i].AcceptVisitor(this); + changed = changed || arguments[i] != type.TypeArguments[i]; + } + if (!changed) + return type; + return new ParameterizedType(genericType, arguments); + } + + public override IType VisitFunctionPointerType(FunctionPointerType type) + { + dynamicTypeIndex++; + if (type.ReturnIsRefReadOnly) + { + dynamicTypeIndex++; + } + var returnType = type.ReturnType.AcceptVisitor(this); + bool changed = type.ReturnType != returnType; + var parameters = new IType[type.ParameterTypes.Length]; + for (int i = 0; i < parameters.Length; i++) + { + dynamicTypeIndex += type.ParameterReferenceKinds[i] switch { + ReferenceKind.None => 1, + ReferenceKind.Ref => 1, + ReferenceKind.Out => 2, // in/out also count the modreq + ReferenceKind.In => 2, + _ => throw new NotSupportedException() + }; + parameters[i] = type.ParameterTypes[i].AcceptVisitor(this); + changed = changed || parameters[i] != type.ParameterTypes[i]; + } + if (!changed) + return type; + return type.WithSignature(returnType, parameters.ToImmutableArray()); + } + + public override IType VisitTypeDefinition(ITypeDefinition type) + { + IType newType = type; + var ktc = type.KnownTypeCode; + if (ktc == KnownTypeCode.Object && dynamicData is not null) + { + if (dynamicTypeIndex >= dynamicData.Length) + newType = SpecialType.Dynamic; + else if (dynamicData[dynamicTypeIndex]) + newType = SpecialType.Dynamic; + } + return newType; + } + } +} diff --git a/ICSharpCode.Decompiler/IL/ILReader.cs b/ICSharpCode.Decompiler/IL/ILReader.cs index 5aa7edb742..ae85ec79ce 100644 --- a/ICSharpCode.Decompiler/IL/ILReader.cs +++ b/ICSharpCode.Decompiler/IL/ILReader.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2014 Daniel Grunwald +// Copyright (c) 2014 Daniel Grunwald // // Permission is hereby granted, free of charge, to any person obtaining a copy of this // software and associated documentation files (the "Software"), to deal in the Software @@ -304,6 +304,14 @@ ILVariable CreateILVariable(int index, IType type) { kind = VariableKind.Local; } + + if (UseDebugSymbols && DebugInfo is not null && + DebugInfo.TryGetExtraTypeInfo((MethodDefinitionHandle)method.MetadataToken, index, + out string[] tupleElementNames, out bool[] dynamicFlags)) + { + type = type.AcceptVisitor(new ApplyPdbLocalTypeInfoTypeVisitor(dynamicFlags, tupleElementNames)); + } + ILVariable ilVar = new ILVariable(kind, type, index); if (!UseDebugSymbols || DebugInfo == null || !DebugInfo.TryGetName((MethodDefinitionHandle)method.MetadataToken, index, out string name)) { diff --git a/ICSharpCode.ILSpyX/PdbProvider/MonoCecilDebugInfoProvider.cs b/ICSharpCode.ILSpyX/PdbProvider/MonoCecilDebugInfoProvider.cs index c7e09d3053..78f468a7e3 100644 --- a/ICSharpCode.ILSpyX/PdbProvider/MonoCecilDebugInfoProvider.cs +++ b/ICSharpCode.ILSpyX/PdbProvider/MonoCecilDebugInfoProvider.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Siegfried Pammer +// Copyright (c) 2018 Siegfried Pammer // // Permission is hereby granted, free of charge, to any person obtaining a copy of this // software and associated documentation files (the "Software"), to deal in the Software @@ -135,5 +135,15 @@ public bool TryGetName(SRM.MethodDefinitionHandle handle, int index, [NotNullWhe name = variable.Name; return name != null; } + + public bool TryGetExtraTypeInfo(SRM.MethodDefinitionHandle method, int index, + [NotNullWhen(true)] out string[]? tupleElementNames, [NotNullWhen(true)] out bool[]? dynamicFlags) + { + // Mono.Cecil's WindowsPDB reader is unable to read tuple element names + // and dynamic flags custom debug information. + tupleElementNames = null; + dynamicFlags = null; + return false; + } } } diff --git a/ICSharpCode.ILSpyX/PdbProvider/PortableDebugInfoProvider.cs b/ICSharpCode.ILSpyX/PdbProvider/PortableDebugInfoProvider.cs index 0f64997ea6..06cf9967f6 100644 --- a/ICSharpCode.ILSpyX/PdbProvider/PortableDebugInfoProvider.cs +++ b/ICSharpCode.ILSpyX/PdbProvider/PortableDebugInfoProvider.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Siegfried Pammer +// Copyright (c) 2018 Siegfried Pammer // // Permission is hereby granted, free of charge, to any person obtaining a copy of this // software and associated documentation files (the "Software"), to deal in the Software @@ -161,5 +161,76 @@ public bool TryGetName(MethodDefinitionHandle method, int index, [NotNullWhen(tr } return false; } + + public bool TryGetExtraTypeInfo(MethodDefinitionHandle method, int index, + [NotNullWhen(true)] out string?[]? tupleElementNames, [NotNullWhen(true)] out bool[]? dynamicFlags) + { + var metadata = GetMetadataReader(); + tupleElementNames = null; + dynamicFlags = null; + + if (metadata == null) + return false; + + LocalVariableHandle localVariableHandle = default; + foreach (var h in metadata.GetLocalScopes(method)) + { + var scope = metadata.GetLocalScope(h); + foreach (var v in scope.GetLocalVariables()) + { + var var = metadata.GetLocalVariable(v); + if (var.Index == index) + { + localVariableHandle = v; + break; + } + } + + if (!localVariableHandle.IsNil) + break; + } + + foreach (var h in metadata.CustomDebugInformation) + { + var cdi = metadata.GetCustomDebugInformation(h); + if (cdi.Parent.IsNil || cdi.Parent.Kind != HandleKind.LocalVariable) + continue; + if (localVariableHandle != (LocalVariableHandle)cdi.Parent) + continue; + if (cdi.Value.IsNil || cdi.Kind.IsNil) + continue; + var reader = metadata.GetBlobReader(cdi.Value); + var kind = metadata.GetGuid(cdi.Kind); + if (kind == KnownGuids.TupleElementNames && tupleElementNames is null) + { + var list = new List(); + while (reader.RemainingBytes > 0) + { + int length = reader.IndexOf(0); + string s = reader.ReadUTF8(length); + reader.ReadByte(); + list.Add(string.IsNullOrWhiteSpace(s) ? null : s); + } + + tupleElementNames = list.ToArray(); + } + else if (kind == KnownGuids.DynamicLocalVariables && dynamicFlags is null) + { + dynamicFlags = new bool[reader.Length * 8]; + int j = 0; + while (reader.Offset < reader.Length) + { + int b = reader.ReadByte(); + for (int i = 1; i < 0x100; i <<= 1) + dynamicFlags[j++] = (b & i) != 0; + } + } + + if (tupleElementNames != null && dynamicFlags != null) + break; + } + + return tupleElementNames != null || dynamicFlags != null; + } } } From 1f333adcc41951a0041d600ee2427ceab4efebb5 Mon Sep 17 00:00:00 2001 From: ElektroKill Date: Wed, 8 Nov 2023 19:27:27 +0100 Subject: [PATCH 2/5] Simplify loop condition --- ICSharpCode.ILSpyX/PdbProvider/PortableDebugInfoProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ICSharpCode.ILSpyX/PdbProvider/PortableDebugInfoProvider.cs b/ICSharpCode.ILSpyX/PdbProvider/PortableDebugInfoProvider.cs index 06cf9967f6..f56d79579d 100644 --- a/ICSharpCode.ILSpyX/PdbProvider/PortableDebugInfoProvider.cs +++ b/ICSharpCode.ILSpyX/PdbProvider/PortableDebugInfoProvider.cs @@ -218,7 +218,7 @@ public bool TryGetExtraTypeInfo(MethodDefinitionHandle method, int index, { dynamicFlags = new bool[reader.Length * 8]; int j = 0; - while (reader.Offset < reader.Length) + while (reader.RemainingBytes > 0) { int b = reader.ReadByte(); for (int i = 1; i < 0x100; i <<= 1) From fdb39469e9cf14561472f3036a8dd5918839e356 Mon Sep 17 00:00:00 2001 From: ElektroKill Date: Wed, 13 Dec 2023 21:24:52 +0100 Subject: [PATCH 3/5] Only create `BlobReader` when absolutely necessary --- ICSharpCode.ILSpyX/PdbProvider/PortableDebugInfoProvider.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ICSharpCode.ILSpyX/PdbProvider/PortableDebugInfoProvider.cs b/ICSharpCode.ILSpyX/PdbProvider/PortableDebugInfoProvider.cs index f56d79579d..e4df859d7b 100644 --- a/ICSharpCode.ILSpyX/PdbProvider/PortableDebugInfoProvider.cs +++ b/ICSharpCode.ILSpyX/PdbProvider/PortableDebugInfoProvider.cs @@ -199,10 +199,10 @@ public bool TryGetExtraTypeInfo(MethodDefinitionHandle method, int index, continue; if (cdi.Value.IsNil || cdi.Kind.IsNil) continue; - var reader = metadata.GetBlobReader(cdi.Value); var kind = metadata.GetGuid(cdi.Kind); if (kind == KnownGuids.TupleElementNames && tupleElementNames is null) { + var reader = metadata.GetBlobReader(cdi.Value); var list = new List(); while (reader.RemainingBytes > 0) { @@ -216,7 +216,7 @@ public bool TryGetExtraTypeInfo(MethodDefinitionHandle method, int index, } else if (kind == KnownGuids.DynamicLocalVariables && dynamicFlags is null) { - dynamicFlags = new bool[reader.Length * 8]; + var reader = metadata.GetBlobReader(cdi.Value); int j = 0; while (reader.RemainingBytes > 0) { From 38019ad5bf52dfa702ef3e8afd0487ac64bd60d6 Mon Sep 17 00:00:00 2001 From: ElektroKill Date: Thu, 14 Dec 2023 18:36:57 +0100 Subject: [PATCH 4/5] Introduce `PdbExtraTypeInfo` struct and adjusted `IDebugInfoProvider` --- .../DebugInfo/IDebugInfoProvider.cs | 8 +++++++- .../IL/ApplyPdbLocalTypeInfoTypeVisitor.cs | 10 +++++++++- ICSharpCode.Decompiler/IL/ILReader.cs | 5 ++--- .../PdbProvider/MonoCecilDebugInfoProvider.cs | 6 ++---- .../PdbProvider/PortableDebugInfoProvider.cs | 19 +++++++++---------- 5 files changed, 29 insertions(+), 19 deletions(-) diff --git a/ICSharpCode.Decompiler/DebugInfo/IDebugInfoProvider.cs b/ICSharpCode.Decompiler/DebugInfo/IDebugInfoProvider.cs index bab259b26b..810919e567 100644 --- a/ICSharpCode.Decompiler/DebugInfo/IDebugInfoProvider.cs +++ b/ICSharpCode.Decompiler/DebugInfo/IDebugInfoProvider.cs @@ -17,13 +17,19 @@ public Variable(int index, string name) public string Name { get; } } + public struct PdbExtraTypeInfo + { + public string[] TupleElementNames; + public bool[] DynamicFlags; + } + public interface IDebugInfoProvider { string Description { get; } IList GetSequencePoints(MethodDefinitionHandle method); IList GetVariables(MethodDefinitionHandle method); bool TryGetName(MethodDefinitionHandle method, int index, out string name); - bool TryGetExtraTypeInfo(MethodDefinitionHandle method, int index, out string[] tupleElementNames, out bool[] dynamicFlags); + bool TryGetExtraTypeInfo(MethodDefinitionHandle method, int index, out PdbExtraTypeInfo extraTypeInfo); string SourceFileName { get; } } } diff --git a/ICSharpCode.Decompiler/IL/ApplyPdbLocalTypeInfoTypeVisitor.cs b/ICSharpCode.Decompiler/IL/ApplyPdbLocalTypeInfoTypeVisitor.cs index a6b629f876..1d8796c1e7 100644 --- a/ICSharpCode.Decompiler/IL/ApplyPdbLocalTypeInfoTypeVisitor.cs +++ b/ICSharpCode.Decompiler/IL/ApplyPdbLocalTypeInfoTypeVisitor.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Immutable; +using ICSharpCode.Decompiler.DebugInfo; using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem.Implementation; @@ -16,12 +17,19 @@ sealed class ApplyPdbLocalTypeInfoTypeVisitor : TypeVisitor private int dynamicTypeIndex = 0; private int tupleTypeIndex = 0; - public ApplyPdbLocalTypeInfoTypeVisitor(bool[] dynamicData, string[] tupleElementNames) + private ApplyPdbLocalTypeInfoTypeVisitor(bool[] dynamicData, string[] tupleElementNames) { this.dynamicData = dynamicData; this.tupleElementNames = tupleElementNames; } + public static IType Apply(IType type, PdbExtraTypeInfo pdbExtraTypeInfo) + { + if (pdbExtraTypeInfo.DynamicFlags is null && pdbExtraTypeInfo.TupleElementNames is null) + return type; + return type.AcceptVisitor(new ApplyPdbLocalTypeInfoTypeVisitor(pdbExtraTypeInfo.DynamicFlags, pdbExtraTypeInfo.TupleElementNames)); + } + public override IType VisitModOpt(ModifiedType type) { dynamicTypeIndex++; diff --git a/ICSharpCode.Decompiler/IL/ILReader.cs b/ICSharpCode.Decompiler/IL/ILReader.cs index ae85ec79ce..4aaa4a739e 100644 --- a/ICSharpCode.Decompiler/IL/ILReader.cs +++ b/ICSharpCode.Decompiler/IL/ILReader.cs @@ -306,10 +306,9 @@ ILVariable CreateILVariable(int index, IType type) } if (UseDebugSymbols && DebugInfo is not null && - DebugInfo.TryGetExtraTypeInfo((MethodDefinitionHandle)method.MetadataToken, index, - out string[] tupleElementNames, out bool[] dynamicFlags)) + DebugInfo.TryGetExtraTypeInfo((MethodDefinitionHandle)method.MetadataToken, index, out var pdbExtraTypeInfo)) { - type = type.AcceptVisitor(new ApplyPdbLocalTypeInfoTypeVisitor(dynamicFlags, tupleElementNames)); + type = ApplyPdbLocalTypeInfoTypeVisitor.Apply(type, pdbExtraTypeInfo); } ILVariable ilVar = new ILVariable(kind, type, index); diff --git a/ICSharpCode.ILSpyX/PdbProvider/MonoCecilDebugInfoProvider.cs b/ICSharpCode.ILSpyX/PdbProvider/MonoCecilDebugInfoProvider.cs index 78f468a7e3..6fe3021bbb 100644 --- a/ICSharpCode.ILSpyX/PdbProvider/MonoCecilDebugInfoProvider.cs +++ b/ICSharpCode.ILSpyX/PdbProvider/MonoCecilDebugInfoProvider.cs @@ -136,13 +136,11 @@ public bool TryGetName(SRM.MethodDefinitionHandle handle, int index, [NotNullWhe return name != null; } - public bool TryGetExtraTypeInfo(SRM.MethodDefinitionHandle method, int index, - [NotNullWhen(true)] out string[]? tupleElementNames, [NotNullWhen(true)] out bool[]? dynamicFlags) + public bool TryGetExtraTypeInfo(SRM.MethodDefinitionHandle method, int index, out PdbExtraTypeInfo extraTypeInfo) { // Mono.Cecil's WindowsPDB reader is unable to read tuple element names // and dynamic flags custom debug information. - tupleElementNames = null; - dynamicFlags = null; + extraTypeInfo = default; return false; } } diff --git a/ICSharpCode.ILSpyX/PdbProvider/PortableDebugInfoProvider.cs b/ICSharpCode.ILSpyX/PdbProvider/PortableDebugInfoProvider.cs index e4df859d7b..0ad89015d9 100644 --- a/ICSharpCode.ILSpyX/PdbProvider/PortableDebugInfoProvider.cs +++ b/ICSharpCode.ILSpyX/PdbProvider/PortableDebugInfoProvider.cs @@ -162,12 +162,10 @@ public bool TryGetName(MethodDefinitionHandle method, int index, [NotNullWhen(tr return false; } - public bool TryGetExtraTypeInfo(MethodDefinitionHandle method, int index, - [NotNullWhen(true)] out string?[]? tupleElementNames, [NotNullWhen(true)] out bool[]? dynamicFlags) + public bool TryGetExtraTypeInfo(MethodDefinitionHandle method, int index, out PdbExtraTypeInfo extraTypeInfo) { var metadata = GetMetadataReader(); - tupleElementNames = null; - dynamicFlags = null; + extraTypeInfo = default; if (metadata == null) return false; @@ -200,7 +198,7 @@ public bool TryGetExtraTypeInfo(MethodDefinitionHandle method, int index, if (cdi.Value.IsNil || cdi.Kind.IsNil) continue; var kind = metadata.GetGuid(cdi.Kind); - if (kind == KnownGuids.TupleElementNames && tupleElementNames is null) + if (kind == KnownGuids.TupleElementNames && extraTypeInfo.TupleElementNames is null) { var reader = metadata.GetBlobReader(cdi.Value); var list = new List(); @@ -212,25 +210,26 @@ public bool TryGetExtraTypeInfo(MethodDefinitionHandle method, int index, list.Add(string.IsNullOrWhiteSpace(s) ? null : s); } - tupleElementNames = list.ToArray(); + extraTypeInfo.TupleElementNames = list.ToArray(); } - else if (kind == KnownGuids.DynamicLocalVariables && dynamicFlags is null) + else if (kind == KnownGuids.DynamicLocalVariables && extraTypeInfo.DynamicFlags is null) { var reader = metadata.GetBlobReader(cdi.Value); + extraTypeInfo.DynamicFlags = new bool[reader.Length * 8]; int j = 0; while (reader.RemainingBytes > 0) { int b = reader.ReadByte(); for (int i = 1; i < 0x100; i <<= 1) - dynamicFlags[j++] = (b & i) != 0; + extraTypeInfo.DynamicFlags[j++] = (b & i) != 0; } } - if (tupleElementNames != null && dynamicFlags != null) + if (extraTypeInfo.TupleElementNames != null && extraTypeInfo.DynamicFlags != null) break; } - return tupleElementNames != null || dynamicFlags != null; + return extraTypeInfo.TupleElementNames != null || extraTypeInfo.DynamicFlags != null; } } } From eefb46688de676e2617ec050aa4c070340b04e92 Mon Sep 17 00:00:00 2001 From: ElektroKill Date: Sun, 24 Dec 2023 13:48:01 +0100 Subject: [PATCH 5/5] Clarify reading of UTF8 null-terminated strings in `TryGetExtraTypeInfo` --- ICSharpCode.ILSpyX/PdbProvider/PortableDebugInfoProvider.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ICSharpCode.ILSpyX/PdbProvider/PortableDebugInfoProvider.cs b/ICSharpCode.ILSpyX/PdbProvider/PortableDebugInfoProvider.cs index 0ad89015d9..5cacbbe6dc 100644 --- a/ICSharpCode.ILSpyX/PdbProvider/PortableDebugInfoProvider.cs +++ b/ICSharpCode.ILSpyX/PdbProvider/PortableDebugInfoProvider.cs @@ -204,8 +204,10 @@ public bool TryGetExtraTypeInfo(MethodDefinitionHandle method, int index, out Pd var list = new List(); while (reader.RemainingBytes > 0) { + // Read a UTF8 null-terminated string int length = reader.IndexOf(0); string s = reader.ReadUTF8(length); + // Skip null terminator reader.ReadByte(); list.Add(string.IsNullOrWhiteSpace(s) ? null : s); }