add .gnu.warning.SYMBOL support to ld.lld(1) to display the warnings in
authorrobert <robert@openbsd.org>
Thu, 17 Nov 2022 12:24:02 +0000 (12:24 +0000)
committerrobert <robert@openbsd.org>
Thu, 17 Nov 2022 12:24:02 +0000 (12:24 +0000)
these sections like ld.bfd(1)

e.g:
add.c(add.o:(add)): warning: sprintf() is often misused, please use snprintf()
add.c(add.o:(add)): warning: strcpy() is almost always misused, please use strlcpy()
add.c(add.o:(add)): warning: strcat() is almost always misused, please use strlcat()

ok deraadt@

gnu/llvm/lld/ELF/InputFiles.cpp
gnu/llvm/lld/ELF/InputFiles.h
gnu/llvm/lld/ELF/Relocations.cpp
gnu/llvm/lld/ELF/SymbolTable.cpp
gnu/llvm/lld/ELF/Symbols.h

index ab65571..7565240 100644 (file)
@@ -52,6 +52,8 @@ std::vector<SharedFile *> elf::sharedFiles;
 
 std::unique_ptr<TarWriter> elf::tar;
 
+DenseMap<StringRef, StringRef> elf::gnuWarnings;
+
 // Returns "<internal>", "foo.a(bar.o)" or "baz.o".
 std::string lld::toString(const InputFile *f) {
   if (!f)
@@ -66,6 +68,17 @@ std::string lld::toString(const InputFile *f) {
   return f->toStringCache;
 }
 
+// .gnu.warning.SYMBOL are treated as warning symbols for the given symbol
+void lld::parseGNUWarning(StringRef name, ArrayRef<char> data, size_t size) {
+  if (!name.empty() && name.startswith(".gnu.warning.")) {
+    StringRef wsym = name.substr(13);
+    StringRef s(data.begin());
+    StringRef wng(s.substr(0, size));
+    symtab->insert(wsym)->gwarn = true;
+    gnuWarnings.insert({wsym, wng});
+  }
+}
+
 static ELFKind getELFKind(MemoryBufferRef mb, StringRef archiveName) {
   unsigned char size;
   unsigned char endian;
@@ -647,6 +660,14 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComdats) {
     case SHT_RELA:
     case SHT_NULL:
       break;
+    case SHT_PROGBITS: {
+      this->sections[i] = createInputSection(sec);
+      StringRef name = CHECK(obj.getSectionName(sec, this->sectionStringTable), this);
+      ArrayRef<char> data =
+          CHECK(obj.template getSectionContentsAsArray<char>(sec), this);
+      parseGNUWarning(name, data, sec.sh_size);
+      }
+      break;
     default:
       this->sections[i] = createInputSection(sec);
     }
@@ -1450,6 +1471,9 @@ template <class ELFT> void SharedFile::parse() {
   const ELFFile<ELFT> obj = this->getObj<ELFT>();
   ArrayRef<Elf_Shdr> sections = CHECK(obj.sections(), this);
 
+  StringRef sectionStringTable =
+      CHECK(obj.getSectionStringTable(sections), this);
+
   const Elf_Shdr *versymSec = nullptr;
   const Elf_Shdr *verdefSec = nullptr;
   const Elf_Shdr *verneedSec = nullptr;
@@ -1472,6 +1496,13 @@ template <class ELFT> void SharedFile::parse() {
     case SHT_GNU_verneed:
       verneedSec = &sec;
       break;
+    case SHT_PROGBITS: {
+      StringRef name = CHECK(obj.getSectionName(sec, sectionStringTable), this);
+      ArrayRef<char> data =
+          CHECK(obj.template getSectionContentsAsArray<char>(sec), this);
+      parseGNUWarning(name, data, sec.sh_size);
+      break;
+    }
     }
   }
 
index bd72cfc..4d64a65 100644 (file)
@@ -37,6 +37,8 @@ class DWARFCache;
 // Returns "<internal>", "foo.a(bar.o)" or "baz.o".
 std::string toString(const elf::InputFile *f);
 
+void parseGNUWarning(StringRef name, ArrayRef<char> data, size_t size);
+
 namespace elf {
 
 using llvm::object::Archive;
index bf57675..114780e 100644 (file)
@@ -954,6 +954,18 @@ template <class ELFT> void elf::reportUndefinedSymbols() {
   undefs.clear();
 }
 
+static void reportGNUWarning(Symbol &sym, InputSectionBase &sec,
+                                 uint64_t offset) {
+  if (sym.gwarn) {
+    StringRef gnuWarning = gnuWarnings.lookup(sym.getName());
+    // report first occurance only
+    sym.gwarn = false;
+    if (!gnuWarning.empty())
+      message(sec.getSrcMsg(sym, offset) + "(" + sec.getObjMsg(offset) +
+              "): warning: " + gnuWarning);
+  }
+}
+
 // Report an undefined symbol if necessary.
 // Returns true if the undefined symbol will produce an error message.
 static bool maybeReportUndefined(Symbol &sym, InputSectionBase &sec,
@@ -1327,6 +1339,8 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
   if (symIndex != 0 && maybeReportUndefined(sym, sec, rel.r_offset))
     return;
 
+  reportGNUWarning(sym, sec, rel.r_offset);
+
   const uint8_t *relocatedAddr = sec.data().begin() + rel.r_offset;
   RelExpr expr = target->getRelExpr(type, sym, relocatedAddr);
 
index 22e6b4f..da1684a 100644 (file)
@@ -90,6 +90,7 @@ Symbol *SymbolTable::insert(StringRef name) {
   sym->canInline = true;
   sym->referenced = false;
   sym->traced = false;
+  sym->gwarn = false;
   sym->scriptDefined = false;
   sym->partition = 1;
   return sym;
index d4a589e..3a4f851 100644 (file)
@@ -142,6 +142,9 @@ public:
   // True if this symbol is specified by --trace-symbol option.
   uint8_t traced : 1;
 
+  // True if the .gnu.warning.SYMBOL is set for the symbol
+  uint8_t gwarn : 1;
+
   inline void replace(const Symbol &newSym);
 
   bool includeInDynsym() const;
@@ -247,7 +250,7 @@ protected:
         type(type), stOther(stOther), symbolKind(k), visibility(stOther & 3),
         isUsedInRegularObj(!file || file->kind() == InputFile::ObjKind),
         exportDynamic(isExportDynamic(k, visibility)), inDynamicList(false),
-        canInline(false), referenced(false), traced(false), needsPltAddr(false),
+        canInline(false), referenced(false), traced(false), gwarn(false), needsPltAddr(false),
         isInIplt(false), gotInIgot(false), isPreemptible(false),
         used(!config->gcSections), needsTocRestore(false),
         scriptDefined(false) {}
@@ -560,6 +563,7 @@ void Symbol::replace(const Symbol &newSym) {
   canInline = old.canInline;
   referenced = old.referenced;
   traced = old.traced;
+  gwarn = old.gwarn;
   isPreemptible = old.isPreemptible;
   scriptDefined = old.scriptDefined;
   partition = old.partition;
@@ -579,6 +583,8 @@ void maybeWarnUnorderableSymbol(const Symbol *sym);
 bool computeIsPreemptible(const Symbol &sym);
 void reportBackrefs();
 
+extern llvm::DenseMap<StringRef, StringRef> gnuWarnings;
+
 // A mapping from a symbol to an InputFile referencing it backward. Used by
 // --warn-backrefs.
 extern llvm::DenseMap<const Symbol *,