public static void UpdateDebugInfo(this MethodDefinition method) { if (!method.HasBody || !method.DebugInformation.HasSequencePoints) { return; } var debugInfo = method.DebugInformation; var instructions = method.Body.Instructions; var scope = debugInfo.Scope; if (scope == null || instructions.Count == 0) { return; } // Step 1: check if all variables are present foreach (var variable in method.Body.Variables) { var hasVariable = scope.Variables.Any(x => x.Index == variable.Index); if (!hasVariable) { var variableDebugInfo = new VariableDebugInformation(variable, $"__var_{variable.Index}"); scope.Variables.Add(variableDebugInfo); } } // Step 2: update the scopes by setting the indices scope.Start = new InstructionOffset(instructions.First()); scope.End = new InstructionOffset(instructions.Last()); }
public static VariableDefinition DeclareVariable(this MethodBody body, string name, TypeReference type) { var variable = new VariableDefinition(type); body.Variables.Add(variable); var variableDebug = new VariableDebugInformation(variable, name); body.Method?.DebugInformation?.Scope?.Variables?.Add(variableDebug); return(variable); }
void DefineLocalVariable(VariableDebugInformation variable, int local_var_token, int start_offset, int end_offset) { writer.DefineLocalVariable2( variable.Name, variable.Attributes, local_var_token, variable.Index, 0, 0, start_offset, end_offset); }
void CreateLocalVariable(VariableDebugInformation variable, SymbolToken local_var_token, int start_offset, int end_offset) { writer.DefineLocalVariable2( variable.Name, variable.Attributes, local_var_token, SymAddressKind.ILOffset, variable.Index, 0, 0, start_offset, end_offset); }
public static void UpdateDebugInfo(this MethodDefinition method) { var debugInfo = method?.DebugInformation; if (debugInfo == null || !method.HasBody || !debugInfo.HasSequencePoints) { return; } var methodBody = method.Body; var instructions = methodBody.Instructions; var scope = debugInfo.Scope; if (scope == null || instructions.Count == 0) { return; } // Step 1: check if all variables are present foreach (var variable in methodBody.Variables) { var hasVariable = scope.Variables.Any(x => x.Index == variable.Index); if (!hasVariable) { var variableDebugInfo = new VariableDebugInformation(variable, $"__var_{variable.Index}"); scope.Variables.Add(variableDebugInfo); } } // Step 2: point the first sequence point to the first instruction; this will include null guard added IL in the first instruction. if (debugInfo.HasSequencePoints) { var sequencePoints = debugInfo.SequencePoints; var s = sequencePoints?.FirstOrDefault(); if (s?.Offset == 0) { var entry = instructions[0]; sequencePoints[0] = new SequencePoint(entry, s.Document) { StartColumn = s.StartColumn, StartLine = s.StartLine, EndColumn = s.EndColumn, EndLine = s.EndLine }; scope.Start = new InstructionOffset(entry); } } }
static ScopeDebugInformation ReadScopeAndLocals(PdbScope scope, MethodDebugInformation info) { var parent = new ScopeDebugInformation(); parent.Start = new InstructionOffset((int)scope.offset); parent.End = new InstructionOffset((int)(scope.offset + scope.length)); if (!scope.slots.IsNullOrEmpty()) { parent.variables = new Collection <VariableDebugInformation> (scope.slots.Length); foreach (PdbSlot slot in scope.slots) { if (slot.flags == 1) // parameter names { continue; } var index = (int)slot.slot; var variable = new VariableDebugInformation(index, slot.name); if (slot.flags == 4) { variable.IsDebuggerHidden = true; } parent.variables.Add(variable); } } if (!scope.constants.IsNullOrEmpty()) { parent.constants = new Collection <ConstantDebugInformation> (scope.constants.Length); foreach (var constant in scope.constants) { parent.constants.Add(new ConstantDebugInformation( constant.name, (TypeReference)info.method.Module.LookupToken((int)constant.token), constant.value)); } } parent.scopes = ReadScopeAndLocals(scope.scopes, info); return(parent); }
static void ReadLocalVariables(MethodEntry entry, ScopeDebugInformation [] scopes) { var locals = entry.GetLocals(); foreach (var local in locals) { var variable = new VariableDebugInformation(local.Index, local.Name); var index = local.BlockIndex; if (index < 0 || index >= scopes.Length) { continue; } var scope = scopes [index]; if (scope == null) { continue; } scope.Variables.Add(variable); } }
public VarInfo(VariableDebugInformation v) { this.Name = v.Name; this.Index = v.Index; }
public static void UpdateDebugInfo(this MethodDefinition method) { if (!method.HasBody || !method.DebugInformation.HasSequencePoints) { return; } var debugInfo = method.DebugInformation; var instructions = method.Body.Instructions; var scope = debugInfo.Scope; if (scope == null || instructions.Count == 0) { return; } var oldSequencePoints = debugInfo.SequencePoints; var newSequencePoints = new Collection <SequencePoint>(); // Step 1: check if all variables are present foreach (var variable in method.Body.Variables) { var hasVariable = scope.Variables.Any(x => x.Index == variable.Index); if (!hasVariable) { var variableDebugInfo = new VariableDebugInformation(variable, $"__var_{variable.Index}"); scope.Variables.Add(variableDebugInfo); } } // Step 2: Make sure the instructions point to the correct items foreach (var oldSequencePoint in oldSequencePoints) { var instructionOffset = (InstructionOffset)SequencePointOffsetFieldInfo.GetValue(oldSequencePoint); var offsetInstruction = (Instruction)InstructionOffsetInstructionFieldInfo.GetValue(instructionOffset); // Fix offset for (var i = 0; i < instructions.Count; i++) { var instruction = instructions[i]; if (instruction == offsetInstruction) { var newSequencePoint = new SequencePoint(instruction, oldSequencePoint.Document) { StartLine = oldSequencePoint.StartLine, StartColumn = oldSequencePoint.StartColumn, EndLine = oldSequencePoint.EndLine, EndColumn = oldSequencePoint.EndColumn }; newSequencePoints.Add(newSequencePoint); break; } } } debugInfo.SequencePoints.Clear(); foreach (var newSequencePoint in newSequencePoints) { debugInfo.SequencePoints.Add(newSequencePoint); } // Step 3: update the scopes by setting the indices scope.Start = new InstructionOffset(instructions.First()); scope.End = new InstructionOffset(instructions.Last()); }
ScopeDebugInformation ReadScopeAndLocals(PdbScope scope, MethodDebugInformation info) { var parent = new ScopeDebugInformation(); parent.Start = new InstructionOffset((int)scope.offset); parent.End = new InstructionOffset((int)(scope.offset + scope.length)); if (!scope.slots.IsNullOrEmpty()) { parent.variables = new Collection <VariableDebugInformation> (scope.slots.Length); foreach (PdbSlot slot in scope.slots) { if ((slot.flags & 1) != 0) // parameter names { continue; } var index = (int)slot.slot; var variable = new VariableDebugInformation(index, slot.name); if ((slot.flags & 4) != 0) { variable.IsDebuggerHidden = true; } parent.variables.Add(variable); } } if (!scope.constants.IsNullOrEmpty()) { parent.constants = new Collection <ConstantDebugInformation> (scope.constants.Length); foreach (var constant in scope.constants) { var type = info.Method.Module.Read(constant, (c, r) => r.ReadConstantSignature(new MetadataToken(c.token))); var value = constant.value; // Object "null" is encoded as integer if (type != null && !type.IsValueType && value is int && (int)value == 0) { value = null; } parent.constants.Add(new ConstantDebugInformation(constant.name, type, value)); } } if (!scope.usedNamespaces.IsNullOrEmpty()) { ImportDebugInformation import; if (imports.TryGetValue(scope, out import)) { parent.import = import; } else { import = GetImport(scope, info.Method.Module); imports.Add(scope, import); parent.import = import; } } parent.scopes = ReadScopeAndLocals(scope.scopes, info); return(parent); }
public static void UpdateDebugInfo(this MethodDefinition method) { var debugInfo = method.DebugInformation; var instructions = method.Body.Instructions; var scope = debugInfo.Scope; if (scope == null || instructions.Count == 0) { return; } var oldSequencePoints = debugInfo.SequencePoints; var newSequencePoints = new Collection <SequencePoint>(); // Step 1: check if all variables are present foreach (var variable in method.Body.Variables) { if (method.IsAsyncMethod()) { // Skip some special items of an async method: // 1) int (state?) // 2) exception if (variable.Index == 0 && variable.VariableType.Name.Contains("Int") || variable.VariableType.Name.Contains("Exception")) { continue; } } if (!ContainsVariable(scope, variable)) { var variableDebugInfo = new VariableDebugInformation(variable, $"__var_{variable.Index}"); scope.Variables.Add(variableDebugInfo); } } // Step 2: Make sure the instructions point to the correct items foreach (var oldSequencePoint in oldSequencePoints) { //var isValid = false; //// Special cases we need to ignore //if (oldSequencePoint.StartLine == AddressToIgnore || // oldSequencePoint.EndLine == AddressToIgnore) //{ // continue; //} var instructionOffset = (InstructionOffset)SequencePointOffsetFieldInfo.GetValue(oldSequencePoint); var offsetInstruction = (Instruction)InstructionOffsetInstructionFieldInfo.GetValue(instructionOffset); // Fix offset for (var i = 0; i < instructions.Count; i++) { var instruction = instructions[i]; if (instruction == offsetInstruction) { var newSequencePoint = new SequencePoint(instruction, oldSequencePoint.Document) { StartLine = oldSequencePoint.StartLine, StartColumn = oldSequencePoint.StartColumn, EndLine = oldSequencePoint.EndLine, EndColumn = oldSequencePoint.EndColumn }; newSequencePoints.Add(newSequencePoint); //isValid = true; break; } } } debugInfo.SequencePoints.Clear(); foreach (var newSequencePoint in newSequencePoints) { debugInfo.SequencePoints.Add(newSequencePoint); } // Step 3: Remove any unused variables RemoveUnusedVariablesFromDebugInfo(scope); // Final step: update the scopes by setting the indices scope.Start = new InstructionOffset(instructions.First()); scope.End = new InstructionOffset(instructions.Last()); }