llvm-objcopy-9.patch 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. From 840d70f854a1d550924ced1d00160efcc7b8549a Mon Sep 17 00:00:00 2001
  2. From: Martin Storsjo <martin@martin.st>
  3. Date: Wed, 23 Jan 2019 08:25:28 +0000
  4. Subject: [PATCH] Reapply: [llvm-objcopy] [COFF] Implement --add-gnu-debuglink
  5. This was reverted since it broke a couple buildbots. The reason
  6. for the breakage is not yet known, but this time, the test has
  7. got more diagnostics added, to hopefully allow figuring out
  8. what goes wrong.
  9. Differential Revision: https://reviews.llvm.org/D57007
  10. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@351931 91177308-0d34-0410-b5e6-96231b3b80d8
  11. ---
  12. .../llvm-objcopy/COFF/add-gnu-debuglink.test | 48 +++++++++++++++
  13. tools/llvm-objcopy/COFF/COFFObjcopy.cpp | 61 +++++++++++++++++++
  14. tools/llvm-objcopy/COFF/Object.cpp | 2 +-
  15. tools/llvm-objcopy/COFF/Object.h | 26 +++++++-
  16. tools/llvm-objcopy/COFF/Reader.cpp | 4 +-
  17. tools/llvm-objcopy/COFF/Writer.cpp | 9 +--
  18. 6 files changed, 143 insertions(+), 7 deletions(-)
  19. create mode 100644 test/tools/llvm-objcopy/COFF/add-gnu-debuglink.test
  20. diff --git a/llvm/test/tools/llvm-objcopy/COFF/add-gnu-debuglink.test b/llvm/test/tools/llvm-objcopy/COFF/add-gnu-debuglink.test
  21. new file mode 100644
  22. index 00000000000..cf3a9bba920
  23. --- /dev/null
  24. +++ b/llvm/test/tools/llvm-objcopy/COFF/add-gnu-debuglink.test
  25. @@ -0,0 +1,48 @@
  26. +RUN: yaml2obj %p/Inputs/x86_64-exe.yaml > %t.in123.exe
  27. +
  28. +# Using a debuglink filename with a length that is a multiple of 4, to
  29. +# showcase padding in CONTENTS below.
  30. +
  31. +RUN: llvm-objcopy --add-gnu-debuglink=%t.in123.exe %t.in123.exe %t.out.exe
  32. +
  33. +# Temporary debugging of issues with this test:
  34. +RUN: ls -l %t.out.exe || true
  35. +RUN: od -Ax -t x1 %t.out.exe || true
  36. +RUN: llvm-readobj -sections %t.out.exe || true
  37. +
  38. +RUN: llvm-readobj -sections %t.out.exe | FileCheck %s --check-prefix=SECTIONS
  39. +RUN: llvm-objdump -s %t.out.exe | FileCheck %s --check-prefix=CONTENTS
  40. +
  41. +# Show the last of the preexisting sections, which is used for choosing
  42. +# a virtual address for the generated one.
  43. +
  44. +SECTIONS: Section {
  45. +SECTIONS: Number: 4
  46. +SECTIONS-NEXT: Name: .pdata
  47. +SECTIONS-NEXT: VirtualSize: 0x18
  48. +SECTIONS-NEXT: VirtualAddress: 0x4000
  49. +SECTIONS-NEXT: RawDataSize: 512
  50. +SECTIONS: Section {
  51. +SECTIONS-NEXT: Number: 5
  52. +SECTIONS-NEXT: Name: .gnu_debuglink
  53. +SECTIONS-NEXT: VirtualSize: 0x2C
  54. +SECTIONS-NEXT: VirtualAddress: 0x5000
  55. +SECTIONS-NEXT: RawDataSize: 512
  56. +SECTIONS-NEXT: PointerToRawData:
  57. +SECTIONS-NEXT: PointerToRelocations:
  58. +SECTIONS-NEXT: PointerToLineNumbers:
  59. +SECTIONS-NEXT: RelocationCount:
  60. +SECTIONS-NEXT: LineNumberCount:
  61. +SECTIONS-NEXT: Characteristics [ (0x42000040)
  62. +SECTIONS-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40)
  63. +SECTIONS-NEXT: IMAGE_SCN_MEM_DISCARDABLE (0x2000000)
  64. +SECTIONS-NEXT: IMAGE_SCN_MEM_READ (0x40000000)
  65. +SECTIONS-NEXT: ]
  66. +
  67. +# Note: The last 4 bytes here are the crc of the referenced file - if the
  68. +# yaml2obj generated file changes, this crc changes.
  69. +
  70. +CONTENTS: Contents of section .gnu_debuglink:
  71. +CONTENTS: 40005000 6164642d 676e752d 64656275 676c696e add-gnu-debuglin
  72. +CONTENTS: 40005010 6b2e7465 73742e74 6d702e69 6e313233 k.test.tmp.in123
  73. +CONTENTS: 40005020 2e657865 00000000 7929adc3 .exe
  74. diff --git a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
  75. index 8d8f53d13d8..20adbe11e7a 100644
  76. --- a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
  77. +++ b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
  78. @@ -17,6 +17,8 @@
  79. #include "llvm/Object/Binary.h"
  80. #include "llvm/Object/COFF.h"
  81. #include "llvm/Support/Errc.h"
  82. +#include "llvm/Support/JamCRC.h"
  83. +#include "llvm/Support/Path.h"
  84. #include <cassert>
  85. namespace llvm {
  86. @@ -30,6 +32,61 @@ static bool isDebugSection(const Section &Sec) {
  87. return Sec.Name.startswith(".debug");
  88. }
  89. +static uint64_t getNextRVA(const Object &Obj) {
  90. + if (Obj.getSections().empty())
  91. + return 0;
  92. + const Section &Last = Obj.getSections().back();
  93. + return alignTo(Last.Header.VirtualAddress + Last.Header.VirtualSize,
  94. + Obj.PeHeader.SectionAlignment);
  95. +}
  96. +
  97. +static uint32_t getCRC32(StringRef Data) {
  98. + JamCRC CRC;
  99. + CRC.update(ArrayRef<char>(Data.data(), Data.size()));
  100. + // The CRC32 value needs to be complemented because the JamCRC dosn't
  101. + // finalize the CRC32 value. It also dosn't negate the initial CRC32 value
  102. + // but it starts by default at 0xFFFFFFFF which is the complement of zero.
  103. + return ~CRC.getCRC();
  104. +}
  105. +
  106. +static std::vector<uint8_t> createGnuDebugLinkSectionContents(StringRef File) {
  107. + ErrorOr<std::unique_ptr<MemoryBuffer>> LinkTargetOrErr =
  108. + MemoryBuffer::getFile(File);
  109. + if (!LinkTargetOrErr)
  110. + error("'" + File + "': " + LinkTargetOrErr.getError().message());
  111. + auto LinkTarget = std::move(*LinkTargetOrErr);
  112. + uint32_t CRC32 = getCRC32(LinkTarget->getBuffer());
  113. +
  114. + StringRef FileName = sys::path::filename(File);
  115. + size_t CRCPos = alignTo(FileName.size() + 1, 4);
  116. + std::vector<uint8_t> Data(CRCPos + 4);
  117. + memcpy(Data.data(), FileName.data(), FileName.size());
  118. + support::endian::write32le(Data.data() + CRCPos, CRC32);
  119. + return Data;
  120. +}
  121. +
  122. +static void addGnuDebugLink(Object &Obj, StringRef DebugLinkFile) {
  123. + uint32_t StartRVA = getNextRVA(Obj);
  124. +
  125. + std::vector<Section> Sections;
  126. + Section Sec;
  127. + Sec.setOwnedContents(createGnuDebugLinkSectionContents(DebugLinkFile));
  128. + Sec.Name = ".gnu_debuglink";
  129. + Sec.Header.VirtualSize = Sec.getContents().size();
  130. + Sec.Header.VirtualAddress = StartRVA;
  131. + Sec.Header.SizeOfRawData =
  132. + alignTo(Sec.Header.VirtualSize, Obj.PeHeader.FileAlignment);
  133. + // Sec.Header.PointerToRawData is filled in by the writer.
  134. + Sec.Header.PointerToRelocations = 0;
  135. + Sec.Header.PointerToLinenumbers = 0;
  136. + // Sec.Header.NumberOfRelocations is filled in by the writer.
  137. + Sec.Header.NumberOfLinenumbers = 0;
  138. + Sec.Header.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA |
  139. + IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE;
  140. + Sections.push_back(Sec);
  141. + Obj.addSections(Sections);
  142. +}
  143. +
  144. static Error handleArgs(const CopyConfig &Config, Object &Obj) {
  145. // Perform the actual section removals.
  146. Obj.removeSections([&Config](const Section &Sec) {
  147. @@ -109,6 +166,10 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj) {
  148. return false;
  149. });
  150. +
  151. + if (!Config.AddGnuDebugLink.empty())
  152. + addGnuDebugLink(Obj, Config.AddGnuDebugLink);
  153. +
  154. return Error::success();
  155. }
  156. diff --git a/llvm/tools/llvm-objcopy/COFF/Object.cpp b/llvm/tools/llvm-objcopy/COFF/Object.cpp
  157. index 83435dffa98..8c382c1faef 100644
  158. --- a/llvm/tools/llvm-objcopy/COFF/Object.cpp
  159. +++ b/llvm/tools/llvm-objcopy/COFF/Object.cpp
  160. @@ -129,7 +129,7 @@ void Object::removeSections(function_ref<bool(const Section &)> ToRemove) {
  161. void Object::truncateSections(function_ref<bool(const Section &)> ToTruncate) {
  162. for (Section &Sec : Sections) {
  163. if (ToTruncate(Sec)) {
  164. - Sec.Contents = ArrayRef<uint8_t>();
  165. + Sec.clearContents();
  166. Sec.Relocs.clear();
  167. Sec.Header.SizeOfRawData = 0;
  168. }
  169. diff --git a/llvm/tools/llvm-objcopy/COFF/Object.h b/llvm/tools/llvm-objcopy/COFF/Object.h
  170. index 0630f9c5ff8..afa272286ef 100644
  171. --- a/llvm/tools/llvm-objcopy/COFF/Object.h
  172. +++ b/llvm/tools/llvm-objcopy/COFF/Object.h
  173. @@ -35,11 +35,35 @@ struct Relocation {
  174. struct Section {
  175. object::coff_section Header;
  176. - ArrayRef<uint8_t> Contents;
  177. std::vector<Relocation> Relocs;
  178. StringRef Name;
  179. ssize_t UniqueId;
  180. size_t Index;
  181. +
  182. + ArrayRef<uint8_t> getContents() const {
  183. + if (!OwnedContents.empty())
  184. + return OwnedContents;
  185. + return ContentsRef;
  186. + }
  187. +
  188. + void setContentsRef(ArrayRef<uint8_t> Data) {
  189. + OwnedContents.clear();
  190. + ContentsRef = Data;
  191. + }
  192. +
  193. + void setOwnedContents(std::vector<uint8_t> &&Data) {
  194. + ContentsRef = ArrayRef<uint8_t>();
  195. + OwnedContents = std::move(Data);
  196. + }
  197. +
  198. + void clearContents() {
  199. + ContentsRef = ArrayRef<uint8_t>();
  200. + OwnedContents.clear();
  201. + }
  202. +
  203. +private:
  204. + ArrayRef<uint8_t> ContentsRef;
  205. + std::vector<uint8_t> OwnedContents;
  206. };
  207. struct Symbol {
  208. diff --git a/llvm/tools/llvm-objcopy/COFF/Reader.cpp b/llvm/tools/llvm-objcopy/COFF/Reader.cpp
  209. index 2446277cc2b..87dd60a43cf 100644
  210. --- a/llvm/tools/llvm-objcopy/COFF/Reader.cpp
  211. +++ b/llvm/tools/llvm-objcopy/COFF/Reader.cpp
  212. @@ -69,8 +69,10 @@ Error COFFReader::readSections(Object &Obj) const {
  213. Sections.push_back(Section());
  214. Section &S = Sections.back();
  215. S.Header = *Sec;
  216. - if (auto EC = COFFObj.getSectionContents(Sec, S.Contents))
  217. + ArrayRef<uint8_t> Contents;
  218. + if (auto EC = COFFObj.getSectionContents(Sec, Contents))
  219. return errorCodeToError(EC);
  220. + S.setContentsRef(Contents);
  221. ArrayRef<coff_relocation> Relocs = COFFObj.getRelocations(Sec);
  222. for (const coff_relocation &R : Relocs)
  223. S.Relocs.push_back(R);
  224. diff --git a/llvm/tools/llvm-objcopy/COFF/Writer.cpp b/llvm/tools/llvm-objcopy/COFF/Writer.cpp
  225. index db3589bb119..05e46291c39 100644
  226. --- a/llvm/tools/llvm-objcopy/COFF/Writer.cpp
  227. +++ b/llvm/tools/llvm-objcopy/COFF/Writer.cpp
  228. @@ -286,14 +286,15 @@ void COFFWriter::writeHeaders(bool IsBigObj) {
  229. void COFFWriter::writeSections() {
  230. for (const auto &S : Obj.getSections()) {
  231. uint8_t *Ptr = Buf.getBufferStart() + S.Header.PointerToRawData;
  232. - std::copy(S.Contents.begin(), S.Contents.end(), Ptr);
  233. + ArrayRef<uint8_t> Contents = S.getContents();
  234. + std::copy(Contents.begin(), Contents.end(), Ptr);
  235. // For executable sections, pad the remainder of the raw data size with
  236. // 0xcc, which is int3 on x86.
  237. if ((S.Header.Characteristics & IMAGE_SCN_CNT_CODE) &&
  238. - S.Header.SizeOfRawData > S.Contents.size())
  239. - memset(Ptr + S.Contents.size(), 0xcc,
  240. - S.Header.SizeOfRawData - S.Contents.size());
  241. + S.Header.SizeOfRawData > Contents.size())
  242. + memset(Ptr + Contents.size(), 0xcc,
  243. + S.Header.SizeOfRawData - Contents.size());
  244. Ptr += S.Header.SizeOfRawData;
  245. for (const auto &R : S.Relocs) {
  246. --
  247. 2.17.1