[ELF] Refactor target error messages

Differential revision: https://reviews.llvm.org/D27097

llvm-svn: 288114
diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp
index e4536ef..4a723d5 100644
--- a/lld/ELF/OutputSections.cpp
+++ b/lld/ELF/OutputSections.cpp
@@ -249,6 +249,7 @@
 }
 
 template <class ELFT> void OutputSection<ELFT>::writeTo(uint8_t *Buf) {
+  Loc = Buf;
   if (uint32_t Filler = Script<ELFT>::X->getFiller(this->Name))
     fill(Buf, this->Size, Filler);
 
diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h
index 2dd213d..a4e59df 100644
--- a/lld/ELF/OutputSections.h
+++ b/lld/ELF/OutputSections.h
@@ -121,6 +121,9 @@
     return B->getKind() == Regular;
   }
   std::vector<InputSection<ELFT> *> Sections;
+
+  // Location in the output buffer.
+  uint8_t *Loc = nullptr;
 };
 
 template <class ELFT>
diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp
index a251f6b..ffbe16d 100644
--- a/lld/ELF/Target.cpp
+++ b/lld/ELF/Target.cpp
@@ -55,24 +55,32 @@
   return getELFRelocationTypeName(Config->EMachine, Type);
 }
 
-template <unsigned N> static void checkInt(int64_t V, uint32_t Type) {
+template <unsigned N>
+static void checkInt(uint8_t *Loc, int64_t V, uint32_t Type) {
   if (!isInt<N>(V))
-    error("relocation " + toString(Type) + " out of range");
+    error(getErrorLocation(Loc) + "relocation " + toString(Type) +
+          " out of range");
 }
 
-template <unsigned N> static void checkUInt(uint64_t V, uint32_t Type) {
+template <unsigned N>
+static void checkUInt(uint8_t *Loc, uint64_t V, uint32_t Type) {
   if (!isUInt<N>(V))
-    error("relocation " + toString(Type) + " out of range");
+    error(getErrorLocation(Loc) + "relocation " + toString(Type) +
+          " out of range");
 }
 
-template <unsigned N> static void checkIntUInt(uint64_t V, uint32_t Type) {
+template <unsigned N>
+static void checkIntUInt(uint8_t *Loc, uint64_t V, uint32_t Type) {
   if (!isInt<N>(V) && !isUInt<N>(V))
-    error("relocation " + toString(Type) + " out of range");
+    error(getErrorLocation(Loc) + "relocation " + toString(Type) +
+          " out of range");
 }
 
-template <unsigned N> static void checkAlignment(uint64_t V, uint32_t Type) {
+template <unsigned N>
+static void checkAlignment(uint8_t *Loc, uint64_t V, uint32_t Type) {
   if ((V & (N - 1)) != 0)
-    error("improper alignment for relocation " + toString(Type));
+    error(getErrorLocation(Loc) + "improper alignment for relocation " +
+          toString(Type));
 }
 
 namespace {
@@ -443,7 +451,7 @@
 
 void X86TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
                                 uint64_t Val) const {
-  checkInt<32>(Val, Type);
+  checkInt<32>(Loc, Val, Type);
   write32le(Loc, Val);
 }
 
@@ -737,7 +745,8 @@
     memcpy(Inst, "\x48\xc7", 2);
     *RegSlot = 0xc0 | Reg;
   } else {
-    fatal("R_X86_64_GOTTPOFF must be used in MOVQ or ADDQ instructions only");
+    fatal(getErrorLocation(Loc - 3) +
+          "R_X86_64_GOTTPOFF must be used in MOVQ or ADDQ instructions only");
   }
 
   // The original code used a PC relative relocation.
@@ -779,7 +788,7 @@
                                          uint64_t Val) const {
   switch (Type) {
   case R_X86_64_32:
-    checkUInt<32>(Val, Type);
+    checkUInt<32>(Loc, Val, Type);
     write32le(Loc, Val);
     break;
   case R_X86_64_32S:
@@ -795,7 +804,7 @@
   case R_X86_64_TLSLD:
   case R_X86_64_DTPOFF32:
   case R_X86_64_SIZE32:
-    checkInt<32>(Val, Type);
+    checkInt<32>(Loc, Val, Type);
     write32le(Loc, Val);
     break;
   case R_X86_64_64:
@@ -806,7 +815,7 @@
     write64le(Loc, Val);
     break;
   default:
-    fatal("unrecognized reloc " + Twine(Type));
+    fatal(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
   }
 }
 
@@ -975,7 +984,7 @@
     or32be(Loc, Val & 0x3FFFFFC);
     break;
   default:
-    fatal("unrecognized reloc " + Twine(Type));
+    fatal(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
   }
 }
 
@@ -1095,18 +1104,18 @@
 
   switch (Type) {
   case R_PPC64_ADDR14: {
-    checkAlignment<4>(Val, Type);
+    checkAlignment<4>(Loc, Val, Type);
     // Preserve the AA/LK bits in the branch instruction
     uint8_t AALK = Loc[3];
     write16be(Loc + 2, (AALK & 3) | (Val & 0xfffc));
     break;
   }
   case R_PPC64_ADDR16:
-    checkInt<16>(Val, Type);
+    checkInt<16>(Loc, Val, Type);
     write16be(Loc, Val);
     break;
   case R_PPC64_ADDR16_DS:
-    checkInt<16>(Val, Type);
+    checkInt<16>(Loc, Val, Type);
     write16be(Loc, (read16be(Loc) & 3) | (Val & ~3));
     break;
   case R_PPC64_ADDR16_HA:
@@ -1138,7 +1147,7 @@
     break;
   case R_PPC64_ADDR32:
   case R_PPC64_REL32:
-    checkInt<32>(Val, Type);
+    checkInt<32>(Loc, Val, Type);
     write32be(Loc, Val);
     break;
   case R_PPC64_ADDR64:
@@ -1148,12 +1157,12 @@
     break;
   case R_PPC64_REL24: {
     uint32_t Mask = 0x03FFFFFC;
-    checkInt<24>(Val, Type);
+    checkInt<24>(Loc, Val, Type);
     write32be(Loc, (read32be(Loc) & ~Mask) | (Val & Mask));
     break;
   }
   default:
-    fatal("unrecognized reloc " + Twine(Type));
+    fatal(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
   }
 }
 
@@ -1311,12 +1320,12 @@
   switch (Type) {
   case R_AARCH64_ABS16:
   case R_AARCH64_PREL16:
-    checkIntUInt<16>(Val, Type);
+    checkIntUInt<16>(Loc, Val, Type);
     write16le(Loc, Val);
     break;
   case R_AARCH64_ABS32:
   case R_AARCH64_PREL32:
-    checkIntUInt<32>(Val, Type);
+    checkIntUInt<32>(Loc, Val, Type);
     write32le(Loc, Val);
     break;
   case R_AARCH64_ABS64:
@@ -1335,26 +1344,26 @@
   case R_AARCH64_ADR_PREL_PG_HI21:
   case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
   case R_AARCH64_TLSDESC_ADR_PAGE21:
-    checkInt<33>(Val, Type);
+    checkInt<33>(Loc, Val, Type);
     updateAArch64Addr(Loc, Val >> 12);
     break;
   case R_AARCH64_ADR_PREL_LO21:
-    checkInt<21>(Val, Type);
+    checkInt<21>(Loc, Val, Type);
     updateAArch64Addr(Loc, Val);
     break;
   case R_AARCH64_CALL26:
   case R_AARCH64_JUMP26:
-    checkInt<28>(Val, Type);
+    checkInt<28>(Loc, Val, Type);
     or32le(Loc, (Val & 0x0FFFFFFC) >> 2);
     break;
   case R_AARCH64_CONDBR19:
-    checkInt<21>(Val, Type);
+    checkInt<21>(Loc, Val, Type);
     or32le(Loc, (Val & 0x1FFFFC) << 3);
     break;
   case R_AARCH64_LD64_GOT_LO12_NC:
   case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
   case R_AARCH64_TLSDESC_LD64_LO12_NC:
-    checkAlignment<8>(Val, Type);
+    checkAlignment<8>(Loc, Val, Type);
     or32le(Loc, (Val & 0xFF8) << 7);
     break;
   case R_AARCH64_LDST128_ABS_LO12_NC:
@@ -1385,11 +1394,11 @@
     or32le(Loc, (Val & 0xFFFF000000000000) >> 43);
     break;
   case R_AARCH64_TSTBR14:
-    checkInt<16>(Val, Type);
+    checkInt<16>(Loc, Val, Type);
     or32le(Loc, (Val & 0xFFFC) << 3);
     break;
   case R_AARCH64_TLSLE_ADD_TPREL_HI12:
-    checkInt<24>(Val, Type);
+    checkInt<24>(Loc, Val, Type);
     updateAArch64Add(Loc, Val >> 12);
     break;
   case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
@@ -1397,7 +1406,7 @@
     updateAArch64Add(Loc, Val);
     break;
   default:
-    fatal("unrecognized reloc " + Twine(Type));
+    fatal(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
   }
 }
 
@@ -1414,7 +1423,7 @@
   //   movk    x0, #0x10
   //   nop
   //   nop
-  checkUInt<32>(Val, Type);
+  checkUInt<32>(Loc, Val, Type);
 
   switch (Type) {
   case R_AARCH64_TLSDESC_ADD_LO12_NC:
@@ -1466,7 +1475,7 @@
 
 void AArch64TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type,
                                        uint64_t Val) const {
-  checkUInt<32>(Val, Type);
+  checkUInt<32>(Loc, Val, Type);
 
   if (Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21) {
     // Generate MOVZ.
@@ -1507,7 +1516,7 @@
     write32le(Loc, Val >> 32);
     break;
   default:
-    fatal("unrecognized reloc " + Twine(Type));
+    fatal(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
   }
 }
 
@@ -1703,7 +1712,7 @@
     write32le(Loc, Val);
     break;
   case R_ARM_PREL31:
-    checkInt<31>(Val, Type);
+    checkInt<31>(Loc, Val, Type);
     write32le(Loc, (read32le(Loc) & 0x80000000) | (Val & ~0x80000000));
     break;
   case R_ARM_CALL:
@@ -1712,7 +1721,7 @@
     if (Val & 1) {
       // If bit 0 of Val is 1 the target is Thumb, we must select a BLX.
       // The BLX encoding is 0xfa:H:imm24 where Val = imm24:H:'1'
-      checkInt<26>(Val, Type);
+      checkInt<26>(Loc, Val, Type);
       write32le(Loc, 0xfa000000 |                    // opcode
                          ((Val & 2) << 23) |         // H
                          ((Val >> 2) & 0x00ffffff)); // imm24
@@ -1726,16 +1735,16 @@
   case R_ARM_JUMP24:
   case R_ARM_PC24:
   case R_ARM_PLT32:
-    checkInt<26>(Val, Type);
+    checkInt<26>(Loc, Val, Type);
     write32le(Loc, (read32le(Loc) & ~0x00ffffff) | ((Val >> 2) & 0x00ffffff));
     break;
   case R_ARM_THM_JUMP11:
-    checkInt<12>(Val, Type);
+    checkInt<12>(Loc, Val, Type);
     write16le(Loc, (read32le(Loc) & 0xf800) | ((Val >> 1) & 0x07ff));
     break;
   case R_ARM_THM_JUMP19:
     // Encoding T3: Val = S:J2:J1:imm6:imm11:0
-    checkInt<21>(Val, Type);
+    checkInt<21>(Loc, Val, Type);
     write16le(Loc,
               (read16le(Loc) & 0xfbc0) |   // opcode cond
                   ((Val >> 10) & 0x0400) | // S
@@ -1760,7 +1769,7 @@
   case R_ARM_THM_JUMP24:
     // Encoding B  T4, BL T1, BLX T2: Val = S:I1:I2:imm10:imm11:0
     // FIXME: Use of I1 and I2 require v6T2ops
-    checkInt<25>(Val, Type);
+    checkInt<25>(Loc, Val, Type);
     write16le(Loc,
               0xf000 |                     // opcode
                   ((Val >> 14) & 0x0400) | // S
@@ -1778,14 +1787,14 @@
     break;
   case R_ARM_MOVT_ABS:
   case R_ARM_MOVT_PREL:
-    checkInt<32>(Val, Type);
+    checkInt<32>(Loc, Val, Type);
     write32le(Loc, (read32le(Loc) & ~0x000f0fff) |
                        (((Val >> 16) & 0xf000) << 4) | ((Val >> 16) & 0xfff));
     break;
   case R_ARM_THM_MOVT_ABS:
   case R_ARM_THM_MOVT_PREL:
     // Encoding T1: A = imm4:i:imm3:imm8
-    checkInt<32>(Val, Type);
+    checkInt<32>(Loc, Val, Type);
     write16le(Loc,
               0xf2c0 |                     // opcode
                   ((Val >> 17) & 0x0400) | // i
@@ -1808,7 +1817,7 @@
                   (Val & 0x00ff));           // imm8
     break;
   default:
-    fatal("unrecognized reloc " + Twine(Type));
+    fatal(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
   }
 }
 
@@ -2014,8 +2023,8 @@
   uint32_t Mask = 0xffffffff >> (32 - BSIZE);
   uint32_t Instr = read32<E>(Loc);
   if (SHIFT > 0)
-    checkAlignment<(1 << SHIFT)>(V, Type);
-  checkInt<BSIZE + SHIFT>(V, Type);
+    checkAlignment<(1 << SHIFT)>(Loc, V, Type);
+  checkInt<BSIZE + SHIFT>(Loc, V, Type);
   write32<E>(Loc, (Instr & ~Mask) | ((V >> SHIFT) & Mask));
 }
 
@@ -2148,8 +2157,8 @@
   }
 }
 
-static std::pair<uint32_t, uint64_t> calculateMipsRelChain(uint32_t Type,
-                                                           uint64_t Val) {
+static std::pair<uint32_t, uint64_t>
+calculateMipsRelChain(uint8_t *Loc, uint32_t Type, uint64_t Val) {
   // MIPS N64 ABI packs multiple relocations into the single relocation
   // record. In general, all up to three relocations can have arbitrary
   // types. In fact, Clang and GCC uses only a few combinations. For now,
@@ -2170,7 +2179,8 @@
     return std::make_pair(Type2, Val);
   if (Type2 == R_MIPS_SUB && (Type3 == R_MIPS_HI16 || Type3 == R_MIPS_LO16))
     return std::make_pair(Type3, -Val);
-  error("unsupported relocations combination " + Twine(Type));
+  error(getErrorLocation(Loc) + "unsupported relocations combination " +
+        Twine(Type));
   return std::make_pair(Type & 0xff, Val);
 }
 
@@ -2187,7 +2197,7 @@
            Type == R_MIPS_TLS_TPREL32 || Type == R_MIPS_TLS_TPREL64)
     Val -= 0x7000;
   if (ELFT::Is64Bits || Config->MipsN32Abi)
-    std::tie(Type, Val) = calculateMipsRelChain(Type, Val);
+    std::tie(Type, Val) = calculateMipsRelChain(Loc, Type, Val);
   switch (Type) {
   case R_MIPS_32:
   case R_MIPS_GPREL32:
@@ -2209,7 +2219,7 @@
   case R_MIPS_GPREL16:
   case R_MIPS_TLS_GD:
   case R_MIPS_TLS_LDM:
-    checkInt<16>(Val, Type);
+    checkInt<16>(Loc, Val, Type);
   // fallthrough
   case R_MIPS_CALL16:
   case R_MIPS_CALL_LO16:
@@ -2255,7 +2265,7 @@
     applyMipsPcReloc<E, 32, 0>(Loc, Type, Val);
     break;
   default:
-    fatal("unrecognized reloc " + Twine(Type));
+    fatal(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
   }
 }
 
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index c7fc9a8..b74c251 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -1558,6 +1558,34 @@
   In<ELFT>::BuildId->writeBuildId({Start, End});
 }
 
+template <class ELFT> static std::string getErrorLoc(uint8_t *Loc) {
+  for (InputSectionData *D : Symtab<ELFT>::X->Sections) {
+    auto *IS = dyn_cast_or_null<InputSection<ELFT>>(D);
+    if (!IS || !IS->OutSec)
+      continue;
+
+    uint8_t *ISLoc = cast<OutputSection<ELFT>>(IS->OutSec)->Loc + IS->OutSecOff;
+    if (ISLoc <= Loc && ISLoc + IS->getSize() > Loc)
+      return IS->getLocation(Loc - ISLoc) + ": ";
+  }
+  return "";
+}
+
+std::string elf::getErrorLocation(uint8_t *Loc) {
+  switch (Config->EKind) {
+  case ELF32LEKind:
+    return getErrorLoc<ELF32LE>(Loc);
+  case ELF32BEKind:
+    return getErrorLoc<ELF32BE>(Loc);
+  case ELF64LEKind:
+    return getErrorLoc<ELF64LE>(Loc);
+  case ELF64BEKind:
+    return getErrorLoc<ELF64BE>(Loc);
+  default:
+    llvm_unreachable("unknown ELF type");
+  }
+}
+
 template void elf::writeResult<ELF32LE>();
 template void elf::writeResult<ELF32BE>();
 template void elf::writeResult<ELF64LE>();
diff --git a/lld/ELF/Writer.h b/lld/ELF/Writer.h
index 4e353ac..a88161f 100644
--- a/lld/ELF/Writer.h
+++ b/lld/ELF/Writer.h
@@ -48,6 +48,7 @@
                          llvm::StringRef FileName);
 
 bool isMipsN32Abi(const InputFile *F);
