17
17
#include " llvm/Object/Binary.h"
18
18
#include " llvm/Object/COFF.h"
19
19
#include " llvm/Support/Errc.h"
20
+ #include " llvm/Support/JamCRC.h"
21
+ #include " llvm/Support/Path.h"
20
22
#include < cassert>
21
23
22
24
namespace llvm {
@@ -30,6 +32,61 @@ static bool isDebugSection(const Section &Sec) {
30
32
return Sec.Name .startswith (" .debug" );
31
33
}
32
34
35
+ static uint64_t getNextRVA (const Object &Obj) {
36
+ if (Obj.getSections ().empty ())
37
+ return 0 ;
38
+ const Section &Last = Obj.getSections ().back ();
39
+ return alignTo (Last.Header .VirtualAddress + Last.Header .VirtualSize ,
40
+ Obj.PeHeader .SectionAlignment );
41
+ }
42
+
43
+ static uint32_t getCRC32 (StringRef Data) {
44
+ JamCRC CRC;
45
+ CRC.update (ArrayRef<char >(Data.data (), Data.size ()));
46
+ // The CRC32 value needs to be complemented because the JamCRC dosn't
47
+ // finalize the CRC32 value. It also dosn't negate the initial CRC32 value
48
+ // but it starts by default at 0xFFFFFFFF which is the complement of zero.
49
+ return ~CRC.getCRC ();
50
+ }
51
+
52
+ static std::vector<uint8_t > createGnuDebugLinkSectionContents (StringRef File) {
53
+ ErrorOr<std::unique_ptr<MemoryBuffer>> LinkTargetOrErr =
54
+ MemoryBuffer::getFile (File);
55
+ if (!LinkTargetOrErr)
56
+ error (" '" + File + " ': " + LinkTargetOrErr.getError ().message ());
57
+ auto LinkTarget = std::move (*LinkTargetOrErr);
58
+ uint32_t CRC32 = getCRC32 (LinkTarget->getBuffer ());
59
+
60
+ StringRef FileName = sys::path::filename (File);
61
+ size_t CRCPos = alignTo (FileName.size () + 1 , 4 );
62
+ std::vector<uint8_t > Data (CRCPos + 4 );
63
+ memcpy (Data.data (), FileName.data (), FileName.size ());
64
+ support::endian::write32le (Data.data () + CRCPos, CRC32);
65
+ return Data;
66
+ }
67
+
68
+ static void addGnuDebugLink (Object &Obj, StringRef DebugLinkFile) {
69
+ uint32_t StartRVA = getNextRVA (Obj);
70
+
71
+ std::vector<Section> Sections;
72
+ Section Sec;
73
+ Sec.setOwnedContents (createGnuDebugLinkSectionContents (DebugLinkFile));
74
+ Sec.Name = " .gnu_debuglink" ;
75
+ Sec.Header .VirtualSize = Sec.getContents ().size ();
76
+ Sec.Header .VirtualAddress = StartRVA;
77
+ Sec.Header .SizeOfRawData =
78
+ alignTo (Sec.Header .VirtualSize , Obj.PeHeader .FileAlignment );
79
+ // Sec.Header.PointerToRawData is filled in by the writer.
80
+ Sec.Header .PointerToRelocations = 0 ;
81
+ Sec.Header .PointerToLinenumbers = 0 ;
82
+ // Sec.Header.NumberOfRelocations is filled in by the writer.
83
+ Sec.Header .NumberOfLinenumbers = 0 ;
84
+ Sec.Header .Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA |
85
+ IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE;
86
+ Sections.push_back (Sec);
87
+ Obj.addSections (Sections);
88
+ }
89
+
33
90
static Error handleArgs (const CopyConfig &Config, Object &Obj) {
34
91
// Perform the actual section removals.
35
92
Obj.removeSections ([&Config](const Section &Sec) {
@@ -109,6 +166,10 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj) {
109
166
110
167
return false ;
111
168
});
169
+
170
+ if (!Config.AddGnuDebugLink .empty ())
171
+ addGnuDebugLink (Obj, Config.AddGnuDebugLink );
172
+
112
173
return Error::success ();
113
174
}
114
175
0 commit comments