You've already forked linux-packaging-mono
Imported Upstream version 4.6.0.125
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
parent
a569aebcfd
commit
e79aa3c0ed
@ -2,167 +2,170 @@ using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Reflection;
|
||||
using System.Diagnostics;
|
||||
using System.Collections.Generic;
|
||||
using Mono.Cecil;
|
||||
using Mono.CompilerServices.SymbolWriter;
|
||||
using Mono.Cecil.Cil;
|
||||
using Mono.Collections.Generic;
|
||||
|
||||
namespace Symbolicate
|
||||
namespace Mono
|
||||
{
|
||||
struct Location {
|
||||
public string FileName;
|
||||
public int Line;
|
||||
}
|
||||
class AssemblyLocationProvider
|
||||
{
|
||||
AssemblyDefinition assembly;
|
||||
Logger logger;
|
||||
|
||||
class LocationProvider {
|
||||
class AssemblyLocationProvider {
|
||||
Assembly assembly;
|
||||
MonoSymbolFile symbolFile;
|
||||
string seqPointDataPath;
|
||||
|
||||
public AssemblyLocationProvider (Assembly assembly, MonoSymbolFile symbolFile, string seqPointDataPath)
|
||||
{
|
||||
this.assembly = assembly;
|
||||
this.symbolFile = symbolFile;
|
||||
this.seqPointDataPath = seqPointDataPath;
|
||||
}
|
||||
|
||||
public bool TryGetLocation (string methodStr, string typeFullName, int offset, bool isOffsetIL, uint methodIndex, out Location location)
|
||||
{
|
||||
location = default (Location);
|
||||
if (symbolFile == null)
|
||||
return false;
|
||||
|
||||
var type = assembly.GetTypes().FirstOrDefault (t => t.FullName == typeFullName);
|
||||
if (type == null)
|
||||
return false;
|
||||
|
||||
var bindingflags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
|
||||
var method = type.GetMethods(bindingflags).FirstOrDefault (m => GetMethodFullName (m) == methodStr);
|
||||
if (method == null)
|
||||
return false;
|
||||
|
||||
int ilOffset = (isOffsetIL)? offset : GetILOffsetFromFile (method.MetadataToken, methodIndex, offset);
|
||||
if (ilOffset < 0)
|
||||
return false;
|
||||
|
||||
var methodSymbol = symbolFile.Methods [(method.MetadataToken & 0x00ffffff) - 1];
|
||||
|
||||
var lineNumbers = methodSymbol.GetLineNumberTable ().LineNumbers;
|
||||
var lineNumber = lineNumbers.FirstOrDefault (l => l.Offset >= ilOffset) ?? lineNumbers.Last ();
|
||||
|
||||
location.FileName = symbolFile.Sources [lineNumber.File-1].FileName;
|
||||
location.Line = lineNumber.Row;
|
||||
return true;
|
||||
}
|
||||
|
||||
static MethodInfo methodGetIL;
|
||||
private int GetILOffsetFromFile (int methodToken, uint methodIndex, int nativeOffset)
|
||||
{
|
||||
if (string.IsNullOrEmpty (seqPointDataPath))
|
||||
return -1;
|
||||
|
||||
if (methodGetIL == null)
|
||||
methodGetIL = typeof (StackFrame).GetMethod ("GetILOffsetFromFile", BindingFlags.NonPublic | BindingFlags.Static);
|
||||
|
||||
if (methodGetIL == null)
|
||||
throw new Exception ("System.Diagnostics.StackFrame.GetILOffsetFromFile could not be found, make sure you have an updated mono installed.");
|
||||
|
||||
return (int) methodGetIL.Invoke (null, new object[] {seqPointDataPath, methodToken, methodIndex, nativeOffset});
|
||||
}
|
||||
|
||||
static MethodInfo methodGetMethodFullName;
|
||||
private string GetMethodFullName (MethodBase m)
|
||||
{
|
||||
|
||||
if (methodGetMethodFullName == null)
|
||||
methodGetMethodFullName = typeof (StackTrace).GetMethod ("GetFullNameForStackTrace", BindingFlags.NonPublic | BindingFlags.Static);
|
||||
|
||||
if (methodGetMethodFullName == null)
|
||||
throw new Exception ("System.Exception.GetFullNameForStackTrace could not be found, make sure you have an updated mono installed.");
|
||||
|
||||
StringBuilder sb = new StringBuilder ();
|
||||
methodGetMethodFullName.Invoke (null, new object[] {sb, m});
|
||||
|
||||
return sb.ToString ();
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary<string, AssemblyLocationProvider> assemblies;
|
||||
HashSet<string> directories;
|
||||
|
||||
public LocationProvider () {
|
||||
assemblies = new Dictionary<string, AssemblyLocationProvider> ();
|
||||
directories = new HashSet<string> ();
|
||||
}
|
||||
|
||||
public void AddAssembly (string assemblyPath)
|
||||
public AssemblyLocationProvider (string assemblyPath, Logger logger)
|
||||
{
|
||||
assemblyPath = Path.GetFullPath (assemblyPath);
|
||||
if (assemblies.ContainsKey (assemblyPath))
|
||||
return;
|
||||
this.logger = logger;
|
||||
|
||||
if (!File.Exists (assemblyPath))
|
||||
throw new ArgumentException ("assemblyPath does not exist: "+ assemblyPath);
|
||||
|
||||
var assembly = Assembly.LoadFrom (assemblyPath);
|
||||
MonoSymbolFile symbolFile = null;
|
||||
var readerParameters = new ReaderParameters { ReadSymbols = true };
|
||||
assembly = AssemblyDefinition.ReadAssembly (assemblyPath, readerParameters);
|
||||
}
|
||||
|
||||
var symbolPath = assemblyPath + ".mdb";
|
||||
if (!File.Exists (symbolPath))
|
||||
Debug.WriteLine (".mdb file was not found for " + assemblyPath);
|
||||
else
|
||||
symbolFile = MonoSymbolFile.ReadSymbolFile (assemblyPath + ".mdb");
|
||||
public bool TryResolveLocation (StackFrameData sfData, SeqPointInfo seqPointInfo)
|
||||
{
|
||||
if (!assembly.MainModule.HasSymbols)
|
||||
return false;
|
||||
|
||||
var seqPointDataPath = assemblyPath + ".msym";
|
||||
if (!File.Exists (seqPointDataPath))
|
||||
seqPointDataPath = null;
|
||||
|
||||
assemblies.Add (assemblyPath, new AssemblyLocationProvider (assembly, symbolFile, seqPointDataPath));
|
||||
|
||||
directories.Add (Path.GetDirectoryName (assemblyPath));
|
||||
|
||||
foreach (var assemblyRef in assembly.GetReferencedAssemblies ()) {
|
||||
string refPath = null;
|
||||
foreach (var dir in directories) {
|
||||
refPath = Path.Combine (dir, assemblyRef.Name);
|
||||
if (File.Exists (refPath))
|
||||
break;
|
||||
refPath = Path.Combine (dir, assemblyRef.Name + ".dll");
|
||||
if (File.Exists (refPath))
|
||||
break;
|
||||
refPath = Path.Combine (dir, assemblyRef.Name + ".exe");
|
||||
if (File.Exists (refPath))
|
||||
break;
|
||||
refPath = null;
|
||||
TypeDefinition type = null;
|
||||
var nested = sfData.TypeFullName.Split ('+');
|
||||
var types = assembly.MainModule.Types;
|
||||
foreach (var ntype in nested) {
|
||||
if (type == null) {
|
||||
// Use namespace first time.
|
||||
type = types.FirstOrDefault (t => t.FullName == ntype);
|
||||
} else {
|
||||
type = types.FirstOrDefault (t => t.Name == ntype);
|
||||
}
|
||||
if (refPath != null)
|
||||
AddAssembly (refPath);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddDirectory (string directory)
|
||||
{
|
||||
directory = Path.GetFullPath (directory);
|
||||
if (!Directory.Exists (directory)) {
|
||||
Console.Error.WriteLine ("Directory " + directory + " does not exist.");
|
||||
return;
|
||||
if (type == null) {
|
||||
logger.LogWarning ("Could not find type: {0}", ntype);
|
||||
return false;
|
||||
}
|
||||
|
||||
types = type.NestedTypes;
|
||||
}
|
||||
|
||||
directories.Add (directory);
|
||||
}
|
||||
var parensStart = sfData.MethodSignature.IndexOf ('(');
|
||||
var methodName = sfData.MethodSignature.Substring (0, parensStart).TrimEnd ();
|
||||
var methodParameters = sfData.MethodSignature.Substring (parensStart);
|
||||
var method = type.Methods.FirstOrDefault (m => CompareName (m, methodName) && CompareParameters (m.Parameters, methodParameters));
|
||||
if (method == null) {
|
||||
logger.LogWarning ("Could not find method: {0}", methodName);
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryGetLocation (string method, string typeFullName, int offset, bool isOffsetIL, uint methodIndex, out Location location)
|
||||
{
|
||||
location = default (Location);
|
||||
foreach (var assembly in assemblies.Values) {
|
||||
if (assembly.TryGetLocation (method, typeFullName, offset, isOffsetIL, methodIndex, out location))
|
||||
int ilOffset;
|
||||
if (sfData.IsILOffset) {
|
||||
ilOffset = sfData.Offset;
|
||||
} else {
|
||||
if (seqPointInfo == null)
|
||||
return false;
|
||||
|
||||
ilOffset = seqPointInfo.GetILOffset (method.MetadataToken.ToInt32 (), sfData.MethodIndex, sfData.Offset);
|
||||
}
|
||||
|
||||
if (ilOffset < 0)
|
||||
return false;
|
||||
|
||||
SequencePoint sp = null;
|
||||
foreach (var instr in method.Body.Instructions) {
|
||||
if (instr.SequencePoint != null)
|
||||
sp = instr.SequencePoint;
|
||||
|
||||
if (instr.Offset >= ilOffset) {
|
||||
sfData.SetLocation (sp.Document.Url, sp.StartLine);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool CompareName (MethodDefinition candidate, string expected)
|
||||
{
|
||||
if (candidate.Name == expected)
|
||||
return true;
|
||||
|
||||
if (!candidate.HasGenericParameters)
|
||||
return false;
|
||||
|
||||
var genStart = expected.IndexOf ('[');
|
||||
if (genStart < 0)
|
||||
return false;
|
||||
|
||||
if (candidate.Name != expected.Substring (0, genStart))
|
||||
return false;
|
||||
|
||||
int arity = 1;
|
||||
for (int pos = genStart; pos < expected.Length; ++pos) {
|
||||
if (expected [pos] == ',')
|
||||
++arity;
|
||||
}
|
||||
|
||||
return candidate.GenericParameters.Count == arity;
|
||||
}
|
||||
|
||||
static bool CompareParameters (Collection<ParameterDefinition> candidate, string expected)
|
||||
{
|
||||
var builder = new StringBuilder ();
|
||||
builder.Append ("(");
|
||||
|
||||
for (int i = 0; i < candidate.Count; i++) {
|
||||
var parameter = candidate [i];
|
||||
if (i > 0)
|
||||
builder.Append (", ");
|
||||
|
||||
if (parameter.ParameterType.IsSentinel)
|
||||
builder.Append ("...,");
|
||||
|
||||
var pt = parameter.ParameterType;
|
||||
if (!string.IsNullOrEmpty (pt.Namespace)) {
|
||||
builder.Append (pt.Namespace);
|
||||
builder.Append (".");
|
||||
}
|
||||
|
||||
FormatElementType (pt, builder);
|
||||
|
||||
builder.Append (" ");
|
||||
builder.Append (parameter.Name);
|
||||
}
|
||||
|
||||
builder.Append (")");
|
||||
|
||||
return builder.ToString () == expected;
|
||||
}
|
||||
|
||||
static void FormatElementType (TypeReference tr, StringBuilder builder)
|
||||
{
|
||||
var ts = tr as TypeSpecification;
|
||||
if (ts != null) {
|
||||
if (ts.IsByReference) {
|
||||
FormatElementType (ts.ElementType, builder);
|
||||
builder.Append ("&");
|
||||
return;
|
||||
}
|
||||
|
||||
var array = ts as ArrayType;
|
||||
if (array != null) {
|
||||
FormatElementType (ts.ElementType, builder);
|
||||
builder.Append ("[");
|
||||
|
||||
for (int ii = 0; ii < array.Rank - 1; ++ii) {
|
||||
builder.Append (",");
|
||||
}
|
||||
|
||||
builder.Append ("]");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
builder.Append (tr.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user