+std::string getErrorLocation(uint8_t *Loc);
 }
 }
 
diff --git a/lld/test/ELF/mips-align-err.s b/lld/test/ELF/mips-align-err.s
index 28b192a..0c71ffb 100644
--- a/lld/test/ELF/mips-align-err.s
+++ b/lld/test/ELF/mips-align-err.s
@@ -4,7 +4,7 @@
 # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
 # RUN:         -mcpu=mips32r6 %S/Inputs/mips-align-err.s -o %t2.o
 # RUN: not ld.lld %t.o %t2.o -o %t.exe 2>&1 | FileCheck %s
-# CHECK: improper alignment for relocation R_MIPS_PC16
+# CHECK: {{.*}}:(.text+0x1): improper alignment for relocation R_MIPS_PC16
 
         .globl  __start
 __start:
diff --git a/lld/test/ELF/x86-64-reloc-error.s b/lld/test/ELF/x86-64-reloc-error.s
index 9b7e17d..ece1bd4 100644
--- a/lld/test/ELF/x86-64-reloc-error.s
+++ b/lld/test/ELF/x86-64-reloc-error.s
@@ -6,5 +6,5 @@
   movl $big, %edx
   movq $foo - 0x1000000000000, %rdx
 
-# CHECK: R_X86_64_32 out of range
-# CHECK: R_X86_64_32S out of range
+# CHECK: {{.*}}:(.text+0x1): relocation R_X86_64_32 out of range
+# CHECK: {{.*}}:(.text+0x8): relocation R_X86_64_32S out of range
diff --git a/lld/test/ELF/x86-64-reloc-range.s b/lld/test/ELF/x86-64-reloc-range.s
index 8319eaa..08f604e 100644
--- a/lld/test/ELF/x86-64-reloc-range.s
+++ b/lld/test/ELF/x86-64-reloc-range.s
@@ -1,7 +1,7 @@
 // RUN: llvm-mc %s -o %t.o -triple x86_64-pc-linux -filetype=obj
 // RUN: not ld.lld %t.o -o %t.so -shared 2>&1 | FileCheck %s
 
-// CHECK: relocation R_X86_64_PC32 out of range
+// CHECK: {{.*}}:(.text+0x3): relocation R_X86_64_PC32 out of range
 // CHECK-NOT: relocation
 
         lea     foo(%rip), %rax