Welcome to mirror list, hosted at ThFree Co, Russian Federation.

Driver.cs « pdb2mdb « tools « mcs - github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 7039503407518ca0c379d85e938c2c6036592531 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
//
// 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);
		}
	}
}