You've already forked linux-packaging-mono
Imported Upstream version 4.2.0.179
Former-commit-id: 0a113cb3a6feb7873f632839b1307cc6033cd595
This commit is contained in:
committed by
Jo Shields
parent
183bba2c9a
commit
6992685b86
168
mcs/tools/mono-symbolicate/LocationProvider.cs
Normal file
168
mcs/tools/mono-symbolicate/LocationProvider.cs
Normal file
@@ -0,0 +1,168 @@
|
||||
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;
|
||||
|
||||
namespace Symbolicate
|
||||
{
|
||||
struct Location {
|
||||
public string FileName;
|
||||
public int Line;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
assemblyPath = Path.GetFullPath (assemblyPath);
|
||||
if (assemblies.ContainsKey (assemblyPath))
|
||||
return;
|
||||
|
||||
if (!File.Exists (assemblyPath))
|
||||
throw new ArgumentException ("assemblyPath does not exist: "+ assemblyPath);
|
||||
|
||||
var assembly = Assembly.LoadFrom (assemblyPath);
|
||||
MonoSymbolFile symbolFile = null;
|
||||
|
||||
var symbolPath = assemblyPath + ".mdb";
|
||||
if (!File.Exists (symbolPath))
|
||||
Debug.WriteLine (".mdb file was not found for " + assemblyPath);
|
||||
else
|
||||
symbolFile = MonoSymbolFile.ReadSymbolFile (assemblyPath + ".mdb");
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
directories.Add (directory);
|
||||
}
|
||||
|
||||
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))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
52
mcs/tools/mono-symbolicate/Makefile
Normal file
52
mcs/tools/mono-symbolicate/Makefile
Normal file
@@ -0,0 +1,52 @@
|
||||
thisdir = tools/mono-symbolicate
|
||||
SUBDIRS =
|
||||
include ../../build/rules.make
|
||||
|
||||
PROGRAM = mono-symbolicate.exe
|
||||
|
||||
LOCAL_MCS_FLAGS = \
|
||||
/r:Mono.Cecil.dll \
|
||||
/r:Mono.CompilerServices.SymbolWriter.dll \
|
||||
/r:System.Xml
|
||||
|
||||
include ../../build/executable.make
|
||||
|
||||
LIB_PATH = $(topdir)/class/lib/$(PROFILE)
|
||||
|
||||
MONO = MONO_PATH=$(LIB_PATH)$(PLATFORM_PATH_SEPARATOR)$$MONO_PATH $(RUNTIME) -O=-inline
|
||||
|
||||
OUT_DIR = Test/out
|
||||
TEST_CS = Test/StackTraceDumper.cs
|
||||
TEST_EXE = $(OUT_DIR)/StackTraceDumper.exe
|
||||
RELEASE_FILE = $(OUT_DIR)/release.out
|
||||
SYMBOLICATE_FILE = $(OUT_DIR)/symbolicate.out
|
||||
SYMBOLICATE_EXPECTED_FILE = Test/symbolicate.expected
|
||||
|
||||
CHECK_DIFF = @\
|
||||
MONO_DEBUG=gen-compact-seq-points $(MONO) $(TEST_EXE) > $(RELEASE_FILE); \
|
||||
$(MONO) $(LIB_PATH)/$(PROGRAM) $(TEST_EXE) $(RELEASE_FILE) | sed "s/).*Test\//) in /" > $(SYMBOLICATE_FILE); \
|
||||
DIFF=$$(diff $(SYMBOLICATE_FILE) $(SYMBOLICATE_EXPECTED_FILE)); \
|
||||
if [ ! -z "$$DIFF" ]; then \
|
||||
echo "Symbolicate tests failed."; \
|
||||
echo "If $(SYMBOLICATE_FILE) is correct copy it to $(SYMBOLICATE_EXPECTED_FILE)."; \
|
||||
echo "Otherwise runtime sequence points need to be fixed."; \
|
||||
echo "$$DIFF"; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
BUILD_TEST_EXE = @\
|
||||
rm -rf $(OUT_DIR); \
|
||||
mkdir -p $(OUT_DIR); \
|
||||
$(MCS) -debug $(TEST_CS) -out:$(TEST_EXE)
|
||||
|
||||
check: all
|
||||
$(BUILD_TEST_EXE)
|
||||
@echo "Checking $(PROGRAM) without AOT"
|
||||
$(CHECK_DIFF)
|
||||
@echo "Checking $(PROGRAM) with AOT"
|
||||
@MONO_DEBUG=gen-compact-seq-points $(MONO) --aot $(TEST_EXE) > /dev/null
|
||||
$(CHECK_DIFF)
|
||||
@echo "Checking $(PROGRAM) with AOT (using .msym)"
|
||||
$(BUILD_TEST_EXE)
|
||||
@MONO_DEBUG=gen-compact-seq-points $(MONO) --aot=gen-seq-points-file $(TEST_EXE) > /dev/null
|
||||
$(CHECK_DIFF)
|
2
mcs/tools/mono-symbolicate/mono-symbolicate.exe.sources
Normal file
2
mcs/tools/mono-symbolicate/mono-symbolicate.exe.sources
Normal file
@@ -0,0 +1,2 @@
|
||||
symbolicate.cs
|
||||
LocationProvider.cs
|
89
mcs/tools/mono-symbolicate/symbolicate.cs
Normal file
89
mcs/tools/mono-symbolicate/symbolicate.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Globalization;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Symbolicate
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
static Regex regex = new Regex (@"\w*at (?<Method>.+) *(\[0x(?<IL>.+)\]|<0x.+ \+ 0x(?<NativeOffset>.+)>( (?<MethodIndex>\d+)|)) in <filename unknown>:0");
|
||||
|
||||
public static int Main (String[] args)
|
||||
{
|
||||
if (args.Length < 2) {
|
||||
Console.Error.WriteLine ("Usage: symbolicate <assembly path> <input file> [lookup directories]");
|
||||
return 1;
|
||||
}
|
||||
|
||||
var assemblyPath = args [0];
|
||||
var inputFile = args [1];
|
||||
|
||||
var locProvider = new LocationProvider ();
|
||||
|
||||
for (var i = 2; i < args.Length; i++)
|
||||
locProvider.AddDirectory (args [i]);
|
||||
|
||||
locProvider.AddAssembly (assemblyPath);
|
||||
|
||||
using (StreamReader r = new StreamReader (inputFile)) {
|
||||
for (var line = r.ReadLine (); line != null; line = r.ReadLine ()) {
|
||||
line = SymbolicateLine (line, locProvider);
|
||||
Console.WriteLine (line);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static string SymbolicateLine (string line, LocationProvider locProvider)
|
||||
{
|
||||
var match = regex.Match (line);
|
||||
if (!match.Success)
|
||||
return line;
|
||||
|
||||
string typeFullName;
|
||||
var methodStr = match.Groups ["Method"].Value.Trim ();
|
||||
if (!TryParseMethodType (methodStr, out typeFullName))
|
||||
return line;
|
||||
|
||||
var isOffsetIL = !string.IsNullOrEmpty (match.Groups ["IL"].Value);
|
||||
var offsetVarName = (isOffsetIL)? "IL" : "NativeOffset";
|
||||
var offset = int.Parse (match.Groups [offsetVarName].Value, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
|
||||
|
||||
uint methodIndex = 0xffffff;
|
||||
if (!string.IsNullOrEmpty (match.Groups ["MethodIndex"].Value))
|
||||
methodIndex = uint.Parse (match.Groups ["MethodIndex"].Value, CultureInfo.InvariantCulture);
|
||||
|
||||
Location location;
|
||||
if (!locProvider.TryGetLocation (methodStr, typeFullName, offset, isOffsetIL, methodIndex, out location))
|
||||
return line;
|
||||
|
||||
return line.Replace ("<filename unknown>:0", string.Format ("{0}:{1}", location.FileName, location.Line));
|
||||
}
|
||||
|
||||
static bool TryParseMethodType (string str, out string typeFullName)
|
||||
{
|
||||
typeFullName = null;
|
||||
|
||||
var methodNameEnd = str.IndexOf ("(");
|
||||
if (methodNameEnd == -1)
|
||||
return false;
|
||||
|
||||
// Remove parameters
|
||||
str = str.Substring (0, methodNameEnd);
|
||||
|
||||
// Remove generic parameters
|
||||
str = Regex.Replace (str, @"\[[^\[\]]*\]", "");
|
||||
|
||||
var typeNameEnd = str.LastIndexOf (".");
|
||||
if (methodNameEnd == -1 || typeNameEnd == -1)
|
||||
return false;
|
||||
|
||||
// Remove method name
|
||||
typeFullName = str.Substring (0, typeNameEnd);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user