obfuz/Plugins/dnlib/DotNet/Pdb/Portable/PortablePdbCustomDebugInfoR...

306 lines
9.9 KiB
C#

// dnlib: See LICENSE.txt for more info
// See Roslyn files: MethodDebugInfo.Portable.cs, MetadataWriter.PortablePdb.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using dnlib.DotNet.Emit;
using dnlib.DotNet.MD;
using dnlib.IO;
namespace dnlib.DotNet.Pdb.Portable {
struct PortablePdbCustomDebugInfoReader {
public static PdbCustomDebugInfo Read(ModuleDef module, TypeDef typeOpt, CilBody bodyOpt, GenericParamContext gpContext, Guid kind, ref DataReader reader) {
try {
var cdiReader = new PortablePdbCustomDebugInfoReader(module, typeOpt, bodyOpt, gpContext, ref reader);
var cdi = cdiReader.Read(kind);
Debug.Assert(cdiReader.reader.Position == cdiReader.reader.Length);
return cdi;
}
catch (ArgumentException) {
}
catch (OutOfMemoryException) {
}
catch (IOException) {
}
return null;
}
readonly ModuleDef module;
readonly TypeDef typeOpt;
readonly CilBody bodyOpt;
readonly GenericParamContext gpContext;
DataReader reader;
PortablePdbCustomDebugInfoReader(ModuleDef module, TypeDef typeOpt, CilBody bodyOpt, GenericParamContext gpContext, ref DataReader reader) {
this.module = module;
this.typeOpt = typeOpt;
this.bodyOpt = bodyOpt;
this.gpContext = gpContext;
this.reader = reader;
}
PdbCustomDebugInfo Read(Guid kind) {
if (kind == CustomDebugInfoGuids.AsyncMethodSteppingInformationBlob)
return ReadAsyncMethodSteppingInformationBlob();
if (kind == CustomDebugInfoGuids.DefaultNamespace)
return ReadDefaultNamespace();
if (kind == CustomDebugInfoGuids.DynamicLocalVariables)
return ReadDynamicLocalVariables(reader.Length);
if (kind == CustomDebugInfoGuids.EmbeddedSource)
return ReadEmbeddedSource();
if (kind == CustomDebugInfoGuids.EncLambdaAndClosureMap)
return ReadEncLambdaAndClosureMap(reader.Length);
if (kind == CustomDebugInfoGuids.EncLocalSlotMap)
return ReadEncLocalSlotMap(reader.Length);
if (kind == CustomDebugInfoGuids.SourceLink)
return ReadSourceLink();
if (kind == CustomDebugInfoGuids.StateMachineHoistedLocalScopes)
return ReadStateMachineHoistedLocalScopes();
if (kind == CustomDebugInfoGuids.TupleElementNames)
return ReadTupleElementNames();
if (kind == CustomDebugInfoGuids.CompilationMetadataReferences)
return ReadCompilationMetadataReferences();
if (kind == CustomDebugInfoGuids.CompilationOptions)
return ReadCompilationOptions();
if (kind == CustomDebugInfoGuids.TypeDefinitionDocuments)
return ReadTypeDefinitionDocuments();
if (kind == CustomDebugInfoGuids.EncStateMachineStateMap)
return ReadEncStateMachineStateMap();
if (kind == CustomDebugInfoGuids.PrimaryConstructorInformationBlob)
return ReadPrimaryConstructorInformationBlob();
Debug.Fail($"Unknown custom debug info guid: {kind}");
return new PdbUnknownCustomDebugInfo(kind, reader.ReadRemainingBytes());
}
PdbCustomDebugInfo ReadAsyncMethodSteppingInformationBlob() {
if (bodyOpt is null)
return null;
uint catchHandlerOffset = reader.ReadUInt32() - 1;
Instruction catchHandler;
if (catchHandlerOffset == uint.MaxValue)
catchHandler = null;
else {
catchHandler = GetInstruction(catchHandlerOffset);
Debug.Assert(catchHandler is not null);
if (catchHandler is null)
return null;
}
var asyncInfo = new PdbAsyncMethodSteppingInformationCustomDebugInfo();
asyncInfo.CatchHandler = catchHandler;
while (reader.Position < reader.Length) {
var yieldInstr = GetInstruction(reader.ReadUInt32());
Debug.Assert(yieldInstr is not null);
if (yieldInstr is null)
return null;
uint resumeOffset = reader.ReadUInt32();
var moveNextRid = reader.ReadCompressedUInt32();
var moveNextToken = new MDToken(Table.Method, moveNextRid);
MethodDef moveNextMethod;
Instruction resumeInstr;
if (gpContext.Method is not null && moveNextToken == gpContext.Method.MDToken) {
moveNextMethod = gpContext.Method;
resumeInstr = GetInstruction(resumeOffset);
}
else {
moveNextMethod = module.ResolveToken(moveNextToken, gpContext) as MethodDef;
Debug.Assert(moveNextMethod is not null);
if (moveNextMethod is null)
return null;
resumeInstr = GetInstruction(moveNextMethod, resumeOffset);
}
Debug.Assert(resumeInstr is not null);
if (resumeInstr is null)
return null;
asyncInfo.AsyncStepInfos.Add(new PdbAsyncStepInfo(yieldInstr, moveNextMethod, resumeInstr));
}
return asyncInfo;
}
PdbCustomDebugInfo ReadDefaultNamespace() {
var defaultNs = reader.ReadUtf8String((int)reader.BytesLeft);
return new PdbDefaultNamespaceCustomDebugInfo(defaultNs);
}
PdbCustomDebugInfo ReadDynamicLocalVariables(long recPosEnd) {
var flags = new bool[(int)reader.Length * 8];
int w = 0;
while (reader.Position < reader.Length) {
int b = reader.ReadByte();
for (int i = 1; i < 0x100; i <<= 1)
flags[w++] = (b & i) != 0;
}
return new PdbDynamicLocalVariablesCustomDebugInfo(flags);
}
PdbCustomDebugInfo ReadEmbeddedSource() => new PdbEmbeddedSourceCustomDebugInfo(reader.ReadRemainingBytes());
PdbCustomDebugInfo ReadEncLambdaAndClosureMap(long recPosEnd) {
var data = reader.ReadBytes((int)(recPosEnd - reader.Position));
return new PdbEditAndContinueLambdaMapCustomDebugInfo(data);
}
PdbCustomDebugInfo ReadEncLocalSlotMap(long recPosEnd) {
var data = reader.ReadBytes((int)(recPosEnd - reader.Position));
return new PdbEditAndContinueLocalSlotMapCustomDebugInfo(data);
}
PdbCustomDebugInfo ReadSourceLink() => new PdbSourceLinkCustomDebugInfo(reader.ReadRemainingBytes());
PdbCustomDebugInfo ReadStateMachineHoistedLocalScopes() {
if (bodyOpt is null)
return null;
int count = (int)(reader.Length / 8);
var smScope = new PdbStateMachineHoistedLocalScopesCustomDebugInfo(count);
for (int i = 0; i < count; i++) {
uint startOffset = reader.ReadUInt32();
uint length = reader.ReadUInt32();
if (startOffset == 0 && length == 0)
smScope.Scopes.Add(new StateMachineHoistedLocalScope());
else {
var start = GetInstruction(startOffset);
var end = GetInstruction(startOffset + length);
Debug.Assert(start is not null);
if (start is null)
return null;
smScope.Scopes.Add(new StateMachineHoistedLocalScope(start, end));
}
}
return smScope;
}
PdbCustomDebugInfo ReadTupleElementNames() {
var tupleListRec = new PortablePdbTupleElementNamesCustomDebugInfo();
while (reader.Position < reader.Length) {
var name = ReadUTF8Z(reader.Length);
tupleListRec.Names.Add(name);
}
return tupleListRec;
}
string ReadUTF8Z(long recPosEnd) {
if (reader.Position > recPosEnd)
return null;
return reader.TryReadZeroTerminatedUtf8String();
}
PdbCustomDebugInfo ReadCompilationMetadataReferences() {
var cdi = new PdbCompilationMetadataReferencesCustomDebugInfo();
while (reader.BytesLeft > 0) {
var name = reader.TryReadZeroTerminatedUtf8String();
Debug.Assert(name is not null);
if (name is null)
break;
var aliases = reader.TryReadZeroTerminatedUtf8String();
Debug.Assert(aliases is not null);
if (aliases is null)
break;
const uint RequiredBytes = 1 + 4 + 4 + 16;
Debug.Assert(reader.BytesLeft >= RequiredBytes);
if (reader.BytesLeft < RequiredBytes)
break;
var flags = (PdbCompilationMetadataReferenceFlags)reader.ReadByte();
uint timestamp = reader.ReadUInt32();
uint sizeOfImage = reader.ReadUInt32();
var mvid = reader.ReadGuid();
var mdRef = new PdbCompilationMetadataReference(name, aliases, flags, timestamp, sizeOfImage, mvid);
cdi.References.Add(mdRef);
}
return cdi;
}
PdbCustomDebugInfo ReadCompilationOptions() {
var cdi = new PdbCompilationOptionsCustomDebugInfo();
while (reader.BytesLeft > 0) {
var key = reader.TryReadZeroTerminatedUtf8String();
Debug.Assert(key is not null);
if (key is null)
break;
var value = reader.TryReadZeroTerminatedUtf8String();
Debug.Assert(value is not null);
if (value is null)
break;
cdi.Options.Add(new KeyValuePair<string, string>(key, value));
}
return cdi;
}
PdbCustomDebugInfo ReadTypeDefinitionDocuments() {
var docList = new List<MDToken>();
while (reader.BytesLeft > 0)
docList.Add(new MDToken(Table.Document, reader.ReadCompressedUInt32()));
return new PdbTypeDefinitionDocumentsDebugInfoMD(module, docList);
}
PdbCustomDebugInfo ReadEncStateMachineStateMap() {
var cdi = new PdbEditAndContinueStateMachineStateMapDebugInfo();
var count = reader.ReadCompressedUInt32();
if (count > 0) {
long syntaxOffsetBaseline = -reader.ReadCompressedUInt32();
while (count > 0) {
int stateNumber = reader.ReadCompressedInt32();
int syntaxOffset = (int)(syntaxOffsetBaseline + reader.ReadCompressedUInt32());
cdi.StateMachineStates.Add(new StateMachineStateInfo(syntaxOffset, (StateMachineState)stateNumber));
count--;
}
}
return cdi;
}
PdbCustomDebugInfo ReadPrimaryConstructorInformationBlob() =>
new PrimaryConstructorInformationBlobDebugInfo(reader.ReadRemainingBytes());
Instruction GetInstruction(uint offset) {
var instructions = bodyOpt.Instructions;
int lo = 0, hi = instructions.Count - 1;
while (lo <= hi && hi != -1) {
int i = (lo + hi) / 2;
var instr = instructions[i];
if (instr.Offset == offset)
return instr;
if (offset < instr.Offset)
hi = i - 1;
else
lo = i + 1;
}
return null;
}
static Instruction GetInstruction(MethodDef method, uint offset) {
if (method is null)
return null;
var body = method.Body;
if (body is null)
return null;
var instructions = body.Instructions;
int lo = 0, hi = instructions.Count - 1;
while (lo <= hi && hi != -1) {
int i = (lo + hi) / 2;
var instr = instructions[i];
if (instr.Offset == offset)
return instr;
if (offset < instr.Offset)
hi = i - 1;
else
lo = i + 1;
}
return null;
}
}
}