Skip to content

Commit ea60a9d

Browse files
authored
Embed PDBs in built binary (#1529)
* Minor refactor of writePortablePdbInfo * Add command line switches for embedded pdbs * Embed PDBs in the .exe * Enable embedded portable pdbs * Update fsharp.build.dll to understand embedded * Clean up * Move BinaryChunk to ilwrite.fsi * Revert "Move BinaryChunk to ilwrite.fsi" This reverts commit 992aa7a944ed62b7aae93311f030278d16a99d29.
1 parent f320958 commit ea60a9d

File tree

18 files changed

+414
-380
lines changed

18 files changed

+414
-380
lines changed
512 Bytes
Binary file not shown.

src/absil/ilwrite.fs

Lines changed: 63 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3054,10 +3054,6 @@ let generateIL requiredDataFixups (desiredMetadataVersion,generatePdb, ilg : ILG
30543054
//=====================================================================
30553055
// TABLES+BLOBS --> PHYSICAL METADATA+BLOBS
30563056
//=====================================================================
3057-
type BinaryChunk =
3058-
{ size: int32
3059-
addr: int32 }
3060-
30613057
let chunk sz next = ({addr=next; size=sz},next + sz)
30623058
let nochunk next = ({addr= 0x0;size= 0x0; } ,next)
30633059

@@ -3541,7 +3537,7 @@ let writeDirectory os dict =
35413537

35423538
let writeBytes (os: BinaryWriter) (chunk:byte[]) = os.Write(chunk,0,chunk.Length)
35433539

3544-
let writeBinaryAndReportMappings (outfile, ilg, pdbfile: string option, signer: ILStrongNameSigner option, portablePDB,
3540+
let writeBinaryAndReportMappings (outfile, ilg, pdbfile: string option, signer: ILStrongNameSigner option, portablePDB, embeddedPDB,
35453541
fixupOverlappingSequencePoints, emitTailcalls, showTimes, dumpDebugInfo) modul noDebugData =
35463542
// Store the public key from the signer into the manifest. This means it will be written
35473543
// to the binary and also acts as an indicator to leave space for delay sign
@@ -3590,7 +3586,7 @@ let writeBinaryAndReportMappings (outfile, ilg, pdbfile: string option, signer:
35903586
with e ->
35913587
failwith ("Could not open file for writing (binary mode): " + outfile)
35923588

3593-
let pdbData,debugDirectoryChunk,debugDataChunk,textV2P,mappings =
3589+
let pdbData,pdbOpt,debugDirectoryChunk,debugDataChunk,debugEmbeddedPdbChunk,textV2P,mappings =
35943590
try
35953591

35963592
let imageBaseReal = modul.ImageBase // FIXED CHOICE
@@ -3683,28 +3679,50 @@ let writeBinaryAndReportMappings (outfile, ilg, pdbfile: string option, signer:
36833679
let importLookupTableChunk,next = chunk 0x14 next
36843680
let importNameHintTableChunk,next = chunk 0x0e next
36853681
let mscoreeStringChunk,next = chunk 0x0c next
3686-
3682+
36873683
let next = align 0x10 (next + 0x05) - 0x05
36883684
let importTableChunk = { addr=importTableChunk.addr; size = next - importTableChunk.addr}
36893685
let importTableChunkPadding = importTableChunk.size - (0x28 + 0x14 + 0x0e + 0x0c)
36903686

36913687
let next = next + 0x03
36923688
let entrypointCodeChunk,next = chunk 0x06 next
36933689
let globalpointerCodeChunk,next = chunk (if isItanium then 0x8 else 0x0) next
3694-
3695-
let debugDirectoryChunk,next = chunk (if pdbfile = None then 0x0 else sizeof_IMAGE_DEBUG_DIRECTORY) next
3690+
3691+
let pdbOpt =
3692+
match portablePDB with
3693+
| true ->
3694+
let struct (uncompressedLength, contentId, stream) as pdbStream = generatePortablePdb fixupOverlappingSequencePoints showTimes pdbData
3695+
if embeddedPDB then Some (compressPortablePdbStream uncompressedLength contentId stream)
3696+
else Some (pdbStream)
3697+
| _ -> None
3698+
let debugDirectoryChunk,next =
3699+
chunk (if pdbfile = None then
3700+
0x0
3701+
else if embeddedPDB && portablePDB then
3702+
sizeof_IMAGE_DEBUG_DIRECTORY * 2
3703+
else
3704+
sizeof_IMAGE_DEBUG_DIRECTORY
3705+
) next
36963706
// The debug data is given to us by the PDB writer and appears to
36973707
// typically be the type of the data plus the PDB file name. We fill
36983708
// this in after we've written the binary. We approximate the size according
36993709
// to what PDB writers seem to require and leave extra space just in case...
37003710
let debugDataJustInCase = 40
37013711
let debugDataChunk,next =
37023712
chunk (align 0x4 (match pdbfile with
3703-
| None -> 0x0
3713+
| None -> 0
37043714
| Some f -> (24
37053715
+ System.Text.Encoding.Unicode.GetByteCount(f) // See bug 748444
37063716
+ debugDataJustInCase))) next
37073717

3718+
let debugEmbeddedPdbChunk,next =
3719+
let streamLength =
3720+
match pdbOpt with
3721+
| Some struct (_,_,stream) -> int(stream.Length)
3722+
| None -> 0
3723+
chunk (align 0x4 (match embeddedPDB with
3724+
| true -> 8 + streamLength
3725+
| _ -> 0 )) next
37083726

37093727
let textSectionSize = next - textSectionAddr
37103728
let nextPhys = align alignPhys (textSectionPhysLoc + textSectionSize)
@@ -4094,11 +4112,14 @@ let writeBinaryAndReportMappings (outfile, ilg, pdbfile: string option, signer:
40944112
if isItanium then
40954113
write (Some (textV2P globalpointerCodeChunk.addr)) os " itanium global pointer"
40964114
[| 0x0uy; 0x0uy; 0x0uy; 0x0uy; 0x0uy; 0x0uy; 0x0uy; 0x0uy |]
4097-
4115+
40984116
if pdbfile.IsSome then
4099-
write (Some (textV2P debugDirectoryChunk.addr)) os "debug directory" (Array.create sizeof_IMAGE_DEBUG_DIRECTORY 0x0uy)
4117+
write (Some (textV2P debugDirectoryChunk.addr)) os "debug directory" (Array.create debugDirectoryChunk.size 0x0uy)
41004118
write (Some (textV2P debugDataChunk.addr)) os "debug data" (Array.create debugDataChunk.size 0x0uy)
4101-
4119+
4120+
if embeddedPDB then
4121+
write (Some (textV2P debugEmbeddedPdbChunk.addr)) os "debug data" (Array.create debugEmbeddedPdbChunk.size 0x0uy)
4122+
41024123
writePadding os "end of .text" (dataSectionPhysLoc - textSectionPhysLoc - textSectionSize)
41034124

41044125
// DATA SECTION
@@ -4145,7 +4166,7 @@ let writeBinaryAndReportMappings (outfile, ilg, pdbfile: string option, signer:
41454166
FileSystemUtilites.setExecutablePermission outfile
41464167
with _ ->
41474168
()
4148-
pdbData,debugDirectoryChunk,debugDataChunk,textV2P,mappings
4169+
pdbData,pdbOpt,debugDirectoryChunk,debugDataChunk,debugEmbeddedPdbChunk,textV2P,mappings
41494170

41504171
// Looks like a finally
41514172
with e ->
@@ -4169,14 +4190,17 @@ let writeBinaryAndReportMappings (outfile, ilg, pdbfile: string option, signer:
41694190
| Some fpdb ->
41704191
try
41714192
let idd =
4193+
match pdbOpt with
4194+
| Some struct(originalLength, contentId, stream) ->
4195+
if embeddedPDB then
4196+
embedPortablePdbInfo originalLength contentId stream showTimes fpdb debugDataChunk debugEmbeddedPdbChunk
4197+
else
4198+
writePortablePdbInfo contentId stream showTimes fpdb debugDataChunk
4199+
| None ->
41724200
#if FX_NO_PDB_WRITER
4173-
ignore portablePDB
4174-
writePortablePdbInfo fixupOverlappingSequencePoints showTimes fpdb pdbData
4201+
Array.empty<idd>
41754202
#else
4176-
if portablePDB then
4177-
writePortablePdbInfo fixupOverlappingSequencePoints showTimes fpdb pdbData
4178-
else
4179-
writePdbInfo fixupOverlappingSequencePoints showTimes outfile fpdb pdbData
4203+
writePdbInfo fixupOverlappingSequencePoints showTimes outfile fpdb pdbData debugDataChunk
41804204
#endif
41814205
reportTime showTimes "Generate PDB Info"
41824206

@@ -4186,19 +4210,22 @@ let writeBinaryAndReportMappings (outfile, ilg, pdbfile: string option, signer:
41864210
try
41874211
// write the IMAGE_DEBUG_DIRECTORY
41884212
os2.BaseStream.Seek (int64 (textV2P debugDirectoryChunk.addr), SeekOrigin.Begin) |> ignore
4189-
writeInt32 os2 idd.iddCharacteristics // IMAGE_DEBUG_DIRECTORY.Characteristics
4190-
writeInt32 os2 idd.iddTimestamp
4191-
writeInt32AsUInt16 os2 idd.iddMajorVersion
4192-
writeInt32AsUInt16 os2 idd.iddMinorVersion
4193-
writeInt32 os2 idd.iddType
4194-
writeInt32 os2 idd.iddData.Length // IMAGE_DEBUG_DIRECTORY.SizeOfData
4195-
writeInt32 os2 debugDataChunk.addr // IMAGE_DEBUG_DIRECTORY.AddressOfRawData
4196-
writeInt32 os2 (textV2P debugDataChunk.addr) // IMAGE_DEBUG_DIRECTORY.PointerToRawData
4197-
4198-
// write the debug raw data as given us by the PDB writer
4199-
os2.BaseStream.Seek (int64 (textV2P debugDataChunk.addr), SeekOrigin.Begin) |> ignore
4200-
if debugDataChunk.size < idd.iddData.Length then failwith "Debug data area is not big enough. Debug info may not be usable"
4201-
writeBytes os2 idd.iddData
4213+
for i in idd do
4214+
writeInt32 os2 i.iddCharacteristics // IMAGE_DEBUG_DIRECTORY.Characteristics
4215+
writeInt32 os2 i.iddTimestamp
4216+
writeInt32AsUInt16 os2 i.iddMajorVersion
4217+
writeInt32AsUInt16 os2 i.iddMinorVersion
4218+
writeInt32 os2 i.iddType
4219+
writeInt32 os2 i.iddData.Length // IMAGE_DEBUG_DIRECTORY.SizeOfData
4220+
writeInt32 os2 i.iddChunk.addr // IMAGE_DEBUG_DIRECTORY.AddressOfRawData
4221+
writeInt32 os2 (textV2P i.iddChunk.addr) // IMAGE_DEBUG_DIRECTORY.PointerToRawData
4222+
4223+
// Write the Debug Data
4224+
for i in idd do
4225+
// write the debug raw data as given us by the PDB writer
4226+
os2.BaseStream.Seek (int64 (textV2P i.iddChunk.addr), SeekOrigin.Begin) |> ignore
4227+
if i.iddChunk.size < i.iddData.Length then failwith "Debug data area is not big enough. Debug info may not be usable"
4228+
writeBytes os2 i.iddData
42024229
os2.Dispose()
42034230
with e ->
42044231
failwith ("Error while writing debug directory entry: "+e.Message)
@@ -4209,6 +4236,7 @@ let writeBinaryAndReportMappings (outfile, ilg, pdbfile: string option, signer:
42094236

42104237
end
42114238
ignore debugDataChunk
4239+
ignore debugEmbeddedPdbChunk
42124240
reportTime showTimes "Finalize PDB"
42134241

42144242
/// Sign the binary. No further changes to binary allowed past this point!
@@ -4228,19 +4256,18 @@ let writeBinaryAndReportMappings (outfile, ilg, pdbfile: string option, signer:
42284256
//Finished writing and signing the binary and debug info...
42294257
mappings
42304258

4231-
42324259
type options =
42334260
{ ilg: ILGlobals;
42344261
pdbfile: string option
42354262
portablePDB: bool
4263+
embeddedPDB: bool
42364264
signer: ILStrongNameSigner option
42374265
fixupOverlappingSequencePoints: bool
42384266
emitTailcalls : bool
42394267
showTimes: bool
42404268
dumpDebugInfo:bool }
42414269

4242-
42434270
let WriteILBinary (outfile, (args: options), modul, noDebugData) =
4244-
ignore (writeBinaryAndReportMappings (outfile, args.ilg, args.pdbfile, args.signer, args.portablePDB,
4271+
ignore (writeBinaryAndReportMappings (outfile, args.ilg, args.pdbfile, args.signer, args.portablePDB, args.embeddedPDB,
42454272
args.fixupOverlappingSequencePoints, args.emitTailcalls, args.showTimes,
42464273
args.dumpDebugInfo) modul noDebugData)

src/absil/ilwrite.fsi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ type options =
1919
{ ilg: ILGlobals
2020
pdbfile: string option
2121
portablePDB: bool
22+
embeddedPDB: bool
2223
signer : ILStrongNameSigner option
2324
fixupOverlappingSequencePoints : bool
2425
emitTailcalls: bool

0 commit comments

Comments
 (0)