From 0f75387cef9c773d97677fba36bccf8ced55a25f Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 31 May 2024 21:05:03 +0000 Subject: [PATCH 1/3] Preserve original PDB path in dll --- Mono.Cecil.Cil/PortablePdb.cs | 19 ++++++++++++++- Test/Mono.Cecil.Tests/PortablePdbTests.cs | 28 ++++++++++++++++++++++ Test/Resources/assemblies/PdbPathLib.dll | Bin 0 -> 4096 bytes Test/Resources/assemblies/PdbPathLib.pdb | Bin 0 -> 10400 bytes 4 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 Test/Resources/assemblies/PdbPathLib.dll create mode 100644 Test/Resources/assemblies/PdbPathLib.pdb diff --git a/Mono.Cecil.Cil/PortablePdb.cs b/Mono.Cecil.Cil/PortablePdb.cs index 6664bee32..0ffa1815d 100644 --- a/Mono.Cecil.Cil/PortablePdb.cs +++ b/Mono.Cecil.Cil/PortablePdb.cs @@ -319,6 +319,20 @@ public void Write () } } + string GetPdbPath () + { + var debugHeader = module.Image.DebugHeader; + foreach (var entry in debugHeader.Entries) { + var data = entry.Data; + // Pdb path is NUL-terminated path at offset 24. + // https://github.com/dotnet/runtime/blob/main/docs/design/specs/PE-COFF.md#codeview-debug-directory-entry-type-2 + if (entry.Directory.Type == ImageDebugType.CodeView && data.Length >= 25) + return System.Text.Encoding.UTF8.GetString (data, 24, data.Length - 25); + } + + return string.Empty; + } + public ImageDebugHeader GetDebugHeader () { if (IsEmbedded) @@ -341,7 +355,10 @@ public ImageDebugHeader GetDebugHeader () // PDB Age buffer.WriteUInt32 (1); // PDB Path - var fileName = writer.BaseStream.GetFileName (); + var fileName = GetPdbPath (); + if (string.IsNullOrEmpty (fileName)) { + fileName = writer.BaseStream.GetFileName (); + } if (string.IsNullOrEmpty (fileName)) { fileName = module.Assembly.Name.Name + ".pdb"; } diff --git a/Test/Mono.Cecil.Tests/PortablePdbTests.cs b/Test/Mono.Cecil.Tests/PortablePdbTests.cs index a89f79d83..617f4b608 100644 --- a/Test/Mono.Cecil.Tests/PortablePdbTests.cs +++ b/Test/Mono.Cecil.Tests/PortablePdbTests.cs @@ -1148,5 +1148,33 @@ static void GetCodeViewPdbId (ModuleDefinition module, out byte[] pdbId) buffer.WriteInt32 (cv.Directory.TimeDateStamp); pdbId = buffer.buffer; } + + [Test] + public void WritePortablePdbPath () + { + const string resource = "PdbPathLib.dll"; + string destination = Path.GetTempFileName (); + + using (var module = GetResourceModule (resource, new ReaderParameters { ReadSymbols = true })) { + module.Write (destination, new WriterParameters { WriteSymbols = true }); + } + + using (var module = ModuleDefinition.ReadModule (destination, new ReaderParameters { ReadSymbols = true })) { + GetCodeViewPdbPath (module, out string pdbPath); + + Assert.AreEqual ("/_/artifacts/obj/PdbPathLib/release/PdbPathLib.pdb", pdbPath); + } + } + + static void GetCodeViewPdbPath (ModuleDefinition module, out string pdbPath) + { + var header = module.GetDebugHeader (); + var cv = Mixin.GetCodeViewEntry (header); + Assert.IsNotNull (cv); + + CollectionAssert.AreEqual (new byte [] { 0x52, 0x53, 0x44, 0x53 }, cv.Data.Take (4)); + + pdbPath = Encoding.UTF8.GetString (cv.Data, 24, cv.Data.Length - 25); + } } } diff --git a/Test/Resources/assemblies/PdbPathLib.dll b/Test/Resources/assemblies/PdbPathLib.dll new file mode 100644 index 0000000000000000000000000000000000000000..8c176d76c519eec84f9f75ad98aea0775cfb1a7d GIT binary patch literal 4096 zcmeHJU2GIp6h60qECos{NKi=~C?d$y2-3R?mKC)$h_p#;$D zuCyFDDy-8Oft&SS$kVfrX$^FTyB{ z>1dB0*Sq80T{}5wBU#`jEYk4`(N*++vYhr^(=K@I@fG%hQ|&mIrc01{3p@5598RLY z3jGr6{g#tO&xCZvzSTraS-CE{X-$yBieOA3VI0fQI5%!Yo(TFT`kgL_CfY5SKTaQr zm2?F|O*Bb|Vc8%~fqz2G9mU^Ne5tbURq}T#!mr|06_U4;SK(hPS{rRsa!Oub*- zk^tH>K+p!>L=S*B)1%<6)TQ`N#rqT=R{UAT4=Zkf3o^l*XfwS)UyzRM+QC;r*Xbb| z0`I`-){)U$;N5fA5iu*c*9(^CV;1?4Lryq(C?>pfj~518J^cgPmek? zWlQ!_Y9^a9{MivROX-T|%c4F}wtcfGDJiq%Lcz#dvd_onX3M^$KF^cItX0XFe$<>X z+=BFnaC69Gj{DML{~^87Q7)XYgQ+$b!C zJ%u`+J%WhgekWc&**JJ$>)5Fif9(F@^!nx0pa~JH*GM!%XlrA&C3b%A)QPt5n|H-T zcx>AF>}TrMJm(svF~=S}o|7d8nVEH+W1fH?9$L^IL2LD~!OVc;%Dz(Ri7@RwM|bFP z1ZY`3e-DcXK3(PDX2Me{%Ew9RPeFm^6722=2QVIic6bTWOR{lxfFhhE$N z_SUoUU8~Q$!!bIiIt|x1^G441I-Ts1&KmAcT;B{iV$w@9c%1h4J-KZ=h0)&lCX5Ee zFaGwocJR@crzy@D^tPvFe*LL=)|*w|!unLdBDoHENhP6}=qFFV*P^MsI8) zZBc5`VE5#^t^)k7B3er{w=lKfO^#=1k)8ec+u=}x=t}TBvk7t!_#~xi3Ve_zAPwVP zGzNVbd?@(pqR$)t`X_k8)N2!Sf_^Ut0r59LB&@RWH-JD?gIvTh@hu?{)22M$%}g8B ztPDmCSUrpzI9t0J@N?2t;#1()n5-~Aro!KBnU-{ZVWJQqPY8@TeE&Q0apz;FvC91fR?2d)3 fG@Ph~6|K$Ty56OP4dn0Qb=&XK{O+Z7#|r!lDC6|_ literal 0 HcmV?d00001 diff --git a/Test/Resources/assemblies/PdbPathLib.pdb b/Test/Resources/assemblies/PdbPathLib.pdb new file mode 100644 index 0000000000000000000000000000000000000000..37b9925c14d9a43adf0c42459bca0ffdba89f498 GIT binary patch literal 10400 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 literal 0 HcmV?d00001 From 4180d2c621bc00d08e9ff8ccc03acc29d6be15d3 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Wed, 5 Jun 2024 18:05:34 +0000 Subject: [PATCH 2/3] Check HasDebugHeader --- Mono.Cecil.Cil/PortablePdb.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Mono.Cecil.Cil/PortablePdb.cs b/Mono.Cecil.Cil/PortablePdb.cs index 0ffa1815d..3b61c6851 100644 --- a/Mono.Cecil.Cil/PortablePdb.cs +++ b/Mono.Cecil.Cil/PortablePdb.cs @@ -321,7 +321,10 @@ public void Write () string GetPdbPath () { - var debugHeader = module.Image.DebugHeader; + if (!module.HasDebugHeader) + return string.Empty; + + var debugHeader = module.GetDebugHeader (); foreach (var entry in debugHeader.Entries) { var data = entry.Data; // Pdb path is NUL-terminated path at offset 24. From 1558d72608ab45ed7a52b733bc2ca1697be478ba Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Wed, 5 Jun 2024 23:04:48 +0000 Subject: [PATCH 3/3] PR feedback --- Test/Mono.Cecil.Tests/PortablePdbTests.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Test/Mono.Cecil.Tests/PortablePdbTests.cs b/Test/Mono.Cecil.Tests/PortablePdbTests.cs index 617f4b608..2fdad6010 100644 --- a/Test/Mono.Cecil.Tests/PortablePdbTests.cs +++ b/Test/Mono.Cecil.Tests/PortablePdbTests.cs @@ -1172,6 +1172,8 @@ static void GetCodeViewPdbPath (ModuleDefinition module, out string pdbPath) var cv = Mixin.GetCodeViewEntry (header); Assert.IsNotNull (cv); + // Sanity check that the CodeView debug directory entry has the expected signature: + // https://github.com/dotnet/runtime/blob/main/docs/design/specs/PE-COFF.md#codeview-debug-directory-entry-type-2 CollectionAssert.AreEqual (new byte [] { 0x52, 0x53, 0x44, 0x53 }, cv.Data.Take (4)); pdbPath = Encoding.UTF8.GetString (cv.Data, 24, cv.Data.Length - 25);