Skip to content

Instantly share code, notes, and snippets.

@santagada
Created February 25, 2019 10:50
Show Gist options
  • Save santagada/b6f5c42a3c83cd52fc663094f34bcc8d to your computer and use it in GitHub Desktop.
Save santagada/b6f5c42a3c83cd52fc663094f34bcc8d to your computer and use it in GitHub Desktop.
diff --git a/llvm/tools/llvm-objcopy/CMakeLists.txt b/llvm/tools/llvm-objcopy/CMakeLists.txt
index 8406786e9e4..0a9e33e568a 100644
--- a/llvm/tools/llvm-objcopy/CMakeLists.txt
+++ b/llvm/tools/llvm-objcopy/CMakeLists.txt
@@ -1,4 +1,5 @@
set(LLVM_LINK_COMPONENTS
+ DebugInfoCodeView
Object
Option
Support
diff --git a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
index 72161e1c4d7..fd801764f61 100644
--- a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
+++ b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
@@ -19,6 +19,8 @@
#include "llvm/Support/Errc.h"
#include "llvm/Support/JamCRC.h"
#include "llvm/Support/Path.h"
+#include "llvm/DebugInfo/CodeView/TypeHashing.h"
+#include "llvm/Support/BinaryStreamWriter.h"
#include <cassert>
namespace llvm {
@@ -27,6 +29,7 @@ namespace coff {
using namespace object;
using namespace COFF;
+using namespace codeview;
static bool isDebugSection(const Section &Sec) {
return Sec.Name.startswith(".debug");
@@ -87,6 +90,129 @@ static void addGnuDebugLink(Object &Obj, StringRef DebugLinkFile) {
Obj.addSections(Sections);
}
+static ArrayRef<uint8_t> consumeDebugMagic(ArrayRef<uint8_t> Data,
+ StringRef SecName) {
+ // First 4 bytes are section magic.
+ if (Data.size() < 4)
+ error(SecName + " too short");
+ if (support::endian::read32le(Data.data()) != COFF::DEBUG_SECTION_MAGIC)
+ error(SecName + " has an invalid magic");
+ return Data.slice(4);
+}
+
+const std::vector<GloballyHashedType> mergeDebugT(const Section *Sec) {
+ std::vector<GloballyHashedType> OwnedHashes;
+
+ ArrayRef<uint8_t> Data = Sec->getContents();
+ Data = consumeDebugMagic(Data, ".debug$T");
+ if (Data.empty())
+ return OwnedHashes;
+
+ BinaryByteStream Stream(Data, support::little);
+ CVTypeArray Types;
+ BinaryStreamReader Reader(Stream);
+ if (auto EC = Reader.readArray(Types, Reader.getLength()))
+ error("Reader::readArray failed: " + toString(std::move(EC)));
+
+ OwnedHashes = GloballyHashedType::hashTypes(Types);
+ return OwnedHashes;
+}
+
+//void CodeViewDebug::emitTypeGlobalHashes() {
+// if (TypeTable.empty())
+// return;
+//
+// // Start the .debug$H section with the version and hash algorithm, currently
+// // hardcoded to version 0, SHA1.
+// OS.SwitchSection(Asm->getObjFileLowering().getCOFFGlobalTypeHashesSection());
+//
+// OS.EmitValueToAlignment(4);
+// OS.AddComment("Magic");
+// OS.EmitIntValue(COFF::DEBUG_HASHES_SECTION_MAGIC, 4);
+// OS.AddComment("Section Version");
+// OS.EmitIntValue(0, 2);
+// OS.AddComment("Hash Algorithm");
+// OS.EmitIntValue(uint16_t(GlobalTypeHashAlg::SHA1_8), 2);
+//
+// TypeIndex TI(TypeIndex::FirstNonSimpleIndex);
+// for (const auto &GHR : TypeTable.hashes()) {
+// if (OS.isVerboseAsm()) {
+// // Emit an EOL-comment describing which TypeIndex this hash corresponds
+// // to, as well as the stringified SHA1 hash.
+// SmallString<32> Comment;
+// raw_svector_ostream CommentOS(Comment);
+// CommentOS << formatv("{0:X+} [{1}]", TI.getIndex(), GHR);
+// OS.AddComment(Comment);
+// ++TI;
+// }
+// assert(GHR.Hash.size() == 8);
+// StringRef S(reinterpret_cast<const char *>(GHR.Hash.data()),
+// GHR.Hash.size());
+// OS.EmitBinaryData(S);
+// }
+//}
+
+ArrayRef<uint8_t> toDebugH(const std::vector<GloballyHashedType> hashes,
+ BumpPtrAllocator &Alloc) {
+ uint32_t Size = 8 + 8 * hashes.size();
+ uint8_t *Data = Alloc.Allocate<uint8_t>(Size);
+ MutableArrayRef<uint8_t> Buffer(Data, Size);
+ BinaryStreamWriter Writer(Buffer, llvm::support::little);
+ uint32_t magic = COFF::DEBUG_HASHES_SECTION_MAGIC;
+ cantFail(Writer.writeInteger(magic));
+ cantFail(Writer.writeInteger(uint16_t(0)));
+ cantFail(Writer.writeInteger(uint16_t(GlobalTypeHashAlg::SHA1_8)));
+ for (const auto &H : hashes) {
+ Writer.writeBytes(H.Hash);
+ }
+ assert(Writer.bytesRemaining() == 0);
+ return Buffer;
+}
+
+static void addGHashes(Object &Obj) {
+ std::vector<GloballyHashedType> hashes;
+
+ for (Section section: Obj.getSections()) {
+ if (section.Name == ".debug$H")
+ error("Already has .debug$H");
+
+ if (section.Name == ".debug$T") {
+ hashes = mergeDebugT(&section);
+ break;
+ }
+ }
+
+
+ std::vector<Section> Sections;
+ Section Sec;
+ BumpPtrAllocator Allocator;
+ Sec.setOwnedContents(toDebugH(hashes, Allocator));
+ Sec.Name = ".debug$H";
+ Sec.Header.VirtualSize = 0; // Sec.getContents().size();
+ Sec.Header.VirtualAddress = 0;
+ Sec.Header.SizeOfRawData = Sec.getContents().size();
+ // Sec.Header.PointerToRawData is filled in by the writer.
+ Sec.Header.PointerToRelocations = 0;
+ Sec.Header.PointerToLinenumbers = 0;
+ // Sec.Header.NumberOfRelocations is filled in by the writer.
+ Sec.Header.NumberOfLinenumbers = 0;
+ Sec.Header.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA |
+ IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_ALIGN_4BYTES;
+ std::vector<Symbol> Symbols;
+ Symbol Sym;
+ Sym.Name = ".debug$H";
+ Sym.Sym.Value = 0;
+ Sym.Sym.StorageClass = IMAGE_SYM_CLASS_STATIC;
+ Sym.Sym.NumberOfAuxSymbols = 1;
+
+
+ Sections.push_back(Sec);
+ Obj.addSections(Sections);
+ Sym.Sym.SectionNumber = Sec.Index;
+ Symbols.push_back(Sym);
+ //Obj.addSymbols(Sym);
+}
+
static Error handleArgs(const CopyConfig &Config, Object &Obj) {
// Perform the actual section removals.
Obj.removeSections([&Config](const Section &Sec) {
@@ -171,6 +297,10 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj) {
if (!Config.AddGnuDebugLink.empty())
addGnuDebugLink(Obj, Config.AddGnuDebugLink);
+ if (Config.AddGHashes)
+ addGHashes(Obj);
+
+
if (!Config.BuildIdLinkDir.empty() || Config.BuildIdLinkInput ||
Config.BuildIdLinkOutput || !Config.SplitDWO.empty() ||
!Config.SymbolsPrefix.empty() || !Config.AddSection.empty() ||
diff --git a/llvm/tools/llvm-objcopy/CopyConfig.cpp b/llvm/tools/llvm-objcopy/CopyConfig.cpp
index 91721962503..0e59f75b034 100644
--- a/llvm/tools/llvm-objcopy/CopyConfig.cpp
+++ b/llvm/tools/llvm-objcopy/CopyConfig.cpp
@@ -328,6 +328,7 @@ DriverConfig parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
}
Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink);
+ Config.AddGHashes = InputArgs.hasArg(OBJCOPY_add_ghashes);
Config.BuildIdLinkDir = InputArgs.getLastArgValue(OBJCOPY_build_id_link_dir);
if (InputArgs.hasArg(OBJCOPY_build_id_link_input))
Config.BuildIdLinkInput =
diff --git a/llvm/tools/llvm-objcopy/CopyConfig.h b/llvm/tools/llvm-objcopy/CopyConfig.h
index 9d16c7b4582..6480a87b6d5 100644
--- a/llvm/tools/llvm-objcopy/CopyConfig.h
+++ b/llvm/tools/llvm-objcopy/CopyConfig.h
@@ -89,6 +89,7 @@ struct CopyConfig {
StringMap<StringRef> SymbolsToRename;
// Boolean options
+ bool AddGHashes = false;
bool DeterministicArchives = true;
bool ExtractDWO = false;
bool KeepFileSymbols = false;
diff --git a/llvm/tools/llvm-objcopy/ObjcopyOpts.td b/llvm/tools/llvm-objcopy/ObjcopyOpts.td
index a25d1f3b515..e8b41132961 100644
--- a/llvm/tools/llvm-objcopy/ObjcopyOpts.td
+++ b/llvm/tools/llvm-objcopy/ObjcopyOpts.td
@@ -63,6 +63,9 @@ defm add_gnu_debuglink
: Eq<"add-gnu-debuglink", "Add a .gnu_debuglink for <debug-file>">,
MetaVarName<"debug-file">;
+def add_ghashes : Flag<["-", "--"], "add-ghashes">,
+ HelpText<"Add .h global hashes">;
+
defm remove_section : Eq<"remove-section", "Remove <section>">,
MetaVarName<"section">;
def R : JoinedOrSeparate<["-"], "R">, Alias<remove_section>;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment