172 lines
6.9 KiB
C#
172 lines
6.9 KiB
C#
//
|
|
// PortablePdbData.cs
|
|
//
|
|
// Author:
|
|
// David Karlaš <david.karlas@xamarin.com>
|
|
//
|
|
// Copyright (c) 2017 Xamarin, Inc (http://www.xamarin.com)
|
|
//
|
|
// 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 without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
// THE SOFTWARE.
|
|
using System;
|
|
using Mono.Debugger.Soft;
|
|
using System.IO;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
namespace Mono.Debugging.Soft
|
|
{
|
|
class PortablePdbData
|
|
{
|
|
static readonly Guid AsyncMethodSteppingInformationBlob = new Guid ("54FD2AC5-E925-401A-9C2A-F94F171072F8");
|
|
static readonly Guid StateMachineHoistedLocalScopes = new Guid ("6DA9A61E-F8C7-4874-BE62-68BC5630DF71");
|
|
static readonly Guid DynamicLocalVariables = new Guid ("83C563C4-B4F3-47D5-B824-BA5441477EA8");
|
|
static readonly Guid TupleElementNames = new Guid ("ED9FDF71-8879-4747-8ED3-FE5EDE3CE710");
|
|
static readonly Guid DefaultNamespace = new Guid ("58b2eab6-209f-4e4e-a22c-b2d0f910c782");
|
|
static readonly Guid EncLocalSlotMap = new Guid ("755F52A8-91C5-45BE-B4B8-209571E552BD");
|
|
static readonly Guid EncLambdaAndClosureMap = new Guid ("A643004C-0240-496F-A783-30D64F4979DE");
|
|
static readonly Guid SourceLinkGuid = new Guid ("CC110556-A091-4D38-9FEC-25AB9A351A6A");
|
|
static readonly Guid EmbeddedSource = new Guid ("0E8A571B-6926-466E-B4AD-8AB04611F5FE");
|
|
|
|
public static bool IsPortablePdb (string pdbFileName)
|
|
{
|
|
if (string.IsNullOrEmpty (pdbFileName) || !File.Exists (pdbFileName))
|
|
return false;
|
|
using (var file = new FileStream (pdbFileName, FileMode.Open, FileAccess.Read, FileShare.Read)) {
|
|
var data = new byte [4];
|
|
int read = file.Read (data, 0, data.Length);
|
|
return read == 4 && BitConverter.ToUInt32 (data, 0) == 0x424a5342;
|
|
}
|
|
}
|
|
|
|
readonly byte [] pdbBytes;
|
|
private readonly string pdbFileName;
|
|
|
|
public PortablePdbData (string pdbFileName)
|
|
{
|
|
this.pdbFileName = Path.GetFullPath (pdbFileName);
|
|
}
|
|
|
|
public PortablePdbData (byte [] pdbBytes)
|
|
{
|
|
this.pdbBytes = pdbBytes ?? throw new ArgumentNullException (nameof(pdbBytes));
|
|
}
|
|
|
|
internal class SoftScope
|
|
{
|
|
public int LiveRangeStart;
|
|
|
|
public int LiveRangeEnd;
|
|
}
|
|
|
|
Stream GetStream()
|
|
{
|
|
if (pdbBytes != null)
|
|
return new MemoryStream (pdbBytes);
|
|
return new FileStream (pdbFileName, FileMode.Open, FileAccess.Read, FileShare.Read);
|
|
}
|
|
|
|
public string GetSourceLinkBlob ()
|
|
{
|
|
/*using (var provider = MetadataReaderProvider.FromPortablePdbStream (GetStream ())) {
|
|
var pdbReader = provider.GetMetadataReader ();
|
|
|
|
var jsonBlob =
|
|
pdbReader.GetCustomDebugInformation (EntityHandle.ModuleDefinition)
|
|
.Select (cdiHandle => pdbReader.GetCustomDebugInformation (cdiHandle))
|
|
.Where (cdi => pdbReader.GetGuid (cdi.Kind) == SourceLinkGuid)
|
|
.Select (cdi => pdbReader.GetBlobBytes (cdi.Value))
|
|
.FirstOrDefault ();
|
|
|
|
if (jsonBlob == null)
|
|
return null;
|
|
|
|
return System.Text.Encoding.UTF8.GetString (jsonBlob);
|
|
}*/
|
|
return null;
|
|
}
|
|
|
|
// We need proxy method to make sure VS2013/15 doesn't crash(this method won't be called if portable .pdb file doesn't exist, which means 2017+)
|
|
[MethodImpl (MethodImplOptions.NoInlining)]
|
|
internal SoftScope [] GetHoistedScopes (MethodMirror method) => GetHoistedScopesPrivate (method);
|
|
|
|
internal SoftScope [] GetHoistedScopesPrivate (MethodMirror method)
|
|
{
|
|
/*using (var metadataReader = MetadataReaderProvider.FromPortablePdbStream (GetStream ())) {
|
|
var reader = metadataReader.GetMetadataReader ();
|
|
var methodHandle = MetadataTokens.MethodDefinitionHandle (method.MetadataToken);
|
|
var customDebugInfos = reader.GetCustomDebugInformation (methodHandle);
|
|
foreach (var item in customDebugInfos) {
|
|
var debugInfo = reader.GetCustomDebugInformation (item);
|
|
if (reader.GetGuid (debugInfo.Kind) == StateMachineHoistedLocalScopes) {
|
|
var bytes = reader.GetBlobBytes (debugInfo.Value);
|
|
var result = new SoftScope [bytes.Length / 8];
|
|
for (int i = 0; i < bytes.Length; i += 8) {
|
|
var offset = BitConverter.ToInt32 (bytes, i);
|
|
var len = BitConverter.ToInt32 (bytes, i + 4);
|
|
result [i / 8] = new SoftScope () {
|
|
LiveRangeStart = offset,
|
|
LiveRangeEnd = offset + len
|
|
};
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
}*/
|
|
return null;
|
|
}
|
|
|
|
// We need proxy method to make sure VS2013/15 doesn't crash(this method won't be called if portable .pdb file doesn't exist, which means 2017+)
|
|
[MethodImpl (MethodImplOptions.NoInlining)]
|
|
internal string [] GetTupleElementNames (MethodMirror method, int localVariableIndex) => TupleElementNamesPrivate (method, localVariableIndex);
|
|
|
|
/*private static string [] DecodeTupleElementNames (BlobReader reader)
|
|
{
|
|
var list = new List<string> ();
|
|
while (reader.RemainingBytes > 0) {
|
|
int byteCount = reader.IndexOf (0);
|
|
string value = reader.ReadUTF8 (byteCount);
|
|
byte terminator = reader.ReadByte ();
|
|
list.Add (value.Length == 0 ? null : value);
|
|
}
|
|
return list.ToArray ();
|
|
}*/
|
|
|
|
internal string [] TupleElementNamesPrivate (MethodMirror method, int localVariableIndex)
|
|
{
|
|
/*using (var metadataReader = MetadataReaderProvider.FromPortablePdbStream (GetStream())) {
|
|
var reader = metadataReader.GetMetadataReader ();
|
|
var methodHandle = MetadataTokens.MethodDefinitionHandle (method.MetadataToken);
|
|
var localScopes = reader.GetLocalScopes (methodHandle);
|
|
// localVariableIndex is not really il_index, but sequential index when fetching locals
|
|
// hence use Skip(index) instead of Index matching.
|
|
var localVar = localScopes.Select (s => reader.GetLocalScope (s)).SelectMany (s => s.GetLocalVariables ()).Skip (localVariableIndex).First ();
|
|
var customDebugInfos = reader.GetCustomDebugInformation (localVar);
|
|
foreach (var item in customDebugInfos) {
|
|
var debugInfo = reader.GetCustomDebugInformation (item);
|
|
if (reader.GetGuid (debugInfo.Kind) == TupleElementNames) {
|
|
return DecodeTupleElementNames (reader.GetBlobReader (debugInfo.Value));
|
|
}
|
|
}
|
|
}*/
|
|
return null;
|
|
}
|
|
}
|
|
}
|