Xamarin Public Jenkins (auto-signing) 4bdbaf4a88 Imported Upstream version 5.0.1.1
Former-commit-id: ffd3a248ace900b177db27aa87e5c702a9bc7322
2017-05-24 10:59:19 +00:00

226 lines
5.1 KiB
C#

//
// Driver.cs
//
// Author:
// Jb Evain (jbevain@novell.com)
//
// (C) 2009 Novell, Inc. (http://www.novell.com)
//
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.Cci;
using Microsoft.Cci.Pdb;
using Mono.Cecil;
using Mono.CompilerServices.SymbolWriter;
namespace Pdb2Mdb {
public class Converter {
MonoSymbolWriter mdb;
Dictionary<string, SourceFile> files = new Dictionary<string, SourceFile> ();
public static void Convert (string filename)
{
using (var asm = AssemblyDefinition.ReadAssembly (filename)) {
var pdb = asm.Name.Name + ".pdb";
pdb = Path.Combine (Path.GetDirectoryName (filename), pdb);
if (!File.Exists (pdb))
throw new FileNotFoundException ("PDB file doesn't exist: " + pdb);
using (var stream = File.OpenRead (pdb)) {
if (IsPortablePdb (stream))
throw new PortablePdbNotSupportedException ();
var funcs = PdbFile.LoadFunctions (stream, true);
Converter.Convert (asm, funcs, new MonoSymbolWriter (filename));
}
}
}
static bool IsPortablePdb (FileStream stream)
{
const uint ppdb_signature = 0x424a5342;
var position = stream.Position;
try {
var reader = new BinaryReader (stream);
return reader.ReadUInt32 () == ppdb_signature;
} finally {
stream.Position = position;
}
}
internal Converter (MonoSymbolWriter mdb)
{
this.mdb = mdb;
}
internal static void Convert (AssemblyDefinition assembly, IEnumerable<PdbFunction> functions, MonoSymbolWriter mdb)
{
var converter = new Converter (mdb);
foreach (var function in functions)
converter.ConvertFunction (function);
mdb.WriteSymbolFile (assembly.MainModule.Mvid);
}
void ConvertFunction (PdbFunction function)
{
if (function.lines == null)
return;
var method = new SourceMethod { Name = function.name, Token = (int) function.token };
var file = GetSourceFile (mdb, function);
var builder = mdb.OpenMethod (file.CompilationUnit, 0, method);
ConvertSequencePoints (function, file, builder);
ConvertVariables (function);
mdb.CloseMethod ();
}
void ConvertSequencePoints (PdbFunction function, SourceFile file, SourceMethodBuilder builder)
{
int last_line = 0;
foreach (var line in function.lines.SelectMany (lines => lines.lines)) {
// 0xfeefee is an MS convention, we can't pass it into mdb files, so we use the last non-hidden line
bool is_hidden = line.lineBegin == 0xfeefee;
builder.MarkSequencePoint (
(int) line.offset,
file.CompilationUnit.SourceFile,
is_hidden ? last_line : (int) line.lineBegin,
(int) line.colBegin, is_hidden ? -1 : (int)line.lineEnd, is_hidden ? -1 : (int)line.colEnd,
is_hidden);
if (!is_hidden)
last_line = (int) line.lineBegin;
}
}
void ConvertVariables (PdbFunction function)
{
foreach (var scope in function.scopes)
ConvertScope (scope);
}
void ConvertScope (PdbScope scope)
{
ConvertSlots (scope, scope.slots);
foreach (var s in scope.scopes)
ConvertScope (s);
}
void ConvertSlots (PdbScope scope, IEnumerable<PdbSlot> slots)
{
int scope_idx = mdb.OpenScope ((int)scope.address);
foreach (var slot in slots) {
mdb.DefineLocalVariable ((int) slot.slot, slot.name);
mdb.DefineScopeVariable (scope_idx, (int)slot.slot);
}
mdb.CloseScope ((int)(scope.address + scope.length));
}
SourceFile GetSourceFile (MonoSymbolWriter mdb, PdbFunction function)
{
var name = (from l in function.lines where l.file != null select l.file.name).First ();
SourceFile file;
if (files.TryGetValue (name, out file))
return file;
var entry = mdb.DefineDocument (name);
var unit = mdb.DefineCompilationUnit (entry);
file = new SourceFile (unit, entry);
files.Add (name, file);
return file;
}
class SourceFile : ISourceFile {
CompileUnitEntry comp_unit;
SourceFileEntry entry;
public SourceFileEntry Entry
{
get { return entry; }
}
public CompileUnitEntry CompilationUnit
{
get { return comp_unit; }
}
public SourceFile (CompileUnitEntry comp_unit, SourceFileEntry entry)
{
this.comp_unit = comp_unit;
this.entry = entry;
}
}
class SourceMethod : IMethodDef {
public string Name { get; set; }
public int Token { get; set; }
}
}
public class PortablePdbNotSupportedException : Exception {
}
class Driver {
static void Main (string [] args)
{
if (args.Length != 1)
Usage ();
var asm = args [0];
if (!File.Exists (asm))
Usage ();
try {
Converter.Convert (asm);
} catch (FileNotFoundException ex) {
Usage ();
} catch (PortablePdbNotSupportedException) {
Console.WriteLine ("Error: A portable PDB can't be converted to mdb.");
Environment.Exit (2);
}
catch (Exception ex) {
Error (ex);
}
}
static void Usage ()
{
Console.WriteLine ("Mono pdb to mdb debug symbol store converter");
Console.WriteLine ("Usage: pdb2mdb assembly");
Environment.Exit (1);
}
static void Error (Exception e)
{
Console.WriteLine ("Fatal error:");
Console.WriteLine (e);
Environment.Exit (1);
}
}
}