Skip to content

Commit

Permalink
Embed PDBs in built binary (#1529)
Browse files Browse the repository at this point in the history
* 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 992aa7a.
  • Loading branch information
KevinRansom authored Sep 15, 2016
1 parent f320958 commit ea60a9d
Show file tree
Hide file tree
Showing 18 changed files with 414 additions and 380 deletions.
Binary file modified lkg/FSharp-14.0.23413.0/bin/FSharp.Build.dll
Binary file not shown.
99 changes: 63 additions & 36 deletions src/absil/ilwrite.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3054,10 +3054,6 @@ let generateIL requiredDataFixups (desiredMetadataVersion,generatePdb, ilg : ILG
//=====================================================================
// TABLES+BLOBS --> PHYSICAL METADATA+BLOBS
//=====================================================================
type BinaryChunk =
{ size: int32
addr: int32 }

let chunk sz next = ({addr=next; size=sz},next + sz)
let nochunk next = ({addr= 0x0;size= 0x0; } ,next)

Expand Down Expand Up @@ -3541,7 +3537,7 @@ let writeDirectory os dict =

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

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

let pdbData,debugDirectoryChunk,debugDataChunk,textV2P,mappings =
let pdbData,pdbOpt,debugDirectoryChunk,debugDataChunk,debugEmbeddedPdbChunk,textV2P,mappings =
try

let imageBaseReal = modul.ImageBase // FIXED CHOICE
Expand Down Expand Up @@ -3683,28 +3679,50 @@ let writeBinaryAndReportMappings (outfile, ilg, pdbfile: string option, signer:
let importLookupTableChunk,next = chunk 0x14 next
let importNameHintTableChunk,next = chunk 0x0e next
let mscoreeStringChunk,next = chunk 0x0c next

let next = align 0x10 (next + 0x05) - 0x05
let importTableChunk = { addr=importTableChunk.addr; size = next - importTableChunk.addr}
let importTableChunkPadding = importTableChunk.size - (0x28 + 0x14 + 0x0e + 0x0c)

let next = next + 0x03
let entrypointCodeChunk,next = chunk 0x06 next
let globalpointerCodeChunk,next = chunk (if isItanium then 0x8 else 0x0) next

let debugDirectoryChunk,next = chunk (if pdbfile = None then 0x0 else sizeof_IMAGE_DEBUG_DIRECTORY) next

let pdbOpt =
match portablePDB with
| true ->
let struct (uncompressedLength, contentId, stream) as pdbStream = generatePortablePdb fixupOverlappingSequencePoints showTimes pdbData
if embeddedPDB then Some (compressPortablePdbStream uncompressedLength contentId stream)
else Some (pdbStream)
| _ -> None
let debugDirectoryChunk,next =
chunk (if pdbfile = None then
0x0
else if embeddedPDB && portablePDB then
sizeof_IMAGE_DEBUG_DIRECTORY * 2
else
sizeof_IMAGE_DEBUG_DIRECTORY
) next
// The debug data is given to us by the PDB writer and appears to
// typically be the type of the data plus the PDB file name. We fill
// this in after we've written the binary. We approximate the size according
// to what PDB writers seem to require and leave extra space just in case...
let debugDataJustInCase = 40
let debugDataChunk,next =
chunk (align 0x4 (match pdbfile with
| None -> 0x0
| None -> 0
| Some f -> (24
+ System.Text.Encoding.Unicode.GetByteCount(f) // See bug 748444
+ debugDataJustInCase))) next

let debugEmbeddedPdbChunk,next =
let streamLength =
match pdbOpt with
| Some struct (_,_,stream) -> int(stream.Length)
| None -> 0
chunk (align 0x4 (match embeddedPDB with
| true -> 8 + streamLength
| _ -> 0 )) next

let textSectionSize = next - textSectionAddr
let nextPhys = align alignPhys (textSectionPhysLoc + textSectionSize)
Expand Down Expand Up @@ -4094,11 +4112,14 @@ let writeBinaryAndReportMappings (outfile, ilg, pdbfile: string option, signer:
if isItanium then
write (Some (textV2P globalpointerCodeChunk.addr)) os " itanium global pointer"
[| 0x0uy; 0x0uy; 0x0uy; 0x0uy; 0x0uy; 0x0uy; 0x0uy; 0x0uy |]

if pdbfile.IsSome then
write (Some (textV2P debugDirectoryChunk.addr)) os "debug directory" (Array.create sizeof_IMAGE_DEBUG_DIRECTORY 0x0uy)
write (Some (textV2P debugDirectoryChunk.addr)) os "debug directory" (Array.create debugDirectoryChunk.size 0x0uy)
write (Some (textV2P debugDataChunk.addr)) os "debug data" (Array.create debugDataChunk.size 0x0uy)


if embeddedPDB then
write (Some (textV2P debugEmbeddedPdbChunk.addr)) os "debug data" (Array.create debugEmbeddedPdbChunk.size 0x0uy)

writePadding os "end of .text" (dataSectionPhysLoc - textSectionPhysLoc - textSectionSize)

// DATA SECTION
Expand Down Expand Up @@ -4145,7 +4166,7 @@ let writeBinaryAndReportMappings (outfile, ilg, pdbfile: string option, signer:
FileSystemUtilites.setExecutablePermission outfile
with _ ->
()
pdbData,debugDirectoryChunk,debugDataChunk,textV2P,mappings
pdbData,pdbOpt,debugDirectoryChunk,debugDataChunk,debugEmbeddedPdbChunk,textV2P,mappings

// Looks like a finally
with e ->
Expand All @@ -4169,14 +4190,17 @@ let writeBinaryAndReportMappings (outfile, ilg, pdbfile: string option, signer:
| Some fpdb ->
try
let idd =
match pdbOpt with
| Some struct(originalLength, contentId, stream) ->
if embeddedPDB then
embedPortablePdbInfo originalLength contentId stream showTimes fpdb debugDataChunk debugEmbeddedPdbChunk
else
writePortablePdbInfo contentId stream showTimes fpdb debugDataChunk
| None ->
#if FX_NO_PDB_WRITER
ignore portablePDB
writePortablePdbInfo fixupOverlappingSequencePoints showTimes fpdb pdbData
Array.empty<idd>
#else
if portablePDB then
writePortablePdbInfo fixupOverlappingSequencePoints showTimes fpdb pdbData
else
writePdbInfo fixupOverlappingSequencePoints showTimes outfile fpdb pdbData
writePdbInfo fixupOverlappingSequencePoints showTimes outfile fpdb pdbData debugDataChunk
#endif
reportTime showTimes "Generate PDB Info"

Expand All @@ -4186,19 +4210,22 @@ let writeBinaryAndReportMappings (outfile, ilg, pdbfile: string option, signer:
try
// write the IMAGE_DEBUG_DIRECTORY
os2.BaseStream.Seek (int64 (textV2P debugDirectoryChunk.addr), SeekOrigin.Begin) |> ignore
writeInt32 os2 idd.iddCharacteristics // IMAGE_DEBUG_DIRECTORY.Characteristics
writeInt32 os2 idd.iddTimestamp
writeInt32AsUInt16 os2 idd.iddMajorVersion
writeInt32AsUInt16 os2 idd.iddMinorVersion
writeInt32 os2 idd.iddType
writeInt32 os2 idd.iddData.Length // IMAGE_DEBUG_DIRECTORY.SizeOfData
writeInt32 os2 debugDataChunk.addr // IMAGE_DEBUG_DIRECTORY.AddressOfRawData
writeInt32 os2 (textV2P debugDataChunk.addr) // IMAGE_DEBUG_DIRECTORY.PointerToRawData

// write the debug raw data as given us by the PDB writer
os2.BaseStream.Seek (int64 (textV2P debugDataChunk.addr), SeekOrigin.Begin) |> ignore
if debugDataChunk.size < idd.iddData.Length then failwith "Debug data area is not big enough. Debug info may not be usable"
writeBytes os2 idd.iddData
for i in idd do
writeInt32 os2 i.iddCharacteristics // IMAGE_DEBUG_DIRECTORY.Characteristics
writeInt32 os2 i.iddTimestamp
writeInt32AsUInt16 os2 i.iddMajorVersion
writeInt32AsUInt16 os2 i.iddMinorVersion
writeInt32 os2 i.iddType
writeInt32 os2 i.iddData.Length // IMAGE_DEBUG_DIRECTORY.SizeOfData
writeInt32 os2 i.iddChunk.addr // IMAGE_DEBUG_DIRECTORY.AddressOfRawData
writeInt32 os2 (textV2P i.iddChunk.addr) // IMAGE_DEBUG_DIRECTORY.PointerToRawData

// Write the Debug Data
for i in idd do
// write the debug raw data as given us by the PDB writer
os2.BaseStream.Seek (int64 (textV2P i.iddChunk.addr), SeekOrigin.Begin) |> ignore
if i.iddChunk.size < i.iddData.Length then failwith "Debug data area is not big enough. Debug info may not be usable"
writeBytes os2 i.iddData
os2.Dispose()
with e ->
failwith ("Error while writing debug directory entry: "+e.Message)
Expand All @@ -4209,6 +4236,7 @@ let writeBinaryAndReportMappings (outfile, ilg, pdbfile: string option, signer:

end
ignore debugDataChunk
ignore debugEmbeddedPdbChunk
reportTime showTimes "Finalize PDB"

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


type options =
{ ilg: ILGlobals;
pdbfile: string option
portablePDB: bool
embeddedPDB: bool
signer: ILStrongNameSigner option
fixupOverlappingSequencePoints: bool
emitTailcalls : bool
showTimes: bool
dumpDebugInfo:bool }


let WriteILBinary (outfile, (args: options), modul, noDebugData) =
ignore (writeBinaryAndReportMappings (outfile, args.ilg, args.pdbfile, args.signer, args.portablePDB,
ignore (writeBinaryAndReportMappings (outfile, args.ilg, args.pdbfile, args.signer, args.portablePDB, args.embeddedPDB,
args.fixupOverlappingSequencePoints, args.emitTailcalls, args.showTimes,
args.dumpDebugInfo) modul noDebugData)
1 change: 1 addition & 0 deletions src/absil/ilwrite.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type options =
{ ilg: ILGlobals
pdbfile: string option
portablePDB: bool
embeddedPDB: bool
signer : ILStrongNameSigner option
fixupOverlappingSequencePoints : bool
emitTailcalls: bool
Expand Down
Loading

0 comments on commit ea60a9d

Please sign in to comment.