Getting the baked-in .pdb location from an assembly with Mono.Cecil 0.9.4
Because it isn't always as simple as
public static string GetPdbFileName (string assemblyFileName) | |
{ | |
return Path.ChangeExtension (assemblyFileName, ".pdb"); | |
} |
as is done in Mono.Cecil.Pdb.PdbHelper
, if assemblies and symbols have been moved to separate locations during a build.
The tools are there -- we just need to get the debug data from the PE image if it's present, skip the first 24 bytes, and interpret the rest as a string. Alas, all the are annoyingly just slightly encapsulated from us. But never mind! Reflection gets us there without having to negotiate a patch or make a fork:
/// <summary> | |
/// Violate Cecil encapsulation to get the PDB path -- a candidate | |
/// for another method on ModuleDefinition | |
/// </summary> | |
/// <param name="assembly">The assembly to find the .pdb path for</param> | |
/// <returns>The path (null if the operation fails)</returns> | |
public static string GetPdbFromImage(AssemblyDefinition assembly) | |
{ | |
var m = assembly.MainModule; | |
var imageField = typeof(ModuleDefinition).GetField("Image", BindingFlags.Instance | BindingFlags.NonPublic); | |
var image = imageField.GetValue(m); | |
var getDebugHeaderInfo = image.GetType().GetMethod("GetDebugHeader"); | |
byte[] result = null; | |
var args = new object[] { result }; | |
try | |
{ | |
getDebugHeaderInfo.Invoke(image, args); | |
var SizeOfDebugInfo = 0x18; | |
result = args[0] as byte[]; | |
if (null == result) | |
{ | |
return null; | |
} | |
var byteValue = result.Skip(SizeOfDebugInfo). | |
TakeWhile(x => x != 0).ToArray(); | |
if (byteValue.Length > 0) | |
{ | |
// UTF-8 encoding works for an assembly named GetÞePdbLocation. | |
return Encoding.UTF8.GetString(byteValue); | |
} | |
} | |
catch (TargetInvocationException) | |
{} | |
return null; | |
} |
No comments :
Post a Comment