From 267829774358b5aebd3e726ae318813bd48129bb Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Thu, 13 Jul 2017 19:26:06 +0000 Subject: [PATCH 01/10] Vendor import of lld trunk r307894: https://llvm.org/svn/llvm-project/lld/trunk@307894 --- COFF/Chunks.cpp | 51 +++ COFF/Chunks.h | 18 + COFF/Config.h | 4 +- COFF/Driver.cpp | 2 +- COFF/DriverUtils.cpp | 15 +- COFF/Error.cpp | 5 +- COFF/Error.h | 1 - COFF/InputFiles.cpp | 2 + COFF/PDB.cpp | 174 ++++++- COFF/PDB.h | 3 +- COFF/Symbols.cpp | 2 + COFF/Writer.cpp | 2 +- ELF/Config.h | 1 + ELF/Driver.cpp | 2 +- ELF/Error.cpp | 5 +- ELF/Error.h | 1 - ELF/Filesystem.cpp | 3 +- ELF/GdbIndex.h | 1 + ELF/InputFiles.cpp | 5 +- ELF/InputSection.cpp | 6 +- ELF/LinkerScript.cpp | 308 ++++++++----- ELF/LinkerScript.h | 30 +- ELF/OutputSections.cpp | 98 +--- ELF/OutputSections.h | 7 +- ELF/Relocations.cpp | 32 +- ELF/Relocations.h | 9 +- ELF/ScriptParser.cpp | 3 +- ELF/SymbolTable.cpp | 49 +- ELF/Symbols.cpp | 20 +- ELF/Symbols.h | 6 +- ELF/SyntheticSections.cpp | 65 +-- ELF/SyntheticSections.h | 5 +- ELF/Thunks.cpp | 32 +- ELF/Thunks.h | 4 + ELF/Writer.cpp | 167 +++---- .../MachO/MachONormalizedFileBinaryReader.cpp | 6 +- test/COFF/Inputs/library-arm64.lib | Bin 0 -> 2000 bytes test/COFF/Inputs/pdb-diff-cl.pdb | Bin 0 -> 102400 bytes test/COFF/Inputs/pdb-diff.cpp | 10 + test/COFF/Inputs/pdb-diff.obj | Bin 0 -> 8602 bytes test/COFF/Inputs/pdb-scopes-a.yaml | 425 ++++++++++++++++++ test/COFF/Inputs/pdb-scopes-b.yaml | 365 +++++++++++++++ test/COFF/arm64-magic.yaml | 46 ++ test/COFF/arm64-relocs-imports.test | 136 ++++++ test/COFF/combined-resources.test | 200 ++++++++- test/COFF/pdb-comdat.test | 6 +- test/COFF/pdb-diff.test | 212 +++++++++ test/COFF/pdb-invalid-func-type.yaml | 146 ++++++ test/COFF/pdb-lib.s | 3 + test/COFF/pdb-linker-module.test | 18 + test/COFF/pdb-none.test | 4 +- test/COFF/pdb-scopes.test | 75 ++++ test/COFF/pdb-source-lines.test | 2 +- test/COFF/pdb-symbol-types.yaml | 2 +- test/COFF/pdb.test | 17 +- test/ELF/Inputs/gnu-ifunc-dso.s | 3 + test/ELF/Inputs/symver-archive1.s | 6 + test/ELF/Inputs/symver-archive2.s | 1 + test/ELF/Inputs/version-script-no-warn2.s | 1 + test/ELF/Inputs/version-script-weak.s | 4 + test/ELF/Inputs/wrap-dynamic-undef.s | 2 + test/ELF/arm-mov-relocs.s | 9 +- test/ELF/copy-in-shared.s | 2 +- test/ELF/defsym.s | 2 +- test/ELF/duplicated-synthetic-sym.s | 10 + test/ELF/gnu-ifunc-dso.s | 13 + .../invalid/Inputs/invalid-relocation-x64.elf | Bin 559 -> 0 bytes .../invalid/invalid-debug-relocations.test | 41 ++ test/ELF/invalid/invalid-relocation-x64.test | 17 +- test/ELF/linkerscript/locationcountererr2.s | 6 +- test/ELF/linkerscript/non-alloc-segment.s | 44 ++ test/ELF/linkerscript/out-of-order.s | 13 +- test/ELF/linkerscript/unused-synthetic.s | 18 + test/ELF/lto/defsym.ll | 14 + test/ELF/lto/wrap-1.ll | 7 + test/ELF/lto/wrap-2.ll | 16 +- test/ELF/symver-archive.s | 15 + test/ELF/version-script-no-warn2.s | 8 + test/ELF/version-script-symver.s | 4 +- test/ELF/version-script-symver2.s | 28 ++ test/ELF/version-script-undef-version.s | 12 + test/ELF/version-script-weak.s | 28 ++ test/ELF/wrap-dynamic-undef.s | 15 + test/ELF/wrap.s | 8 +- test/lit.cfg | 4 +- 85 files changed, 2668 insertions(+), 494 deletions(-) create mode 100644 test/COFF/Inputs/library-arm64.lib create mode 100644 test/COFF/Inputs/pdb-diff-cl.pdb create mode 100644 test/COFF/Inputs/pdb-diff.cpp create mode 100644 test/COFF/Inputs/pdb-diff.obj create mode 100644 test/COFF/Inputs/pdb-scopes-a.yaml create mode 100644 test/COFF/Inputs/pdb-scopes-b.yaml create mode 100644 test/COFF/arm64-magic.yaml create mode 100644 test/COFF/arm64-relocs-imports.test create mode 100644 test/COFF/pdb-diff.test create mode 100644 test/COFF/pdb-invalid-func-type.yaml create mode 100644 test/COFF/pdb-linker-module.test create mode 100644 test/COFF/pdb-scopes.test create mode 100644 test/ELF/Inputs/gnu-ifunc-dso.s create mode 100644 test/ELF/Inputs/symver-archive1.s create mode 100644 test/ELF/Inputs/symver-archive2.s create mode 100644 test/ELF/Inputs/version-script-no-warn2.s create mode 100644 test/ELF/Inputs/version-script-weak.s create mode 100644 test/ELF/Inputs/wrap-dynamic-undef.s create mode 100644 test/ELF/duplicated-synthetic-sym.s create mode 100644 test/ELF/gnu-ifunc-dso.s delete mode 100644 test/ELF/invalid/Inputs/invalid-relocation-x64.elf create mode 100644 test/ELF/invalid/invalid-debug-relocations.test create mode 100644 test/ELF/linkerscript/non-alloc-segment.s create mode 100644 test/ELF/linkerscript/unused-synthetic.s create mode 100644 test/ELF/symver-archive.s create mode 100644 test/ELF/version-script-no-warn2.s create mode 100644 test/ELF/version-script-symver2.s create mode 100644 test/ELF/version-script-undef-version.s create mode 100644 test/ELF/version-script-weak.s create mode 100644 test/ELF/wrap-dynamic-undef.s diff --git a/COFF/Chunks.cpp b/COFF/Chunks.cpp index 9b642dcaf137..c0996f55f9d1 100644 --- a/COFF/Chunks.cpp +++ b/COFF/Chunks.cpp @@ -52,6 +52,7 @@ static void add16(uint8_t *P, int16_t V) { write16le(P, read16le(P) + V); } static void add32(uint8_t *P, int32_t V) { write32le(P, read32le(P) + V); } static void add64(uint8_t *P, int64_t V) { write64le(P, read64le(P) + V); } static void or16(uint8_t *P, uint16_t V) { write16le(P, read16le(P) | V); } +static void or32(uint8_t *P, uint32_t V) { write32le(P, read32le(P) | V); } static void applySecRel(const SectionChunk *Sec, uint8_t *Off, OutputSection *OS, uint64_t S) { @@ -166,6 +167,41 @@ void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS, } } +static void applyArm64Addr(uint8_t *Off, uint64_t Imm) { + uint32_t ImmLo = (Imm & 0x3) << 29; + uint32_t ImmHi = (Imm & 0x1FFFFC) << 3; + uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3); + write32le(Off, (read32le(Off) & ~Mask) | ImmLo | ImmHi); +} + +// Update the immediate field in a AARCH64 ldr, str, and add instruction. +static void applyArm64Imm(uint8_t *Off, uint64_t Imm) { + uint32_t Orig = read32le(Off); + Imm += (Orig >> 10) & 0xFFF; + Orig &= ~(0xFFF << 10); + write32le(Off, Orig | ((Imm & 0xFFF) << 10)); +} + +static void applyArm64Ldr(uint8_t *Off, uint64_t Imm) { + int Size = read32le(Off) >> 30; + Imm >>= Size; + applyArm64Imm(Off, Imm); +} + +void SectionChunk::applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS, + uint64_t S, uint64_t P) const { + switch (Type) { + case IMAGE_REL_ARM64_PAGEBASE_REL21: applyArm64Addr(Off, (S >> 12) - (P >> 12)); break; + case IMAGE_REL_ARM64_PAGEOFFSET_12A: applyArm64Imm(Off, S & 0xfff); break; + case IMAGE_REL_ARM64_PAGEOFFSET_12L: applyArm64Ldr(Off, S & 0xfff); break; + case IMAGE_REL_ARM64_BRANCH26: or32(Off, ((S - P) & 0x0FFFFFFC) >> 2); break; + case IMAGE_REL_ARM64_ADDR32: add32(Off, S + Config->ImageBase); break; + case IMAGE_REL_ARM64_ADDR64: add64(Off, S + Config->ImageBase); break; + default: + fatal("unsupported relocation type 0x" + Twine::utohexstr(Type)); + } +} + void SectionChunk::writeTo(uint8_t *Buf) const { if (!hasData()) return; @@ -210,6 +246,9 @@ void SectionChunk::writeTo(uint8_t *Buf) const { case ARMNT: applyRelARM(Off, Rel.Type, OS, S, P); break; + case ARM64: + applyRelARM64(Off, Rel.Type, OS, S, P); + break; default: llvm_unreachable("unknown machine type"); } @@ -236,6 +275,10 @@ static uint8_t getBaserelType(const coff_relocation &Rel) { if (Rel.Type == IMAGE_REL_ARM_MOV32T) return IMAGE_REL_BASED_ARM_MOV32T; return IMAGE_REL_BASED_ABSOLUTE; + case ARM64: + if (Rel.Type == IMAGE_REL_ARM64_ADDR64) + return IMAGE_REL_BASED_DIR64; + return IMAGE_REL_BASED_ABSOLUTE; default: llvm_unreachable("unknown machine type"); } @@ -345,6 +388,14 @@ void ImportThunkChunkARM::writeTo(uint8_t *Buf) const { applyMOV32T(Buf + OutputSectionOff, ImpSymbol->getRVA() + Config->ImageBase); } +void ImportThunkChunkARM64::writeTo(uint8_t *Buf) const { + int64_t PageOff = (ImpSymbol->getRVA() >> 12) - (RVA >> 12); + int64_t Off = ImpSymbol->getRVA() & 0xfff; + memcpy(Buf + OutputSectionOff, ImportThunkARM64, sizeof(ImportThunkARM64)); + applyArm64Addr(Buf + OutputSectionOff, PageOff); + applyArm64Ldr(Buf + OutputSectionOff + 4, Off); +} + void LocalImportChunk::getBaserels(std::vector *Res) { Res->emplace_back(getRVA()); } diff --git a/COFF/Chunks.h b/COFF/Chunks.h index 6e1bf94da1a5..fc3f5d0df4b6 100644 --- a/COFF/Chunks.h +++ b/COFF/Chunks.h @@ -151,6 +151,8 @@ class SectionChunk : public Chunk { uint64_t P) const; void applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, uint64_t P) const; + void applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, + uint64_t P) const; // Called if the garbage collector decides to not include this chunk // in a final output. It's supposed to print out a log message to stdout. @@ -264,6 +266,12 @@ static const uint8_t ImportThunkARM[] = { 0xdc, 0xf8, 0x00, 0xf0, // ldr.w pc, [ip] }; +static const uint8_t ImportThunkARM64[] = { + 0x10, 0x00, 0x00, 0x90, // adrp x16, #0 + 0x10, 0x02, 0x40, 0xf9, // ldr x16, [x16] + 0x00, 0x02, 0x1f, 0xd6, // br x16 +}; + // Windows-specific. // A chunk for DLL import jump table entry. In a final output, it's // contents will be a JMP instruction to some __imp_ symbol. @@ -299,6 +307,16 @@ class ImportThunkChunkARM : public Chunk { Defined *ImpSymbol; }; +class ImportThunkChunkARM64 : public Chunk { +public: + explicit ImportThunkChunkARM64(Defined *S) : ImpSymbol(S) {} + size_t getSize() const override { return sizeof(ImportThunkARM64); } + void writeTo(uint8_t *Buf) const override; + +private: + Defined *ImpSymbol; +}; + // Windows-specific. // See comments for DefinedLocalImport class. class LocalImportChunk : public Chunk { diff --git a/COFF/Config.h b/COFF/Config.h index 9fcea96d65d3..25fdc7abd67b 100644 --- a/COFF/Config.h +++ b/COFF/Config.h @@ -31,6 +31,7 @@ class SymbolBody; // Short aliases. static const auto AMD64 = llvm::COFF::IMAGE_FILE_MACHINE_AMD64; +static const auto ARM64 = llvm::COFF::IMAGE_FILE_MACHINE_ARM64; static const auto ARMNT = llvm::COFF::IMAGE_FILE_MACHINE_ARMNT; static const auto I386 = llvm::COFF::IMAGE_FILE_MACHINE_I386; @@ -73,7 +74,7 @@ enum class DebugType { // Global configuration. struct Configuration { enum ManifestKind { SideBySide, Embed, No }; - bool is64() { return Machine == AMD64; } + bool is64() { return Machine == AMD64 || Machine == ARM64; } llvm::COFF::MachineTypes Machine = IMAGE_FILE_MACHINE_UNKNOWN; bool Verbose = false; @@ -91,6 +92,7 @@ struct Configuration { bool WriteSymtab = true; unsigned DebugTypes = static_cast(DebugType::None); llvm::SmallString<128> PDBPath; + std::vector Argv; // Symbols in this set are considered as live by the garbage collector. std::set GCRoot; diff --git a/COFF/Driver.cpp b/COFF/Driver.cpp index 22efb312ae49..3620297b8b94 100644 --- a/COFF/Driver.cpp +++ b/COFF/Driver.cpp @@ -55,8 +55,8 @@ std::vector SpecificAllocBase::Instances; bool link(ArrayRef Args, raw_ostream &Diag) { ErrorCount = 0; ErrorOS = &Diag; - Argv0 = Args[0]; Config = make(); + Config->Argv = {Args.begin(), Args.end()}; Config->ColorDiagnostics = (ErrorOS == &llvm::errs() && Process::StandardErrHasColors()); Driver = make(); diff --git a/COFF/DriverUtils.cpp b/COFF/DriverUtils.cpp index d0152b0917b6..39d582469640 100644 --- a/COFF/DriverUtils.cpp +++ b/COFF/DriverUtils.cpp @@ -85,6 +85,7 @@ MachineTypes getMachineType(StringRef S) { .Cases("x64", "amd64", AMD64) .Cases("x86", "i386", I386) .Case("arm", ARMNT) + .Case("arm64", ARM64) .Default(IMAGE_FILE_MACHINE_UNKNOWN); if (MT != IMAGE_FILE_MACHINE_UNKNOWN) return MT; @@ -95,6 +96,8 @@ StringRef machineToStr(MachineTypes MT) { switch (MT) { case ARMNT: return "arm"; + case ARM64: + return "arm64"; case AMD64: return "x64"; case I386: @@ -378,13 +381,11 @@ static std::string createManifestXml() { static std::unique_ptr createMemoryBufferForManifestRes(size_t ManifestSize) { - size_t ResSize = alignTo(object::WIN_RES_MAGIC_SIZE + - object::WIN_RES_NULL_ENTRY_SIZE + - sizeof(object::WinResHeaderPrefix) + - sizeof(object::WinResIDs) + - sizeof(object::WinResHeaderSuffix) + - ManifestSize, - object::WIN_RES_DATA_ALIGNMENT); + size_t ResSize = alignTo( + object::WIN_RES_MAGIC_SIZE + object::WIN_RES_NULL_ENTRY_SIZE + + sizeof(object::WinResHeaderPrefix) + sizeof(object::WinResIDs) + + sizeof(object::WinResHeaderSuffix) + ManifestSize, + object::WIN_RES_DATA_ALIGNMENT); return MemoryBuffer::getNewMemBuffer(ResSize); } diff --git a/COFF/Error.cpp b/COFF/Error.cpp index 166b1971e77f..34abc280f6bf 100644 --- a/COFF/Error.cpp +++ b/COFF/Error.cpp @@ -29,7 +29,6 @@ namespace lld { static std::mutex Mu; namespace coff { -StringRef Argv0; uint64_t ErrorCount; raw_ostream *ErrorOS; @@ -45,7 +44,7 @@ static LLVM_ATTRIBUTE_NORETURN void exitLld(int Val) { } static void print(StringRef S, raw_ostream::Colors C) { - *ErrorOS << Argv0 + ": "; + *ErrorOS << Config->Argv[0] << ": "; if (Config->ColorDiagnostics) { ErrorOS->changeColor(C, true); *ErrorOS << S; @@ -58,7 +57,7 @@ static void print(StringRef S, raw_ostream::Colors C) { void log(const Twine &Msg) { if (Config->Verbose) { std::lock_guard Lock(Mu); - outs() << Argv0 << ": " << Msg << "\n"; + outs() << Config->Argv[0] << ": " << Msg << "\n"; outs().flush(); } } diff --git a/COFF/Error.h b/COFF/Error.h index a4f44fb1e36c..e1e4c1e5216f 100644 --- a/COFF/Error.h +++ b/COFF/Error.h @@ -18,7 +18,6 @@ namespace coff { extern uint64_t ErrorCount; extern llvm::raw_ostream *ErrorOS; -extern llvm::StringRef Argv0; void log(const Twine &Msg); void message(const Twine &Msg); diff --git a/COFF/InputFiles.cpp b/COFF/InputFiles.cpp index c26483e3e368..7d41caebb4b9 100644 --- a/COFF/InputFiles.cpp +++ b/COFF/InputFiles.cpp @@ -380,6 +380,8 @@ MachineTypes BitcodeFile::getMachineType() { return I386; case Triple::arm: return ARMNT; + case Triple::aarch64: + return ARM64; default: return IMAGE_FILE_MACHINE_UNKNOWN; } diff --git a/COFF/PDB.cpp b/COFF/PDB.cpp index c9842cfd1b9a..508f59e3af1f 100644 --- a/COFF/PDB.cpp +++ b/COFF/PDB.cpp @@ -18,19 +18,20 @@ #include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" #include "llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h" #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" +#include "llvm/DebugInfo/CodeView/SymbolSerializer.h" #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" #include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h" #include "llvm/DebugInfo/CodeView/TypeStreamMerger.h" #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" #include "llvm/DebugInfo/MSF/MSFBuilder.h" #include "llvm/DebugInfo/MSF/MSFCommon.h" +#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h" #include "llvm/DebugInfo/PDB/Native/DbiStream.h" #include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h" #include "llvm/DebugInfo/PDB/Native/InfoStream.h" #include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h" -#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h" #include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h" #include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h" #include "llvm/DebugInfo/PDB/Native/TpiStream.h" @@ -124,26 +125,25 @@ static bool remapTypeIndex(TypeIndex &TI, ArrayRef TypeIndexMap) { return true; } -static bool remapTypesInSymbolRecord(ObjectFile *File, +static void remapTypesInSymbolRecord(ObjectFile *File, MutableArrayRef Contents, ArrayRef TypeIndexMap, ArrayRef TypeRefs) { for (const TiReference &Ref : TypeRefs) { unsigned ByteSize = Ref.Count * sizeof(TypeIndex); - if (Contents.size() < Ref.Offset + ByteSize) { - log("ignoring short symbol record"); - return false; - } + if (Contents.size() < Ref.Offset + ByteSize) + fatal("symbol record too short"); MutableArrayRef TIs( reinterpret_cast(Contents.data() + Ref.Offset), Ref.Count); - for (TypeIndex &TI : TIs) + for (TypeIndex &TI : TIs) { if (!remapTypeIndex(TI, TypeIndexMap)) { + TI = TypeIndex(SimpleTypeKind::NotTranslated); log("ignoring symbol record in " + File->getName() + " with bad type index 0x" + utohexstr(TI.getIndex())); - return false; + continue; } + } } - return true; } /// MSVC translates S_PROC_ID_END to S_END. @@ -176,6 +176,70 @@ static MutableArrayRef copySymbolForPdb(const CVSymbol &Sym, return NewData; } +/// Return true if this symbol opens a scope. This implies that the symbol has +/// "parent" and "end" fields, which contain the offset of the S_END or +/// S_INLINESITE_END record. +static bool symbolOpensScope(SymbolKind Kind) { + switch (Kind) { + case SymbolKind::S_GPROC32: + case SymbolKind::S_LPROC32: + case SymbolKind::S_LPROC32_ID: + case SymbolKind::S_GPROC32_ID: + case SymbolKind::S_BLOCK32: + case SymbolKind::S_SEPCODE: + case SymbolKind::S_THUNK32: + case SymbolKind::S_INLINESITE: + case SymbolKind::S_INLINESITE2: + return true; + default: + break; + } + return false; +} + +static bool symbolEndsScope(SymbolKind Kind) { + switch (Kind) { + case SymbolKind::S_END: + case SymbolKind::S_PROC_ID_END: + case SymbolKind::S_INLINESITE_END: + return true; + default: + break; + } + return false; +} + +struct ScopeRecord { + ulittle32_t PtrParent; + ulittle32_t PtrEnd; +}; + +struct SymbolScope { + ScopeRecord *OpeningRecord; + uint32_t ScopeOffset; +}; + +static void scopeStackOpen(SmallVectorImpl &Stack, + uint32_t CurOffset, CVSymbol &Sym) { + assert(symbolOpensScope(Sym.kind())); + SymbolScope S; + S.ScopeOffset = CurOffset; + S.OpeningRecord = const_cast( + reinterpret_cast(Sym.content().data())); + S.OpeningRecord->PtrParent = Stack.empty() ? 0 : Stack.back().ScopeOffset; + Stack.push_back(S); +} + +static void scopeStackClose(SmallVectorImpl &Stack, + uint32_t CurOffset, ObjectFile *File) { + if (Stack.empty()) { + warn("symbol scopes are not balanced in " + File->getName()); + return; + } + SymbolScope S = Stack.pop_back_val(); + S.OpeningRecord->PtrEnd = CurOffset; +} + static void mergeSymbolRecords(BumpPtrAllocator &Alloc, ObjectFile *File, ArrayRef TypeIndexMap, BinaryStreamRef SymData) { @@ -184,6 +248,7 @@ static void mergeSymbolRecords(BumpPtrAllocator &Alloc, ObjectFile *File, CVSymbolArray Syms; BinaryStreamReader Reader(SymData); ExitOnErr(Reader.readArray(Syms, Reader.getLength())); + SmallVector Scopes; for (const CVSymbol &Sym : Syms) { // Discover type index references in the record. Skip it if we don't know // where they are. @@ -199,14 +264,17 @@ static void mergeSymbolRecords(BumpPtrAllocator &Alloc, ObjectFile *File, // Re-map all the type index references. MutableArrayRef Contents = NewData.drop_front(sizeof(RecordPrefix)); - if (!remapTypesInSymbolRecord(File, Contents, TypeIndexMap, TypeRefs)) - continue; + remapTypesInSymbolRecord(File, Contents, TypeIndexMap, TypeRefs); - // FIXME: Fill in "Parent" and "End" fields by maintaining a stack of - // scopes. + // Fill in "Parent" and "End" fields by maintaining a stack of scopes. + CVSymbol NewSym(Sym.kind(), NewData); + if (symbolOpensScope(Sym.kind())) + scopeStackOpen(Scopes, File->ModuleDBI->getNextSymbolOffset(), NewSym); + else if (symbolEndsScope(Sym.kind())) + scopeStackClose(Scopes, File->ModuleDBI->getNextSymbolOffset(), File); // Add the symbol to the module. - File->ModuleDBI->addSymbol(CVSymbol(Sym.kind(), NewData)); + File->ModuleDBI->addSymbol(NewSym); } } @@ -246,7 +314,9 @@ static void addObjectsToPDB(BumpPtrAllocator &Alloc, SymbolTable *Symtab, bool InArchive = !File->ParentName.empty(); SmallString<128> Path = InArchive ? File->ParentName : File->getName(); sys::fs::make_absolute(Path); + sys::path::native(Path, llvm::sys::path::Style::windows); StringRef Name = InArchive ? File->getName() : StringRef(Path); + File->ModuleDBI = &ExitOnErr(Builder.getDbiBuilder().addModuleInfo(Name)); File->ModuleDBI->setObjFileName(Path); @@ -325,9 +395,52 @@ static void addObjectsToPDB(BumpPtrAllocator &Alloc, SymbolTable *Symtab, addTypeInfo(Builder.getIpiBuilder(), IDTable); } +static void addLinkerModuleSymbols(StringRef Path, + pdb::DbiModuleDescriptorBuilder &Mod, + BumpPtrAllocator &Allocator) { + codeview::SymbolSerializer Serializer(Allocator, CodeViewContainer::Pdb); + codeview::ObjNameSym ONS(SymbolRecordKind::ObjNameSym); + codeview::Compile3Sym CS(SymbolRecordKind::Compile3Sym); + codeview::EnvBlockSym EBS(SymbolRecordKind::EnvBlockSym); + + ONS.Name = "* Linker *"; + ONS.Signature = 0; + + CS.Machine = Config->is64() ? CPUType::X64 : CPUType::Intel80386; + CS.Flags = CompileSym3Flags::None; + CS.VersionBackendBuild = 0; + CS.VersionBackendMajor = 0; + CS.VersionBackendMinor = 0; + CS.VersionBackendQFE = 0; + CS.VersionFrontendBuild = 0; + CS.VersionFrontendMajor = 0; + CS.VersionFrontendMinor = 0; + CS.VersionFrontendQFE = 0; + CS.Version = "LLVM Linker"; + CS.setLanguage(SourceLanguage::Link); + + ArrayRef Args = makeArrayRef(Config->Argv).drop_front(); + std::string ArgStr = llvm::join(Args, " "); + EBS.Fields.push_back("cwd"); + SmallString<64> cwd; + llvm::sys::fs::current_path(cwd); + EBS.Fields.push_back(cwd); + EBS.Fields.push_back("exe"); + EBS.Fields.push_back(Config->Argv[0]); + EBS.Fields.push_back("pdb"); + EBS.Fields.push_back(Path); + EBS.Fields.push_back("cmd"); + EBS.Fields.push_back(ArgStr); + Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( + ONS, Allocator, CodeViewContainer::Pdb)); + Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( + CS, Allocator, CodeViewContainer::Pdb)); + Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( + EBS, Allocator, CodeViewContainer::Pdb)); +} + // Creates a PDB file. -void coff::createPDB(StringRef Path, SymbolTable *Symtab, - ArrayRef SectionTable, +void coff::createPDB(SymbolTable *Symtab, ArrayRef SectionTable, const llvm::codeview::DebugInfo *DI) { BumpPtrAllocator Alloc; pdb::PDBFileBuilder Builder(Alloc); @@ -342,22 +455,37 @@ void coff::createPDB(StringRef Path, SymbolTable *Symtab, auto &InfoBuilder = Builder.getInfoBuilder(); InfoBuilder.setAge(DI ? DI->PDB70.Age : 0); + llvm::SmallString<128> NativePath(Config->PDBPath.begin(), + Config->PDBPath.end()); + llvm::sys::fs::make_absolute(NativePath); + llvm::sys::path::native(NativePath, llvm::sys::path::Style::windows); + pdb::PDB_UniqueId uuid{}; if (DI) memcpy(&uuid, &DI->PDB70.Signature, sizeof(uuid)); InfoBuilder.setGuid(uuid); - // Should be the current time, but set 0 for reproducibilty. - InfoBuilder.setSignature(0); + InfoBuilder.setSignature(time(nullptr)); InfoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70); - // Add an empty DPI stream. + // Add an empty DBI stream. pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder(); - DbiBuilder.setVersionHeader(pdb::PdbDbiV110); + DbiBuilder.setVersionHeader(pdb::PdbDbiV70); + ExitOnErr(DbiBuilder.addDbgStream(pdb::DbgHeaderType::NewFPO, {})); + + // It's not entirely clear what this is, but the * Linker * module uses it. + uint32_t PdbFilePathNI = DbiBuilder.addECName(NativePath); TypeTableBuilder TypeTable(BAlloc); TypeTableBuilder IDTable(BAlloc); addObjectsToPDB(Alloc, Symtab, Builder, TypeTable, IDTable); + // Add public and symbol records stream. + + // For now we don't actually write any thing useful to the publics stream, but + // the act of "getting" it also creates it lazily so that we write an empty + // stream. + (void)Builder.getPublicsBuilder(); + // Add Section Contributions. addSectionContribs(Symtab, DbiBuilder); @@ -369,12 +497,14 @@ void coff::createPDB(StringRef Path, SymbolTable *Symtab, pdb::DbiStreamBuilder::createSectionMap(Sections); DbiBuilder.setSectionMap(SectionMap); - ExitOnErr(DbiBuilder.addModuleInfo("* Linker *")); + auto &LinkerModule = ExitOnErr(DbiBuilder.addModuleInfo("* Linker *")); + LinkerModule.setPdbFilePathNI(PdbFilePathNI); + addLinkerModuleSymbols(NativePath, LinkerModule, Alloc); // Add COFF section header stream. ExitOnErr( DbiBuilder.addDbgStream(pdb::DbgHeaderType::SectionHdr, SectionTable)); // Write to a file. - ExitOnErr(Builder.commit(Path)); + ExitOnErr(Builder.commit(Config->PDBPath)); } diff --git a/COFF/PDB.h b/COFF/PDB.h index c9c37914299a..9aaa3178df21 100644 --- a/COFF/PDB.h +++ b/COFF/PDB.h @@ -23,8 +23,7 @@ namespace lld { namespace coff { class SymbolTable; -void createPDB(llvm::StringRef Path, SymbolTable *Symtab, - llvm::ArrayRef SectionTable, +void createPDB(SymbolTable *Symtab, llvm::ArrayRef SectionTable, const llvm::codeview::DebugInfo *DI); } } diff --git a/COFF/Symbols.cpp b/COFF/Symbols.cpp index 1cf2934a355b..9b59079072a8 100644 --- a/COFF/Symbols.cpp +++ b/COFF/Symbols.cpp @@ -68,6 +68,8 @@ static Chunk *makeImportThunk(DefinedImportData *S, uint16_t Machine) { return make(S); if (Machine == I386) return make(S); + if (Machine == ARM64) + return make(S); assert(Machine == ARMNT); return make(S); } diff --git a/COFF/Writer.cpp b/COFF/Writer.cpp index 4cf718a48d8b..a6a5e278498a 100644 --- a/COFF/Writer.cpp +++ b/COFF/Writer.cpp @@ -239,7 +239,7 @@ void Writer::run() { const llvm::codeview::DebugInfo *DI = nullptr; if (Config->DebugTypes & static_cast(coff::DebugType::CV)) DI = BuildId->DI; - createPDB(Config->PDBPath, Symtab, SectionTable, DI); + createPDB(Symtab, SectionTable, DI); } writeMapFile(OutputSections); diff --git a/ELF/Config.h b/ELF/Config.h index 32e86b0ec7b6..5e3b77637316 100644 --- a/ELF/Config.h +++ b/ELF/Config.h @@ -97,6 +97,7 @@ struct Configuration { llvm::StringRef ThinLTOCacheDir; std::string Rpath; std::vector VersionDefinitions; + std::vector Argv; std::vector AuxiliaryList; std::vector SearchPaths; std::vector SymbolOrderingFile; diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp index 5fb33caea46f..10ad13f214d5 100644 --- a/ELF/Driver.cpp +++ b/ELF/Driver.cpp @@ -74,13 +74,13 @@ bool elf::link(ArrayRef Args, bool CanExitEarly, raw_ostream &Error) { ErrorCount = 0; ErrorOS = &Error; - Argv0 = Args[0]; InputSections.clear(); Tar = nullptr; Config = make(); Driver = make(); Script = make(); + Config->Argv = {Args.begin(), Args.end()}; Driver->main(Args, CanExitEarly); freeArena(); diff --git a/ELF/Error.cpp b/ELF/Error.cpp index 7a58668bdcc0..224570ea7424 100644 --- a/ELF/Error.cpp +++ b/ELF/Error.cpp @@ -27,7 +27,6 @@ using namespace lld::elf; uint64_t elf::ErrorCount; raw_ostream *elf::ErrorOS; -StringRef elf::Argv0; // The functions defined in this file can be called from multiple threads, // but outs() or errs() are not thread-safe. We protect them using a mutex. @@ -46,7 +45,7 @@ static void newline(const Twine &Msg) { } static void print(StringRef S, raw_ostream::Colors C) { - *ErrorOS << Argv0 + ": "; + *ErrorOS << Config->Argv[0] << ": "; if (Config->ColorDiagnostics) { ErrorOS->changeColor(C, true); *ErrorOS << S; @@ -59,7 +58,7 @@ static void print(StringRef S, raw_ostream::Colors C) { void elf::log(const Twine &Msg) { if (Config->Verbose) { std::lock_guard Lock(Mu); - outs() << Argv0 << ": " << Msg << "\n"; + outs() << Config->Argv[0] << ": " << Msg << "\n"; outs().flush(); } } diff --git a/ELF/Error.h b/ELF/Error.h index dd6e37c99b15..89bc2111b44e 100644 --- a/ELF/Error.h +++ b/ELF/Error.h @@ -37,7 +37,6 @@ namespace elf { extern uint64_t ErrorCount; extern llvm::raw_ostream *ErrorOS; -extern llvm::StringRef Argv0; void log(const Twine &Msg); void message(const Twine &Msg); diff --git a/ELF/Filesystem.cpp b/ELF/Filesystem.cpp index b63d521a83b0..d468ae0c618a 100644 --- a/ELF/Filesystem.cpp +++ b/ELF/Filesystem.cpp @@ -38,7 +38,8 @@ using namespace lld::elf; // This function spawns a background thread to call unlink. // The calling thread returns almost immediately. void elf::unlinkAsync(StringRef Path) { - if (!Config->Threads || !sys::fs::exists(Config->OutputFile)) + if (!Config->Threads || !sys::fs::exists(Config->OutputFile) || + !sys::fs::is_regular_file(Config->OutputFile)) return; // First, rename Path to avoid race condition. We cannot remove diff --git a/ELF/GdbIndex.h b/ELF/GdbIndex.h index 527667f7280e..c49f8946e199 100644 --- a/ELF/GdbIndex.h +++ b/ELF/GdbIndex.h @@ -45,6 +45,7 @@ struct NameTypeEntry { // debug information performed. That information futher used // for filling gdb index section areas. struct GdbIndexChunk { + InputSection *DebugInfoSec; std::vector AddressArea; std::vector CompilationUnits; std::vector NamesAndTypes; diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp index e07f24d665df..d3c307d5cb6b 100644 --- a/ELF/InputFiles.cpp +++ b/ELF/InputFiles.cpp @@ -45,14 +45,11 @@ namespace { // LLVM DWARF parser will not be able to parse .debug_line correctly, unless // we assign each section some unique address. This callback method assigns // each section an address equal to its offset in ELF object file. -class ObjectInfo : public LoadedObjectInfo { +class ObjectInfo : public LoadedObjectInfoHelper { public: uint64_t getSectionLoadAddress(const object::SectionRef &Sec) const override { return static_cast(Sec).getOffset(); } - std::unique_ptr clone() const override { - return std::unique_ptr(); - } }; } diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp index b1d5e1349460..c6a539b8dfa5 100644 --- a/ELF/InputSection.cpp +++ b/ELF/InputSection.cpp @@ -276,7 +276,9 @@ template std::string InputSectionBase::getSrcMsg(uint64_t Offset) { template std::string InputSectionBase::getObjMsg(uint64_t Off) { // Synthetic sections don't have input files. elf::ObjectFile *File = getFile(); - std::string Filename = File ? File->getName() : "(internal)"; + if (!File) + return ("(internal):(" + Name + "+0x" + utohexstr(Off) + ")").str(); + std::string Filename = File->getName(); std::string Archive; if (!File->ArchiveName.empty()) @@ -466,7 +468,7 @@ static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t Type, uint64_t A, static uint64_t getARMStaticBase(const SymbolBody &Body) { OutputSection *OS = Body.getOutputSection(); if (!OS || !OS->FirstInPtLoad) - fatal("SBREL relocation to " + Body.getName() + " without static base\n"); + fatal("SBREL relocation to " + Body.getName() + " without static base"); return OS->FirstInPtLoad->Addr; } diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp index d369a6f978a2..a182d5a3a096 100644 --- a/ELF/LinkerScript.cpp +++ b/ELF/LinkerScript.cpp @@ -111,17 +111,13 @@ LinkerScript::getOrCreateOutputSectionCommand(StringRef Name) { void LinkerScript::setDot(Expr E, const Twine &Loc, bool InSec) { uint64_t Val = E().getValue(); - if (Val < Dot) { - if (InSec) - error(Loc + ": unable to move location counter backward for: " + - CurOutSec->Name); - else - error(Loc + ": unable to move location counter backward"); - } + if (Val < Dot && InSec) + error(Loc + ": unable to move location counter backward for: " + + CurAddressState->OutSec->Name); Dot = Val; // Update to location counter means update to section size. if (InSec) - CurOutSec->Size = Dot - CurOutSec->Addr; + CurAddressState->OutSec->Size = Dot - CurAddressState->OutSec->Addr; } // Sets value of a symbol. Two kinds of symbols are processed: synthetic @@ -373,7 +369,13 @@ void LinkerScript::processCommands(OutputSectionFactory &Factory) { // which will map to whatever the first actual section is. Aether = make("", 0, SHF_ALLOC); Aether->SectionIndex = 1; - CurOutSec = Aether; + auto State = make_unique(Opt); + // CurAddressState captures the local AddressState and makes it accessible + // deliberately. This is needed as there are some cases where we cannot just + // thread the current state through to a lambda function created by the + // script parser. + CurAddressState = State.get(); + CurAddressState->OutSec = Aether; Dot = 0; for (size_t I = 0; I < Opt.Commands.size(); ++I) { @@ -435,7 +437,7 @@ void LinkerScript::processCommands(OutputSectionFactory &Factory) { } } } - CurOutSec = nullptr; + CurAddressState = nullptr; } void LinkerScript::fabricateDefaultCommands() { @@ -481,20 +483,31 @@ void LinkerScript::fabricateDefaultCommands() { // Add sections that didn't match any sections command. void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) { + unsigned NumCommands = Opt.Commands.size(); for (InputSectionBase *S : InputSections) { if (!S->Live || S->Parent) continue; StringRef Name = getOutputSectionName(S->Name); - auto I = std::find_if( - Opt.Commands.begin(), Opt.Commands.end(), [&](BaseCommand *Base) { - if (auto *Cmd = dyn_cast(Base)) - return Cmd->Name == Name; - return false; - }); - if (I == Opt.Commands.end()) { + auto End = Opt.Commands.begin() + NumCommands; + auto I = std::find_if(Opt.Commands.begin(), End, [&](BaseCommand *Base) { + if (auto *Cmd = dyn_cast(Base)) + return Cmd->Name == Name; + return false; + }); + OutputSectionCommand *Cmd; + if (I == End) { Factory.addInputSec(S, Name); + OutputSection *Sec = S->getOutputSection(); + assert(Sec->SectionIndex == INT_MAX); + OutputSectionCommand *&CmdRef = SecToCommand[Sec]; + if (!CmdRef) { + CmdRef = createOutputSectionCommand(Sec->Name, ""); + CmdRef->Sec = Sec; + Opt.Commands.push_back(CmdRef); + } + Cmd = CmdRef; } else { - auto *Cmd = cast(*I); + Cmd = cast(*I); Factory.addInputSec(S, Name, Cmd->Sec); if (OutputSection *Sec = Cmd->Sec) { SecToCommand[Sec] = Cmd; @@ -502,21 +515,22 @@ void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) { assert(Sec->SectionIndex == INT_MAX || Sec->SectionIndex == Index); Sec->SectionIndex = Index; } - auto *ISD = make(""); - ISD->Sections.push_back(cast(S)); - Cmd->Commands.push_back(ISD); } + auto *ISD = make(""); + ISD->Sections.push_back(cast(S)); + Cmd->Commands.push_back(ISD); } } uint64_t LinkerScript::advance(uint64_t Size, unsigned Align) { - bool IsTbss = (CurOutSec->Flags & SHF_TLS) && CurOutSec->Type == SHT_NOBITS; - uint64_t Start = IsTbss ? Dot + ThreadBssOffset : Dot; + bool IsTbss = (CurAddressState->OutSec->Flags & SHF_TLS) && + CurAddressState->OutSec->Type == SHT_NOBITS; + uint64_t Start = IsTbss ? Dot + CurAddressState->ThreadBssOffset : Dot; Start = alignTo(Start, Align); uint64_t End = Start + Size; if (IsTbss) - ThreadBssOffset = End - Dot; + CurAddressState->ThreadBssOffset = End - Dot; else Dot = End; return End; @@ -524,40 +538,43 @@ uint64_t LinkerScript::advance(uint64_t Size, unsigned Align) { void LinkerScript::output(InputSection *S) { uint64_t Pos = advance(S->getSize(), S->Alignment); - S->OutSecOff = Pos - S->getSize() - CurOutSec->Addr; + S->OutSecOff = Pos - S->getSize() - CurAddressState->OutSec->Addr; // Update output section size after adding each section. This is so that // SIZEOF works correctly in the case below: // .foo { *(.aaa) a = SIZEOF(.foo); *(.bbb) } - CurOutSec->Size = Pos - CurOutSec->Addr; + CurAddressState->OutSec->Size = Pos - CurAddressState->OutSec->Addr; // If there is a memory region associated with this input section, then // place the section in that region and update the region index. - if (CurMemRegion) { - CurMemRegion->Offset += CurOutSec->Size; - uint64_t CurSize = CurMemRegion->Offset - CurMemRegion->Origin; - if (CurSize > CurMemRegion->Length) { - uint64_t OverflowAmt = CurSize - CurMemRegion->Length; - error("section '" + CurOutSec->Name + "' will not fit in region '" + - CurMemRegion->Name + "': overflowed by " + Twine(OverflowAmt) + - " bytes"); + if (CurAddressState->MemRegion) { + uint64_t &CurOffset = + CurAddressState->MemRegionOffset[CurAddressState->MemRegion]; + CurOffset += CurAddressState->OutSec->Size; + uint64_t CurSize = CurOffset - CurAddressState->MemRegion->Origin; + if (CurSize > CurAddressState->MemRegion->Length) { + uint64_t OverflowAmt = CurSize - CurAddressState->MemRegion->Length; + error("section '" + CurAddressState->OutSec->Name + + "' will not fit in region '" + CurAddressState->MemRegion->Name + + "': overflowed by " + Twine(OverflowAmt) + " bytes"); } } } void LinkerScript::switchTo(OutputSection *Sec) { - if (CurOutSec == Sec) + if (CurAddressState->OutSec == Sec) return; - CurOutSec = Sec; - CurOutSec->Addr = advance(0, CurOutSec->Alignment); + CurAddressState->OutSec = Sec; + CurAddressState->OutSec->Addr = + advance(0, CurAddressState->OutSec->Alignment); // If neither AT nor AT> is specified for an allocatable section, the linker // will set the LMA such that the difference between VMA and LMA for the // section is the same as the preceding output section in the same region // https://sourceware.org/binutils/docs-2.20/ld/Output-Section-LMA.html - if (LMAOffset) - CurOutSec->LMAOffset = LMAOffset(); + if (CurAddressState->LMAOffset) + CurAddressState->OutSec->LMAOffset = CurAddressState->LMAOffset(); } void LinkerScript::process(BaseCommand &Base) { @@ -569,9 +586,9 @@ void LinkerScript::process(BaseCommand &Base) { // Handle BYTE(), SHORT(), LONG(), or QUAD(). if (auto *Cmd = dyn_cast(&Base)) { - Cmd->Offset = Dot - CurOutSec->Addr; + Cmd->Offset = Dot - CurAddressState->OutSec->Addr; Dot += Cmd->Size; - CurOutSec->Size = Dot - CurOutSec->Addr; + CurAddressState->OutSec->Size = Dot - CurAddressState->OutSec->Addr; return; } @@ -596,7 +613,7 @@ void LinkerScript::process(BaseCommand &Base) { if (!Sec->Live) continue; - assert(CurOutSec == Sec->getParent()); + assert(CurAddressState->OutSec == Sec->getParent()); output(Sec); } } @@ -649,17 +666,17 @@ void LinkerScript::assignOffsets(OutputSectionCommand *Cmd) { if (Cmd->LMAExpr) { uint64_t D = Dot; - LMAOffset = [=] { return Cmd->LMAExpr().getValue() - D; }; + CurAddressState->LMAOffset = [=] { return Cmd->LMAExpr().getValue() - D; }; } - CurMemRegion = Cmd->MemRegion; - if (CurMemRegion) - Dot = CurMemRegion->Offset; + CurAddressState->MemRegion = Cmd->MemRegion; + if (CurAddressState->MemRegion) + Dot = CurAddressState->MemRegionOffset[CurAddressState->MemRegion]; switchTo(Sec); // We do not support custom layout for compressed debug sectons. // At this point we already know their size and have compressed content. - if (CurOutSec->Flags & SHF_COMPRESSED) + if (CurAddressState->OutSec->Flags & SHF_COMPRESSED) return; for (BaseCommand *C : Cmd->Commands) @@ -746,30 +763,20 @@ void LinkerScript::adjustSectionsAfterSorting() { if (!Cmd) continue; - if (Cmd->Phdrs.empty()) - Cmd->Phdrs = DefPhdrs; - else + if (Cmd->Phdrs.empty()) { + OutputSection *Sec = Cmd->Sec; + // To match the bfd linker script behaviour, only propagate program + // headers to sections that are allocated. + if (Sec && (Sec->Flags & SHF_ALLOC)) + Cmd->Phdrs = DefPhdrs; + } else { DefPhdrs = Cmd->Phdrs; + } } removeEmptyCommands(); } -void LinkerScript::createOrphanCommands() { - for (OutputSection *Sec : OutputSections) { - if (Sec->SectionIndex != INT_MAX) - continue; - OutputSectionCommand *Cmd = - createOutputSectionCommand(Sec->Name, ""); - Cmd->Sec = Sec; - SecToCommand[Sec] = Cmd; - auto *ISD = make(""); - ISD->Sections = Sec->Sections; - Cmd->Commands.push_back(ISD); - Opt.Commands.push_back(Cmd); - } -} - void LinkerScript::processNonSectionCommands() { for (BaseCommand *Base : Opt.Commands) { if (auto *Cmd = dyn_cast(Base)) @@ -779,22 +786,25 @@ void LinkerScript::processNonSectionCommands() { } } -static bool -allocateHeaders(std::vector &Phdrs, - ArrayRef OutputSectionCommands, - uint64_t Min) { - auto FirstPTLoad = - std::find_if(Phdrs.begin(), Phdrs.end(), - [](const PhdrEntry &E) { return E.p_type == PT_LOAD; }); +void LinkerScript::allocateHeaders(std::vector &Phdrs) { + uint64_t Min = std::numeric_limits::max(); + for (OutputSectionCommand *Cmd : OutputSectionCommands) { + OutputSection *Sec = Cmd->Sec; + if (Sec->Flags & SHF_ALLOC) + Min = std::min(Min, Sec->Addr); + } + + auto FirstPTLoad = llvm::find_if( + Phdrs, [](const PhdrEntry &E) { return E.p_type == PT_LOAD; }); if (FirstPTLoad == Phdrs.end()) - return false; + return; uint64_t HeaderSize = getHeaderSize(); if (HeaderSize <= Min || Script->hasPhdrsCommands()) { Min = alignDown(Min - HeaderSize, Config->MaxPageSize); Out::ElfHeader->Addr = Min; Out::ProgramHeaders->Addr = Min + Out::ElfHeader->Size; - return true; + return; } assert(FirstPTLoad->First == Out::ElfHeader); @@ -817,17 +827,28 @@ allocateHeaders(std::vector &Phdrs, Phdrs.erase(FirstPTLoad); } - auto PhdrI = std::find_if(Phdrs.begin(), Phdrs.end(), [](const PhdrEntry &E) { - return E.p_type == PT_PHDR; - }); + auto PhdrI = llvm::find_if( + Phdrs, [](const PhdrEntry &E) { return E.p_type == PT_PHDR; }); if (PhdrI != Phdrs.end()) Phdrs.erase(PhdrI); - return false; } -void LinkerScript::assignAddresses(std::vector &Phdrs) { +LinkerScript::AddressState::AddressState(const ScriptConfiguration &Opt) { + for (auto &MRI : Opt.MemoryRegions) { + const MemoryRegion *MR = &MRI.second; + MemRegionOffset[MR] = MR->Origin; + } +} + +void LinkerScript::assignAddresses() { // Assign addresses as instructed by linker script SECTIONS sub-commands. Dot = 0; + auto State = make_unique(Opt); + // CurAddressState captures the local AddressState and makes it accessible + // deliberately. This is needed as there are some cases where we cannot just + // thread the current state through to a lambda function created by the + // script parser. + CurAddressState = State.get(); ErrorOnMissingSection = true; switchTo(Aether); @@ -845,15 +866,7 @@ void LinkerScript::assignAddresses(std::vector &Phdrs) { auto *Cmd = cast(Base); assignOffsets(Cmd); } - - uint64_t MinVA = std::numeric_limits::max(); - for (OutputSectionCommand *Cmd : OutputSectionCommands) { - OutputSection *Sec = Cmd->Sec; - if (Sec->Flags & SHF_ALLOC) - MinVA = std::min(MinVA, Sec->Addr); - } - - allocateHeaders(Phdrs, OutputSectionCommands, MinVA); + CurAddressState = nullptr; } // Creates program headers as instructed by PHDRS linker script command. @@ -879,12 +892,9 @@ std::vector LinkerScript::createPhdrs() { // Add output sections to program headers. for (OutputSectionCommand *Cmd : OutputSectionCommands) { - OutputSection *Sec = Cmd->Sec; - if (!(Sec->Flags & SHF_ALLOC)) - break; - // Assign headers specified by linker script - for (size_t Id : getPhdrIndices(Sec)) { + for (size_t Id : getPhdrIndices(Cmd)) { + OutputSection *Sec = Cmd->Sec; Ret[Id].add(Sec); if (Opt.PhdrsCommands[Id].Flags == UINT_MAX) Ret[Id].p_flags |= Sec->getPhdrFlags(); @@ -911,6 +921,92 @@ OutputSectionCommand *LinkerScript::getCmd(OutputSection *Sec) const { return I->second; } +void OutputSectionCommand::sort(std::function Order) { + typedef std::pair Pair; + auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; }; + + std::vector V; + assert(Commands.size() == 1); + auto *ISD = cast(Commands[0]); + for (InputSection *S : ISD->Sections) + V.push_back({Order(S), S}); + std::stable_sort(V.begin(), V.end(), Comp); + ISD->Sections.clear(); + for (Pair &P : V) + ISD->Sections.push_back(P.second); +} + +// Returns true if S matches /Filename.?\.o$/. +static bool isCrtBeginEnd(StringRef S, StringRef Filename) { + if (!S.endswith(".o")) + return false; + S = S.drop_back(2); + if (S.endswith(Filename)) + return true; + return !S.empty() && S.drop_back().endswith(Filename); +} + +static bool isCrtbegin(StringRef S) { return isCrtBeginEnd(S, "crtbegin"); } +static bool isCrtend(StringRef S) { return isCrtBeginEnd(S, "crtend"); } + +// .ctors and .dtors are sorted by this priority from highest to lowest. +// +// 1. The section was contained in crtbegin (crtbegin contains +// some sentinel value in its .ctors and .dtors so that the runtime +// can find the beginning of the sections.) +// +// 2. The section has an optional priority value in the form of ".ctors.N" +// or ".dtors.N" where N is a number. Unlike .{init,fini}_array, +// they are compared as string rather than number. +// +// 3. The section is just ".ctors" or ".dtors". +// +// 4. The section was contained in crtend, which contains an end marker. +// +// In an ideal world, we don't need this function because .init_array and +// .ctors are duplicate features (and .init_array is newer.) However, there +// are too many real-world use cases of .ctors, so we had no choice to +// support that with this rather ad-hoc semantics. +static bool compCtors(const InputSection *A, const InputSection *B) { + bool BeginA = isCrtbegin(A->File->getName()); + bool BeginB = isCrtbegin(B->File->getName()); + if (BeginA != BeginB) + return BeginA; + bool EndA = isCrtend(A->File->getName()); + bool EndB = isCrtend(B->File->getName()); + if (EndA != EndB) + return EndB; + StringRef X = A->Name; + StringRef Y = B->Name; + assert(X.startswith(".ctors") || X.startswith(".dtors")); + assert(Y.startswith(".ctors") || Y.startswith(".dtors")); + X = X.substr(6); + Y = Y.substr(6); + if (X.empty() && Y.empty()) + return false; + return X < Y; +} + +// Sorts input sections by the special rules for .ctors and .dtors. +// Unfortunately, the rules are different from the one for .{init,fini}_array. +// Read the comment above. +void OutputSectionCommand::sortCtorsDtors() { + assert(Commands.size() == 1); + auto *ISD = cast(Commands[0]); + std::stable_sort(ISD->Sections.begin(), ISD->Sections.end(), compCtors); +} + +// Sorts input sections by section name suffixes, so that .foo.N comes +// before .foo.M if N < M. Used to sort .{init,fini}_array.N sections. +// We want to keep the original order if the priorities are the same +// because the compiler keeps the original initialization order in a +// translation unit and we need to respect that. +// For more detail, read the section of the GCC's manual about init_priority. +void OutputSectionCommand::sortInitFini() { + // Sort sections by priority. + sort([](InputSectionBase *S) { return getPriority(S->Name); }); +} + uint32_t OutputSectionCommand::getFiller() { if (Filler) return *Filler; @@ -1085,16 +1181,9 @@ template void OutputSectionCommand::writeTo(uint8_t *Buf) { writeInt(Buf + Data->Offset, Data->Expression().getValue(), Data->Size); } -bool LinkerScript::hasLMA(OutputSection *Sec) { - if (OutputSectionCommand *Cmd = getCmd(Sec)) - if (Cmd->LMAExpr) - return true; - return false; -} - ExprValue LinkerScript::getSymbolValue(const Twine &Loc, StringRef S) { if (S == ".") - return {CurOutSec, Dot - CurOutSec->Addr, Loc}; + return {CurAddressState->OutSec, Dot - CurAddressState->OutSec->Addr, Loc}; if (SymbolBody *B = findSymbol(S)) { if (auto *D = dyn_cast(B)) return {D->Section, D->Value, Loc}; @@ -1111,17 +1200,14 @@ static const size_t NoPhdr = -1; // Returns indices of ELF headers containing specific section. Each index is a // zero based number of ELF header listed within PHDRS {} script block. -std::vector LinkerScript::getPhdrIndices(OutputSection *Sec) { - if (OutputSectionCommand *Cmd = getCmd(Sec)) { - std::vector Ret; - for (StringRef PhdrName : Cmd->Phdrs) { - size_t Index = getPhdrIndex(Cmd->Location, PhdrName); - if (Index != NoPhdr) - Ret.push_back(Index); - } - return Ret; +std::vector LinkerScript::getPhdrIndices(OutputSectionCommand *Cmd) { + std::vector Ret; + for (StringRef PhdrName : Cmd->Phdrs) { + size_t Index = getPhdrIndex(Cmd->Location, PhdrName); + if (Index != NoPhdr) + Ret.push_back(Index); } - return {}; + return Ret; } // Returns the index of the segment named PhdrName if found otherwise diff --git a/ELF/LinkerScript.h b/ELF/LinkerScript.h index f8a34a1e97dd..dd5a7d797f60 100644 --- a/ELF/LinkerScript.h +++ b/ELF/LinkerScript.h @@ -110,7 +110,6 @@ struct MemoryRegion { std::string Name; uint64_t Origin; uint64_t Length; - uint64_t Offset; uint32_t Flags; uint32_t NegFlags; }; @@ -140,6 +139,10 @@ struct OutputSectionCommand : BaseCommand { template void writeTo(uint8_t *Buf); template void maybeCompress(); uint32_t getFiller(); + + void sort(std::function Order); + void sortInitFini(); + void sortCtorsDtors(); }; // This struct represents one section match pattern in SECTIONS() command. @@ -222,6 +225,17 @@ struct ScriptConfiguration { }; class LinkerScript final { + // Temporary state used in processCommands() and assignAddresses() + // that must be reinitialized for each call to the above functions, and must + // not be used outside of the scope of a call to the above functions. + struct AddressState { + uint64_t ThreadBssOffset = 0; + OutputSection *OutSec = nullptr; + MemoryRegion *MemRegion = nullptr; + llvm::DenseMap MemRegionOffset; + std::function LMAOffset; + AddressState(const ScriptConfiguration &Opt); + }; llvm::DenseMap SecToCommand; llvm::DenseMap NameToOutputSectionCommand; @@ -234,7 +248,7 @@ class LinkerScript final { std::vector createInputSectionList(OutputSectionCommand &Cmd); - std::vector getPhdrIndices(OutputSection *Sec); + std::vector getPhdrIndices(OutputSectionCommand *Cmd); size_t getPhdrIndex(const Twine &Loc, StringRef PhdrName); MemoryRegion *findMemoryRegion(OutputSectionCommand *Cmd); @@ -244,14 +258,10 @@ class LinkerScript final { void output(InputSection *Sec); void process(BaseCommand &Base); + AddressState *CurAddressState = nullptr; OutputSection *Aether; uint64_t Dot; - uint64_t ThreadBssOffset = 0; - - std::function LMAOffset; - OutputSection *CurOutSec = nullptr; - MemoryRegion *CurMemRegion = nullptr; public: bool ErrorOnMissingSection = false; @@ -276,13 +286,11 @@ class LinkerScript final { std::vector createPhdrs(); bool ignoreInterpSection(); - bool hasLMA(OutputSection *Sec); bool shouldKeep(InputSectionBase *S); void assignOffsets(OutputSectionCommand *Cmd); - void createOrphanCommands(); void processNonSectionCommands(); - void assignAddresses(std::vector &Phdrs); - + void assignAddresses(); + void allocateHeaders(std::vector &Phdrs); void addSymbol(SymbolAssignment *Cmd); void processCommands(OutputSectionFactory &Factory); diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp index c0bf6b32e6e2..d6ae5dcae167 100644 --- a/ELF/OutputSections.cpp +++ b/ELF/OutputSections.cpp @@ -101,100 +101,6 @@ void OutputSection::addSection(InputSection *S) { this->Entsize = std::max(this->Entsize, S->Entsize); } -// This function is called after we sort input sections -// and scan relocations to setup sections' offsets. -void OutputSection::assignOffsets() { - OutputSectionCommand *Cmd = Script->getCmd(this); - uint64_t Off = 0; - for (BaseCommand *Base : Cmd->Commands) - if (auto *ISD = dyn_cast(Base)) - for (InputSection *S : ISD->Sections) - Off = updateOffset(Off, S); - this->Size = Off; -} - -void OutputSection::sort(std::function Order) { - typedef std::pair Pair; - auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; }; - - std::vector V; - for (InputSection *S : Sections) - V.push_back({Order(S), S}); - std::stable_sort(V.begin(), V.end(), Comp); - Sections.clear(); - for (Pair &P : V) - Sections.push_back(P.second); -} - -// Sorts input sections by section name suffixes, so that .foo.N comes -// before .foo.M if N < M. Used to sort .{init,fini}_array.N sections. -// We want to keep the original order if the priorities are the same -// because the compiler keeps the original initialization order in a -// translation unit and we need to respect that. -// For more detail, read the section of the GCC's manual about init_priority. -void OutputSection::sortInitFini() { - // Sort sections by priority. - sort([](InputSectionBase *S) { return getPriority(S->Name); }); -} - -// Returns true if S matches /Filename.?\.o$/. -static bool isCrtBeginEnd(StringRef S, StringRef Filename) { - if (!S.endswith(".o")) - return false; - S = S.drop_back(2); - if (S.endswith(Filename)) - return true; - return !S.empty() && S.drop_back().endswith(Filename); -} - -static bool isCrtbegin(StringRef S) { return isCrtBeginEnd(S, "crtbegin"); } -static bool isCrtend(StringRef S) { return isCrtBeginEnd(S, "crtend"); } - -// .ctors and .dtors are sorted by this priority from highest to lowest. -// -// 1. The section was contained in crtbegin (crtbegin contains -// some sentinel value in its .ctors and .dtors so that the runtime -// can find the beginning of the sections.) -// -// 2. The section has an optional priority value in the form of ".ctors.N" -// or ".dtors.N" where N is a number. Unlike .{init,fini}_array, -// they are compared as string rather than number. -// -// 3. The section is just ".ctors" or ".dtors". -// -// 4. The section was contained in crtend, which contains an end marker. -// -// In an ideal world, we don't need this function because .init_array and -// .ctors are duplicate features (and .init_array is newer.) However, there -// are too many real-world use cases of .ctors, so we had no choice to -// support that with this rather ad-hoc semantics. -static bool compCtors(const InputSection *A, const InputSection *B) { - bool BeginA = isCrtbegin(A->File->getName()); - bool BeginB = isCrtbegin(B->File->getName()); - if (BeginA != BeginB) - return BeginA; - bool EndA = isCrtend(A->File->getName()); - bool EndB = isCrtend(B->File->getName()); - if (EndA != EndB) - return EndB; - StringRef X = A->Name; - StringRef Y = B->Name; - assert(X.startswith(".ctors") || X.startswith(".dtors")); - assert(Y.startswith(".ctors") || Y.startswith(".dtors")); - X = X.substr(6); - Y = Y.substr(6); - if (X.empty() && Y.empty()) - return false; - return X < Y; -} - -// Sorts input sections by the special rules for .ctors and .dtors. -// Unfortunately, the rules are different from the one for .{init,fini}_array. -// Read the comment above. -void OutputSection::sortCtorsDtors() { - std::stable_sort(Sections.begin(), Sections.end(), compCtors); -} - static SectionKey createKey(InputSectionBase *C, StringRef OutsecName) { // The ELF spec just says // ---------------------------------------------------------------- @@ -249,9 +155,7 @@ static SectionKey createKey(InputSectionBase *C, StringRef OutsecName) { return SectionKey{OutsecName, Flags, Alignment}; } -OutputSectionFactory::OutputSectionFactory( - std::vector &OutputSections) - : OutputSections(OutputSections) {} +OutputSectionFactory::OutputSectionFactory() {} static uint64_t getIncompatibleFlags(uint64_t Flags) { return Flags & (SHF_ALLOC | SHF_TLS); diff --git a/ELF/OutputSections.h b/ELF/OutputSections.h index d5f77838d530..68ee066a13da 100644 --- a/ELF/OutputSections.h +++ b/ELF/OutputSections.h @@ -80,10 +80,6 @@ class OutputSection final : public SectionBase { uint32_t ShName = 0; void addSection(InputSection *S); - void sort(std::function Order); - void sortInitFini(); - void sortCtorsDtors(); - void assignOffsets(); std::vector Sections; // Used for implementation of --compress-debug-sections option. @@ -135,7 +131,7 @@ namespace elf { // linker scripts. class OutputSectionFactory { public: - OutputSectionFactory(std::vector &OutputSections); + OutputSectionFactory(); ~OutputSectionFactory(); void addInputSec(InputSectionBase *IS, StringRef OutsecName); @@ -144,7 +140,6 @@ class OutputSectionFactory { private: llvm::SmallDenseMap Map; - std::vector &OutputSections; }; uint64_t getHeaderSize(); diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp index fd823fe0ed42..52dbe4b583d0 100644 --- a/ELF/Relocations.cpp +++ b/ELF/Relocations.cpp @@ -557,9 +557,9 @@ static RelExpr adjustExpr(SymbolBody &Body, RelExpr Expr, uint32_t Type, // the refered symbol can be preemepted to refer to the executable. if (Config->Shared || (Config->Pic && !isRelExpr(Expr))) { error("can't create dynamic relocation " + toString(Type) + " against " + - (Body.getName().empty() ? "local symbol in readonly segment" + (Body.getName().empty() ? "local symbol" : "symbol: " + toString(Body)) + - getLocation(S, Body, RelOff)); + " in readonly segment" + getLocation(S, Body, RelOff)); return Expr; } @@ -1049,10 +1049,17 @@ ThunkSection *ThunkCreator::addThunkSection(OutputSection *OS, std::pair ThunkCreator::getThunk(SymbolBody &Body, uint32_t Type) { - auto res = ThunkedSymbols.insert({&Body, nullptr}); - if (res.second) - res.first->second = addThunk(Type, Body); - return std::make_pair(res.first->second, res.second); + auto Res = ThunkedSymbols.insert({&Body, std::vector()}); + if (!Res.second) { + // Check existing Thunks for Body to see if they can be reused + for (Thunk *ET : Res.first->second) + if (ET->isCompatibleWith(Type)) + return std::make_pair(ET, false); + } + // No existing compatible Thunk in range, create a new one + Thunk *T = addThunk(Type, Body); + Res.first->second.push_back(T); + return std::make_pair(T, true); } // Call Fn on every executable InputSection accessed via the linker script @@ -1066,13 +1073,12 @@ void ThunkCreator::forEachExecInputSection( OutputSection *OS = Cmd->Sec; if (!(OS->Flags & SHF_ALLOC) || !(OS->Flags & SHF_EXECINSTR)) continue; - if (OutputSectionCommand *C = Script->getCmd(OS)) - for (BaseCommand *BC : C->Commands) - if (auto *ISD = dyn_cast(BC)) { - CurTS = nullptr; - for (InputSection* IS : ISD->Sections) - Fn(OS, &ISD->Sections, IS); - } + for (BaseCommand *BC : Cmd->Commands) + if (auto *ISD = dyn_cast(BC)) { + CurTS = nullptr; + for (InputSection *IS : ISD->Sections) + Fn(OS, &ISD->Sections, IS); + } } } diff --git a/ELF/Relocations.h b/ELF/Relocations.h index 445308b27cec..fc3e3444ac24 100644 --- a/ELF/Relocations.h +++ b/ELF/Relocations.h @@ -144,14 +144,17 @@ class ThunkCreator { std::pair getThunk(SymbolBody &Body, uint32_t Type); ThunkSection *addThunkSection(OutputSection *OS, std::vector *, uint64_t Off); - // Track Symbols that already have a Thunk - llvm::DenseMap ThunkedSymbols; + // Record all the available Thunks for a Symbol + llvm::DenseMap> ThunkedSymbols; // Find a Thunk from the Thunks symbol definition, we can use this to find // the Thunk from a relocation to the Thunks symbol definition. llvm::DenseMap Thunks; - // Track InputSections that have a ThunkSection placed in front + // Track InputSections that have an inline ThunkSection placed in front + // an inline ThunkSection may have control fall through to the section below + // so we need to make sure that there is only one of them. + // The Mips LA25 Thunk is an example of an inline ThunkSection. llvm::DenseMap ThunkedSections; // All the ThunkSections that we have created, organised by OutputSection diff --git a/ELF/ScriptParser.cpp b/ELF/ScriptParser.cpp index 4a44944fe7ed..72940ca0cfd4 100644 --- a/ELF/ScriptParser.cpp +++ b/ELF/ScriptParser.cpp @@ -1191,8 +1191,7 @@ void ScriptParser::readMemory() { if (It != Script->Opt.MemoryRegions.end()) setError("region '" + Name + "' already defined"); else - Script->Opt.MemoryRegions[Name] = {Name, Origin, Length, - Origin, Flags, NegFlags}; + Script->Opt.MemoryRegions[Name] = {Name, Origin, Length, Flags, NegFlags}; } } diff --git a/ELF/SymbolTable.cpp b/ELF/SymbolTable.cpp index d75b89f17527..c802d74b8ff8 100644 --- a/ELF/SymbolTable.cpp +++ b/ELF/SymbolTable.cpp @@ -211,6 +211,13 @@ static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) { // Find an existing symbol or create and insert a new one. template std::pair SymbolTable::insert(StringRef Name) { + // @@ means the symbol is the default version. In that + // case symbol must exist and @@ will be used to + // resolve references to . + size_t Pos = Name.find("@@"); + if (Pos != StringRef::npos) + Name = Name.take_front(Pos); + auto P = Symtab.insert( {CachedHashStringRef(Name), SymIndex((int)SymVector.size(), false)}); SymIndex &V = P.first->second; @@ -319,7 +326,7 @@ static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding) { if (WasInserted) return 1; SymbolBody *Body = S->body(); - if (Body->isLazy() || !Body->isInCurrentDSO()) + if (!Body->isInCurrentDSO()) return 1; if (Binding == STB_WEAK) return -1; @@ -689,6 +696,12 @@ void SymbolTable::assignExactVersion(SymbolVersion Ver, uint16_t VersionId // Assign the version. for (SymbolBody *B : Syms) { + // Skip symbols containing version info because symbol versions + // specified by symbol names take precedence over version scripts. + // See parseSymbolVersion(). + if (B->getName().find('@') != StringRef::npos) + continue; + Symbol *Sym = B->symbol(); if (Sym->InVersionScript) warn("duplicate symbol '" + Ver.Name + "' in version script"); @@ -702,47 +715,21 @@ void SymbolTable::assignWildcardVersion(SymbolVersion Ver, uint16_t VersionId) { if (!Ver.HasWildcard) return; - std::vector Syms = findAllByVersion(Ver); // Exact matching takes precendence over fuzzy matching, // so we set a version to a symbol only if no version has been assigned // to the symbol. This behavior is compatible with GNU. - for (SymbolBody *B : Syms) + for (SymbolBody *B : findAllByVersion(Ver)) if (B->symbol()->VersionId == Config->DefaultSymbolVersion) B->symbol()->VersionId = VersionId; } -static bool isDefaultVersion(SymbolBody *B) { - return B->isInCurrentDSO() && B->getName().find("@@") != StringRef::npos; -} - // This function processes version scripts by updating VersionId // member of symbols. template void SymbolTable::scanVersionScript() { - // Symbol themselves might know their versions because symbols - // can contain versions in the form of @. - // Let them parse and update their names to exclude version suffix. - for (Symbol *Sym : SymVector) { - SymbolBody *Body = Sym->body(); - bool IsDefault = isDefaultVersion(Body); - Body->parseSymbolVersion(); - - if (!IsDefault) - continue; - - // @@ means the symbol is the default version. If that's the - // case, the symbol is not used only to resolve of version - // but also undefined unversioned symbols with name . - SymbolBody *S = find(Body->getName()); - if (S && S->isUndefined()) - S->copy(Body); - } - // Handle edge cases first. handleAnonymousVersion(); - if (Config->VersionDefinitions.empty()) - return; // Now we have version definitions, so we need to set version ids to symbols. // Each version definition has a glob pattern, and all symbols that match @@ -761,6 +748,12 @@ template void SymbolTable::scanVersionScript() { for (VersionDefinition &V : llvm::reverse(Config->VersionDefinitions)) for (SymbolVersion &Ver : V.Globals) assignWildcardVersion(Ver, V.Id); + + // Symbol themselves might know their versions because symbols + // can contain versions in the form of @. + // Let them parse and update their names to exclude version suffix. + for (Symbol *Sym : SymVector) + Sym->body()->parseSymbolVersion(); } template class elf::SymbolTable; diff --git a/ELF/Symbols.cpp b/ELF/Symbols.cpp index e8cd662c69ac..1d17f57f0c30 100644 --- a/ELF/Symbols.cpp +++ b/ELF/Symbols.cpp @@ -159,19 +159,12 @@ bool SymbolBody::isPreemptible() const { return true; } -// Overwrites all attributes except symbol name with Other's so that -// this symbol becomes an alias to Other. This is useful for handling -// some options such as --wrap. -// -// The reason why we want to keep the symbol name is because, if we -// copy symbol names, we'll end up having symbol tables in resulting -// executables or DSOs containing two or more identical symbols, which -// is just inconvenient. +// Overwrites all attributes with Other's so that this symbol becomes +// an alias to Other. This is useful for handling some options such as +// --wrap. void SymbolBody::copy(SymbolBody *Other) { - StringRef S = Name; memcpy(symbol()->Body.buffer, Other->symbol()->Body.buffer, sizeof(Symbol::Body)); - Name = S; } uint64_t SymbolBody::getVA(int64_t Addend) const { @@ -272,7 +265,12 @@ void SymbolBody::parseSymbolVersion() { } // It is an error if the specified version is not defined. - error(toString(File) + ": symbol " + S + " has undefined version " + Verstr); + // Usually version script is not provided when linking executable, + // but we may still want to override a versioned symbol from DSO, + // so we do not report error in this case. + if (Config->Shared) + error(toString(File) + ": symbol " + S + " has undefined version " + + Verstr); } Defined::Defined(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther, diff --git a/ELF/Symbols.h b/ELF/Symbols.h index 773e1ad9588a..a1b3a6fba911 100644 --- a/ELF/Symbols.h +++ b/ELF/Symbols.h @@ -65,7 +65,9 @@ class SymbolBody { return SymbolKind == LazyArchiveKind || SymbolKind == LazyObjectKind; } bool isShared() const { return SymbolKind == SharedKind; } - bool isInCurrentDSO() const { return !isUndefined() && !isShared(); } + bool isInCurrentDSO() const { + return !isUndefined() && !isShared() && !isLazy(); + } bool isLocal() const { return IsLocal; } bool isPreemptible() const; StringRef getName() const { return Name; } @@ -218,7 +220,7 @@ class SharedSymbol : public Defined { Verdef(Verdef), ElfSym(ElfSym) { // IFuncs defined in DSOs are treated as functions by the static linker. if (isGnuIFunc()) - Type = llvm::ELF::STT_FUNC; + this->Type = llvm::ELF::STT_FUNC; this->File = File; } diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp index 995d05692ee2..fd724fac327c 100644 --- a/ELF/SyntheticSections.cpp +++ b/ELF/SyntheticSections.cpp @@ -1071,10 +1071,11 @@ template void DynamicSection::finalizeContents() { return; // Already finalized. this->Link = InX::DynStrTab->getParent()->SectionIndex; - if (In::RelaDyn->getParent()->Size > 0) { + if (In::RelaDyn->getParent() && !In::RelaDyn->empty()) { bool IsRela = Config->IsRela; add({IsRela ? DT_RELA : DT_REL, In::RelaDyn}); - add({IsRela ? DT_RELASZ : DT_RELSZ, In::RelaDyn->getParent()->Size}); + add({IsRela ? DT_RELASZ : DT_RELSZ, In::RelaDyn->getParent(), + Entry::SecSize}); add({IsRela ? DT_RELAENT : DT_RELENT, uint64_t(IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel))}); @@ -1087,9 +1088,9 @@ template void DynamicSection::finalizeContents() { add({IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels}); } } - if (In::RelaPlt->getParent()->Size > 0) { + if (In::RelaPlt->getParent() && !In::RelaPlt->empty()) { add({DT_JMPREL, In::RelaPlt}); - add({DT_PLTRELSZ, In::RelaPlt->getParent()->Size}); + add({DT_PLTRELSZ, In::RelaPlt->getParent(), Entry::SecSize}); switch (Config->EMachine) { case EM_MIPS: add({DT_MIPS_PLTGOT, In::GotPlt}); @@ -1699,9 +1700,9 @@ unsigned PltSection::getPltRelocOff() const { return (HeaderSize == 0) ? InX::Plt->getSize() : 0; } -GdbIndexSection::GdbIndexSection() +GdbIndexSection::GdbIndexSection(std::vector &&Chunks) : SyntheticSection(0, SHT_PROGBITS, 1, ".gdb_index"), - StringPool(llvm::StringTableBuilder::ELF) {} + StringPool(llvm::StringTableBuilder::ELF), Chunks(std::move(Chunks)) {} // Iterative hash function for symbol's name is described in .gdb_index format // specification. Note that we use one for version 5 to 7 here, it is different @@ -1713,11 +1714,10 @@ static uint32_t hash(StringRef Str) { return R; } -static std::vector readCuList(DWARFContext &Dwarf, - InputSection *Sec) { +static std::vector readCuList(DWARFContext &Dwarf) { std::vector Ret; for (std::unique_ptr &CU : Dwarf.compile_units()) - Ret.push_back({Sec->OutSecOff + CU->getOffset(), CU->getLength() + 4}); + Ret.push_back({CU->getOffset(), CU->getLength() + 4}); return Ret; } @@ -1764,19 +1764,15 @@ static std::vector getDebugInfoSections() { std::vector Ret; for (InputSectionBase *S : InputSections) if (InputSection *IS = dyn_cast(S)) - if (IS->getParent() && IS->Name == ".debug_info") + if (IS->Name == ".debug_info") Ret.push_back(IS); return Ret; } void GdbIndexSection::buildIndex() { - std::vector V = getDebugInfoSections(); - if (V.empty()) + if (Chunks.empty()) return; - for (InputSection *Sec : V) - Chunks.push_back(readDwarf(Sec)); - uint32_t CuId = 0; for (GdbIndexChunk &D : Chunks) { for (AddressEntry &E : D.AddressArea) @@ -1802,23 +1798,33 @@ void GdbIndexSection::buildIndex() { } } -GdbIndexChunk GdbIndexSection::readDwarf(InputSection *Sec) { - Expected> Obj = - object::ObjectFile::createObjectFile(Sec->File->MB); - if (!Obj) { - error(toString(Sec->File) + ": error creating DWARF context"); - return {}; - } - - DWARFContextInMemory Dwarf(*Obj.get()); - +static GdbIndexChunk readDwarf(DWARFContextInMemory &Dwarf, InputSection *Sec) { GdbIndexChunk Ret; - Ret.CompilationUnits = readCuList(Dwarf, Sec); + Ret.DebugInfoSec = Sec; + Ret.CompilationUnits = readCuList(Dwarf); Ret.AddressArea = readAddressArea(Dwarf, Sec); Ret.NamesAndTypes = readPubNamesAndTypes(Dwarf, Config->IsLE); return Ret; } +template GdbIndexSection *elf::createGdbIndex() { + std::vector Chunks; + for (InputSection *Sec : getDebugInfoSections()) { + InputFile *F = Sec->File; + std::error_code EC; + ELFObjectFile Obj(F->MB, EC); + if (EC) + fatal(EC.message()); + DWARFContextInMemory Dwarf(Obj, nullptr, [&](Error E) { + error(toString(F) + ": error parsing DWARF data:\n>>> " + + toString(std::move(E))); + return ErrorPolicy::Continue; + }); + Chunks.push_back(readDwarf(Dwarf, Sec)); + } + return make(std::move(Chunks)); +} + static size_t getCuSize(std::vector &C) { size_t Ret = 0; for (GdbIndexChunk &D : C) @@ -1876,7 +1882,7 @@ void GdbIndexSection::writeTo(uint8_t *Buf) { // Write the CU list. for (GdbIndexChunk &D : Chunks) { for (CompilationUnitEntry &Cu : D.CompilationUnits) { - write64le(Buf, Cu.CuOffset); + write64le(Buf, D.DebugInfoSec->OutSecOff + Cu.CuOffset); write64le(Buf + 8, Cu.CuLength); Buf += 16; } @@ -2345,6 +2351,11 @@ StringTableSection *InX::ShStrTab; StringTableSection *InX::StrTab; SymbolTableBaseSection *InX::SymTab; +template GdbIndexSection *elf::createGdbIndex(); +template GdbIndexSection *elf::createGdbIndex(); +template GdbIndexSection *elf::createGdbIndex(); +template GdbIndexSection *elf::createGdbIndex(); + template void PltSection::addEntry(SymbolBody &Sym); template void PltSection::addEntry(SymbolBody &Sym); template void PltSection::addEntry(SymbolBody &Sym); diff --git a/ELF/SyntheticSections.h b/ELF/SyntheticSections.h index be9a43c8155b..ddd8ca99a61b 100644 --- a/ELF/SyntheticSections.h +++ b/ELF/SyntheticSections.h @@ -503,7 +503,7 @@ class GdbIndexSection final : public SyntheticSection { const unsigned SymTabEntrySize = 2 * OffsetTypeSize; public: - GdbIndexSection(); + GdbIndexSection(std::vector &&Chunks); void finalizeContents() override; void writeTo(uint8_t *Buf) override; size_t getSize() const override; @@ -524,7 +524,6 @@ class GdbIndexSection final : public SyntheticSection { std::vector Chunks; private: - GdbIndexChunk readDwarf(InputSection *Sec); void buildIndex(); uint32_t CuTypesOffset; @@ -538,6 +537,8 @@ class GdbIndexSection final : public SyntheticSection { bool Finalized = false; }; +template GdbIndexSection *createGdbIndex(); + // --eh-frame-hdr option tells linker to construct a header for all the // .eh_frame sections. This header is placed to a section named .eh_frame_hdr // and also to a PT_GNU_EH_FRAME segment. diff --git a/ELF/Thunks.cpp b/ELF/Thunks.cpp index 752a881d7867..cae31027e557 100644 --- a/ELF/Thunks.cpp +++ b/ELF/Thunks.cpp @@ -57,6 +57,7 @@ class ARMV7ABSLongThunk final : public Thunk { uint32_t size() const override { return 12; } void writeTo(uint8_t *Buf, ThunkSection &IS) const override; void addSymbols(ThunkSection &IS) override; + bool isCompatibleWith(uint32_t RelocType) const override; }; class ARMV7PILongThunk final : public Thunk { @@ -66,28 +67,31 @@ class ARMV7PILongThunk final : public Thunk { uint32_t size() const override { return 16; } void writeTo(uint8_t *Buf, ThunkSection &IS) const override; void addSymbols(ThunkSection &IS) override; + bool isCompatibleWith(uint32_t RelocType) const override; }; class ThumbV7ABSLongThunk final : public Thunk { public: ThumbV7ABSLongThunk(const SymbolBody &Dest) : Thunk(Dest) { - this->alignment = 2; + alignment = 2; } uint32_t size() const override { return 10; } void writeTo(uint8_t *Buf, ThunkSection &IS) const override; void addSymbols(ThunkSection &IS) override; + bool isCompatibleWith(uint32_t RelocType) const override; }; class ThumbV7PILongThunk final : public Thunk { public: ThumbV7PILongThunk(const SymbolBody &Dest) : Thunk(Dest) { - this->alignment = 2; + alignment = 2; } uint32_t size() const override { return 12; } void writeTo(uint8_t *Buf, ThunkSection &IS) const override; void addSymbols(ThunkSection &IS) override; + bool isCompatibleWith(uint32_t RelocType) const override; }; // MIPS LA25 thunk @@ -128,6 +132,11 @@ void ARMV7ABSLongThunk::addSymbols(ThunkSection &IS) { addSyntheticLocal("$a", STT_NOTYPE, Offset, 0, &IS); } +bool ARMV7ABSLongThunk::isCompatibleWith(uint32_t RelocType) const { + // Thumb branch relocations can't use BLX + return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24; +} + void ThumbV7ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { const uint8_t Data[] = { 0x40, 0xf2, 0x00, 0x0c, // movw ip, :lower16:S @@ -147,6 +156,12 @@ void ThumbV7ABSLongThunk::addSymbols(ThunkSection &IS) { addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, &IS); } +bool ThumbV7ABSLongThunk::isCompatibleWith(uint32_t RelocType) const { + // ARM branch relocations can't use BLX + return RelocType != R_ARM_JUMP24 && RelocType != R_ARM_PC24 && + RelocType != R_ARM_PLT32; +} + void ARMV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { const uint8_t Data[] = { 0xf0, 0xcf, 0x0f, 0xe3, // P: movw ip,:lower16:S - (P + (L1-P) +8) @@ -168,6 +183,11 @@ void ARMV7PILongThunk::addSymbols(ThunkSection &IS) { addSyntheticLocal("$a", STT_NOTYPE, Offset, 0, &IS); } +bool ARMV7PILongThunk::isCompatibleWith(uint32_t RelocType) const { + // Thumb branch relocations can't use BLX + return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24; +} + void ThumbV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { const uint8_t Data[] = { 0x4f, 0xf6, 0xf4, 0x7c, // P: movw ip,:lower16:S - (P + (L1-P) + 4) @@ -189,9 +209,15 @@ void ThumbV7PILongThunk::addSymbols(ThunkSection &IS) { addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, &IS); } +bool ThumbV7PILongThunk::isCompatibleWith(uint32_t RelocType) const { + // ARM branch relocations can't use BLX + return RelocType != R_ARM_JUMP24 && RelocType != R_ARM_PC24 && + RelocType != R_ARM_PLT32; +} + // Write MIPS LA25 thunk code to call PIC function from the non-PIC one. void MipsThunk::writeTo(uint8_t *Buf, ThunkSection &) const { - uint64_t S = this->Destination.getVA(); + uint64_t S = Destination.getVA(); write32(Buf, 0x3c190000, Config->Endianness); // lui $25, %hi(func) write32(Buf + 4, 0x08000000 | (S >> 2), Config->Endianness); // j func write32(Buf + 8, 0x27390000, Config->Endianness); // addiu $25, $25, %lo(func) diff --git a/ELF/Thunks.h b/ELF/Thunks.h index 38ee090e75e1..00b6b2cf2994 100644 --- a/ELF/Thunks.h +++ b/ELF/Thunks.h @@ -41,6 +41,10 @@ class Thunk { // a branch and fall through to the first Symbol in the Target. virtual InputSection *getTargetInputSection() const { return nullptr; } + // To reuse a Thunk the caller as identified by the RelocType must be + // compatible with it. + virtual bool isCompatibleWith(uint32_t RelocType) const { return true; } + // The alignment requirement for this Thunk, defaults to the size of the // typical code section alignment. const SymbolBody &Destination; diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp index 080d8e787301..bf43ee5c5f91 100644 --- a/ELF/Writer.cpp +++ b/ELF/Writer.cpp @@ -73,13 +73,12 @@ template class Writer { std::unique_ptr Buffer; - OutputSectionFactory Factory{OutputSections}; + OutputSectionFactory Factory; void addRelIpltSymbols(); void addStartEndSymbols(); void addStartStopSymbols(OutputSection *Sec); uint64_t getEntryAddr(); - OutputSection *findSection(StringRef Name); OutputSection *findSectionInScript(StringRef Name); OutputSectionCommand *findSectionCommand(StringRef Name); @@ -152,10 +151,6 @@ template static void combineEhFrameSections() { } template void Writer::clearOutputSections() { - if (Script->Opt.HasSections) - Script->createOrphanCommands(); - else - Script->fabricateDefaultCommands(); // Clear the OutputSections to make sure it is not used anymore. Any // code from this point on should be using the linker script // commands. @@ -190,9 +185,10 @@ template void Writer::run() { // output sections by default rules. We still need to give the // linker script a chance to run, because it might contain // non-SECTIONS commands such as ASSERT. - createSections(); Script->processCommands(Factory); + createSections(); } + clearOutputSections(); if (Config->Discard != DiscardPolicy::All) copyLocalSymbols(); @@ -218,7 +214,8 @@ template void Writer::run() { OutputSectionCommands.begin(), OutputSectionCommands.end(), [](OutputSectionCommand *Cmd) { Cmd->maybeCompress(); }); - Script->assignAddresses(Phdrs); + Script->assignAddresses(); + Script->allocateHeaders(Phdrs); // Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a // 0 sized region. This has to be done late since only after assignAddresses @@ -383,7 +380,7 @@ template void Writer::createSyntheticSections() { Add(InX::IgotPlt); if (Config->GdbIndex) { - InX::GdbIndex = make(); + InX::GdbIndex = createGdbIndex(); Add(InX::GdbIndex); } @@ -499,11 +496,18 @@ template void Writer::copyLocalSymbols() { template void Writer::addSectionSymbols() { // Create one STT_SECTION symbol for each output section we might // have a relocation with. - for (OutputSection *Sec : OutputSections) { - if (Sec->Sections.empty()) + for (BaseCommand *Base : Script->Opt.Commands) { + auto *Cmd = dyn_cast(Base); + if (!Cmd) continue; - - InputSection *IS = Sec->Sections[0]; + auto I = llvm::find_if(Cmd->Commands, [](BaseCommand *Base) { + if (auto *ISD = dyn_cast(Base)) + return !ISD->Sections.empty(); + return false; + }); + if (I == Cmd->Commands.end()) + continue; + InputSection *IS = cast(*I)->Sections[0]; if (isa(IS) || IS->Type == SHT_REL || IS->Type == SHT_RELA) continue; @@ -864,20 +868,19 @@ template void Writer::addReservedSymbols() { // Sort input sections by section name suffixes for // __attribute__((init_priority(N))). -static void sortInitFini(OutputSection *S) { - if (S) - reinterpret_cast(S)->sortInitFini(); +static void sortInitFini(OutputSectionCommand *Cmd) { + if (Cmd) + Cmd->sortInitFini(); } // Sort input sections by the special rule for .ctors and .dtors. -static void sortCtorsDtors(OutputSection *S) { - if (S) - reinterpret_cast(S)->sortCtorsDtors(); +static void sortCtorsDtors(OutputSectionCommand *Cmd) { + if (Cmd) + Cmd->sortCtorsDtors(); } // Sort input sections using the list provided by --symbol-ordering-file. -template -static void sortBySymbolsOrder(ArrayRef OutputSections) { +template static void sortBySymbolsOrder() { if (Config->SymbolOrderingFile.empty()) return; @@ -902,9 +905,9 @@ static void sortBySymbolsOrder(ArrayRef OutputSections) { } // Sort sections by priority. - for (OutputSection *Base : OutputSections) - if (auto *Sec = dyn_cast(Base)) - Sec->sort([&](InputSectionBase *S) { return SectionOrder.lookup(S); }); + for (BaseCommand *Base : Script->Opt.Commands) + if (auto *Cmd = dyn_cast(Base)) + Cmd->sort([&](InputSectionBase *S) { return SectionOrder.lookup(S); }); } template @@ -934,11 +937,12 @@ template void Writer::createSections() { if (IS) Factory.addInputSec(IS, getOutputSectionName(IS->Name)); - sortBySymbolsOrder(OutputSections); - sortInitFini(findSection(".init_array")); - sortInitFini(findSection(".fini_array")); - sortCtorsDtors(findSection(".ctors")); - sortCtorsDtors(findSection(".dtors")); + Script->fabricateDefaultCommands(); + sortBySymbolsOrder(); + sortInitFini(findSectionCommand(".init_array")); + sortInitFini(findSectionCommand(".fini_array")); + sortCtorsDtors(findSectionCommand(".ctors")); + sortCtorsDtors(findSectionCommand(".dtors")); } // We want to find how similar two ranks are. @@ -1132,7 +1136,7 @@ static void applySynthetic(const std::vector &Sections, // to make them visible from linkescript side. But not all sections are always // required to be in output. For example we don't need dynamic section content // sometimes. This function filters out such unused sections from the output. -static void removeUnusedSyntheticSections(std::vector &V) { +static void removeUnusedSyntheticSections() { // All input synthetic sections that can be empty are placed after // all regular ones. We iterate over them all and exit at first // non-synthetic. @@ -1145,29 +1149,53 @@ static void removeUnusedSyntheticSections(std::vector &V) { continue; if ((SS == InX::Got || SS == InX::MipsGot) && ElfSym::GlobalOffsetTable) continue; - OS->Sections.erase(std::find(OS->Sections.begin(), OS->Sections.end(), SS)); - SS->Live = false; + + OutputSectionCommand *Cmd = Script->getCmd(OS); + std::vector::iterator Empty = Cmd->Commands.end(); + for (auto I = Cmd->Commands.begin(), E = Cmd->Commands.end(); I != E; ++I) { + BaseCommand *B = *I; + if (auto *ISD = dyn_cast(B)) { + auto P = std::find(ISD->Sections.begin(), ISD->Sections.end(), SS); + if (P != ISD->Sections.end()) + ISD->Sections.erase(P); + if (ISD->Sections.empty()) + Empty = I; + } + } + if (Empty != Cmd->Commands.end()) + Cmd->Commands.erase(Empty); + // If there are no other sections in the output section, remove it from the // output. - if (OS->Sections.empty()) - V.erase(std::find(V.begin(), V.end(), OS)); + if (Cmd->Commands.empty()) { + // Also remove script commands matching the output section. + auto &Cmds = Script->Opt.Commands; + auto I = std::remove_if(Cmds.begin(), Cmds.end(), [&](BaseCommand *Cmd) { + if (auto *OSCmd = dyn_cast(Cmd)) + return OSCmd->Sec == OS; + return false; + }); + Cmds.erase(I, Cmds.end()); + } } } // Create output section objects and add them to OutputSections. template void Writer::finalizeSections() { - Out::DebugInfo = findSection(".debug_info"); - Out::PreinitArray = findSection(".preinit_array"); - Out::InitArray = findSection(".init_array"); - Out::FiniArray = findSection(".fini_array"); + Out::DebugInfo = findSectionInScript(".debug_info"); + Out::PreinitArray = findSectionInScript(".preinit_array"); + Out::InitArray = findSectionInScript(".init_array"); + Out::FiniArray = findSectionInScript(".fini_array"); // The linker needs to define SECNAME_start, SECNAME_end and SECNAME_stop // symbols for sections, so that the runtime can get the start and end // addresses of each section by section name. Add such symbols. if (!Config->Relocatable) { addStartEndSymbols(); - for (OutputSection *Sec : OutputSections) - addStartStopSymbols(Sec); + for (BaseCommand *Base : Script->Opt.Commands) + if (auto *Cmd = dyn_cast(Base)) + if (Cmd->Sec) + addStartStopSymbols(Cmd->Sec); } // Add _DYNAMIC symbol. Unlike GNU gold, our _DYNAMIC symbol has no type. @@ -1218,9 +1246,8 @@ template void Writer::finalizeSections() { return; addPredefinedSections(); - removeUnusedSyntheticSections(OutputSections); + removeUnusedSyntheticSections(); - clearOutputSections(); sortSections(); // Now that we have the final list, create a list of all the @@ -1257,12 +1284,6 @@ template void Writer::finalizeSections() { Out::ProgramHeaders->Size = sizeof(Elf_Phdr) * Phdrs.size(); } - // Compute the size of .rela.dyn and .rela.plt early since we need - // them to populate .dynamic. - for (SyntheticSection *SS : {In::RelaDyn, In::RelaPlt}) - if (SS->getParent() && !SS->empty()) - SS->getParent()->assignOffsets(); - // Dynamic section must be the last one in this list and dynamic // symbol table section (DynSymTab) must be the first one. applySynthetic({InX::DynSymTab, InX::Bss, InX::BssRelRo, @@ -1286,6 +1307,7 @@ template void Writer::finalizeSections() { // are out of range. This will need to turn into a loop that converges // when no more Thunks are added ThunkCreator TC; + Script->assignAddresses(); if (TC.createThunks(OutputSectionCommands)) { applySynthetic({InX::MipsGot}, [](SyntheticSection *SS) { SS->updateAllocSize(); }); @@ -1308,21 +1330,18 @@ template void Writer::finalizeSections() { template void Writer::addPredefinedSections() { // ARM ABI requires .ARM.exidx to be terminated by some piece of data. // We have the terminater synthetic section class. Add that at the end. - auto *OS = dyn_cast_or_null(findSection(".ARM.exidx")); - if (!OS || OS->Sections.empty() || Config->Relocatable) + OutputSectionCommand *Cmd = findSectionCommand(".ARM.exidx"); + if (!Cmd || Cmd->Commands.empty() || Config->Relocatable) return; auto *Sentinel = make(); - OS->addSection(Sentinel); - // If there are linker script commands existing at this point then add the - // sentinel to the last of these too. - if (OutputSectionCommand *C = Script->getCmd(OS)) { - auto ISD = std::find_if(C->Commands.rbegin(), C->Commands.rend(), - [](const BaseCommand *Base) { - return isa(Base); - }); - cast(*ISD)->Sections.push_back(Sentinel); - } + Cmd->Sec->addSection(Sentinel); + // Add the sentinel to the last of these too. + auto ISD = std::find_if(Cmd->Commands.rbegin(), Cmd->Commands.rend(), + [](const BaseCommand *Base) { + return isa(Base); + }); + cast(*ISD)->Sections.push_back(Sentinel); } // The linker is expected to define SECNAME_start and SECNAME_end @@ -1346,7 +1365,7 @@ template void Writer::addStartEndSymbols() { Define("__init_array_start", "__init_array_end", Out::InitArray); Define("__fini_array_start", "__fini_array_end", Out::FiniArray); - if (OutputSection *Sec = findSection(".ARM.exidx")) + if (OutputSection *Sec = findSectionInScript(".ARM.exidx")) Define("__exidx_start", "__exidx_end", Sec); } @@ -1366,9 +1385,10 @@ void Writer::addStartStopSymbols(OutputSection *Sec) { template OutputSectionCommand *Writer::findSectionCommand(StringRef Name) { - for (OutputSectionCommand *Cmd : OutputSectionCommands) - if (Cmd->Name == Name) - return Cmd; + for (BaseCommand *Base : Script->Opt.Commands) + if (auto *Cmd = dyn_cast(Base)) + if (Cmd->Name == Name) + return Cmd; return nullptr; } @@ -1378,13 +1398,6 @@ template OutputSection *Writer::findSectionInScript(StringRef return nullptr; } -template OutputSection *Writer::findSection(StringRef Name) { - for (OutputSection *Sec : OutputSections) - if (Sec->Name == Name) - return Sec; - return nullptr; -} - static bool needsPtLoad(OutputSection *Sec) { if (!(Sec->Flags & SHF_ALLOC)) return false; @@ -1446,7 +1459,7 @@ template std::vector Writer::createPhdrs() { // different flags or is loaded at a discontiguous address using AT linker // script command. uint64_t NewFlags = computeFlags(Sec->getPhdrFlags()); - if (Script->hasLMA(Sec) || Flags != NewFlags) { + if (Cmd->LMAExpr || Flags != NewFlags) { Load = AddHdr(PT_LOAD, NewFlags); Flags = NewFlags; } @@ -1514,7 +1527,7 @@ template std::vector Writer::createPhdrs() { for (OutputSectionCommand *Cmd : OutputSectionCommands) { OutputSection *Sec = Cmd->Sec; if (Sec->Type == SHT_NOTE) { - if (!Note || Script->hasLMA(Sec)) + if (!Note || Cmd->LMAExpr) Note = AddHdr(PT_NOTE, PF_R); Note->add(Sec); } else { @@ -1528,11 +1541,9 @@ template void Writer::addPtArmExid(std::vector &Phdrs) { if (Config->EMachine != EM_ARM) return; - auto I = - std::find_if(OutputSectionCommands.begin(), OutputSectionCommands.end(), - [](OutputSectionCommand *Cmd) { - return Cmd->Sec->Type == SHT_ARM_EXIDX; - }); + auto I = llvm::find_if(OutputSectionCommands, [](OutputSectionCommand *Cmd) { + return Cmd->Sec->Type == SHT_ARM_EXIDX; + }); if (I == OutputSectionCommands.end()) return; diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp index edbe576f0086..b54054726dfe 100644 --- a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp +++ b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp @@ -508,9 +508,9 @@ readBinary(std::unique_ptr &mb, if (dyldInfo) { // If any exports, extract and add to normalized exportInfo vector. if (dyldInfo->export_size) { - const uint8_t *trieStart = reinterpret_cast(start + - dyldInfo->export_off); - ArrayRef trie(trieStart, dyldInfo->export_size); + const uint8_t *trieStart = reinterpret_cast( + start + read32(&dyldInfo->export_off, isBig)); + ArrayRef trie(trieStart, read32(&dyldInfo->export_size, isBig)); for (const ExportEntry &trieExport : MachOObjectFile::exports(trie)) { Export normExport; normExport.name = trieExport.name().copy(f->ownedAllocations); diff --git a/test/COFF/Inputs/library-arm64.lib b/test/COFF/Inputs/library-arm64.lib new file mode 100644 index 0000000000000000000000000000000000000000..04e193dd16baa943aa4afe2c2ffd0c4dc70405cb GIT binary patch literal 2000 zcmb_dPj3=I6#wn=r%H{Xv>r_`X`)^bSZGUP%%U}cl+uQ74|>^dcdezN&`^5tnHG9-`kxTmb55THko-dzj?Fo{bt^K^W>$|b&p>qUZlsrT%lCT zI!^ZCAHeb)Z`qq=t4uqZr)T!jMceH)J8h^zfO}5Q5h`w{ecp50 zJ*dI#OgD;(X`HBDX+SCpRARu%0#T=SNee_38g#@FLzMa`BILv!SO+AO!#6l7wn{}I z6AvsQPBP=QTK-l4>wXKR(fxY;2&`}K-z^ezX31a1`*3*iadj`40c9F|krN?JBwuHm zd>gBIxwJxq@6>(?AVShab}01L1dInXxTYrc7&nm~>LgRR&r>XhNIk`Jk}d+j{T1LL z5*RqC?WWu9oOh0T>1U1S=~}hECDz9T8)HZK=M=>LC`motFkvApFx}4S8TmSJH0_%F z<6XfHmb_nwq-+91Mvf)olj9u`i4<6efRRpdgfO1wPJDrPB{?Ojqe1DPQG8NRAXfhPg+;H23PC9{-RNAz5$kr#tP*P7KIdPqvVgFBZQ{ voTOf#tJfo+WqkA!gno>f>!Y!LyOkxfqEX@S-=P1p@HZYh6)9Ep$E^GTU*m|6 literal 0 HcmV?d00001 diff --git a/test/COFF/Inputs/pdb-diff-cl.pdb b/test/COFF/Inputs/pdb-diff-cl.pdb new file mode 100644 index 0000000000000000000000000000000000000000..ba5d8380e7c359bb0d3eb63d344282f33ea9d425 GIT binary patch literal 102400 zcmeI5e{3Abb;sZCkrGAyB56r>6h~PrvLjjM=_t{Ze6^#aNhzU4+Db^tvU4@Fyc?3| z?A=~=_b5?F93n7~#zop9HBcmOP!~yz0x6KT2#{X|;^v?7+##_9J(mWv`1cZPP5CTF#2nYco zAOwVf5D)@ydjgw(IA9#(wF+40AMOYkN=F!G@P8CvA8sI{k7e7at0&+C-k>8(nLcwT z=d0O4WkJ!eFD-N2ppsjq=-8yHU9;y@8F7y`BDKq89VYTmPcM|F?I7?fGmSv``Mg?C zwP4zJ8(v8b$MSqWSgfmQMcL!Sj}Au1h14?(>l79Ww7k1nN58I6i>Q8n<)WhHi>QyO z>(g-+^>OP#r3wvkomS)R*Xv2@+)1>=k6R?Rbq%--5hih_T>|KnZqVL<_I2Z-j&Ag& zff6%_@1{*X+KF+rZaSpo?J_XJ_Xc6nx{k6>TPQ+LF z(DHT=-wau5^NB^5c{xAPmNqTy zYI#1`v?=wV>pIG=k+yp^Rtwae@}js&>ZIe^LHxPMkQ#LxGmb(#KL^|E(6+Y?b#CeT zdF9lVx8~!qFfeU90n@$mha=^@LW{bT56d&{*<_2Vd_JYb5Ne9Nt(rtO+XF61o869h zY?qwYi=Az@4w(>BQG#WvUrd%6Yjl$sFR8lM~68n-_K8``1uaZ1Ov_RMv*|B@Mx zt!lWoc*e&Ns>d!h;*L1B@2|>WXCseHu<3cTc1cAEdMw^Rp-mA+r+slZiZz7S^P#D&w>z)G4ZGvY4oBGFH=8i_>Wt^?t{lv7KaLx-Hb9 z(?;#UPSlaQRDy`s)3e&{)3#?<73d`MzxC@`b zcE-d8e=-uoVHl6Un02JE_N2B(pr@{REL>YyI1H>6wN*ZUXWs?}$?>m2tK%Q1y#qUs zf4dR#me=Fot%&QU6OVuIjN?sC(RV28!^mhm4TbOTXzaUP>*AF5#=fj^|?ILp3Sr>3!$}&)5>7Gu+XNYUA!Cd_Bl-1DKo!8T%&?VPt4eYT&Z|FIwSYOxD@ zZqCCn7TCB(YgQ=L|42PEt&VM8=cnom%_21=r6jbEZR2jVD`^`C5Rdzx(+*;1+qefI zZ>?z%>a^H4`VnW_$RdnwgZ0MOSZo)E5KpbDzNY8%ApV#p4|7_;N!7lc^L5= z!nlvG)&K7!V;A?40ew}wQsd83A8p*V6>;_@8<;>a(9bN}sbzQa`C9faEgMM4-m7IV zKtX)ofR>=)XMI8-#S$Z{NlqWrcR!l96ePW%noG-;`$aF)hktb zjfR0-GZ#8FmmL^9a^I0`uGlDf!F4O~=WS1wuUie8gU@=$F8-|Zya#_C&%z#fKH&;o z(^fmrS88EHr%qe_=U}&(N85#KDrn|eAD;2ySseDBFD;{Z*@S=)5CTF#2nYcoAOwVf z5O|Xjcs4s={OY+U9%G;VvtNDX`TZ*|jXd|YTR(jM8|58wRXL6K zEm%kX9h;ir>MisAA39(?60MKN`YLP0t=4gC-J`pyCoJ~|TsXFF?7XI=3p=kXz#rxv zjBt6up5}^P2-j|(;s+5-+JJxKy}Sna65=`RQT|9TX9?Fb@c}lJwZ!qw2)Vp12wz9Y zzin_9dyg^qmw*4Ug$qMJ`^?V57aseEAG=Y#_*sc@?6L^~As_^VfDjM@LO=)z0U;m+ zgn$sZnFz4|kG1@vAAYwrUa5UldDh+h9RK~j8Jaz0Fm{38~H7x0($ z%6OhB$~THt94tdNGAT}p(pXl&-w4h@nu>A}?Lm1LbUw}>=i7Jj;>GgJTv%p?%S2|j zF9a`Ub>>~j%d#cN5Wv2&Grk|yvxD=Tj^!t2w3C-Y?!0zyCt2mv7=1cZPP5CTF#2nd0jm;in)Jbd>bHz7mEr>E-;PnB%P zDHM*J9zHkB@;;oyx953|z@X{yJ#~F_XPEEfp)7iJ-EP|2o6#=|$k3`Pobo2ytQ$}t zo;7)UZag=zPdA-^e}N6fz?&rAo;0M@LO=)z0U;m+gn$qb0zyCt2!S^zfqUTChrhRn z>hb&j*o%$B^=kt-jrTish~OsOtQ$~o@&6gB`2RP+v_z#45CTF#2nYcoAOwVf5D)@F z;P*g){k86OdOm}A{NDe09FHc_`H}xg>;{cD9bP`*+rF&FqSGHiK!d?wyviY-Dxe=n z2Xqdh5zZiJ0fMXhF}|!j^W?Q;iOP#B9MzLP633&|t@LGHUjno)#tUQ;lyUzhCa?W zggA%Cba)@aCn(d`voq2kEY{VuqUG&7Gn7Y~T2QrM8m}Nwl?CMu2Z2|aX#|S4BAx3) z#5ri0<2l4S$gvmQMlfAgbyX`PGcDJsbLR%?GyfnwpY!lD4%5>MrD;1>=;!m7D=K?@ z_{?R}3hR^<3iRts%a5ZyChB8Q*>UL7G9R0yE+~DRAzyh5l~NqPD(45 zp8zw=9%#=#M27!L#=2IO^a1bZB2ab!a!xK9&!&e2IVT!RXr#`TG!m zFtKynbJ$tN$8lOLkJDHl+a#A&z`ohsP9q3;i|v~Ax1MLv34LB`8ZtN2BD)?%obCFg z4&RS(#)#~i^(XE61BkDK6xuVNm$YZDe+Sj$-4xIVv^$z^x`_gM6;r z@Jebr1jBZE3qIRpI6vNw{T}T!)+wP75CTF#2nYcoAOwVf5O^yR*!;r*gYQMNe{%}^ zzwTf^X=R1){jRLAhl6W)Oa}1I_kIU?VgTC)_-Y((qplvl{tq|g&uU+o;Ku}T;rUuV z@{LQlu#bJ?s$H|^Lf_Yef1A<%t%>|C9%tlxozR(j-O-Ui3{qYTGpZ3SY`JN2o zvG2=i8?kRT4fJr-y{&1G>$E(7+>c3{Axo{k z_F-8^(pP339ZfB(^FduyRwdW7F=e#OJU7Bu+!E&H{OmioXJJ>%^TDP~sRv!xQFe{A z-K#Np)pN>=;+PjY>9}?fe=ahlM%~5?T0bH6k#b(4MO})iJky>{wy4VIQ%Ve>rpVi>NiK|U|G!Cs6ww;-NUlW>lM&y8)3+n<3A?a=x-rQ=$A<~rMd$&BV1@ktr3EuQf) zgzB+NjkqI@?fa`T*xAS<6Ks0ktX)!3f*y-EP-v5hglJsuA~m6^Gs=t34(+#xWx>2# zPROi8{$wJLqlGnTtI9ZS33ZCk_%{R8V81;}hXzYm_C@X)e(cdc&lMLFw1H-%E5YAj=nil!<1f956e49ov1ackyy8n<>;4DHCw5vDSK{x9`w&-;5AA? zlo0kA=RqHhyLgZ9`t#90r#%;=NT3ZUQ4ad&1W&)O&x5|1Qq{VHK{ZNBt850})$w&-` zVLbj~){(;6liC`Ap1S6-aBX4XFtAqCR{1lG__rG&Z+Sib z-HNzwI`R1T&N$xW6n%%XK8%dE(@^;Sj>f**wJuI+Z|qy!xNB|iL;5?_AiHjRL6vXr zupOD?V-_1j^|?ILp3Sr>3!$}&)5>7Gu+XNYUA!Cd*e*Ej4(x0fdlB;1 zng*dxi?8M0gE(Ky?L)}dH+=2JdYiQZ7QS}7GbwA*i0p~akL`(Bbl|)6u29DERC{Ww zUsc7onOenZEE4_)E+;+x{fPIOyXO=4+HB{%z38+3B>j*5s8@?!*mH9phOxlLHCnSm zsdw2@&rGXho7efN`a-ivO-U&U?PJ@x8|_Nk#sS3R{^zuV*x5GjLC9Nc8iYD6wvB$o z**3BWW7}Z8@ii9P#UaE~tE#W*`TY1gi-D-TLA4-ze|k7yKU@uhc#|R-1L{5Z{0EG5B)F@Wl;J0z?}> zP#+)j%L94)=?9M(;{RhlK>UC4|Hc20R`Kvao#J)3b@eO$zxe-&nFxLDFaE#y|Lf;O z*Lt7%eC+pz6Z1ME{=c3NX!Ow z;{UhK##}8E@&8x-|M;2f@9{^!&4;!4q8uy0?1hqMf@mo45<%Tc!L4aS?p)HHQ4lG zh47f)YRD58vIzkpAOwVf5D)@FKnMr{As_^VfDm~55lF88=e4sIT;%QR*8h(J3-7%C ze_SK#BZGemfDGiR+LiG6-agv6Yb)aHbvK}gpYLYbPA!XmH!zaDOUnjWhd%GUTJ{1I z#IgY`v#{hnkPMXZmU!{SiuBxW*vYyX8~ zLkEfzm6GTB?rdP4t@sVwu_l8?x#AWN=LU{)hFRtFL)x}eJUddH!UAx=I5COCfx+xR zE_?W1K5eE_D}KQBgL6ZJMJO%em37fO0(R-L*Srl6_qT?wrVYh~(!gLYd>mR<}kcNHmX;u@)`{Txn?eOYA!o4c;vn#*<7(v@`CGD;?LWdSG#UC zXb#r;bnN0~I{e%Ne;&`m9{72JD|Ag;?L1$pg$6yuuevy70~nbv~b=i{B;s=3N>3`qzp6?rD?0^h-Pg-k+i094C4e`HFWM zRCp5JgKf}nzGcwl6B&B_71ZH=gWmX0qQ5?!p-=ucLx1|RLI3twM1SPtsjrvtJQLm+ z|Eg!uzjtQno8N)Ivl;Ii{5e+F{4>$_KVi@dpEv37pAmiGXLttc2PVBSYSJC|n)IW8 zGU(f8hK6z|;~9gt{5nG~{2!iFg7@;hSHWW1q)&X=p!z(@{J24{FM$ctWD^2HKnMr{ zAs_^VfDjM@LO=)z0U>ZR64*OTbldH?H;8>d_HEd2$NpaIAH=>;#BTuZFzNgEne^u$ z&CtR*gTDJCqW|$tdU@WUFMS2A7Qgsr?0TuQ5D)@FKnMr{As_^VfDjM@LO=+-jR>&o zz8^bo-xI&z^S`lh_#D>m^L7dQJ%|^v&*PZi{r^0|V+j8SG7HE2JODozz&{4S?+avo z{2Olg83DQlJ8s9*R_t4_Lp^?5AbM3GKdHYBd$>p+p=?4x2nYcoAOwVf5D)@FKnMr{ sAs_^Vz>Ont>y1+_nuUN65CTF#2nYcoAOwVf5D)@FKnMtdHwl6N2jN_#@&Et; literal 0 HcmV?d00001 diff --git a/test/COFF/Inputs/pdb-diff.cpp b/test/COFF/Inputs/pdb-diff.cpp new file mode 100644 index 000000000000..f9acd68d1199 --- /dev/null +++ b/test/COFF/Inputs/pdb-diff.cpp @@ -0,0 +1,10 @@ +// Build with cl: +// cl.exe /Z7 pdb-diff.cpp /link /debug /pdb:pdb-diff-cl.pdb +// /nodefaultlib /entry:main +// Build with lld (after running the above cl command): +// lld-link.exe /debug /pdb:pdb-diff-lld.pdb /nodefaultlib +// /entry:main pdb-diff.obj + +void *__purecall = 0; + +int main() { return 42; } diff --git a/test/COFF/Inputs/pdb-diff.obj b/test/COFF/Inputs/pdb-diff.obj new file mode 100644 index 0000000000000000000000000000000000000000..a8948bd0c513c1f202d38a57ea49efd4e5d291a9 GIT binary patch literal 8602 zcmcIq&2JmW6@MfpS(V~gQernr({$^qi9aHmiWS>olbHHU6ic=c$&QmUR+i*Q+JM|; zcbD=9&{QZ2q)mHCF9q73+jDy=kV}F73kBLkfucR92Py42{rz@l$d$N`DF+!~I5ThF zn|br*H*Y?cOPPN8&u?zM{h=lDsKg;(^Hnw6R=OzXkokuxm~?1F@--Fu%M8k7Esm8(8qPh(-Lz)CM$@S)U*v!2a~#nG4lNm`P{<(~U9Td4 zMqZ0_HGGsI&mdxU#85L0+i~S-8EaEajZS|&CRw?Lmi9m>Br1&#Y}4ol+78RZNZHRL zNOzI0fcSMeI+~+`QCMGZwg4x)UY7|O9Q{7JUtiy@uG?YgJCzn}SuCn;<%a8l*Yc}s z+R!lvgQKfGvlokAY*4kX)ep6AV=>qENeP96nVA*$&7)F4QX&BWQGAf zj7jDMvl-+gclO!d?k(v*4(F34y%Qcd3;D~_*AL80>3~qFBxwH~$&F=?=V1LBT-e?& z^I1`Ml+NcQQ2w@4HRV2Oxj|D^oef9T+Whl3=iB_N^Kaf*oMm}KjvOD5!7RtvcNj=O z`?scIXHk0aC@_Zp$ZkCX#8)-7;kc@1RnMNaY~zpv>r_>5RF>n0%6IMhY0S~U3Bq{* z@!!!bW=5JAPX^-~!u~S|`p}NZ4CeG0=;ZxcB692nMADcyb%t*0NN0OFrauvR3Y^@5 zSRQ7~9uu5NqA-NMpi0zNH(y4MYQF9|2({}5#@PNNC^LOjr^k?1GP$u4ppIkFE_?SF za4~}Nf$5N=pp!4=lwFoNmOgRqhU%0D1%4=SJQsE|Jda4L<&Ij)I|_aiEWrRx}2x*^h z1CRz^q!E)RnI`rLmY+i$&SvCUqzndYojMS8-I&B!JB2c_b{gr7#u)qPU@R+VP)=1` z`(^SQjBy_OfTOb!jdbFzH;Y9mO6@4cLYNm~h-Ylt$byY3ykvxq%J$IG#z4FAQbW7_K0eb#=Lyn?tvu5Nwpc!oNNl};l)+%DQwO51 zGuWC!nb>*}slgWeXlsdk(y`-Nxsar_HIMgX@{4TS^_Gg}m)N=((MV6lR=fF5Q@zhG zZNtkUZSy7f?seXVwZBrc-fZ0tf({Mm z_StL8i#)q-*i{u*Xgm&xI#3bs!GoffRimQ(m^;Gj2x;M#S4+^WgnY7+_%7|M>omr? z9q1J6nd~O+TQZ%xPItO4r(Uaj6}z77OpitSbln`T(Fq-8P$ev)+ZpMMd&Tx~CWUp9 zG6g->1C`WWN@{U#X*s&!#v*Z>*&W%zY+t!HE=Smgsr7h1!hZXV_KV-cI_&a`T?Ddxi?Tw(JQ(ukk_2!IM2l072O_d zdc$2>>tAl3X%D_z4kX!A+e3Vb}Rb43XVaksjBB=>y%w$^$6C{JCQ8q`8BCGR3vWI z2T+`X0$`Qvgdd=2-xlnf*YBb|edWU#?`i(oVj1U!O&pf21w4-7Vf4#s)v#4_yz&c$$%_=&PyrwK?0WgeYwyL zQ)M(-uGaJMTl1dod*Ypo*2MCfHL-Z|D^z28ZE1O77M~2N^;S)t{EB-^??!fqGV#0h zJ}bZFxHa!~U|n(W<@M_P+QQA%xhv(V{Du6a(YM@ce38ogT9_=fr7#JF{N&X6m(J%4 zya7DeNWWledK%|#$BhQMwqi}(1jbKj zoVCAc^D`0F&IL{HX|0sEtCLfOJldeIJ<%`kLepD_Rm2)%1#xfp`p-Z8(;1BE-M^Ih zWg+j>KC$~VpMOs8RN7E>m@gDQ&d5$oN&YPX7f;D$_{W6(A^DdCS}T{~pAz^-gic8Q z9f4jjm*F20_J@4puLy7y;Nfp~FjS^l$tV7pfNmjWzMW5nzxrD&y&iqIiu3)rk!10` S94F$=XYx|%{L1vrY570;VZ(L+ literal 0 HcmV?d00001 diff --git a/test/COFF/Inputs/pdb-scopes-a.yaml b/test/COFF/Inputs/pdb-scopes-a.yaml new file mode 100644 index 000000000000..e9f4484c7060 --- /dev/null +++ b/test/COFF/Inputs/pdb-scopes-a.yaml @@ -0,0 +1,425 @@ +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ ] +sections: + - Name: .drectve + Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ] + Alignment: 1 + SectionData: 2020202F44454641554C544C49423A224C4942434D5422202F44454641554C544C49423A224F4C444E414D45532220 + - Name: '.debug$S' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + Subsections: + - !Symbols + Records: + - Kind: S_OBJNAME + ObjNameSym: + Signature: 0 + ObjectName: 'C:\src\llvm-project\build\a.obj' + - Kind: S_COMPILE3 + Compile3Sym: + Flags: [ SecurityChecks, HotPatch ] + Machine: X64 + FrontendMajor: 19 + FrontendMinor: 0 + FrontendBuild: 24215 + FrontendQFE: 1 + BackendMajor: 19 + BackendMinor: 0 + BackendBuild: 24215 + BackendQFE: 1 + Version: 'Microsoft (R) Optimizing Compiler' + - !Symbols + Records: + - Kind: S_GPROC32_ID + ProcSym: + CodeSize: 5 + DbgStart: 4 + DbgEnd: 4 + FunctionType: 4099 + Flags: [ ] + DisplayName: g + - Kind: S_FRAMEPROC + FrameProcSym: + TotalFrameBytes: 0 + PaddingFrameBytes: 0 + OffsetToPadding: 0 + BytesOfCalleeSavedRegisters: 0 + OffsetOfExceptionHandler: 0 + SectionIdOfExceptionHandler: 0 + Flags: [ AsynchronousExceptionHandling, OptimizedForSpeed ] + - Kind: S_REGREL32 + RegRelativeSym: + Offset: 8 + Type: 116 + Register: RSP + VarName: x + - Kind: S_PROC_ID_END + ScopeEndSym: + - !Lines + CodeSize: 5 + Flags: [ ] + RelocOffset: 0 + RelocSegment: 0 + Blocks: + - FileName: 'c:\src\llvm-project\build\a.c' + Lines: + - Offset: 0 + LineStart: 1 + IsStatement: true + EndDelta: 0 + Columns: + - !Symbols + Records: + - Kind: S_GPROC32_ID + ProcSym: + CodeSize: 58 + DbgStart: 8 + DbgEnd: 53 + FunctionType: 4101 + Flags: [ ] + DisplayName: main + - Kind: S_FRAMEPROC + FrameProcSym: + TotalFrameBytes: 56 + PaddingFrameBytes: 0 + OffsetToPadding: 0 + BytesOfCalleeSavedRegisters: 0 + OffsetOfExceptionHandler: 0 + SectionIdOfExceptionHandler: 0 + Flags: [ AsynchronousExceptionHandling, OptimizedForSpeed ] + - Kind: S_REGREL32 + RegRelativeSym: + Offset: 64 + Type: 116 + Register: RSP + VarName: argc + - Kind: S_BLOCK32 + BlockSym: + CodeSize: 17 + Offset: 15 + BlockName: '' + - Kind: S_REGREL32 + RegRelativeSym: + Offset: 32 + Type: 116 + Register: RSP + VarName: x + - Kind: S_END + ScopeEndSym: + - Kind: S_BLOCK32 + BlockSym: + CodeSize: 17 + Offset: 34 + BlockName: '' + - Kind: S_REGREL32 + RegRelativeSym: + Offset: 36 + Type: 116 + Register: RSP + VarName: y + - Kind: S_END + ScopeEndSym: + - Kind: S_PROC_ID_END + ScopeEndSym: + - !Lines + CodeSize: 58 + Flags: [ ] + RelocOffset: 0 + RelocSegment: 0 + Blocks: + - FileName: 'c:\src\llvm-project\build\a.c' + Lines: + - Offset: 0 + LineStart: 3 + IsStatement: true + EndDelta: 0 + - Offset: 8 + LineStart: 4 + IsStatement: true + EndDelta: 0 + - Offset: 15 + LineStart: 5 + IsStatement: true + EndDelta: 0 + - Offset: 23 + LineStart: 6 + IsStatement: true + EndDelta: 0 + - Offset: 32 + LineStart: 7 + IsStatement: true + EndDelta: 0 + - Offset: 34 + LineStart: 8 + IsStatement: true + EndDelta: 0 + - Offset: 42 + LineStart: 9 + IsStatement: true + EndDelta: 0 + - Offset: 51 + LineStart: 11 + IsStatement: true + EndDelta: 0 + Columns: + - !FileChecksums + Checksums: + - FileName: 'c:\src\llvm-project\build\a.c' + Kind: MD5 + Checksum: 7FA72225C3F5630316383BD8BCC3EF72 + - !StringTable + Strings: + - 'c:\src\llvm-project\build\a.c' + - !Symbols + Records: + - Kind: S_BUILDINFO + BuildInfoSym: + BuildId: 4110 + Relocations: + - VirtualAddress: 152 + SymbolName: g + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 156 + SymbolName: g + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 220 + SymbolName: g + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 224 + SymbolName: g + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 292 + SymbolName: main + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 296 + SymbolName: main + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 369 + SymbolName: main + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 373 + SymbolName: main + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 412 + SymbolName: main + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 416 + SymbolName: main + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 452 + SymbolName: main + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 456 + SymbolName: main + Type: IMAGE_REL_AMD64_SECTION + - Name: '.debug$T' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + Types: + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 116 ] + - Kind: LF_PROCEDURE + Procedure: + ReturnType: 3 + CallConv: NearC + Options: [ None ] + ParameterCount: 1 + ArgumentList: 4096 + - Kind: LF_POINTER + Pointer: + ReferentType: 4097 + Attrs: 65548 + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4097 + Name: g + - Kind: LF_PROCEDURE + Procedure: + ReturnType: 116 + CallConv: NearC + Options: [ None ] + ParameterCount: 1 + ArgumentList: 4096 + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4100 + Name: main + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4097 + Name: f + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'C:\src\llvm-project\build' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'C:\PROGRA~2\MICROS~1.0\VC\Bin\amd64\cl.exe' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: '-c -Z7 -MT -IC:\PROGRA~2\MICROS~1.0\VC\include -IC:\PROGRA~2\MICROS~1.0\VC\atlmfc\include -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\ucrt -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\shared -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\um' + - Kind: LF_SUBSTR_LIST + StringList: + StringIndices: [ 4105 ] + - Kind: LF_STRING_ID + StringId: + Id: 4106 + String: ' -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\winrt -TC -X' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: a.c + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'C:\src\llvm-project\build\vc140.pdb' + - Kind: LF_BUILDINFO + BuildInfo: + ArgIndices: [ 4103, 4104, 4108, 4109, 4107 ] + - Name: '.text$mn' + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: 894C2408C3CCCCCCCCCCCCCCCCCCCCCC894C24084883EC38837C2440007413C74424202A0000008B4C2420E800000000EB11C74424240D0000008B4C2424E80000000033C04883C438C3 + Relocations: + - VirtualAddress: 44 + SymbolName: f + Type: IMAGE_REL_AMD64_REL32 + - VirtualAddress: 63 + SymbolName: f + Type: IMAGE_REL_AMD64_REL32 + - Name: .xdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: '0108010008620000' + - Name: .pdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: 000000003A00000000000000 + Relocations: + - VirtualAddress: 0 + SymbolName: '$LN5' + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 4 + SymbolName: '$LN5' + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 8 + SymbolName: '$unwind$main' + Type: IMAGE_REL_AMD64_ADDR32NB +symbols: + - Name: .drectve + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 47 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.debug$S' + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 628 + NumberOfRelocations: 12 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.debug$T' + Value: 0 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 624 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.text$mn' + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 74 + NumberOfRelocations: 2 + NumberOfLinenumbers: 0 + CheckSum: 2120072435 + Number: 0 + - Name: g + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: f + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: main + Value: 16 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: '$LN5' + Value: 16 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_LABEL + - Name: .xdata + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 8 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 3137252093 + Number: 0 + - Name: '$unwind$main' + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .pdata + Value: 0 + SectionNumber: 6 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 12 + NumberOfRelocations: 3 + NumberOfLinenumbers: 0 + CheckSum: 336416693 + Number: 0 + - Name: '$pdata$main' + Value: 0 + SectionNumber: 6 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC +... diff --git a/test/COFF/Inputs/pdb-scopes-b.yaml b/test/COFF/Inputs/pdb-scopes-b.yaml new file mode 100644 index 000000000000..2839bf7e3538 --- /dev/null +++ b/test/COFF/Inputs/pdb-scopes-b.yaml @@ -0,0 +1,365 @@ +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ ] +sections: + - Name: .drectve + Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ] + Alignment: 1 + SectionData: 2020202F44454641554C544C49423A224C4942434D5422202F44454641554C544C49423A224F4C444E414D45532220 + - Name: '.debug$S' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + Subsections: + - !Symbols + Records: + - Kind: S_OBJNAME + ObjNameSym: + Signature: 0 + ObjectName: 'C:\src\llvm-project\build\b.obj' + - Kind: S_COMPILE3 + Compile3Sym: + Flags: [ SecurityChecks, HotPatch ] + Machine: X64 + FrontendMajor: 19 + FrontendMinor: 0 + FrontendBuild: 24215 + FrontendQFE: 1 + BackendMajor: 19 + BackendMinor: 0 + BackendBuild: 24215 + BackendQFE: 1 + Version: 'Microsoft (R) Optimizing Compiler' + - !Symbols + Records: + - Kind: S_GPROC32_ID + ProcSym: + CodeSize: 62 + DbgStart: 8 + DbgEnd: 57 + FunctionType: 4101 + Flags: [ ] + DisplayName: f + - Kind: S_FRAMEPROC + FrameProcSym: + TotalFrameBytes: 56 + PaddingFrameBytes: 0 + OffsetToPadding: 0 + BytesOfCalleeSavedRegisters: 0 + OffsetOfExceptionHandler: 0 + SectionIdOfExceptionHandler: 0 + Flags: [ AsynchronousExceptionHandling, OptimizedForSpeed ] + - Kind: S_REGREL32 + RegRelativeSym: + Offset: 64 + Type: 116 + Register: RSP + VarName: x + - Kind: S_BLOCK32 + BlockSym: + CodeSize: 20 + Offset: 15 + BlockName: '' + - Kind: S_REGREL32 + RegRelativeSym: + Offset: 32 + Type: 116 + Register: RSP + VarName: y + - Kind: S_END + ScopeEndSym: + - Kind: S_BLOCK32 + BlockSym: + CodeSize: 20 + Offset: 37 + BlockName: '' + - Kind: S_REGREL32 + RegRelativeSym: + Offset: 36 + Type: 116 + Register: RSP + VarName: w + - Kind: S_END + ScopeEndSym: + - Kind: S_PROC_ID_END + ScopeEndSym: + - !Lines + CodeSize: 62 + Flags: [ ] + RelocOffset: 0 + RelocSegment: 0 + Blocks: + - FileName: 'c:\src\llvm-project\build\b.c' + Lines: + - Offset: 0 + LineStart: 2 + IsStatement: true + EndDelta: 0 + - Offset: 8 + LineStart: 3 + IsStatement: true + EndDelta: 0 + - Offset: 15 + LineStart: 4 + IsStatement: true + EndDelta: 0 + - Offset: 26 + LineStart: 5 + IsStatement: true + EndDelta: 0 + - Offset: 35 + LineStart: 6 + IsStatement: true + EndDelta: 0 + - Offset: 37 + LineStart: 7 + IsStatement: true + EndDelta: 0 + - Offset: 48 + LineStart: 8 + IsStatement: true + EndDelta: 0 + - Offset: 57 + LineStart: 10 + IsStatement: true + EndDelta: 0 + Columns: + - !FileChecksums + Checksums: + - FileName: 'c:\src\llvm-project\build\b.c' + Kind: MD5 + Checksum: 8E8C92DB46478902EBEAEBFCFF15A6E0 + - !StringTable + Strings: + - 'c:\src\llvm-project\build\b.c' + - !Symbols + Records: + - Kind: S_BUILDINFO + BuildInfoSym: + BuildId: 4110 + Relocations: + - VirtualAddress: 152 + SymbolName: f + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 156 + SymbolName: f + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 223 + SymbolName: f + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 227 + SymbolName: f + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 266 + SymbolName: f + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 270 + SymbolName: f + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 308 + SymbolName: f + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 312 + SymbolName: f + Type: IMAGE_REL_AMD64_SECTION + - Name: '.debug$T' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + Types: + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 0 ] + - Kind: LF_PROCEDURE + Procedure: + ReturnType: 3 + CallConv: NearC + Options: [ None ] + ParameterCount: 0 + ArgumentList: 4096 + - Kind: LF_POINTER + Pointer: + ReferentType: 4097 + Attrs: 65548 + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 116 ] + - Kind: LF_PROCEDURE + Procedure: + ReturnType: 3 + CallConv: NearC + Options: [ None ] + ParameterCount: 1 + ArgumentList: 4099 + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4100 + Name: f + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4097 + Name: g + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'C:\src\llvm-project\build' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'C:\PROGRA~2\MICROS~1.0\VC\Bin\amd64\cl.exe' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: '-c -Z7 -MT -IC:\PROGRA~2\MICROS~1.0\VC\include -IC:\PROGRA~2\MICROS~1.0\VC\atlmfc\include -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\ucrt -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\shared -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\um' + - Kind: LF_SUBSTR_LIST + StringList: + StringIndices: [ 4105 ] + - Kind: LF_STRING_ID + StringId: + Id: 4106 + String: ' -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\winrt -TC -X' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: b.c + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'C:\src\llvm-project\build\vc140.pdb' + - Kind: LF_BUILDINFO + BuildInfo: + ArgIndices: [ 4103, 4104, 4108, 4109, 4107 ] + - Name: '.text$mn' + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: 894C24084883EC38837C24400074168B44244083C003894424208B4C2420E800000000EB148B44244083C004894424248B4C2424E8000000004883C438C3 + Relocations: + - VirtualAddress: 31 + SymbolName: g + Type: IMAGE_REL_AMD64_REL32 + - VirtualAddress: 53 + SymbolName: g + Type: IMAGE_REL_AMD64_REL32 + - Name: .xdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: '0108010008620000' + - Name: .pdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: '000000003E00000000000000' + Relocations: + - VirtualAddress: 0 + SymbolName: '$LN5' + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 4 + SymbolName: '$LN5' + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 8 + SymbolName: '$unwind$f' + Type: IMAGE_REL_AMD64_ADDR32NB +symbols: + - Name: .drectve + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 47 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.debug$S' + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 484 + NumberOfRelocations: 8 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.debug$T' + Value: 0 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 616 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.text$mn' + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 62 + NumberOfRelocations: 2 + NumberOfLinenumbers: 0 + CheckSum: 3841032836 + Number: 0 + - Name: g + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: f + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: '$LN5' + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_LABEL + - Name: .xdata + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 8 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 3137252093 + Number: 0 + - Name: '$unwind$f' + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .pdata + Value: 0 + SectionNumber: 6 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 12 + NumberOfRelocations: 3 + NumberOfLinenumbers: 0 + CheckSum: 2420588879 + Number: 0 + - Name: '$pdata$f' + Value: 0 + SectionNumber: 6 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC +... diff --git a/test/COFF/arm64-magic.yaml b/test/COFF/arm64-magic.yaml new file mode 100644 index 000000000000..a35eeca483c7 --- /dev/null +++ b/test/COFF/arm64-magic.yaml @@ -0,0 +1,46 @@ +# RUN: yaml2obj < %s > %t.obj +# RUN: lld-link /out:%t.exe /entry:mainCRTStartup /subsystem:console %t.obj +# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s + +# CHECK: Format: COFF-ARM64 +# CHECK: Arch: aarch64 +# CHECK: AddressSize: 64bit +# CHECK: ImageFileHeader { +# CHECK: Machine: IMAGE_FILE_MACHINE_ARM64 (0xAA64) +# CHECK: Characteristics [ (0x22) +# CHECK: IMAGE_FILE_EXECUTABLE_IMAGE (0x2) +# CHECK: IMAGE_FILE_LARGE_ADDRESS_AWARE (0x20) +# CHECK: ] +# CHECK: } +# CHECK: ImageOptionalHeader { +# CHECK: Magic: 0x20B + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_ARM64 + Characteristics: [] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_PURGEABLE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: 'e0031f2ac0035fd6' +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 8 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 1 + - Name: mainCRTStartup + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/test/COFF/arm64-relocs-imports.test b/test/COFF/arm64-relocs-imports.test new file mode 100644 index 000000000000..3d252aaa2801 --- /dev/null +++ b/test/COFF/arm64-relocs-imports.test @@ -0,0 +1,136 @@ +# REQUIRES: aarch64 + +# RUN: yaml2obj < %s > %t.obj +# RUN: llvm-objdump -d %t.obj | FileCheck %s -check-prefix BEFORE +# RUN: lld-link /entry:main /subsystem:console /out:%t.exe %t.obj %p/Inputs/library-arm64.lib +# RUN: llvm-objdump -d %t.exe | FileCheck %s -check-prefix AFTER + +# BEFORE: Disassembly of section .text: +# BEFORE: 0: fe 0f 1f f8 str x30, [sp, #-16]! +# BEFORE: 4: 00 00 00 90 adrp x0, #0 +# BEFORE: 8: 00 08 00 91 add x0, x0, #2 +# BEFORE: c: 00 00 00 94 bl #0 +# BEFORE: 10: 00 01 40 39 ldrb w0, [x8] +# BEFORE: 14: 00 01 40 79 ldrh w0, [x8] +# BEFORE: 18: 00 01 40 b9 ldr w0, [x8] +# BEFORE: 1c: 00 01 40 f9 ldr x0, [x8] +# BEFORE: 20: e0 03 1f 2a mov w0, wzr +# BEFORE: 24: fe 07 41 f8 ldr x30, [sp], #16 +# BEFORE: 28: c0 03 5f d6 ret +# BEFORE: 2c: 08 00 00 00 +# BEFORE: 30: 00 00 00 00 + +# AFTER: Disassembly of section .text: +# AFTER: 140002000: fe 0f 1f f8 str x30, [sp, #-16]! +# AFTER: 140002004: e0 ff ff f0 adrp x0, #-4096 +# AFTER: 140002008: 00 18 00 91 add x0, x0, #6 +# AFTER: 14000200c: 0a 00 00 94 bl #40 +# AFTER: 140002010: 00 21 40 39 ldrb w0, [x8, #8] +# AFTER: 140002014: 00 11 40 79 ldrh w0, [x8, #8] +# AFTER: 140002018: 00 09 40 b9 ldr w0, [x8, #8] +# AFTER: 14000201c: 00 05 40 f9 ldr x0, [x8, #8] +# AFTER: 140002020: e0 03 1f 2a mov w0, wzr +# AFTER: 140002024: fe 07 41 f8 ldr x30, [sp], #16 +# AFTER: 140002028: c0 03 5f d6 ret +# AFTER: 14000202c: 10 10 00 40 +# AFTER: 140002030: 01 00 00 00 +# AFTER: 140002034: 10 00 00 b0 adrp x16, #4096 +# AFTER: 140002038: 10 1e 40 f9 ldr x16, [x16, #56] +# AFTER: 14000203c: 00 02 1f d6 br x16 + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_ARM64 + Characteristics: [ ] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: FE0F1FF80000009000080091000000940001403900014079000140B9000140F9E0031F2AFE0741F8C0035FD60800000000000000 + Relocations: + - VirtualAddress: 4 + SymbolName: .Lstr + Type: 4 + - VirtualAddress: 8 + SymbolName: .Lstr + Type: 6 + - VirtualAddress: 12 + SymbolName: function + Type: 3 + - VirtualAddress: 16 + SymbolName: .Lglobal + Type: 7 + - VirtualAddress: 20 + SymbolName: .Lglobal + Type: 7 + - VirtualAddress: 24 + SymbolName: .Lglobal + Type: 7 + - VirtualAddress: 28 + SymbolName: .Lglobal + Type: 7 + - VirtualAddress: 44 + SymbolName: .Lglobal + Type: 14 + - Name: .data + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 4 + SectionData: '' + - Name: .bss + Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 4 + SectionData: '' + - Name: .rdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 1 + SectionData: 00000000202068656C6C6F20776F726C6400 +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 28 + NumberOfRelocations: 3 + NumberOfLinenumbers: 0 + CheckSum: 1438860354 + Number: 1 + - Name: .rdata + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 12 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 872944732 + Number: 4 + - Name: main + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: .Lstr + Value: 4 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .Lglobal + Value: 8 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: function + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/test/COFF/combined-resources.test b/test/COFF/combined-resources.test index dc6c87af0f77..e8d5d65008d5 100644 --- a/test/COFF/combined-resources.test +++ b/test/COFF/combined-resources.test @@ -8,10 +8,206 @@ # RUN: lld-link /out:%t.exe /entry:main %t.obj %p/Inputs/resource.res \ # RUN: %p/Inputs/combined-resources.res %p/Inputs/combined-resources-2.res -# RUN: llvm-readobj -coff-resources -file-headers %t.exe | FileCheck %s - +# RUN: llvm-readobj -coff-resources -file-headers -section-data %t.exe | \ +# RUN: FileCheck %s CHECK: ResourceTableRVA: 0x1000 CHECK-NEXT: ResourceTableSize: 0xC1C CHECK-DAG: Resources [ CHECK-NEXT: Total Number of Resources: 13 +CHECK-DAG: .rsrc Data ( +CHECK-NEXT: 0000: 00000000 00000000 00000000 01000600 |................| +CHECK-NEXT: 0010: 38030080 48000080 02000000 60000080 |8...H.......`...| +CHECK-NEXT: 0020: 04000000 80000080 05000000 A0000080 |................| +CHECK-NEXT: 0030: 06000000 B8000080 09000000 D0000080 |................| +CHECK-NEXT: 0040: 0A000000 F0000080 00000000 00000000 |................| +CHECK-NEXT: 0050: 00000000 01000000 50030080 08010080 |........P.......| +CHECK-NEXT: 0060: 00000000 00000000 00000000 02000000 |................| +CHECK-NEXT: 0070: FE020080 20010080 0C030080 38010080 |.... .......8...| +CHECK-NEXT: 0080: 00000000 00000000 00000000 01000100 |................| +CHECK-NEXT: 0090: 2C030080 50010080 60380000 68010080 |,...P...`8..h...| +CHECK-NEXT: 00A0: 00000000 00000000 00000000 01000000 |................| +CHECK-NEXT: 00B0: 16030080 80010080 00000000 00000000 |................| +CHECK-NEXT: 00C0: 00000000 00000100 01000000 98010080 |................| +CHECK-NEXT: 00D0: 00000000 00000000 00000000 01000100 |................| +CHECK-NEXT: 00E0: E0020080 B0010080 0C000000 D0010080 |................| +CHECK-NEXT: 00F0: 00000000 00000000 00000000 01000000 |................| +CHECK-NEXT: 0100: 66030080 E8010080 00000000 00000000 |f...............| +CHECK-NEXT: 0110: 00000000 00000100 09040000 10020000 |................| +CHECK-NEXT: 0120: 00000000 00000000 00000000 00000100 |................| +CHECK-NEXT: 0130: 09040000 20020000 00000000 00000000 |.... ...........| +CHECK-NEXT: 0140: 00000000 00000100 09040000 30020000 |............0...| +CHECK-NEXT: 0150: 00000000 00000000 00000000 00000100 |................| +CHECK-NEXT: 0160: 090C0000 40020000 00000000 00000000 |....@...........| +CHECK-NEXT: 0170: 00000000 00000100 04080000 50020000 |............P...| +CHECK-NEXT: 0180: 00000000 00000000 00000000 00000100 |................| +CHECK-NEXT: 0190: 09040000 60020000 00000000 00000000 |....`...........| +CHECK-NEXT: 01A0: 00000000 00000100 09040000 70020000 |............p...| +CHECK-NEXT: 01B0: 00000000 00000000 00000000 00000200 |................| +CHECK-NEXT: 01C0: 09040000 80020000 04080000 90020000 |................| +CHECK-NEXT: 01D0: 00000000 00000000 00000000 00000100 |................| +CHECK-NEXT: 01E0: 09040000 A0020000 00000000 00000000 |................| +CHECK-NEXT: 01F0: 00000000 00000300 09040000 B0020000 |................| +CHECK-NEXT: 0200: 04080000 C0020000 07100000 D0020000 |................| +CHECK-NEXT: 0210: FC1A0000 39000000 00000000 00000000 |....9...........| +CHECK-NEXT: 0220: C4130000 28030000 00000000 00000000 |....(...........| +CHECK-NEXT: 0230: EC160000 28030000 00000000 00000000 |....(...........| +CHECK-NEXT: 0240: CC1A0000 30000000 00000000 00000000 |....0...........| +CHECK-NEXT: 0250: 141A0000 2E000000 00000000 00000000 |................| +CHECK-NEXT: 0260: 441A0000 6C000000 00000000 00000000 |D...l...........| +CHECK-NEXT: 0270: 7C130000 2A000000 00000000 00000000 ||...*...........| +CHECK-NEXT: 0280: AC130000 18000000 00000000 00000000 |................| +CHECK-NEXT: 0290: 041C0000 18000000 00000000 00000000 |................| +CHECK-NEXT: 02A0: B41A0000 18000000 00000000 00000000 |................| +CHECK-NEXT: 02B0: 3C1B0000 36000000 00000000 00000000 |<...6...........| +CHECK-NEXT: 02C0: 741B0000 43000000 00000000 00000000 |t...C...........| +CHECK-NEXT: 02D0: BC1B0000 42000000 00000000 00000000 |....B...........| +CHECK-NEXT: 02E0: 0E004D00 59004100 43004300 45004C00 |..M.Y.A.C.C.E.L.| +CHECK-NEXT: 02F0: 45005200 41005400 4F005200 53000600 |E.R.A.T.O.R.S...| +CHECK-NEXT: 0300: 43005500 52005300 4F005200 04004F00 |C.U.R.S.O.R...O.| +CHECK-NEXT: 0310: 4B004100 59000A00 54004500 53005400 |K.A.Y...T.E.S.T.| +CHECK-NEXT: 0320: 44004900 41004C00 4F004700 05002200 |D.I.A.L.O.G...".| +CHECK-NEXT: 0330: 45004100 54002200 0B005300 54005200 |E.A.T."...S.T.R.| +CHECK-NEXT: 0340: 49004E00 47004100 52005200 41005900 |I.N.G.A.R.R.A.Y.| +CHECK-NEXT: 0350: 0A004D00 59005200 45005300 4F005500 |..M.Y.R.E.S.O.U.| +CHECK-NEXT: 0360: 52004300 45000900 52004100 4E004400 |R.C.E...R.A.N.D.| +CHECK-NEXT: 0370: 4F004D00 44004100 54000000 00000500 |O.M.D.A.T.......| +CHECK-NEXT: 0380: 48006500 6C006C00 6F000000 00000000 |H.e.l.l.o.......| +CHECK-NEXT: 0390: 00000000 00000000 00000000 00000000 |................| +CHECK-NEXT: 03A0: 00000000 00000000 00000000 11000300 |................| +CHECK-NEXT: 03B0: E7030000 0D004400 4C040000 82001200 |......D.L.......| +CHECK-NEXT: 03C0: BC010000 28000000 10000000 10000000 |....(...........| +CHECK-NEXT: 03D0: 01001800 00000000 00030000 C40E0000 |................| +CHECK-NEXT: 03E0: C40E0000 00000000 00000000 FFFFFFFF |................| +CHECK-NEXT: 03F0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0400: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0410: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0420: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0430: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0440: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0450: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0460: FF7F7F7F 7C7C7C78 78787575 75FFFFFF |....|||xxxuuu...| +CHECK-NEXT: 0470: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0480: FFFFFFFF FFFFFFFF 979797FF FFFFFFFF |................| +CHECK-NEXT: 0490: FF838383 AAAAAADB DBDB7979 79757575 |..........yyyuuu| +CHECK-NEXT: 04A0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 04B0: FFFFFFFF FFFFFFFF 9C9C9C98 9898FFFF |................| +CHECK-NEXT: 04C0: FF888888 DBDBDBB7 B7B77D7D 7DFFFFFF |..........}}}...| +CHECK-NEXT: 04D0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 04E0: FFFFFFFF FFFFFFFF A0A0A09C 9C9C9393 |................| +CHECK-NEXT: 04F0: 93ADADAD F2F2F284 84848181 81FFFFFF |................| +CHECK-NEXT: 0500: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0510: FFFFFFFF FFFFFFFF A4A4A4D7 D7D79D9D |................| +CHECK-NEXT: 0520: 9DD0D0D0 EEEEEE91 91918D8D 8DFFFFFF |................| +CHECK-NEXT: 0530: FFFFFF81 81817E7E 7EFFFFFF FFFFFFFF |......~~~.......| +CHECK-NEXT: 0540: FFFFFFFF FFFFFFFF A9A9A9F2 F2F2E5E5 |................| +CHECK-NEXT: 0550: E5E2E2E2 95959591 91918D8D 8D898989 |................| +CHECK-NEXT: 0560: 868686FF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0570: FFFFFFFF FFFFFFFF ADADADF2 F2F2E1E1 |................| +CHECK-NEXT: 0580: E1DFDFDF E7E7E7E4 E4E4BBBB BB8E8E8E |................| +CHECK-NEXT: 0590: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 05A0: FFFFFFFF FFFFFFFF B5B5B5F2 F2F2E8E8 |................| +CHECK-NEXT: 05B0: E8E7E7E7 EAEAEAC6 C6C69E9E 9EFFFFFF |................| +CHECK-NEXT: 05C0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 05D0: FFFFFFFF FFFFFFFF B9B9B9F4 F4F4ECEC |................| +CHECK-NEXT: 05E0: ECEDEDED CBCBCBA7 A7A7FFFF FFFFFFFF |................| +CHECK-NEXT: 05F0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0600: FFFFFFFF FFFFFFFF BDBDBDF7 F7F7EFEF |................| +CHECK-NEXT: 0610: EFD0D0D0 AFAFAFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0620: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0630: FFFFFFFF FFFFFFFF C1C1C1F7 F7F7D5D5 |................| +CHECK-NEXT: 0640: D5B6B6B6 FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0650: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0660: FFFFFFFF FFFFFFFF C4C4C4D9 D9D9BEBE |................| +CHECK-NEXT: 0670: BEFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0680: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0690: FFFFFFFF FFFFFFFF C8C8C8C5 C5C5FFFF |................| +CHECK-NEXT: 06A0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 06B0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 06C0: FFFFFFFF FFFFFFFF CBCBCBFF FFFFFFFF |................| +CHECK-NEXT: 06D0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 06E0: FFFFFFFF FFFFFFFF FFFFFFFF 28000000 |............(...| +CHECK-NEXT: 06F0: 10000000 10000000 01001800 00000000 |................| +CHECK-NEXT: 0700: 00030000 C40E0000 C40E0000 00000000 |................| +CHECK-NEXT: 0710: 00000000 FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0720: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0730: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0740: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0750: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0760: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0770: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0780: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0790: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 07A0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 07B0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 07C0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 07D0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 07E0: A0E3A901 B31801B3 1801B318 01B31801 |................| +CHECK-NEXT: 07F0: B31801B3 1861D06F FFFFFFFF FFFFFFFF |.....a.o........| +CHECK-NEXT: 0800: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0810: 01B31800 D7331CDB 49DBF9E2 9BEFAF00 |.....3..I.......| +CHECK-NEXT: 0820: D73300D7 3301B318 FFFFFFFF FFFFFFFF |.3..3...........| +CHECK-NEXT: 0830: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0840: 01B31800 DE55F6FE F9DBFAE7 FEFFFE86 |.....U..........| +CHECK-NEXT: 0850: EFAE00DE 5501B318 FFFFFFFF FFFFFFFF |....U...........| +CHECK-NEXT: 0860: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0870: 01B31800 E676DBFB EC00E676 57EFA5FB |.....v.....vW...| +CHECK-NEXT: 0880: FFFD55EE A401B318 FFFFFFFF FFFFFFFF |..U.............| +CHECK-NEXT: 0890: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 08A0: 01B31800 ED9800ED 9800ED98 00ED9887 |................| +CHECK-NEXT: 08B0: F7CFFEFF FF01B318 FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 08C0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 08D0: 01B31800 F4BA00F4 BA00F4BA 00F4BA00 |................| +CHECK-NEXT: 08E0: F4BA9CFB E401B318 FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 08F0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0900: 01B31800 FBDB00FB DB00FBDB 00FBDB00 |................| +CHECK-NEXT: 0910: FBDB00FB DB01B318 FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0920: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0930: 9FE2A801 B31801B3 1801B318 01B31801 |................| +CHECK-NEXT: 0940: B31801B3 1861D06F FFFFFFFF FFFFFFFF |.....a.o........| +CHECK-NEXT: 0950: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0960: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0970: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0980: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0990: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 09A0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 09B0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 09C0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 09D0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 09E0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 09F0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0A00: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0A10: FFFFFFFF 00000000 00006400 79007500 |..........d.y.u.| +CHECK-NEXT: 0A20: 00000000 65007300 68006100 6C006100 |....e.s.h.a.l.a.| +CHECK-NEXT: 0A30: 00008000 66006B00 61006F00 79006100 |....f.k.a.o.y.a.| +CHECK-NEXT: 0A40: 00000000 0000C080 00000000 02000A00 |................| +CHECK-NEXT: 0A50: 0A00C800 2C010000 00005400 65007300 |....,.....T.e.s.| +CHECK-NEXT: 0A60: 74000000 01000250 00000000 0A000A00 |t......P........| +CHECK-NEXT: 0A70: E6000E00 0100FFFF 82004300 6F006E00 |..........C.o.n.| +CHECK-NEXT: 0A80: 74006900 6E007500 65003A00 00000000 |t.i.n.u.e.:.....| +CHECK-NEXT: 0A90: 00000150 00000000 42008600 A1000D00 |...P....B.......| +CHECK-NEXT: 0AA0: 0200FFFF 80002600 4F004B00 00000000 |......&.O.K.....| +CHECK-NEXT: 0AB0: 00000000 11005800 A4000000 0D004800 |......X.......H.| +CHECK-NEXT: 0AC0: 2E160000 82001200 BC010000 00000000 |................| +CHECK-NEXT: 0AD0: 00006400 66006900 73006800 00000000 |..d.f.i.s.h.....| +CHECK-NEXT: 0AE0: 65007300 61006C00 61006400 00008000 |e.s.a.l.a.d.....| +CHECK-NEXT: 0AF0: 66006400 75006300 6B000000 74686973 |f.d.u.c.k...this| +CHECK-NEXT: 0B00: 20697320 61207573 65722064 6566696E | is a user defin| +CHECK-NEXT: 0B10: 65642072 65736F75 72636500 69742063 |ed resource.it c| +CHECK-NEXT: 0B20: 6F6E7461 696E7320 6D616E79 20737472 |ontains many str| +CHECK-NEXT: 0B30: 696E6773 00000000 00000000 74686973 |ings........this| +CHECK-NEXT: 0B40: 20697320 61207261 6E646F6D 20626974 | is a random bit| +CHECK-NEXT: 0B50: 206F6620 64617461 20746861 74206D65 | of data that me| +CHECK-NEXT: 0B60: 616E7320 6E6F7468 696E6700 A9230E14 |ans nothing..#..| +CHECK-NEXT: 0B70: F4F60000 7A686534 20736869 34207969 |....zhe4 shi4 yi| +CHECK-NEXT: 0B80: 31676534 20737569 326A6931 20646520 |1ge4 sui2ji1 de | +CHECK-NEXT: 0B90: 73687534 6A75342C 207A6865 34207969 |shu4ju4, zhe4 yi| +CHECK-NEXT: 0BA0: 34776569 347A6865 20736865 6E326D65 |4wei4zhe shen2me| +CHECK-NEXT: 0BB0: 00A9230E 14F4F600 00000000 44696573 |..#.........Dies| +CHECK-NEXT: 0BC0: 20697374 2065696E 207A7566 C3A46C6C | ist ein zuf..ll| +CHECK-NEXT: 0BD0: 69676573 20426974 20766F6E 20446174 |iges Bit von Dat| +CHECK-NEXT: 0BE0: 656E2C20 64696520 6E696368 74732062 |en, die nichts b| +CHECK-NEXT: 0BF0: 65646575 74657400 A9230E14 F4F60000 |edeutet..#......| +CHECK-NEXT: 0C00: 00000000 11000300 E7030000 0D004400 |..............D.| +CHECK-NEXT: 0C10: 4C040000 82001200 BC010000 |L...........| +CHECK-NEXT: ) diff --git a/test/COFF/pdb-comdat.test b/test/COFF/pdb-comdat.test index a7b5c401ab92..ea691aec87ad 100644 --- a/test/COFF/pdb-comdat.test +++ b/test/COFF/pdb-comdat.test @@ -47,7 +47,7 @@ CHECK: machine = intel x86-x64, Ver = Microsoft (R) Optimizing Compiler, CHECK: frontend = 19.0.24215.1, backend = 19.0.24215.1 CHECK: flags = security checks | hot patchable CHECK: 120 | S_GPROC32_ID [size = 44] `main` -CHECK: parent = 0, end = 0, addr = 0002:0000, code size = 24 +CHECK: parent = 0, end = 196, addr = 0002:0000, code size = 24 CHECK: debug start = 4, debug end = 19, flags = none CHECK: 164 | S_FRAMEPROC [size = 32] CHECK: size = 40, padding size = 0, offset to padding = 0 @@ -58,7 +58,7 @@ CHECK: 200 | S_GDATA32 [size = 24] `global` CHECK: type = 0x0074 (int), addr = 0000:0000 CHECK: 224 | S_BUILDINFO [size = 8] BuildId = `4106` CHECK: 232 | S_GPROC32_ID [size = 44] `foo` -CHECK: parent = 0, end = 0, addr = 0002:0032, code size = 15 +CHECK: parent = 0, end = 308, addr = 0002:0032, code size = 15 CHECK: debug start = 0, debug end = 14, flags = none CHECK: 276 | S_FRAMEPROC [size = 32] CHECK: size = 0, padding size = 0, offset to padding = 0 @@ -72,7 +72,7 @@ CHECK: machine = intel x86-x64, Ver = Microsoft (R) Optimizing Compiler, l CHECK: frontend = 19.0.24215.1, backend = 19.0.24215.1 CHECK: flags = security checks | hot patchable CHECK: 120 | S_GPROC32_ID [size = 44] `bar` -CHECK: parent = 0, end = 0, addr = 0002:0048, code size = 14 +CHECK: parent = 0, end = 196, addr = 0002:0048, code size = 14 CHECK: debug start = 4, debug end = 9, flags = none CHECK: 164 | S_FRAMEPROC [size = 32] CHECK: size = 40, padding size = 0, offset to padding = 0 diff --git a/test/COFF/pdb-diff.test b/test/COFF/pdb-diff.test new file mode 100644 index 000000000000..79b23a5c026d --- /dev/null +++ b/test/COFF/pdb-diff.test @@ -0,0 +1,212 @@ +This test verifies that we produce PDBs compatible with MSVC in various ways. +We check in a cl-generated object file, PDB, and original source which serve +as the "baseline" for us to measure against. Then we link the same object +file with LLD and compare the two PDBs. Since the baseline object file and +PDB are already checked in, we just run LLD on the object file. + +RUN: lld-link /debug /pdb:%T/pdb-diff-lld.pdb /nodefaultlib /entry:main %S/Inputs/pdb-diff.obj +RUN: llvm-pdbutil diff -result -values=false -left-bin-root=%S -right-bin-root=D:/src/llvm-mono/lld/test/COFF/ %T/pdb-diff-lld.pdb %S/Inputs/pdb-diff-cl.pdb | FileCheck %s + +CHECK: ---------------------- +CHECK-NEXT: | MSF Super Block | +CHECK-NEXT: |----------------+---| +CHECK-NEXT: | File | | +CHECK-NEXT: |----------------+---| +CHECK-NEXT: | Block Size | I | +CHECK-NEXT: |----------------+---| +CHECK-NEXT: | Block Count | +CHECK-NEXT: |----------------+---| +CHECK-NEXT: | Unknown 1 | I | +CHECK-NEXT: |----------------+---| +CHECK-NEXT: | Directory Size | +CHECK-NEXT: |----------------+---| +CHECK-NEXT: ------------------------------------ +CHECK-NEXT: | Stream Directory | +CHECK-NEXT: |------------------------------+---| +CHECK-NEXT: | File | | +CHECK-NEXT: |------------------------------+---| +CHECK-NEXT: | Stream Count | D | +CHECK-NEXT: |------------------------------+---| +CHECK-NEXT: | Old MSF Directory | I | +CHECK-NEXT: |------------------------------+---| +CHECK-NEXT: | PDB Stream | I | +CHECK-NEXT: |------------------------------+---| +CHECK-NEXT: | TPI Stream | I | +CHECK-NEXT: |------------------------------+---| +CHECK-NEXT: | DBI Stream | I | +CHECK-NEXT: |------------------------------+---| +CHECK-NEXT: | IPI Stream | I | +CHECK-NEXT: |------------------------------+---| +CHECK-NEXT: | New FPO Data | {{[EI]}} | +CHECK-NEXT: |------------------------------+---| +CHECK-NEXT: | Section Header Data | {{[EI]}} | +CHECK-NEXT: |------------------------------+---| +CHECK-NEXT: | Named Stream "/names" | {{[EI]}} | +CHECK-NEXT: |------------------------------+---| +CHECK-NEXT: | Named Stream "/LinkInfo" | {{[EI]}} | +CHECK-NEXT: |------------------------------+---| +CHECK-NEXT: | Module "Inputs\pdb-diff.obj" | {{[EI]}} | +CHECK-NEXT: |------------------------------+---| +CHECK-NEXT: | Module "* Linker *" | {{[EI]}} | +CHECK-NEXT: |------------------------------+---| +CHECK-NEXT: | TPI Hash | {{[EI]}} | +CHECK-NEXT: |------------------------------+---| +CHECK-NEXT: | IPI Hash | {{[EI]}} | +CHECK-NEXT: |------------------------------+---| +CHECK-NEXT: | Public Symbol Hash | {{[EI]}} | +CHECK-NEXT: |------------------------------+---| +CHECK-NEXT: | Public Symbol Records | {{[EI]}} | +CHECK-NEXT: |------------------------------+---| +CHECK-NEXT: | Global Symbol Hash | D | +CHECK-NEXT: |------------------------------+---| +CHECK-NEXT: ------------------------------------ +CHECK-NEXT: | String Table | +CHECK-NEXT: |------------------------------+---| +CHECK-NEXT: | File | | +CHECK-NEXT: |------------------------------+---| +CHECK-NEXT: | Number of Strings | D | +CHECK-NEXT: |------------------------------+---| +CHECK-NEXT: | Hash Version | I | +CHECK-NEXT: |------------------------------+---| +CHECK-NEXT: | Byte Size | +CHECK-NEXT: |------------------------------+---| +CHECK-NEXT: | Signature | I | +CHECK-NEXT: |------------------------------+---| +CHECK-NEXT: | Empty Strings | +CHECK-NEXT: |------------------------------+---| +CHECK-NEXT: | {{.*}}pdb-diff.cpp | {{[EI]}} | +CHECK-NEXT: |------------------------------+---| +CHECK-NEXT: | $T0 $ebp = $...p $T0 8 + = | D | +CHECK-NEXT: |------------------------------+---| +CHECK-NEXT: | d:\src\llvm-...er internal) | D | +CHECK-NEXT: |------------------------------+---| +CHECK-NEXT: ---------------------------- +CHECK-NEXT: | PDB Stream | +CHECK-NEXT: |----------------------+---| +CHECK-NEXT: | File | | +CHECK-NEXT: |----------------------+---| +CHECK-NEXT: | Stream Size | +CHECK-NEXT: |----------------------+---| +CHECK-NEXT: | Age | I | +CHECK-NEXT: |----------------------+---| +CHECK-NEXT: | Guid | D | +CHECK-NEXT: |----------------------+---| +CHECK-NEXT: | Signature | D | +CHECK-NEXT: |----------------------+---| +CHECK-NEXT: | Version | I | +CHECK-NEXT: |----------------------+---| +CHECK-NEXT: | Features (set) | I | +CHECK-NEXT: |----------------------+---| +CHECK-NEXT: | Feature | I | +CHECK-NEXT: |----------------------+---| +CHECK-NEXT: | Named Stream Size | +CHECK-NEXT: |----------------------+---| +CHECK-NEXT: | Named Streams (map) | {{[EI]}} | +CHECK-NEXT: |----------------------+---| +CHECK-NEXT: | /names | {{[EI]}} | +CHECK-NEXT: |----------------------+---| +CHECK-NEXT: | /LinkInfo | {{[EI]}} | +CHECK-NEXT: |----------------------+---| +CHECK-NEXT: ---------------------------------------------- +CHECK-NEXT: | DBI Stream | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | File | | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | Dbi Version | I | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | Age | I | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | Machine | I | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | Flags | D | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | Build Major | D | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | Build Minor | D | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | Build Number | D | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | PDB DLL Version | D | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | PDB DLL RBLD | I | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | DBG (FPO) | I | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | DBG (Exception) | I | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | DBG (Fixup) | I | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | DBG (OmapToSrc) | I | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | DBG (OmapFromSrc) | I | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | DBG (SectionHdr) | {{[EI]}} | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | DBG (TokenRidMap) | I | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | DBG (Xdata) | I | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | DBG (Pdata) | I | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | DBG (NewFPO) | {{[EI]}} | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | DBG (SectionHdrOrig) | I | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | Globals Stream | D | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | Publics Stream | {{[EI]}} | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | Symbol Records | {{[EI]}} | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | Has CTypes | I | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | Is Incrementally Linked | D | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | Is Stripped | I | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | Module Count | I | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | Source File Count | I | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | Module "Inputs\pdb-diff.obj" | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | - Modi | I | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | - Obj File Name | {{[EI]}} | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | - Debug Stream | {{[EI]}} | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | - C11 Byte Size | I | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | - C13 Byte Size | I | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | - # of files | I | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | - Pdb File Path Index | I | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | - Source File Name Index | I | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | - Symbol Byte Size | D | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | Module "* Linker *" | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | - Modi | I | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | - Obj File Name | I | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | - Debug Stream | {{[EI]}} | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | - C11 Byte Size | I | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | - C13 Byte Size | I | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | - # of files | I | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | - Pdb File Path Index | {{[EI]}} | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | - Source File Name Index | {{[EI]}} | +CHECK-NEXT: |----------------------------------------+---| +CHECK-NEXT: | - Symbol Byte Size | +CHECK-NEXT: |----------------------------------------+---| + + diff --git a/test/COFF/pdb-invalid-func-type.yaml b/test/COFF/pdb-invalid-func-type.yaml new file mode 100644 index 000000000000..686079e7d8e4 --- /dev/null +++ b/test/COFF/pdb-invalid-func-type.yaml @@ -0,0 +1,146 @@ +# This test has an S_GPROC32_ID symbol with an invalid type index. Make sure we +# keep the record, or we'll have unbalanced scopes, which is bad. This situation +# can arise when we can't find the type server PDB. + +# RUN: yaml2obj %s -o %t.obj +# RUN: lld-link %t.obj -out:%t.exe -debug -pdb:%t.pdb -nodefaultlib -entry:main +# RUN: llvm-pdbutil dump -symbols %t.pdb | FileCheck %s + +# CHECK: Mod 0000 | `{{.*}}pdb-invalid-func-type.yaml.tmp.obj`: +# CHECK: 4 | S_GPROC32_ID [size = 44] `main` +# CHECK: parent = 0, end = 80, addr = 0001:0000, code size = 3 +# CHECK: 48 | S_FRAMEPROC [size = 32] +# CHECK: 80 | S_END [size = 4] + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ ] +sections: + - Name: '.debug$S' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + Subsections: + - !Symbols + Records: + - Kind: S_GPROC32_ID + ProcSym: + CodeSize: 3 + DbgStart: 0 + DbgEnd: 2 + # Corrupt function type! + FunctionType: 4101 + Flags: [ ] + DisplayName: main + - Kind: S_FRAMEPROC + FrameProcSym: + TotalFrameBytes: 0 + PaddingFrameBytes: 0 + OffsetToPadding: 0 + BytesOfCalleeSavedRegisters: 0 + OffsetOfExceptionHandler: 0 + SectionIdOfExceptionHandler: 0 + Flags: [ AsynchronousExceptionHandling, OptimizedForSpeed ] + - Kind: S_PROC_ID_END + ScopeEndSym: + - !Lines + CodeSize: 3 + Flags: [ ] + RelocOffset: 0 + RelocSegment: 0 + Blocks: + - FileName: 'c:\src\llvm-project\build\t.c' + Lines: + - Offset: 0 + LineStart: 1 + IsStatement: true + EndDelta: 0 + Columns: + - !FileChecksums + Checksums: + - FileName: 'c:\src\llvm-project\build\t.c' + Kind: MD5 + Checksum: 270A878DCC1B845655B162F56C4F5020 + - !StringTable + Strings: + - 'c:\src\llvm-project\build\t.c' + Relocations: + - VirtualAddress: 44 + SymbolName: main + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 48 + SymbolName: main + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 100 + SymbolName: main + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 104 + SymbolName: main + Type: IMAGE_REL_AMD64_SECTION + - Name: '.debug$T' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + Types: + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 0 ] + - Kind: LF_PROCEDURE + Procedure: + ReturnType: 116 + CallConv: NearC + Options: [ None ] + ParameterCount: 0 + ArgumentList: 4096 + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4097 + Name: main + - Name: '.text$mn' + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: 33C0C3 +symbols: + - Name: '.debug$S' + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 328 + NumberOfRelocations: 4 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.debug$T' + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 564 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.text$mn' + Value: 0 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 3 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 4021952397 + Number: 0 + - Name: main + Value: 0 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/test/COFF/pdb-lib.s b/test/COFF/pdb-lib.s index 47375cc26ff2..ab95f82a2a91 100644 --- a/test/COFF/pdb-lib.s +++ b/test/COFF/pdb-lib.s @@ -13,12 +13,15 @@ # CHECK-NEXT: Mod 0000 | Name: `{{.*pdb-lib.s.tmp[/\\]foo.obj}}`: # CHECK-NEXT: Obj: `{{.*pdb-lib.s.tmp[/\\]foo.obj}}`: # CHECK-NEXT: debug stream: 9, # files: 0, has ec info: false +# CHECK-NEXT: pdb file ni: 0 ``, src file ni: 0 `` # CHECK-NEXT: Mod 0001 | Name: `bar.obj`: # CHECK-NEXT: Obj: `{{.*pdb-lib.s.tmp[/\\]bar.lib}}`: # CHECK-NEXT: debug stream: 10, # files: 0, has ec info: false +# CHECK-NEXT: pdb file ni: 0 ``, src file ni: 0 `` # CHECK-NEXT: Mod 0002 | Name: `* Linker *`: # CHECK-NEXT: Obj: ``: # CHECK-NEXT: debug stream: 11, # files: 0, has ec info: false +# CHECK-NEXT: pdb file ni: 1 `{{.*foo.pdb}}`, src file ni: 0 `` .def _main; .scl 2; diff --git a/test/COFF/pdb-linker-module.test b/test/COFF/pdb-linker-module.test new file mode 100644 index 000000000000..ce366b6d6482 --- /dev/null +++ b/test/COFF/pdb-linker-module.test @@ -0,0 +1,18 @@ +RUN: lld-link /debug /pdb:%t.pdb /nodefaultlib /entry:main %S/Inputs/pdb-diff.obj +RUN: llvm-pdbutil dump -modules -symbols %t.pdb | FileCheck %s + +CHECK: Mod 0001 | `* Linker *`: +CHECK-NEXT: 4 | S_OBJNAME [size = 20] sig=0, `* Linker *` +CHECK-NEXT: 24 | S_COMPILE3 [size = 40] +CHECK-NEXT: machine = intel 80386, Ver = LLVM Linker, language = link +CHECK-NEXT: frontend = 0.0.0.0, backend = 0.0.0.0 +CHECK-NEXT: flags = none +CHECK-NEXT: 64 | S_ENVBLOCK +CHECK-NEXT: - cwd +CHECK-NEXT: - +CHECK-NEXT: - exe +CHECK-NEXT: - {{.*}}lld-link +CHECK-NEXT: - pdb +CHECK-NEXT: - {{.*}}pdb-linker-module{{.*}}pdb +CHECK-NEXT: - cmd +CHECK-NEXT: - /debug /pdb:{{.*}}pdb-linker-module{{.*}}pdb /nodefaultlib /entry:main {{.*}}pdb-diff.obj diff --git a/test/COFF/pdb-none.test b/test/COFF/pdb-none.test index a028cf05547e..c1becbad7a3b 100644 --- a/test/COFF/pdb-none.test +++ b/test/COFF/pdb-none.test @@ -7,8 +7,8 @@ # CHECK: PdbStream: # CHECK-NEXT: Age: 0 -# CHECK-NEXT: Guid: '{00000000-0000-0000-0000-000000000000}' -# CHECK-NEXT: Signature: 0 +# CHECK-NEXT: Guid: +# CHECK-NEXT: Signature: # CHECK-NEXT: Features: [ VC140 ] # CHECK-NEXT: Version: VC70 diff --git a/test/COFF/pdb-scopes.test b/test/COFF/pdb-scopes.test new file mode 100644 index 000000000000..7beb59766cc5 --- /dev/null +++ b/test/COFF/pdb-scopes.test @@ -0,0 +1,75 @@ +Consider this program: + +$ cat a.c +void g(int x) {} +void f(int x); +int main(int argc) { + if (argc) { + int x = 42; + f(x); + } else { + int y = 13; + f(y); + } +} + +$ cat b.c +extern void g(); +void f(int x) { + if (x) { + int y = x + 3; + g(y); + } else { + int w = x + 4; + g(w); + } +} + +This program is interesting because there are two TUs, and each TU has nested +scopes. Make sure we get the right parent and end offsets. + +RUN: yaml2obj %S/Inputs/pdb-scopes-a.yaml -o %t-a.obj +RUN: yaml2obj %S/Inputs/pdb-scopes-b.yaml -o %t-b.obj +RUN: lld-link %t-a.obj %t-b.obj -debug -entry:main -nodefaultlib -out:%t.exe -pdb:%t.pdb +RUN: llvm-pdbutil dump -symbols %t.pdb | FileCheck %s + +CHECK-LABEL: Mod 0000 | `{{.*}}pdb-scopes.test.tmp-a.obj`: +CHECK: 104 | S_GPROC32_ID [size = 44] `g` +CHECK: parent = 0, end = 196, addr = 0002:0000, code size = 5 +CHECK: debug start = 4, debug end = 4, flags = none +CHECK: 180 | S_REGREL32 [size = 16] `x` +CHECK: 196 | S_END [size = 4] +CHECK: 200 | S_GPROC32_ID [size = 44] `main` +CHECK: parent = 0, end = 384, addr = 0002:0016, code size = 58 +CHECK: debug start = 8, debug end = 53, flags = none +CHECK: 276 | S_REGREL32 [size = 20] `argc` +CHECK: 296 | S_BLOCK32 [size = 24] `` +CHECK: parent = 200, end = 336 +CHECK: code size = 17, addr = 0002:0031 +CHECK: 320 | S_REGREL32 [size = 16] `x` +CHECK: 336 | S_END [size = 4] +CHECK: 340 | S_BLOCK32 [size = 24] `` +CHECK: parent = 200, end = 380 +CHECK: code size = 17, addr = 0002:0050 +CHECK: 364 | S_REGREL32 [size = 16] `y` +CHECK: 380 | S_END [size = 4] +CHECK: 384 | S_END [size = 4] + +CHECK-LABEL: Mod 0001 | `{{.*}}pdb-scopes.test.tmp-b.obj`: +CHECK: 104 | S_GPROC32_ID [size = 44] `f` +CHECK: parent = 0, end = 284, addr = 0002:0080, code size = 62 +CHECK: debug start = 8, debug end = 57, flags = none +CHECK: 180 | S_REGREL32 [size = 16] `x` +CHECK: 196 | S_BLOCK32 [size = 24] `` +CHECK: parent = 104, end = 236 +CHECK: code size = 20, addr = 0002:0095 +CHECK: 220 | S_REGREL32 [size = 16] `y` +CHECK: 236 | S_END [size = 4] +CHECK: 240 | S_BLOCK32 [size = 24] `` +CHECK: parent = 104, end = 280 +CHECK: code size = 20, addr = 0002:0117 +CHECK: 264 | S_REGREL32 [size = 16] `w` +CHECK: 280 | S_END [size = 4] +CHECK: 284 | S_END [size = 4] + +CHECK-LABEL: Mod 0002 | `* Linker *`: diff --git a/test/COFF/pdb-source-lines.test b/test/COFF/pdb-source-lines.test index a630ecb22d62..f9e0e5c7487f 100644 --- a/test/COFF/pdb-source-lines.test +++ b/test/COFF/pdb-source-lines.test @@ -23,7 +23,7 @@ RUN: lld-link -debug -entry:main -nodefaultlib -out:%t.exe -pdb:%t.pdb %t.pdb_li RUN: llvm-pdbutil pdb2yaml -modules -module-files -subsections=lines,fc %t.pdb | FileCheck %s CHECK-LABEL: DbiStream: -CHECK-NEXT: VerHeader: V110 +CHECK-NEXT: VerHeader: V70 CHECK-NEXT: Age: 1 CHECK-NEXT: BuildNumber: 0 CHECK-NEXT: PdbDllVersion: 0 diff --git a/test/COFF/pdb-symbol-types.yaml b/test/COFF/pdb-symbol-types.yaml index eceb434f0d0f..8abbc365b34e 100644 --- a/test/COFF/pdb-symbol-types.yaml +++ b/test/COFF/pdb-symbol-types.yaml @@ -22,7 +22,7 @@ # CHECK: frontend = 19.0.24215.1, backend = 19.0.24215.1 # CHECK: flags = security checks | hot patchable # CHECK: 116 | S_GPROC32_ID [size = 44] `main` -# CHECK: parent = 0, end = 0, addr = 0002:0000, code size = 7 +# CHECK: parent = 0, end = 192, addr = 0002:0000, code size = 7 # CHECK: debug start = 0, debug end = 6, flags = none # CHECK: 160 | S_FRAMEPROC [size = 32] # CHECK: size = 0, padding size = 0, offset to padding = 0 diff --git a/test/COFF/pdb.test b/test/COFF/pdb.test index 3acb7188df49..a4cd4f7c35b3 100644 --- a/test/COFF/pdb.test +++ b/test/COFF/pdb.test @@ -26,11 +26,11 @@ # CHECK: PdbStream: # CHECK-NEXT: Age: 1 # CHECK-NEXT: Guid: -# CHECK-NEXT: Signature: 0 +# CHECK-NEXT: Signature: # CHECK-NEXT: Features: [ VC140 ] # CHECK-NEXT: Version: VC70 # CHECK-NEXT: DbiStream: -# CHECK-NEXT: VerHeader: V110 +# CHECK-NEXT: VerHeader: V70 # CHECK-NEXT: Age: 1 # CHECK-NEXT: BuildNumber: 0 # CHECK-NEXT: PdbDllVersion: 0 @@ -120,12 +120,15 @@ RAW-NEXT: ============================================================ RAW-NEXT: Mod 0000 | Name: `{{.*}}pdb.test.tmp1.obj`: RAW-NEXT: Obj: `{{.*}}pdb.test.tmp1.obj`: RAW-NEXT: debug stream: 9, # files: 1, has ec info: false +RAW-NEXT: pdb file ni: 0 ``, src file ni: 0 `` RAW-NEXT: Mod 0001 | Name: `{{.*}}pdb.test.tmp2.obj`: RAW-NEXT: Obj: `{{.*}}pdb.test.tmp2.obj`: RAW-NEXT: debug stream: 10, # files: 1, has ec info: false +RAW-NEXT: pdb file ni: 0 ``, src file ni: 0 `` RAW-NEXT: Mod 0002 | Name: `* Linker *`: RAW-NEXT: Obj: ``: RAW-NEXT: debug stream: 11, # files: 0, has ec info: false +RAW-NEXT: pdb file ni: 1 `{{.*pdb.test.tmp.pdb}}`, src file ni: 0 `` RAW: Types (TPI Stream) RAW-NEXT: ============================================================ RAW-NEXT: Showing 5 records @@ -183,17 +186,17 @@ RAW-NEXT: IMAGE_SCN_MEM_READ RAW: Section Map RAW-NEXT: ============================================================ RAW-NEXT: Section 0000 | ovl = 0, group = 0, frame = 0, name = 1 -RAW-NEXT: class = 65535, offset = 0, size = +RAW-NEXT: class = 65535, offset = 0, size = RAW-NEXT: flags = read | 32 bit addr | selector RAW-NEXT: Section 0001 | ovl = 1, group = 0, frame = 0, name = 2 -RAW-NEXT: class = 65535, offset = 0, size = +RAW-NEXT: class = 65535, offset = 0, size = RAW-NEXT: flags = read | execute | 32 bit addr | selector RAW-NEXT: Section 0002 | ovl = 2, group = 0, frame = 0, name = 3 -RAW-NEXT: class = 65535, offset = 0, size = +RAW-NEXT: class = 65535, offset = 0, size = RAW-NEXT: flags = read | 32 bit addr | selector RAW-NEXT: Section 0003 | ovl = 3, group = 0, frame = 0, name = 4 -RAW-NEXT: class = 65535, offset = 0, size = +RAW-NEXT: class = 65535, offset = 0, size = RAW-NEXT: flags = read | 32 bit addr | selector RAW-NEXT: Section 0004 | ovl = 4, group = 0, frame = 0, name = 5 -RAW-NEXT: class = 65535, offset = 0, size = +RAW-NEXT: class = 65535, offset = 0, size = RAW-NEXT: flags = 32 bit addr | absolute addr diff --git a/test/ELF/Inputs/gnu-ifunc-dso.s b/test/ELF/Inputs/gnu-ifunc-dso.s new file mode 100644 index 000000000000..bd82718718be --- /dev/null +++ b/test/ELF/Inputs/gnu-ifunc-dso.s @@ -0,0 +1,3 @@ +.type foo STT_GNU_IFUNC +.globl foo +foo: diff --git a/test/ELF/Inputs/symver-archive1.s b/test/ELF/Inputs/symver-archive1.s new file mode 100644 index 000000000000..be7c64494215 --- /dev/null +++ b/test/ELF/Inputs/symver-archive1.s @@ -0,0 +1,6 @@ +.text +.globl x +.type x, @function +x: + +.symver x, xx@@VER diff --git a/test/ELF/Inputs/symver-archive2.s b/test/ELF/Inputs/symver-archive2.s new file mode 100644 index 000000000000..a9b9d0b0a35b --- /dev/null +++ b/test/ELF/Inputs/symver-archive2.s @@ -0,0 +1 @@ +call xx@PLT diff --git a/test/ELF/Inputs/version-script-no-warn2.s b/test/ELF/Inputs/version-script-no-warn2.s new file mode 100644 index 000000000000..59de9d470b76 --- /dev/null +++ b/test/ELF/Inputs/version-script-no-warn2.s @@ -0,0 +1 @@ +call foo@plt diff --git a/test/ELF/Inputs/version-script-weak.s b/test/ELF/Inputs/version-script-weak.s new file mode 100644 index 000000000000..09f5cf09db7d --- /dev/null +++ b/test/ELF/Inputs/version-script-weak.s @@ -0,0 +1,4 @@ +.text +.globl foo +.type foo,@function +foo: diff --git a/test/ELF/Inputs/wrap-dynamic-undef.s b/test/ELF/Inputs/wrap-dynamic-undef.s new file mode 100644 index 000000000000..ade79556db7b --- /dev/null +++ b/test/ELF/Inputs/wrap-dynamic-undef.s @@ -0,0 +1,2 @@ +.global foo +foo: diff --git a/test/ELF/arm-mov-relocs.s b/test/ELF/arm-mov-relocs.s index 31ccba4cceaf..7e3ce67e0615 100644 --- a/test/ELF/arm-mov-relocs.s +++ b/test/ELF/arm-mov-relocs.s @@ -26,14 +26,9 @@ _start: .section .R_ARM_MOVT_ABS, "ax",%progbits movt r0, :upper16:label movt r1, :upper16:label1 -// FIXME: We shouldn't need to multiply by 65536. -// arguably llvm-mc incorrectly assembles addends for -// SHT_REL relocated movt instructions. When there is a relocation -// the interpretation of the addend for SHT_REL is not shifted - movt r2, :upper16:label2 + (4 * 65536) + movt r2, :upper16:label2 + 4 movt r3, :upper16:label3 -// FIXME: We shouldn't need to multiply by 65536 see comment above. - movt r4, :upper16:label3 + (4 * 65536) + movt r4, :upper16:label3 + 4 // CHECK: Disassembly of section .R_ARM_MOVT_ABS // CHECK: movt r0, #2 // CHECK: movt r1, #2 diff --git a/test/ELF/copy-in-shared.s b/test/ELF/copy-in-shared.s index 1d77eaf3a141..70439853c7c1 100644 --- a/test/ELF/copy-in-shared.s +++ b/test/ELF/copy-in-shared.s @@ -4,7 +4,7 @@ // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t2.o // RUN: not ld.lld %t2.o %t1.so -o %t2.so -shared 2>&1 | FileCheck %s -// CHECK: can't create dynamic relocation R_X86_64_64 against symbol: foo +// CHECK: can't create dynamic relocation R_X86_64_64 against symbol: foo in readonly segment // CHECK: >>> defined in {{.*}}.so // CHECK: >>> referenced by {{.*}}.o:(.text+0x0) diff --git a/test/ELF/defsym.s b/test/ELF/defsym.s index 253d5d8f408d..b821484261b2 100644 --- a/test/ELF/defsym.s +++ b/test/ELF/defsym.s @@ -19,7 +19,7 @@ # CHECK-NEXT: Section: Absolute # CHECK-NEXT: } # CHECK-NEXT: Symbol { -# CHECK-NEXT: Name: foo2 +# CHECK-NEXT: Name: foo1 # CHECK-NEXT: Value: 0x123 # CHECK-NEXT: Size: # CHECK-NEXT: Binding: Global diff --git a/test/ELF/duplicated-synthetic-sym.s b/test/ELF/duplicated-synthetic-sym.s new file mode 100644 index 000000000000..cfd8642d2d17 --- /dev/null +++ b/test/ELF/duplicated-synthetic-sym.s @@ -0,0 +1,10 @@ +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +// RUN: cd %S +// RUN: not ld.lld %t.o --format=binary duplicated-synthetic-sym.s -o %t.elf 2>&1 | FileCheck %s + +// CHECK: duplicate symbol: _binary_duplicated_synthetic_sym_s_start +// CHECK: defined at (internal):(.data+0x0) + + .globl _binary_duplicated_synthetic_sym_s_start +_binary_duplicated_synthetic_sym_s_start: + .long 0 diff --git a/test/ELF/gnu-ifunc-dso.s b/test/ELF/gnu-ifunc-dso.s new file mode 100644 index 000000000000..6ceff3b17d42 --- /dev/null +++ b/test/ELF/gnu-ifunc-dso.s @@ -0,0 +1,13 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/gnu-ifunc-dso.s -o %t1.o +# RUN: ld.lld -shared %t1.o -o %t.so +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t2.o +# RUN: ld.lld -shared %t2.o %t.so -o %t +# RUN: llvm-readobj -dyn-relocations %t | FileCheck %s + +# CHECK: Dynamic Relocations { +# CHECK-NEXT: 0x1000 R_X86_64_64 foo 0x0 +# CHECK-NEXT: } + +.data + .quad foo diff --git a/test/ELF/invalid/Inputs/invalid-relocation-x64.elf b/test/ELF/invalid/Inputs/invalid-relocation-x64.elf deleted file mode 100644 index 25df2944614ead659ad0b20c32c98097ea72b90b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 559 zcmb<-^>JfjWaMOk0!9Wq21XbMiFUwXJ20>@up)_)$7BO)1KG!fru_gmN1&+zaY4#h zu!zI-8$jilp=x1DC7=vBAdPM}Na_RBewaFt9UvhNkR%Ym#KnMYklE;f18OL`H_-V! zK#kb+b3*m2p&5*>A0|Bm#z3QIqVaKa^@>t+67@<_D@qvjiZhB!ib@ibfGikYnG50r E0Oe8?3IG5A diff --git a/test/ELF/invalid/invalid-debug-relocations.test b/test/ELF/invalid/invalid-debug-relocations.test new file mode 100644 index 000000000000..75e41d18514f --- /dev/null +++ b/test/ELF/invalid/invalid-debug-relocations.test @@ -0,0 +1,41 @@ +# REQUIRES: x86 +# RUN: yaml2obj %s -o %t.o +# RUN: not ld.lld -gdb-index %t.o -o %t.exe 2>&1 | FileCheck %s + +# CHECK: error: {{.*}}.o: error parsing DWARF data: +# CHECK-NEXT: >>> failed to compute relocation: Unknown, Invalid data was encountered while parsing the file + +!ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_386 +Sections: + - Type: SHT_PROGBITS + Name: .text + Flags: [ ] + AddressAlign: 0x04 + Content: "0000" + - Type: SHT_PROGBITS + Name: .debug_info + Flags: [ ] + AddressAlign: 0x04 + Content: "0000" + - Type: SHT_REL + Name: .rel.debug_info + Link: .symtab + Info: .debug_info + Relocations: + - Offset: 0 + Symbol: _start + Type: 0xFF + - Offset: 4 + Symbol: _start + Type: 0xFF +Symbols: + Global: + - Name: _start + Type: STT_FUNC + Section: .text + Value: 0x0 diff --git a/test/ELF/invalid/invalid-relocation-x64.test b/test/ELF/invalid/invalid-relocation-x64.test index d52cf87c1b35..9b8ebb59e474 100644 --- a/test/ELF/invalid/invalid-relocation-x64.test +++ b/test/ELF/invalid/invalid-relocation-x64.test @@ -1,7 +1,8 @@ -## invalid-relocation-x64.elf contains relocations with invalid relocation number. -## Next yaml code was used to create initial binary. After that it -## was modified with hex-editor to replace known relocations with fake ones, -## that have 0x98 and 0x98 numbers. +# RUN: yaml2obj %s -o %t.o +# RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s +# CHECK: {{.*}}.o: unknown relocation type: Unknown (152) +# CHECK: {{.*}}.o: unknown relocation type: Unknown (153) + !ELF FileHeader: Class: ELFCLASS64 @@ -20,11 +21,7 @@ Sections: Relocations: - Offset: 0x0000000000000000 Symbol: '' - Type: R_X86_64_NONE + Type: 0x98 - Offset: 0x0000000000000000 Symbol: '' - Type: R_X86_64_NONE - -# RUN: not ld.lld %p/Inputs/invalid-relocation-x64.elf -o %t2 2>&1 | FileCheck %s -# CHECK: {{.*}}invalid-relocation-x64.elf: unknown relocation type: Unknown (152) -# CHECK: {{.*}}invalid-relocation-x64.elf: unknown relocation type: Unknown (153) + Type: 0x99 diff --git a/test/ELF/linkerscript/locationcountererr2.s b/test/ELF/linkerscript/locationcountererr2.s index 54ee4a34da2e..8968f6740ee4 100644 --- a/test/ELF/linkerscript/locationcountererr2.s +++ b/test/ELF/linkerscript/locationcountererr2.s @@ -2,8 +2,10 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o # RUN: echo "SECTIONS {" > %t.script # RUN: echo ". = 0x20; . = 0x10; .text : {} }" >> %t.script -# RUN: not ld.lld %t.o --script %t.script -o %t -shared 2>&1 | FileCheck %s -# CHECK: {{.*}}.script:2: unable to move location counter backward +# RUN: ld.lld %t.o --script %t.script -o %t -shared +# RUN: llvm-objdump -section-headers %t | FileCheck %s +# CHECK: Idx Name Size Address +# CHECK: 1 .text 00000000 0000000000000010 # RUN: echo "SECTIONS { . = 0x20; . = ASSERT(0x1, "foo"); }" > %t2.script # RUN: ld.lld %t.o --script %t2.script -o %t -shared diff --git a/test/ELF/linkerscript/non-alloc-segment.s b/test/ELF/linkerscript/non-alloc-segment.s new file mode 100644 index 000000000000..229f028a16b2 --- /dev/null +++ b/test/ELF/linkerscript/non-alloc-segment.s @@ -0,0 +1,44 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o + +################################################################################ +## Test that non-alloc section .foo can be assigned to a segment. Check that +## the values of the offset and file size of this segment's PHDR are correct. +## +## This functionality allows non-alloc metadata, which is not required at +## run-time, to be added to a custom segment in a file. This metadata may be +## read/edited by tools/loader using the values of the offset and file size from +## the custom segment's PHDR. This is particularly important if section headers +## have been stripped. +# RUN: echo "PHDRS {text PT_LOAD; foo 0x12345678;} \ +# RUN: SECTIONS { \ +# RUN: .text : {*(.text .text*)} :text \ +# RUN: .foo : {*(.foo)} :foo \ +# RUN: }" > %t.script +# RUN: ld.lld -o %t --script %t.script %t.o +# RUN: llvm-readobj -elf-output-style=GNU -s -l %t | FileCheck %s +# RUN: llvm-readobj -l %t | FileCheck --check-prefix=PHDR %s + +# CHECK: Program Headers: +# CHECK-NEXT: Type +# CHECK-NEXT: LOAD +# CHECK-NEXT: : 0x12345678 + +# CHECK: Section to Segment mapping: +# CHECK-NEXT: Segment Sections... +# CHECK-NEXT: 00 .text +# CHECK-NEXT: 01 .foo + +# PHDR: Type: (0x12345678) +# PHDR-NEXT: Offset: 0x1004 +# PHDR-NEXT: VirtualAddress +# PHDR-NEXT: PhysicalAddress +# PHDR-NEXT: FileSize: 4 + +.global _start +_start: + nop + +.section .foo + .align 4 + .long 0 diff --git a/test/ELF/linkerscript/out-of-order.s b/test/ELF/linkerscript/out-of-order.s index 9c6547a68643..6cfd533c4e14 100644 --- a/test/ELF/linkerscript/out-of-order.s +++ b/test/ELF/linkerscript/out-of-order.s @@ -1,9 +1,18 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-linux %s -o %t.o # RUN: echo "SECTIONS { .data 0x4000 : { *(.data) } .text 0x2000 : { *(.text) } }" > %t.script -# RUN: not ld.lld -o %t.so --script %t.script %t.o -shared 2>&1 | FileCheck %s +# RUN: ld.lld -o %t.so --script %t.script %t.o -shared +# RUN: llvm-objdump -section-headers %t.so | FileCheck %s -# CHECK: error: {{.*}}.script:1: unable to move location counter backward +# CHECK: Sections: +# CHECK-NEXT: Idx Name Size Address Type +# CHECK-NEXT: 0 00000000 0000000000000000 +# CHECK-NEXT: 1 .data 00000008 0000000000004000 DATA +# CHECK-NEXT: 2 .dynamic 00000060 0000000000004008 +# CHECK-NEXT: 3 .text 00000008 0000000000002000 TEXT DATA +# CHECK-NEXT: 4 .dynsym 00000018 0000000000002008 +# CHECK-NEXT: 5 .hash 00000010 0000000000002020 +# CHECK-NEXT: 6 .dynstr 00000001 0000000000002030 .quad 0 .data diff --git a/test/ELF/linkerscript/unused-synthetic.s b/test/ELF/linkerscript/unused-synthetic.s new file mode 100644 index 000000000000..c9295fff7b59 --- /dev/null +++ b/test/ELF/linkerscript/unused-synthetic.s @@ -0,0 +1,18 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: echo "SECTIONS { \ +# RUN: .got : { *(.got) } \ +# RUN: .plt : { *(.plt) } \ +# RUN: .text : { *(.text) } \ +# RUN: }" > %t.script +# RUN: ld.lld -shared -o %t.so --script %t.script %t.o + +# RUN: llvm-objdump -section-headers %t.so | FileCheck %s +# CHECK-NOT: .got +# CHECK-NOT: .plt +# CHECK: .text +# CHECK-NEXT: .dynsym + +.global _start +_start: + nop diff --git a/test/ELF/lto/defsym.ll b/test/ELF/lto/defsym.ll index 4c2fe45b3c53..2ce8570f9b68 100644 --- a/test/ELF/lto/defsym.ll +++ b/test/ELF/lto/defsym.ll @@ -1,9 +1,16 @@ ; REQUIRES: x86 +; LTO ; RUN: llvm-as %s -o %t.o ; RUN: llvm-as %S/Inputs/defsym-bar.ll -o %t1.o ; RUN: ld.lld %t.o %t1.o -shared -o %t.so -defsym=bar2=bar3 ; RUN: llvm-objdump -d %t.so | FileCheck %s +; ThinLTO +; RUN: opt -module-summary %s -o %t.o +; RUN: opt -module-summary %S/Inputs/defsym-bar.ll -o %t1.o +; RUN: ld.lld %t.o %t1.o -shared -o %t.so -defsym=bar2=bar3 +; RUN: llvm-objdump -d %t.so | FileCheck %s --check-prefix=THIN + ; Call to bar2() should not be inlined and should be routed to bar3() ; Symbol bar3 should not be eliminated @@ -13,6 +20,13 @@ ; CHECK-NEXT: callq{{.*}} ; CHECK-NEXT: callq +; THIN: foo +; THIN-NEXT: pushq %rax +; THIN-NEXT: callq +; THIN-NEXT: callq{{.*}} +; THIN-NEXT: popq %rax +; THIN-NEXT: jmp + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" diff --git a/test/ELF/lto/wrap-1.ll b/test/ELF/lto/wrap-1.ll index b61dfaeb5903..1dd9139808b6 100644 --- a/test/ELF/lto/wrap-1.ll +++ b/test/ELF/lto/wrap-1.ll @@ -1,9 +1,16 @@ ; REQUIRES: x86 +; LTO ; RUN: llvm-as %s -o %t.o ; RUN: ld.lld %t.o -o %t.out -wrap=bar -save-temps ; RUN: llvm-readobj -t %t.out | FileCheck %s ; RUN: cat %t.out.resolution.txt | FileCheck -check-prefix=RESOLS %s +; ThinLTO +; RUN: opt -module-summary %s -o %t.o +; RUN: ld.lld %t.o -o %t.out -wrap=bar -save-temps +; RUN: llvm-readobj -t %t.out | FileCheck %s +; RUN: cat %t.out.resolution.txt | FileCheck -check-prefix=RESOLS %s + ; CHECK: Name: __wrap_bar ; CHECK-NEXT: Value: ; CHECK-NEXT: Size: diff --git a/test/ELF/lto/wrap-2.ll b/test/ELF/lto/wrap-2.ll index b318b7f65f2d..06ef4064e4d1 100644 --- a/test/ELF/lto/wrap-2.ll +++ b/test/ELF/lto/wrap-2.ll @@ -1,17 +1,31 @@ ; REQUIRES: x86 +; LTO ; RUN: llvm-as %s -o %t.o ; RUN: llvm-as %S/Inputs/wrap-bar.ll -o %t1.o ; RUN: ld.lld %t.o %t1.o -shared -o %t.so -wrap=bar ; RUN: llvm-objdump -d %t.so | FileCheck %s ; RUN: llvm-readobj -t %t.so | FileCheck -check-prefix=BIND %s +; ThinLTO +; RUN: opt -module-summary %s -o %t.o +; RUN: opt -module-summary %S/Inputs/wrap-bar.ll -o %t1.o +; RUN: ld.lld %t.o %t1.o -shared -o %t.so -wrap=bar +; RUN: llvm-objdump -d %t.so | FileCheck %s -check-prefix=THIN +; RUN: llvm-readobj -t %t.so | FileCheck -check-prefix=BIND %s + ; Make sure that calls in foo() are not eliminated and that bar is ; routed to __wrap_bar and __real_bar is routed to bar. ; CHECK: foo: ; CHECK-NEXT: pushq %rax +; CHECK-NEXT: callq{{.*}}<__wrap_bar> ; CHECK-NEXT: callq{{.*}} -; CHECK-NEXT: callq{{.*}}<__real_bar> + +; THIN: foo: +; THIN-NEXT: pushq %rax +; THIN-NEXT: callq{{.*}}<__wrap_bar> +; THIN-NEXT: popq %rax +; THIN-NEXT: jmp{{.*}} ; Check that bar and __wrap_bar retain their original binding. ; BIND: Name: bar diff --git a/test/ELF/symver-archive.s b/test/ELF/symver-archive.s new file mode 100644 index 000000000000..be50503a3f5d --- /dev/null +++ b/test/ELF/symver-archive.s @@ -0,0 +1,15 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1 +# RUN: rm -f %t.a +# RUN: llvm-ar rcs %t.a %t1 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/symver-archive1.s -o %t2.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/symver-archive2.s -o %t3.o +# RUN: ld.lld -o %t.out %t2.o %t3.o %t.a + +.text +.globl x +.type x, @function +x: + +.globl xx +xx = x diff --git a/test/ELF/version-script-no-warn2.s b/test/ELF/version-script-no-warn2.s new file mode 100644 index 000000000000..52beff366bb7 --- /dev/null +++ b/test/ELF/version-script-no-warn2.s @@ -0,0 +1,8 @@ +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/version-script-no-warn2.s -o %t1.o +# RUN: ld.lld %t1.o -o %t1.so -shared +# RUN: echo "{ global: foo; local: *; };" > %t.script +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t2.o +# RUN: ld.lld -shared --version-script %t.script %t2.o %t1.so -o %t2.so --fatal-warnings + +.global foo +foo: diff --git a/test/ELF/version-script-symver.s b/test/ELF/version-script-symver.s index 7798330b053d..0a4eddd46cec 100644 --- a/test/ELF/version-script-symver.s +++ b/test/ELF/version-script-symver.s @@ -1,8 +1,6 @@ # REQUIRES: x86 - # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o -# RUN: echo "VERSION { global: *; };" > %t.map -# RUN: ld.lld %t.o --version-script %t.map -o %t +# RUN: ld.lld %t.o -o %t .global _start .global bar diff --git a/test/ELF/version-script-symver2.s b/test/ELF/version-script-symver2.s new file mode 100644 index 000000000000..5961d9a7c3a6 --- /dev/null +++ b/test/ELF/version-script-symver2.s @@ -0,0 +1,28 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: echo "VER1 { global: foo; local: *; }; VER2 { global: foo; }; VER3 { global: foo; };" > %t.map +# RUN: ld.lld -shared %t.o --version-script %t.map -o %t.so --fatal-warnings +# RUN: llvm-readobj -V %t.so | FileCheck %s + +# CHECK: Symbols [ +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Version: 0 +# CHECK-NEXT: Name: @ +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Version: 3 +# CHECK-NEXT: Name: foo@@VER2 +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Version: 2 +# CHECK-NEXT: Name: foo@VER1 +# CHECK-NEXT: } +# CHECK-NEXT: ] + +.global bar +bar: +.symver bar, foo@VER1 + +.global zed +zed: +.symver zed, foo@@VER2 diff --git a/test/ELF/version-script-undef-version.s b/test/ELF/version-script-undef-version.s new file mode 100644 index 000000000000..40dc816f5005 --- /dev/null +++ b/test/ELF/version-script-undef-version.s @@ -0,0 +1,12 @@ +# REQUIRES: x86 + +# Test that we don't error on undefined versions when static linking. +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: ld.lld %t.o -o %t +# RUN: echo "DEFINED { global: *; };" > %t.map +# RUN: ld.lld %t.o --version-script %t.map -o %t + +.global _start +.global bar +.symver _start, bar@@UNDEFINED +_start: diff --git a/test/ELF/version-script-weak.s b/test/ELF/version-script-weak.s new file mode 100644 index 000000000000..cc3df8da5dc5 --- /dev/null +++ b/test/ELF/version-script-weak.s @@ -0,0 +1,28 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/version-script-weak.s -o %tmp.o +# RUN: rm -f %t.a +# RUN: llvm-ar rcs %t.a %tmp.o +# RUN: echo "{ local: *; };" > %t.script +# RUN: ld.lld -shared --version-script %t.script %t.o %t.a -o %t.so +# RUN: llvm-readobj -dyn-symbols -r %t.so | FileCheck %s + +# CHECK: Relocations [ +# CHECK-NEXT: Section ({{.*}}) .rela.plt { +# CHECK-NEXT: 0x2018 R_X86_64_JUMP_SLOT foo +# CHECK-NEXT: } +# CHECK-NEXT: ] +# CHECK: Symbol { +# CHECK: Name: foo@ +# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Weak +# CHECK-NEXT: Type: None +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: Undefined +# CHECK-NEXT: } + +.text + callq foo@PLT +.weak foo diff --git a/test/ELF/wrap-dynamic-undef.s b/test/ELF/wrap-dynamic-undef.s new file mode 100644 index 000000000000..95b985981013 --- /dev/null +++ b/test/ELF/wrap-dynamic-undef.s @@ -0,0 +1,15 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/wrap-dynamic-undef.s -o %t2.o +# RUN: ld.lld %t2.o -o %t2.so -shared +# RUN: ld.lld %t1.o %t2.so -o %t --wrap foo +# RUN: llvm-readobj -dyn-symbols --elf-output-style=GNU %t | FileCheck %s + +# Test that the dynamic relocation uses foo. We used to produce a +# relocation with __real_foo. + +# CHECK: NOTYPE GLOBAL DEFAULT UND foo + +.global _start +_start: + callq __real_foo@plt diff --git a/test/ELF/wrap.s b/test/ELF/wrap.s index d8d802bb8ca4..3e75fdbad811 100644 --- a/test/ELF/wrap.s +++ b/test/ELF/wrap.s @@ -12,12 +12,16 @@ // CHECK-NEXT: movl $0x11010, %edx // CHECK-NEXT: movl $0x11000, %edx +// This shows an oddity of our implementation. The symbol foo gets +// mapped to __wrap_foo, but stays in the symbol table. This results +// in it showing up twice in the output. + // RUN: llvm-readobj -t -s %t3 | FileCheck -check-prefix=SYM %s -// SYM: Name: __real_foo +// SYM: Name: foo // SYM-NEXT: Value: 0x11000 // SYM: Name: __wrap_foo // SYM-NEXT: Value: 0x11010 -// SYM: Name: foo +// SYM: Name: __wrap_foo // SYM-NEXT: Value: 0x11010 .global _start diff --git a/test/lit.cfg b/test/lit.cfg index cba56c642907..95bf3c0dc434 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -122,8 +122,8 @@ if config.test_exec_root is None: lit_config.fatal('No site specific configuration available!') # Get the source and object roots. - llvm_src_root = lit.util.capture(['llvm-config', '--src-root']).strip() - llvm_obj_root = lit.util.capture(['llvm-config', '--obj-root']).strip() + llvm_src_root = subprocess.check_output(['llvm-config', '--src-root']).strip() + llvm_obj_root = subprocess.check_output(['llvm-config', '--obj-root']).strip() lld_src_root = os.path.join(llvm_src_root, "tools", "lld") lld_obj_root = os.path.join(llvm_obj_root, "tools", "lld") From e75e363cb71a7339552b9d943e78ac62b737379b Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Thu, 13 Jul 2017 19:26:17 +0000 Subject: [PATCH 02/10] Vendor import of lldb trunk r307894: https://llvm.org/svn/llvm-project/lldb/trunk@307894 --- docs/lldb-gdb-remote.txt | 45 ++- include/lldb/Host/Host.h | 18 +- .../lldb/Host/common/NativeProcessProtocol.h | 121 +++---- lit/lit.cfg | 6 +- lldb.xcodeproj/project.pbxproj | 38 ++- .../call-restarts/TestCallThatRestarts.py | 24 +- .../call-throws/TestCallThatThrows.py | 24 +- .../expression_command/char/TestExprsChar.py | 21 +- .../expression_command/fixits/TestFixIts.py | 24 +- .../issue_11588/Test11588.py | 23 +- .../expression_command/macros/TestMacros.py | 28 +- .../options/TestExprOptions.py | 21 +- .../save_jit_objects/TestSaveJITObjects.py | 13 +- .../timeout/TestCallWithTimeout.py | 28 +- .../test/functionalities/mtc/simple/Makefile | 6 + .../mtc/simple/TestMTCSimple.py | 57 ++++ .../test/functionalities/mtc/simple/main.m | 15 + .../return-value/TestReturnValue.py | 2 - .../functionalities/signal/raise/TestRaise.py | 5 + .../test/functionalities/signal/raise/main.c | 7 + .../ubsan/user-expression/Makefile | 6 + .../TestUbsanUserExpression.py | 49 +++ .../ubsan/user-expression/main.c | 9 + .../test/lang/go/types/TestGoASTContext.py | 1 + .../Python/lldbsuite/test/lldbplatformutil.py | 14 + packages/Python/lldbsuite/test/lldbutil.py | 41 +++ .../Python/lldbsuite/test/make/Android.rules | 4 - .../test/sample_test/TestSampleTest.py | 40 +-- source/Commands/CommandObjectThread.cpp | 6 +- source/Core/DumpDataExtractor.cpp | 3 +- source/Host/common/File.cpp | 74 ++-- source/Host/common/MainLoop.cpp | 27 +- source/Host/common/NativeProcessProtocol.cpp | 33 +- source/Host/common/SocketAddress.cpp | 2 +- source/Host/macosx/Host.mm | 6 +- .../posix/ConnectionFileDescriptorPosix.cpp | 21 +- .../DynamicLoader/POSIX-DYLD/AuxVector.cpp | 76 ++--- .../DynamicLoader/POSIX-DYLD/AuxVector.h | 69 ++-- .../POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp | 4 +- .../ASan/ASanRuntime.cpp | 6 +- .../MainThreadCheckerRuntime.cpp | 5 +- .../TSan/TSanRuntime.cpp | 6 +- .../UBSan/UBSanRuntime.cpp | 3 + source/Plugins/Language/ObjC/Cocoa.cpp | 12 +- .../Platform/Android/PlatformAndroid.cpp | 8 +- .../Platform/Android/PlatformAndroid.h | 2 +- .../Plugins/Platform/POSIX/PlatformPOSIX.cpp | 8 +- source/Plugins/Platform/POSIX/PlatformPOSIX.h | 4 +- .../Process/FreeBSD/ProcessMonitor.cpp | 24 +- .../Process/Linux/NativeProcessLinux.cpp | 321 ++++++------------ .../Process/Linux/NativeProcessLinux.h | 39 ++- .../NativeRegisterContextLinux_arm64.cpp | 6 +- .../NativeRegisterContextLinux_x86_64.cpp | 21 +- .../Plugins/Process/Linux/ProcessorTrace.cpp | 37 +- .../Process/NetBSD/NativeProcessNetBSD.cpp | 267 +++++---------- .../Process/NetBSD/NativeProcessNetBSD.h | 30 +- .../Plugins/Process/gdb-remote/CMakeLists.txt | 8 - .../GDBRemoteCommunicationClient.cpp | 28 +- .../gdb-remote/GDBRemoteCommunicationClient.h | 3 + .../GDBRemoteCommunicationServer.cpp | 26 +- .../gdb-remote/GDBRemoteCommunicationServer.h | 7 + .../GDBRemoteCommunicationServerCommon.cpp | 9 +- .../GDBRemoteCommunicationServerLLGS.cpp | 71 ++-- .../GDBRemoteCommunicationServerLLGS.h | 15 +- .../Process/gdb-remote/ProcessGDBRemote.cpp | 1 + .../Python/ScriptInterpreterPython.cpp | 14 +- .../x86/x86AssemblyInspectionEngine.cpp | 20 +- .../x86/x86AssemblyInspectionEngine.h | 2 +- source/Utility/StringExtractorGDBRemote.cpp | 37 +- source/Utility/StringExtractorGDBRemote.h | 4 + tools/lldb-server/CMakeLists.txt | 12 +- tools/lldb-server/lldb-gdbserver.cpp | 34 +- tools/lldb-server/lldb-platform.cpp | 57 ++-- .../Process/Linux/ProcessorTraceTest.cpp | 32 +- .../x86/Testx86AssemblyInspectionEngine.cpp | 25 ++ www/architecture.html | 294 ---------------- www/architecture/index.html | 133 ++++---- www/sidebar.incl | 2 +- 78 files changed, 1155 insertions(+), 1489 deletions(-) create mode 100644 packages/Python/lldbsuite/test/functionalities/mtc/simple/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/mtc/simple/TestMTCSimple.py create mode 100644 packages/Python/lldbsuite/test/functionalities/mtc/simple/main.m create mode 100644 packages/Python/lldbsuite/test/functionalities/ubsan/user-expression/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/ubsan/user-expression/TestUbsanUserExpression.py create mode 100644 packages/Python/lldbsuite/test/functionalities/ubsan/user-expression/main.c delete mode 100755 www/architecture.html diff --git a/docs/lldb-gdb-remote.txt b/docs/lldb-gdb-remote.txt index a4427a70444d..0000738b556b 100644 --- a/docs/lldb-gdb-remote.txt +++ b/docs/lldb-gdb-remote.txt @@ -125,6 +125,32 @@ read packet: $OK#00 This packet can be sent one or more times _prior_ to sending a "A" packet. +//---------------------------------------------------------------------- +// "QEnableErrorStrings" +// +// BRIEF +// This packet enables reporting of Error strings in remote packet +// replies from the server to client. If the server supports this +// feature, it should send an OK response. The client can expect the +// following error replies if this feature is enabled in the server -> +// +// EXX;AAAAAAAAA +// +// where AAAAAAAAA will be a hex encoded ASCII string. +// XX is hex encoded byte number. +// +// It must be noted that even if the client has enabled reporting +// strings in error replies, it must not expect error strings to all +// error replies. +// +// PRIORITY TO IMPLEMENT +// Low. Only needed if the remote target wants to provide strings that +// are human readable along with an error code. +//---------------------------------------------------------------------- + +send packet: $QErrorStringInPacketSupported +read packet: $OK#00 + //---------------------------------------------------------------------- // "QSetSTDIN:" // "QSetSTDOUT:" @@ -250,11 +276,12 @@ read packet: OK // // Each tracing instance is identified by a trace id which is returned // as the reply to this packet. In case the tracing failed to begin an -// error code is returned instead. +// error code along with a hex encoded ASCII message is returned +// instead. //---------------------------------------------------------------------- send packet: jTraceStart:{"type":,"buffersize":}] -read packet: /E +read packet: /E;AAAAAAAAA //---------------------------------------------------------------------- // jTraceStop: @@ -283,12 +310,12 @@ read packet: /E // to stop tracing on that thread. // ========== ==================================================== // -// An OK response is sent in case of success else an error code is -// returned. +// An OK response is sent in case of success else an error code along +// with a hex encoded ASCII message is returned. //---------------------------------------------------------------------- send packet: jTraceStop:{"traceid":}] -read packet: /E +read packet: /E;AAAAAAAAA //---------------------------------------------------------------------- // jTraceBufferRead: @@ -317,11 +344,11 @@ read packet: /E // ========== ==================================================== // // The trace data is sent as raw binary data if the read was successful -// else an error code is sent. +// else an error code along with a hex encoded ASCII message is sent. //---------------------------------------------------------------------- send packet: jTraceBufferRead:{"traceid":,"offset":,"buffersize":}] -read packet: /E +read packet: /E;AAAAAAAAA //---------------------------------------------------------------------- // jTraceMetaRead: @@ -359,11 +386,11 @@ read packet: /E // gdb-remote protocol has certain limitations, binary escaping // convention is used. // In case the trace instance with the was not found, an -// error code is returned. +// error code along with a hex encoded ASCII message is returned. //---------------------------------------------------------------------- send packet: jTraceConfigRead:{"traceid":} -read packet: {"conf1":,"conf2":,"params":{"paramName":paramValue}]}];/E +read packet: {"conf1":,"conf2":,"params":{"paramName":paramValue}]}];/E;AAAAAAAAA //---------------------------------------------------------------------- // "qRegisterInfo" diff --git a/include/lldb/Host/Host.h b/include/lldb/Host/Host.h index c41e4796f532..da0b8e14c4a7 100644 --- a/include/lldb/Host/Host.h +++ b/include/lldb/Host/Host.h @@ -7,14 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_Host_h_ -#define liblldb_Host_h_ -#if defined(__cplusplus) - -#include - -#include -#include +#ifndef LLDB_HOST_HOST_H +#define LLDB_HOST_HOST_H #include "lldb/Host/File.h" #include "lldb/Host/HostThread.h" @@ -22,6 +16,11 @@ #include "lldb/Utility/StringList.h" #include "lldb/lldb-private-forward.h" #include "lldb/lldb-private.h" +#include +#include +#include +#include +#include namespace lldb_private { @@ -254,5 +253,4 @@ template <> struct format_provider { }; } // namespace llvm -#endif // #if defined(__cplusplus) -#endif // liblldb_Host_h_ +#endif // LLDB_HOST_HOST_H diff --git a/include/lldb/Host/common/NativeProcessProtocol.h b/include/lldb/Host/common/NativeProcessProtocol.h index a97540499cd3..5f2157510c0a 100644 --- a/include/lldb/Host/common/NativeProcessProtocol.h +++ b/include/lldb/Host/common/NativeProcessProtocol.h @@ -19,6 +19,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" #include "llvm/Support/MemoryBuffer.h" #include @@ -244,68 +245,57 @@ class NativeProcessProtocol virtual Status GetFileLoadAddress(const llvm::StringRef &file_name, lldb::addr_t &load_addr) = 0; - //------------------------------------------------------------------ - /// Launch a process for debugging. This method will create an concrete - /// instance of NativeProcessProtocol, based on the host platform. - /// (e.g. NativeProcessLinux on linux, etc.) - /// - /// @param[in] launch_info - /// Information required to launch the process. - /// - /// @param[in] native_delegate - /// The delegate that will receive messages regarding the - /// inferior. Must outlive the NativeProcessProtocol - /// instance. - /// - /// @param[in] mainloop - /// The mainloop instance with which the process can register - /// callbacks. Must outlive the NativeProcessProtocol - /// instance. - /// - /// @param[out] process_sp - /// On successful return from the method, this parameter - /// contains the shared pointer to the - /// NativeProcessProtocol that can be used to manipulate - /// the native process. - /// - /// @return - /// An error object indicating if the operation succeeded, - /// and if not, what error occurred. - //------------------------------------------------------------------ - static Status Launch(ProcessLaunchInfo &launch_info, - NativeDelegate &native_delegate, MainLoop &mainloop, - NativeProcessProtocolSP &process_sp); + class Factory { + public: + virtual ~Factory(); + //------------------------------------------------------------------ + /// Launch a process for debugging. + /// + /// @param[in] launch_info + /// Information required to launch the process. + /// + /// @param[in] native_delegate + /// The delegate that will receive messages regarding the + /// inferior. Must outlive the NativeProcessProtocol + /// instance. + /// + /// @param[in] mainloop + /// The mainloop instance with which the process can register + /// callbacks. Must outlive the NativeProcessProtocol + /// instance. + /// + /// @return + /// A NativeProcessProtocol shared pointer if the operation succeeded or + /// an error object if it failed. + //------------------------------------------------------------------ + virtual llvm::Expected + Launch(ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate, + MainLoop &mainloop) const = 0; - //------------------------------------------------------------------ - /// Attach to an existing process. This method will create an concrete - /// instance of NativeProcessProtocol, based on the host platform. - /// (e.g. NativeProcessLinux on linux, etc.) - /// - /// @param[in] pid - /// pid of the process locatable - /// - /// @param[in] native_delegate - /// The delegate that will receive messages regarding the - /// inferior. Must outlive the NativeProcessProtocol - /// instance. - /// - /// @param[in] mainloop - /// The mainloop instance with which the process can register - /// callbacks. Must outlive the NativeProcessProtocol - /// instance. - /// - /// @param[out] process_sp - /// On successful return from the method, this parameter - /// contains the shared pointer to the - /// NativeProcessProtocol that can be used to manipulate - /// the native process. - /// - /// @return - /// An error object indicating if the operation succeeded, - /// and if not, what error occurred. - //------------------------------------------------------------------ - static Status Attach(lldb::pid_t pid, NativeDelegate &native_delegate, - MainLoop &mainloop, NativeProcessProtocolSP &process_sp); + //------------------------------------------------------------------ + /// Attach to an existing process. + /// + /// @param[in] pid + /// pid of the process locatable + /// + /// @param[in] native_delegate + /// The delegate that will receive messages regarding the + /// inferior. Must outlive the NativeProcessProtocol + /// instance. + /// + /// @param[in] mainloop + /// The mainloop instance with which the process can register + /// callbacks. Must outlive the NativeProcessProtocol + /// instance. + /// + /// @return + /// A NativeProcessProtocol shared pointer if the operation succeeded or + /// an error object if it failed. + //------------------------------------------------------------------ + virtual llvm::Expected + Attach(lldb::pid_t pid, NativeDelegate &native_delegate, + MainLoop &mainloop) const = 0; + }; //------------------------------------------------------------------ /// StartTracing API for starting a tracing instance with the @@ -413,10 +403,10 @@ class NativeProcessProtocol lldb::pid_t m_pid; std::vector m_threads; - lldb::tid_t m_current_thread_id; + lldb::tid_t m_current_thread_id = LLDB_INVALID_THREAD_ID; mutable std::recursive_mutex m_threads_mutex; - lldb::StateType m_state; + lldb::StateType m_state = lldb::eStateInvalid; mutable std::recursive_mutex m_state_mutex; llvm::Optional m_exit_status; @@ -427,7 +417,7 @@ class NativeProcessProtocol NativeWatchpointList m_watchpoint_list; HardwareBreakpointMap m_hw_breakpoints_map; int m_terminal_fd; - uint32_t m_stop_id; + uint32_t m_stop_id = 0; // Set of signal numbers that LLDB directly injects back to inferior // without stopping it. @@ -438,7 +428,8 @@ class NativeProcessProtocol // then the process should be attached to. When attaching to a process // lldb_private::Host calls should be used to locate the process to attach to, // and then this function should be called. - NativeProcessProtocol(lldb::pid_t pid); + NativeProcessProtocol(lldb::pid_t pid, int terminal_fd, + NativeDelegate &delegate); // ----------------------------------------------------------- // Internal interface for state handling diff --git a/lit/lit.cfg b/lit/lit.cfg index a3d5f9ca7524..8dea61b27169 100644 --- a/lit/lit.cfg +++ b/lit/lit.cfg @@ -95,8 +95,8 @@ if config.test_exec_root is None: lit_config.fatal('No site specific configuration available!') # Get the source and object roots. - llvm_src_root = lit.util.capture(['llvm-config', '--src-root']).strip() - llvm_obj_root = lit.util.capture(['llvm-config', '--obj-root']).strip() + llvm_src_root = subprocess.check_output(['llvm-config', '--src-root']).strip() + llvm_obj_root = subprocess.check_output(['llvm-config', '--obj-root']).strip() lldb_src_root = os.path.join(llvm_src_root, "tools", "lldb") lldb_obj_root = os.path.join(llvm_obj_root, "tools", "lldb") @@ -132,7 +132,7 @@ if not os.path.exists(config.cxx): if platform.system() in ['Darwin']: try: - out = lit.util.capture(['xcrun', '--show-sdk-path']).strip() + out = subprocess.check_output(['xcrun', '--show-sdk-path']).strip() res = 0 except OSError: res = -1 diff --git a/lldb.xcodeproj/project.pbxproj b/lldb.xcodeproj/project.pbxproj index 8c59fc888412..8353da30bd8e 100644 --- a/lldb.xcodeproj/project.pbxproj +++ b/lldb.xcodeproj/project.pbxproj @@ -868,6 +868,8 @@ 966C6B7C18E6A56A0093F5EC /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 966C6B7818E6A56A0093F5EC /* libz.dylib */; }; 9694FA711B32AA64005EBB16 /* ABISysV_mips.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9694FA6F1B32AA64005EBB16 /* ABISysV_mips.cpp */; }; 9A0FDEA71E8EF5110086B2F5 /* RegisterContextLinux_mips.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A0FDE971E8EF5010086B2F5 /* RegisterContextLinux_mips.cpp */; }; + 9A1542F91F0EE48600DEA1D8 /* MockTildeExpressionResolver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A1542F51F0EE44000DEA1D8 /* MockTildeExpressionResolver.cpp */; }; + 9A1542FA1F0EE48600DEA1D8 /* TestUtilities.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A1542F71F0EE44000DEA1D8 /* TestUtilities.cpp */; }; 9A19A6AF1163BBB200E0D453 /* SBValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A19A6A51163BB7E00E0D453 /* SBValue.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9A19A6B01163BBB300E0D453 /* SBValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A19A6AD1163BB9800E0D453 /* SBValue.cpp */; }; 9A1E595C1EB2B141002206A5 /* SBTrace.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A1E59521EB2B0B9002206A5 /* SBTrace.cpp */; }; @@ -2815,6 +2817,11 @@ 9A0FDE991E8EF5010086B2F5 /* RegisterInfos_arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegisterInfos_arm.h; path = Utility/RegisterInfos_arm.h; sourceTree = ""; }; 9A0FDE9A1E8EF5010086B2F5 /* RegisterInfos_arm64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegisterInfos_arm64.h; path = Utility/RegisterInfos_arm64.h; sourceTree = ""; }; 9A0FDE9B1E8EF5010086B2F5 /* RegisterInfos_mips.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegisterInfos_mips.h; path = Utility/RegisterInfos_mips.h; sourceTree = ""; }; + 9A1542F41F0EE44000DEA1D8 /* CMakeLists.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + 9A1542F51F0EE44000DEA1D8 /* MockTildeExpressionResolver.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MockTildeExpressionResolver.cpp; sourceTree = ""; }; + 9A1542F61F0EE44000DEA1D8 /* MockTildeExpressionResolver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockTildeExpressionResolver.h; sourceTree = ""; }; + 9A1542F71F0EE44000DEA1D8 /* TestUtilities.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = TestUtilities.cpp; sourceTree = ""; }; + 9A1542F81F0EE44000DEA1D8 /* TestUtilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestUtilities.h; sourceTree = ""; }; 9A19A6A51163BB7E00E0D453 /* SBValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBValue.h; path = include/lldb/API/SBValue.h; sourceTree = ""; }; 9A19A6AD1163BB9800E0D453 /* SBValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBValue.cpp; path = source/API/SBValue.cpp; sourceTree = ""; }; 9A1E59521EB2B0B9002206A5 /* SBTrace.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBTrace.cpp; path = source/API/SBTrace.cpp; sourceTree = ""; }; @@ -3305,6 +3312,7 @@ 2321F9421BDD343A00BA9A93 /* Utility */ = { isa = PBXGroup; children = ( + 9A1542F31F0EE44000DEA1D8 /* Helpers */, 2321F9431BDD346100BA9A93 /* CMakeLists.txt */, 23CB15041D66CD9200EDDDE1 /* Inputs */, 2321F9441BDD346100BA9A93 /* StringExtractorTest.cpp */, @@ -6216,6 +6224,18 @@ name = "SysV-mips"; sourceTree = ""; }; + 9A1542F31F0EE44000DEA1D8 /* Helpers */ = { + isa = PBXGroup; + children = ( + 9A1542F41F0EE44000DEA1D8 /* CMakeLists.txt */, + 9A1542F51F0EE44000DEA1D8 /* MockTildeExpressionResolver.cpp */, + 9A1542F61F0EE44000DEA1D8 /* MockTildeExpressionResolver.h */, + 9A1542F71F0EE44000DEA1D8 /* TestUtilities.cpp */, + 9A1542F81F0EE44000DEA1D8 /* TestUtilities.h */, + ); + path = Helpers; + sourceTree = ""; + }; AE44FB371BB35A2E0033EB62 /* Go */ = { isa = PBXGroup; children = ( @@ -7003,12 +7023,14 @@ 23CB15371D66DA9300EDDDE1 /* PythonTestSuite.cpp in Sources */, 23E2E5321D903832006F38BB /* BreakpointIDTest.cpp in Sources */, 23CB15381D66DA9300EDDDE1 /* PythonExceptionStateTests.cpp in Sources */, + 9A1542F91F0EE48600DEA1D8 /* MockTildeExpressionResolver.cpp in Sources */, 23CB15391D66DA9300EDDDE1 /* DataExtractorTest.cpp in Sources */, 23CB153A1D66DA9300EDDDE1 /* GDBRemoteClientBaseTest.cpp in Sources */, 23CB153B1D66DA9300EDDDE1 /* SocketTest.cpp in Sources */, 23CB153C1D66DA9300EDDDE1 /* TestArgs.cpp in Sources */, 23CB153D1D66DA9300EDDDE1 /* GDBRemoteCommunicationClientTest.cpp in Sources */, 23CB153E1D66DA9300EDDDE1 /* PythonDataObjectsTests.cpp in Sources */, + 9A1542FA1F0EE48600DEA1D8 /* TestUtilities.cpp in Sources */, 23CB153F1D66DA9300EDDDE1 /* SymbolsTest.cpp in Sources */, AFEC5FD81D94F9380076A480 /* Testx86AssemblyInspectionEngine.cpp in Sources */, 23CB15401D66DA9300EDDDE1 /* TestClangASTContext.cpp in Sources */, @@ -8256,7 +8278,7 @@ "$(LLVM_SOURCE_DIR)/tools/clang/include", "$(LLVM_BUILD_DIR)/$(LLVM_BUILD_DIR_ARCH)/tools/clang/include", ); - LLDB_GTESTS_CFLAGS = "-I $(LLVM_SOURCE_DIR)/utils/unittest/googletest/include -I $(LLVM_SOURCE_DIR)/include -I $(LLVM_BUILD_DIR)/x86_64/include -I include -I source -I $(PYTHON_FRAMEWORK_PATH)/Headers"; + LLDB_GTESTS_CFLAGS = "-I ${SOURCE_ROOT} -I $(LLVM_SOURCE_DIR)/utils/unittest/googlemock/include -I $(LLVM_SOURCE_DIR)/utils/unittest/googletest/include -I $(LLVM_SOURCE_DIR)/include -I $(LLVM_BUILD_DIR)/x86_64/include -I include -I source -I $(PYTHON_FRAMEWORK_PATH)/Headers"; LLDB_GTESTS_LDFLAGS = "$(LLVM_BUILD_DIR)/x86_64/lib/libgtest.a -L $(PYTHON_FRAMEWORK_PATH)/Versions/$(PYTHON_VERSION_MAJOR).$(PYTHON_VERSION_MINOR)/lib -l python$(PYTHON_VERSION_MAJOR).$(PYTHON_VERSION_MINOR)"; OTHER_CFLAGS = ( "-fno-rtti", @@ -8298,7 +8320,7 @@ "$(LLVM_SOURCE_DIR)/tools/clang/include", "$(LLVM_BUILD_DIR)/$(LLVM_BUILD_DIR_ARCH)/tools/clang/include", ); - LLDB_GTESTS_CFLAGS = "-I $(LLVM_SOURCE_DIR)/utils/unittest/googletest/include -I $(LLVM_SOURCE_DIR)/include -I $(LLVM_BUILD_DIR)/x86_64/include -I include -I source -I $(PYTHON_FRAMEWORK_PATH)/Headers"; + LLDB_GTESTS_CFLAGS = "-I ${SOURCE_ROOT} -I $(LLVM_SOURCE_DIR)/utils/unittest/googlemock/include -I $(LLVM_SOURCE_DIR)/utils/unittest/googletest/include -I $(LLVM_SOURCE_DIR)/include -I $(LLVM_BUILD_DIR)/x86_64/include -I include -I source -I $(PYTHON_FRAMEWORK_PATH)/Headers"; LLDB_GTESTS_LDFLAGS = "$(LLVM_BUILD_DIR)/x86_64/lib/libgtest.a -L $(PYTHON_FRAMEWORK_PATH)/Versions/$(PYTHON_VERSION_MAJOR).$(PYTHON_VERSION_MINOR)/lib -l python$(PYTHON_VERSION_MAJOR).$(PYTHON_VERSION_MINOR)"; OTHER_CFLAGS = ( "-fno-rtti", @@ -8340,7 +8362,7 @@ "$(LLVM_SOURCE_DIR)/tools/clang/include", "$(LLVM_BUILD_DIR)/$(LLVM_BUILD_DIR_ARCH)/tools/clang/include", ); - LLDB_GTESTS_CFLAGS = "-I $(LLVM_SOURCE_DIR)/utils/unittest/googletest/include -I $(LLVM_SOURCE_DIR)/include -I $(LLVM_BUILD_DIR)/x86_64/include -I include -I source -I $(PYTHON_FRAMEWORK_PATH)/Headers"; + LLDB_GTESTS_CFLAGS = "-I ${SOURCE_ROOT} -I $(LLVM_SOURCE_DIR)/utils/unittest/googlemock/include -I $(LLVM_SOURCE_DIR)/utils/unittest/googletest/include -I $(LLVM_SOURCE_DIR)/include -I $(LLVM_BUILD_DIR)/x86_64/include -I include -I source -I $(PYTHON_FRAMEWORK_PATH)/Headers"; LLDB_GTESTS_LDFLAGS = "$(LLVM_BUILD_DIR)/x86_64/lib/libgtest.a -L $(PYTHON_FRAMEWORK_PATH)/Versions/$(PYTHON_VERSION_MAJOR).$(PYTHON_VERSION_MINOR)/lib -l python$(PYTHON_VERSION_MAJOR).$(PYTHON_VERSION_MINOR)"; OTHER_CFLAGS = ( "-fno-rtti", @@ -8382,7 +8404,7 @@ "$(LLVM_SOURCE_DIR)/tools/clang/include", "$(LLVM_BUILD_DIR)/$(LLVM_BUILD_DIR_ARCH)/tools/clang/include", ); - LLDB_GTESTS_CFLAGS = "-I $(LLVM_SOURCE_DIR)/utils/unittest/googletest/include -I $(LLVM_SOURCE_DIR)/include -I $(LLVM_BUILD_DIR)/x86_64/include -I include -I source -I $(PYTHON_FRAMEWORK_PATH)/Headers"; + LLDB_GTESTS_CFLAGS = "-I ${SOURCE_ROOT} -I $(LLVM_SOURCE_DIR)/utils/unittest/googlemock/include -I $(LLVM_SOURCE_DIR)/utils/unittest/googletest/include -I $(LLVM_SOURCE_DIR)/include -I $(LLVM_BUILD_DIR)/x86_64/include -I include -I source -I $(PYTHON_FRAMEWORK_PATH)/Headers"; LLDB_GTESTS_LDFLAGS = "$(LLVM_BUILD_DIR)/x86_64/lib/libgtest.a -L $(PYTHON_FRAMEWORK_PATH)/Versions/$(PYTHON_VERSION_MAJOR).$(PYTHON_VERSION_MINOR)/lib -l python$(PYTHON_VERSION_MAJOR).$(PYTHON_VERSION_MINOR)"; OTHER_CFLAGS = ( "-fno-rtti", @@ -8424,7 +8446,7 @@ "$(LLVM_SOURCE_DIR)/tools/clang/include", "$(LLVM_BUILD_DIR)/$(LLVM_BUILD_DIR_ARCH)/tools/clang/include", ); - LLDB_GTESTS_CFLAGS = "-I $(LLVM_SOURCE_DIR)/utils/unittest/googletest/include -I $(LLVM_SOURCE_DIR)/include -I $(LLVM_BUILD_DIR)/x86_64/include -I include -I source -I $(PYTHON_FRAMEWORK_PATH)/Headers"; + LLDB_GTESTS_CFLAGS = "-I ${SOURCE_ROOT} -I $(LLVM_SOURCE_DIR)/utils/unittest/googlemock/include -I $(LLVM_SOURCE_DIR)/utils/unittest/googletest/include -I $(LLVM_SOURCE_DIR)/include -I $(LLVM_BUILD_DIR)/x86_64/include -I include -I source -I $(PYTHON_FRAMEWORK_PATH)/Headers"; LLDB_GTESTS_LDFLAGS = "$(LLVM_BUILD_DIR)/x86_64/lib/libgtest.a -L $(PYTHON_FRAMEWORK_PATH)/Versions/$(PYTHON_VERSION_MAJOR).$(PYTHON_VERSION_MINOR)/lib -l python$(PYTHON_VERSION_MAJOR).$(PYTHON_VERSION_MINOR)"; OTHER_CFLAGS = ( "-fno-rtti", @@ -8466,7 +8488,7 @@ "$(LLVM_SOURCE_DIR)/tools/clang/include", "$(LLVM_BUILD_DIR)/$(LLVM_BUILD_DIR_ARCH)/tools/clang/include", ); - LLDB_GTESTS_CFLAGS = "-I $(LLVM_SOURCE_DIR)/utils/unittest/googletest/include -I $(LLVM_SOURCE_DIR)/include -I $(LLVM_BUILD_DIR)/x86_64/include -I include -I source -I $(PYTHON_FRAMEWORK_PATH)/Headers"; + LLDB_GTESTS_CFLAGS = "-I ${SOURCE_ROOT} -I $(LLVM_SOURCE_DIR)/utils/unittest/googlemock/include -I $(LLVM_SOURCE_DIR)/utils/unittest/googletest/include -I $(LLVM_SOURCE_DIR)/include -I $(LLVM_BUILD_DIR)/x86_64/include -I include -I source -I $(PYTHON_FRAMEWORK_PATH)/Headers"; LLDB_GTESTS_LDFLAGS = "$(LLVM_BUILD_DIR)/x86_64/lib/libgtest.a -L $(PYTHON_FRAMEWORK_PATH)/Versions/$(PYTHON_VERSION_MAJOR).$(PYTHON_VERSION_MINOR)/lib -l python$(PYTHON_VERSION_MAJOR).$(PYTHON_VERSION_MINOR)"; OTHER_CFLAGS = ( "-fno-rtti", @@ -8508,7 +8530,7 @@ "$(LLVM_SOURCE_DIR)/tools/clang/include", "$(LLVM_BUILD_DIR)/$(LLVM_BUILD_DIR_ARCH)/tools/clang/include", ); - LLDB_GTESTS_CFLAGS = "-I $(LLVM_SOURCE_DIR)/utils/unittest/googletest/include -I $(LLVM_SOURCE_DIR)/include -I $(LLVM_BUILD_DIR)/x86_64/include -I include -I source -I $(PYTHON_FRAMEWORK_PATH)/Headers"; + LLDB_GTESTS_CFLAGS = "-I ${SOURCE_ROOT} -I $(LLVM_SOURCE_DIR)/utils/unittest/googlemock/include -I $(LLVM_SOURCE_DIR)/utils/unittest/googletest/include -I $(LLVM_SOURCE_DIR)/include -I $(LLVM_BUILD_DIR)/x86_64/include -I include -I source -I $(PYTHON_FRAMEWORK_PATH)/Headers"; LLDB_GTESTS_LDFLAGS = "$(LLVM_BUILD_DIR)/x86_64/lib/libgtest.a -L $(PYTHON_FRAMEWORK_PATH)/Versions/$(PYTHON_VERSION_MAJOR).$(PYTHON_VERSION_MINOR)/lib -l python$(PYTHON_VERSION_MAJOR).$(PYTHON_VERSION_MINOR)"; OTHER_CFLAGS = ( "-fno-rtti", @@ -8550,7 +8572,7 @@ "$(LLVM_SOURCE_DIR)/tools/clang/include", "$(LLVM_BUILD_DIR)/$(LLVM_BUILD_DIR_ARCH)/tools/clang/include", ); - LLDB_GTESTS_CFLAGS = "-I $(LLVM_SOURCE_DIR)/utils/unittest/googletest/include -I $(LLVM_SOURCE_DIR)/include -I $(LLVM_BUILD_DIR)/x86_64/include -I include -I source -I $(PYTHON_FRAMEWORK_PATH)/Headers"; + LLDB_GTESTS_CFLAGS = "-I ${SOURCE_ROOT} -I $(LLVM_SOURCE_DIR)/utils/unittest/googlemock/include -I $(LLVM_SOURCE_DIR)/utils/unittest/googletest/include -I $(LLVM_SOURCE_DIR)/include -I $(LLVM_BUILD_DIR)/x86_64/include -I include -I source -I $(PYTHON_FRAMEWORK_PATH)/Headers"; LLDB_GTESTS_LDFLAGS = "$(LLVM_BUILD_DIR)/x86_64/lib/libgtest.a -L $(PYTHON_FRAMEWORK_PATH)/Versions/$(PYTHON_VERSION_MAJOR).$(PYTHON_VERSION_MINOR)/lib -l python$(PYTHON_VERSION_MAJOR).$(PYTHON_VERSION_MINOR)"; OTHER_CFLAGS = ( "-fno-rtti", diff --git a/packages/Python/lldbsuite/test/expression_command/call-restarts/TestCallThatRestarts.py b/packages/Python/lldbsuite/test/expression_command/call-restarts/TestCallThatRestarts.py index 0b9ad0ed6323..5eb7b309c94a 100644 --- a/packages/Python/lldbsuite/test/expression_command/call-restarts/TestCallThatRestarts.py +++ b/packages/Python/lldbsuite/test/expression_command/call-restarts/TestCallThatRestarts.py @@ -48,28 +48,8 @@ def check_after_call(self, num_sigchld): "Restored the zeroth frame correctly") def call_function(self): - exe_name = "a.out" - exe = os.path.join(os.getcwd(), exe_name) - - target = self.dbg.CreateTarget(exe) - self.assertTrue(target, VALID_TARGET) - empty = lldb.SBFileSpec() - breakpoint = target.BreakpointCreateBySourceRegex( - 'Stop here in main.', self.main_source_spec) - self.assertTrue(breakpoint.GetNumLocations() > 0, VALID_BREAKPOINT) - - # Launch the process, and do not stop at the entry point. - process = target.LaunchSimple( - None, None, self.get_process_working_directory()) - - self.assertTrue(process, PROCESS_IS_VALID) - - # Frame #0 should be at our breakpoint. - threads = lldbutil.get_threads_stopped_at_breakpoint( - process, breakpoint) - - self.assertTrue(len(threads) == 1) - self.thread = threads[0] + (target, process, self.thread, bkpt) = lldbutil.run_to_source_breakpoint(self, + 'Stop here in main.', self.main_source_spec) # Make sure the SIGCHLD behavior is pass/no-stop/no-notify: return_obj = lldb.SBCommandReturnObject() diff --git a/packages/Python/lldbsuite/test/expression_command/call-throws/TestCallThatThrows.py b/packages/Python/lldbsuite/test/expression_command/call-throws/TestCallThatThrows.py index e5162609dfa6..f2ec340ac845 100644 --- a/packages/Python/lldbsuite/test/expression_command/call-throws/TestCallThatThrows.py +++ b/packages/Python/lldbsuite/test/expression_command/call-throws/TestCallThatThrows.py @@ -37,28 +37,8 @@ def check_after_call(self): def call_function(self): """Test calling function that throws.""" - exe_name = "a.out" - exe = os.path.join(os.getcwd(), exe_name) - - target = self.dbg.CreateTarget(exe) - self.assertTrue(target, VALID_TARGET) - - breakpoint = target.BreakpointCreateBySourceRegex( - 'I am about to throw.', self.main_source_spec) - self.assertTrue(breakpoint.GetNumLocations() > 0, VALID_BREAKPOINT) - - # Launch the process, and do not stop at the entry point. - process = target.LaunchSimple( - None, None, self.get_process_working_directory()) - - self.assertTrue(process, PROCESS_IS_VALID) - - # Frame #0 should be at our breakpoint. - threads = lldbutil.get_threads_stopped_at_breakpoint( - process, breakpoint) - - self.assertTrue(len(threads) == 1) - self.thread = threads[0] + (target, process, self.thread, bkpt) = lldbutil.run_to_source_breakpoint(self, + 'I am about to throw.', self.main_source_spec) options = lldb.SBExpressionOptions() options.SetUnwindOnError(True) diff --git a/packages/Python/lldbsuite/test/expression_command/char/TestExprsChar.py b/packages/Python/lldbsuite/test/expression_command/char/TestExprsChar.py index a771e7004c94..74991999d926 100644 --- a/packages/Python/lldbsuite/test/expression_command/char/TestExprsChar.py +++ b/packages/Python/lldbsuite/test/expression_command/char/TestExprsChar.py @@ -17,29 +17,14 @@ def setUp(self): self.main_source = "main.cpp" self.main_source_spec = lldb.SBFileSpec(self.main_source) - self.exe = os.path.join(os.getcwd(), "a.out") def do_test(self, dictionary=None): """These basic expression commands should work as expected.""" self.build(dictionary=dictionary) - target = self.dbg.CreateTarget(self.exe) - self.assertTrue(target) - - breakpoint = target.BreakpointCreateBySourceRegex( - '// Break here', self.main_source_spec) - self.assertTrue(breakpoint) - - # Launch the process, and do not stop at the entry point. - process = target.LaunchSimple( - None, None, self.get_process_working_directory()) - self.assertTrue(process) - - threads = lldbutil.get_threads_stopped_at_breakpoint( - process, breakpoint) - self.assertEqual(len(threads), 1) - - frame = threads[0].GetFrameAtIndex(0) + (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self, + '// Break here', self.main_source_spec) + frame = thread.GetFrameAtIndex(0) value = frame.EvaluateExpression("foo(c)") self.assertTrue(value.IsValid()) diff --git a/packages/Python/lldbsuite/test/expression_command/fixits/TestFixIts.py b/packages/Python/lldbsuite/test/expression_command/fixits/TestFixIts.py index 418c5325ad08..4b096149e728 100644 --- a/packages/Python/lldbsuite/test/expression_command/fixits/TestFixIts.py +++ b/packages/Python/lldbsuite/test/expression_command/fixits/TestFixIts.py @@ -37,28 +37,8 @@ def test_with_dummy_target(self): def try_expressions(self): """Test calling expressions with errors that can be fixed by the FixIts.""" - exe_name = "a.out" - exe = os.path.join(os.getcwd(), exe_name) - - target = self.dbg.CreateTarget(exe) - self.assertTrue(target, VALID_TARGET) - - breakpoint = target.BreakpointCreateBySourceRegex( - 'Stop here to evaluate expressions', self.main_source_spec) - self.assertTrue(breakpoint.GetNumLocations() > 0, VALID_BREAKPOINT) - - # Launch the process, and do not stop at the entry point. - process = target.LaunchSimple( - None, None, self.get_process_working_directory()) - - self.assertTrue(process, PROCESS_IS_VALID) - - # Frame #0 should be at our breakpoint. - threads = lldbutil.get_threads_stopped_at_breakpoint( - process, breakpoint) - - self.assertTrue(len(threads) == 1) - self.thread = threads[0] + (target, process, self.thread, bkpt) = lldbutil.run_to_source_breakpoint(self, + 'Stop here to evaluate expressions', self.main_source_spec) options = lldb.SBExpressionOptions() options.SetAutoApplyFixIts(True) diff --git a/packages/Python/lldbsuite/test/expression_command/issue_11588/Test11588.py b/packages/Python/lldbsuite/test/expression_command/issue_11588/Test11588.py index afb497e04b5b..a2d68cffe548 100644 --- a/packages/Python/lldbsuite/test/expression_command/issue_11588/Test11588.py +++ b/packages/Python/lldbsuite/test/expression_command/issue_11588/Test11588.py @@ -32,26 +32,9 @@ def cleanup(): """valobj.AddressOf() should return correct values.""" self.build() - exe = os.path.join(os.getcwd(), "a.out") - - target = self.dbg.CreateTarget(exe) - self.assertTrue(target, VALID_TARGET) - - breakpoint = target.BreakpointCreateBySourceRegex( - 'Set breakpoint here.', lldb.SBFileSpec("main.cpp", False)) - - process = target.LaunchSimple( - None, None, self.get_process_working_directory()) - self.assertTrue(process, "Created a process.") - self.assertTrue( - process.GetState() == lldb.eStateStopped, - "Stopped it too.") - - thread_list = lldbutil.get_threads_stopped_at_breakpoint( - process, breakpoint) - self.assertTrue(len(thread_list) == 1) - thread = thread_list[0] - + (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self, + 'Set breakpoint here.', + lldb.SBFileSpec("main.cpp", False)) self.runCmd("command script import --allow-reload s11588.py") self.runCmd( "type synthetic add --python-class s11588.Issue11581SyntheticProvider StgClosure") diff --git a/packages/Python/lldbsuite/test/expression_command/macros/TestMacros.py b/packages/Python/lldbsuite/test/expression_command/macros/TestMacros.py index 70b862bf4867..817f6cb3944a 100644 --- a/packages/Python/lldbsuite/test/expression_command/macros/TestMacros.py +++ b/packages/Python/lldbsuite/test/expression_command/macros/TestMacros.py @@ -30,32 +30,8 @@ def test_expr_with_macros(self): src_file_spec = lldb.SBFileSpec(src_file) self.assertTrue(src_file_spec.IsValid(), "Main source file") - # Get the path of the executable - cwd = os.getcwd() - exe_file = "a.out" - exe_path = os.path.join(cwd, exe_file) - - # Load the executable - target = self.dbg.CreateTarget(exe_path) - self.assertTrue(target.IsValid(), VALID_TARGET) - - # Set breakpoints - bp1 = target.BreakpointCreateBySourceRegex("Break here", src_file_spec) - self.assertTrue( - bp1.IsValid() and bp1.GetNumLocations() >= 1, - VALID_BREAKPOINT) - - # Launch the process - process = target.LaunchSimple( - None, None, self.get_process_working_directory()) - self.assertTrue(process.IsValid(), PROCESS_IS_VALID) - - # Get the thread of the process - self.assertTrue( - process.GetState() == lldb.eStateStopped, - PROCESS_STOPPED) - thread = lldbutil.get_stopped_thread( - process, lldb.eStopReasonBreakpoint) + (target, process, thread, bp1) = lldbutil.run_to_source_breakpoint( + self, "Break here", src_file_spec) # Get frame for current thread frame = thread.GetSelectedFrame() diff --git a/packages/Python/lldbsuite/test/expression_command/options/TestExprOptions.py b/packages/Python/lldbsuite/test/expression_command/options/TestExprOptions.py index 0d1a17352a3f..b4e9a8bfeab8 100644 --- a/packages/Python/lldbsuite/test/expression_command/options/TestExprOptions.py +++ b/packages/Python/lldbsuite/test/expression_command/options/TestExprOptions.py @@ -37,25 +37,10 @@ def test_expr_options(self): # Set debugger into synchronous mode self.dbg.SetAsync(False) - # Create a target by the debugger. - target = self.dbg.CreateTarget(self.exe) - self.assertTrue(target, VALID_TARGET) + (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( + self, '// breakpoint_in_main', self.main_source_spec) - # Set breakpoints inside main. - breakpoint = target.BreakpointCreateBySourceRegex( - '// breakpoint_in_main', self.main_source_spec) - self.assertTrue(breakpoint) - - # Now launch the process, and do not stop at entry point. - process = target.LaunchSimple( - None, None, self.get_process_working_directory()) - self.assertTrue(process, PROCESS_IS_VALID) - - threads = lldbutil.get_threads_stopped_at_breakpoint( - process, breakpoint) - self.assertEqual(len(threads), 1) - - frame = threads[0].GetFrameAtIndex(0) + frame = thread.GetFrameAtIndex(0) options = lldb.SBExpressionOptions() # test --language on C++ expression using the SB API's diff --git a/packages/Python/lldbsuite/test/expression_command/save_jit_objects/TestSaveJITObjects.py b/packages/Python/lldbsuite/test/expression_command/save_jit_objects/TestSaveJITObjects.py index 7f796971d0ed..f6938b1ea98b 100644 --- a/packages/Python/lldbsuite/test/expression_command/save_jit_objects/TestSaveJITObjects.py +++ b/packages/Python/lldbsuite/test/expression_command/save_jit_objects/TestSaveJITObjects.py @@ -31,17 +31,10 @@ def test_save_jit_objects(self): src_file = "main.c" src_file_spec = lldb.SBFileSpec(src_file) - exe_path = os.path.join(os.getcwd(), "a.out") - target = self.dbg.CreateTarget(exe_path) + (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( + self, "break", src_file_spec) - breakpoint = target.BreakpointCreateBySourceRegex( - "break", src_file_spec) - - process = target.LaunchSimple(None, None, - self.get_process_working_directory()) - - thread = process.GetSelectedThread() - frame = thread.GetSelectedFrame() + frame = thread.frames[0] cleanJITFiles() frame.EvaluateExpression("(void*)malloc(0x1)") diff --git a/packages/Python/lldbsuite/test/expression_command/timeout/TestCallWithTimeout.py b/packages/Python/lldbsuite/test/expression_command/timeout/TestCallWithTimeout.py index 29c03b1d7ef9..7862477001ea 100644 --- a/packages/Python/lldbsuite/test/expression_command/timeout/TestCallWithTimeout.py +++ b/packages/Python/lldbsuite/test/expression_command/timeout/TestCallWithTimeout.py @@ -25,36 +25,14 @@ def setUp(self): @expectedFlakeyFreeBSD("llvm.org/pr19605") @expectedFailureAll( oslist=[ - "windows", - "macosx"], + "windows"], bugnumber="llvm.org/pr21765") def test(self): """Test calling std::String member function.""" self.build() - exe_name = "a.out" - exe = os.path.join(os.getcwd(), exe_name) - - target = self.dbg.CreateTarget(exe) - self.assertTrue(target, VALID_TARGET) - - breakpoint = target.BreakpointCreateBySourceRegex( - 'stop here in main.', self.main_source_spec) - self.assertTrue(breakpoint, VALID_BREAKPOINT) - self.runCmd("breakpoint list") - - # Launch the process, and do not stop at the entry point. - process = target.LaunchSimple( - None, None, self.get_process_working_directory()) - - self.assertTrue(process, PROCESS_IS_VALID) - - # Frame #0 should be on self.step_out_of_malloc. - threads = lldbutil.get_threads_stopped_at_breakpoint( - process, breakpoint) - - self.assertTrue(len(threads) == 1) - thread = threads[0] + (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( + self, 'stop here in main.', self.main_source_spec) # First set the timeout too short, and make sure we fail. options = lldb.SBExpressionOptions() diff --git a/packages/Python/lldbsuite/test/functionalities/mtc/simple/Makefile b/packages/Python/lldbsuite/test/functionalities/mtc/simple/Makefile new file mode 100644 index 000000000000..5665652329dc --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/mtc/simple/Makefile @@ -0,0 +1,6 @@ +LEVEL = ../../../make + +OBJC_SOURCES := main.m +LDFLAGS = $(CFLAGS) -lobjc -framework Foundation -framework AppKit + +include $(LEVEL)/Makefile.rules diff --git a/packages/Python/lldbsuite/test/functionalities/mtc/simple/TestMTCSimple.py b/packages/Python/lldbsuite/test/functionalities/mtc/simple/TestMTCSimple.py new file mode 100644 index 000000000000..6a779ecfac5b --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/mtc/simple/TestMTCSimple.py @@ -0,0 +1,57 @@ +""" +Tests basic Main Thread Checker support (detecting a main-thread-only violation). +""" + +import os +import time +import lldb +from lldbsuite.test.lldbtest import * +from lldbsuite.test.decorators import * +import lldbsuite.test.lldbutil as lldbutil +from lldbsuite.test.lldbplatformutil import * +import json + + +class MTCSimpleTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @skipUnlessDarwin + def test(self): + self.mtc_dylib_path = findMainThreadCheckerDylib() + if self.mtc_dylib_path == "": + self.skipTest("This test requires libMainThreadChecker.dylib.") + + self.build() + self.mtc_tests() + + def setUp(self): + # Call super's setUp(). + TestBase.setUp(self) + + def mtc_tests(self): + # Load the test + exe = os.path.join(os.getcwd(), "a.out") + self.expect("file " + exe, patterns=["Current executable set to .*a.out"]) + + self.runCmd("env DYLD_INSERT_LIBRARIES=%s" % self.mtc_dylib_path) + self.runCmd("run") + + process = self.dbg.GetSelectedTarget().process + thread = process.GetSelectedThread() + frame = thread.GetSelectedFrame() + + self.expect("thread info", substrs=['stop reason = -[NSView superview] must be used from main thread only']) + + self.expect( + "thread info -s", + substrs=["instrumentation_class", "api_name", "class_name", "selector", "description"]) + self.assertEqual(thread.GetStopReason(), lldb.eStopReasonInstrumentation) + output_lines = self.res.GetOutput().split('\n') + json_line = '\n'.join(output_lines[2:]) + data = json.loads(json_line) + self.assertEqual(data["instrumentation_class"], "MainThreadChecker") + self.assertEqual(data["api_name"], "-[NSView superview]") + self.assertEqual(data["class_name"], "NSView") + self.assertEqual(data["selector"], "superview") + self.assertEqual(data["description"], "-[NSView superview] must be used from main thread only") diff --git a/packages/Python/lldbsuite/test/functionalities/mtc/simple/main.m b/packages/Python/lldbsuite/test/functionalities/mtc/simple/main.m new file mode 100644 index 000000000000..651347cf74ee --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/mtc/simple/main.m @@ -0,0 +1,15 @@ +#import +#import + +int main() { + NSView *view = [[NSView alloc] init]; + dispatch_group_t g = dispatch_group_create(); + dispatch_group_enter(g); + [NSThread detachNewThreadWithBlock:^{ + @autoreleasepool { + [view superview]; + } + dispatch_group_leave(g); + }]; + dispatch_group_wait(g, DISPATCH_TIME_FOREVER); +} diff --git a/packages/Python/lldbsuite/test/functionalities/return-value/TestReturnValue.py b/packages/Python/lldbsuite/test/functionalities/return-value/TestReturnValue.py index cf435a4aae91..1750bd31b3df 100644 --- a/packages/Python/lldbsuite/test/functionalities/return-value/TestReturnValue.py +++ b/packages/Python/lldbsuite/test/functionalities/return-value/TestReturnValue.py @@ -31,8 +31,6 @@ def affected_by_pr33042(self): "<=", "3.6"], archs=["i386"]) - @expectedFailureAll(compiler="clang", compiler_version=["<=", "5.0.300080"], - triple='.*-android', archs=["i386"]) @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24778") @add_test_categories(['pyapi']) def test_with_python(self): diff --git a/packages/Python/lldbsuite/test/functionalities/signal/raise/TestRaise.py b/packages/Python/lldbsuite/test/functionalities/signal/raise/TestRaise.py index efadea51f669..79175562fe7a 100644 --- a/packages/Python/lldbsuite/test/functionalities/signal/raise/TestRaise.py +++ b/packages/Python/lldbsuite/test/functionalities/signal/raise/TestRaise.py @@ -16,6 +16,7 @@ class RaiseTestCase(TestBase): mydir = TestBase.compute_mydir(__file__) + NO_DEBUG_INFO_TESTCASE = True def test_sigstop(self): self.build() @@ -29,6 +30,10 @@ def test_sigsigrtmin(self): self.build() self.signal_test('SIGRTMIN', True) + def test_sigtrap(self): + self.build() + self.signal_test('SIGTRAP', True) + def launch(self, target, signal): # launch the process, do not stop at entry point. process = target.LaunchSimple( diff --git a/packages/Python/lldbsuite/test/functionalities/signal/raise/main.c b/packages/Python/lldbsuite/test/functionalities/signal/raise/main.c index 8827174e758e..4203fe5d4c89 100644 --- a/packages/Python/lldbsuite/test/functionalities/signal/raise/main.c +++ b/packages/Python/lldbsuite/test/functionalities/signal/raise/main.c @@ -10,6 +10,11 @@ void handler(int signo) int main (int argc, char *argv[]) { + if (signal(SIGTRAP, handler) == SIG_ERR) + { + perror("signal(SIGTRAP)"); + return 1; + } #ifndef __APPLE__ // Real time signals not supported on apple platforms. if (signal(SIGRTMIN, handler) == SIG_ERR) @@ -27,6 +32,8 @@ int main (int argc, char *argv[]) if (strcmp(argv[1], "SIGSTOP") == 0) raise(SIGSTOP); + else if (strcmp(argv[1], "SIGTRAP") == 0) + raise(SIGTRAP); #ifndef __APPLE__ else if (strcmp(argv[1], "SIGRTMIN") == 0) raise(SIGRTMIN); diff --git a/packages/Python/lldbsuite/test/functionalities/ubsan/user-expression/Makefile b/packages/Python/lldbsuite/test/functionalities/ubsan/user-expression/Makefile new file mode 100644 index 000000000000..6e7d19b6f48c --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/ubsan/user-expression/Makefile @@ -0,0 +1,6 @@ +LEVEL = ../../../make + +C_SOURCES := main.c +CFLAGS_EXTRAS := -fsanitize=undefined -g + +include $(LEVEL)/Makefile.rules diff --git a/packages/Python/lldbsuite/test/functionalities/ubsan/user-expression/TestUbsanUserExpression.py b/packages/Python/lldbsuite/test/functionalities/ubsan/user-expression/TestUbsanUserExpression.py new file mode 100644 index 000000000000..a5e5f572a979 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/ubsan/user-expression/TestUbsanUserExpression.py @@ -0,0 +1,49 @@ +""" +Test that hitting a UBSan issue while running user expression doesn't break the evaluation. +""" + +import os +import time +import lldb +from lldbsuite.test.lldbtest import * +from lldbsuite.test.decorators import * +import lldbsuite.test.lldbutil as lldbutil +import json + + +class UbsanUserExpressionTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @skipUnlessUndefinedBehaviorSanitizer + def test(self): + self.build() + self.ubsan_tests() + + def setUp(self): + # Call super's setUp(). + TestBase.setUp(self) + self.line_breakpoint = line_number('main.c', '// breakpoint line') + + def ubsan_tests(self): + # Load the test + exe = os.path.join(os.getcwd(), "a.out") + self.expect( + "file " + exe, + patterns=["Current executable set to .*a.out"]) + + self.runCmd("breakpoint set -f main.c -l %d" % self.line_breakpoint) + + self.runCmd("run") + + process = self.dbg.GetSelectedTarget().process + thread = process.GetSelectedThread() + frame = thread.GetSelectedFrame() + + self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, + substrs=['stopped', 'stop reason = breakpoint']) + + self.expect("p foo()", substrs=["(int) $0 = 42"]) + + self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, + substrs=['stopped', 'stop reason = breakpoint']) diff --git a/packages/Python/lldbsuite/test/functionalities/ubsan/user-expression/main.c b/packages/Python/lldbsuite/test/functionalities/ubsan/user-expression/main.c new file mode 100644 index 000000000000..4786aaa89b27 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/ubsan/user-expression/main.c @@ -0,0 +1,9 @@ +int foo() { + int data[4]; + int x = *(int *)(((char *)&data[0]) + 2); + return 42; +} + +int main() { + return 0; // breakpoint line +} diff --git a/packages/Python/lldbsuite/test/lang/go/types/TestGoASTContext.py b/packages/Python/lldbsuite/test/lang/go/types/TestGoASTContext.py index 8e158c3e82d4..9571e259629f 100644 --- a/packages/Python/lldbsuite/test/lang/go/types/TestGoASTContext.py +++ b/packages/Python/lldbsuite/test/lang/go/types/TestGoASTContext.py @@ -20,6 +20,7 @@ class TestGoASTContext(TestBase): @skipIfRemote # Not remote test suit ready @no_debug_info_test @skipUnlessGoInstalled + @expectedFailureAll(bugnumber="llvm.org/pr33643") def test_with_dsym_and_python_api(self): """Test GoASTContext dwarf parsing.""" self.buildGo() diff --git a/packages/Python/lldbsuite/test/lldbplatformutil.py b/packages/Python/lldbsuite/test/lldbplatformutil.py index 89ce1d468bd0..4f45643241ed 100644 --- a/packages/Python/lldbsuite/test/lldbplatformutil.py +++ b/packages/Python/lldbsuite/test/lldbplatformutil.py @@ -8,6 +8,7 @@ import re import subprocess import sys +import os # Third-party modules import six @@ -140,6 +141,19 @@ def platformIsDarwin(): return getPlatform() in getDarwinOSTriples() +def findMainThreadCheckerDylib(): + if not platformIsDarwin(): + return "" + + with os.popen('xcode-select -p') as output: + xcode_developer_path = output.read().strip() + mtc_dylib_path = '%s/usr/lib/libMainThreadChecker.dylib' % xcode_developer_path + if os.path.isfile(mtc_dylib_path): + return mtc_dylib_path + + return "" + + class _PlatformContext(object): """Value object class which contains platform-specific options.""" diff --git a/packages/Python/lldbsuite/test/lldbutil.py b/packages/Python/lldbsuite/test/lldbutil.py index 7732dbe6dff3..58a1ead1ea0b 100644 --- a/packages/Python/lldbsuite/test/lldbutil.py +++ b/packages/Python/lldbsuite/test/lldbutil.py @@ -725,6 +725,47 @@ def get_crashed_threads(test, process): threads.append(thread) return threads +def run_to_source_breakpoint(test, bkpt_pattern, source_spec, launch_info = None, exe_name = "a.out", in_cwd = True): + """Start up a target, using exe_name as the executable, and run it to + a breakpoint set by source regex bkpt_pattern. + If you want to pass in launch arguments or environment variables, you can optionally pass in + an SBLaunchInfo. If you do that, remember to set the working directory as well. + If your executable isn't called a.out, you can pass that in. And if your executable isn't + in the CWD, pass in the absolute path to the executable in exe_name, and set in_cwd to False. + If the target isn't valid, the breakpoint isn't found, or hit, the + function will cause a testsuite failure. + If successful it returns a tuple with the target process and thread that hit the breakpoint.""" + + if in_cwd: + exe = os.path.join(os.getcwd(), exe_name) + + # Create the target + target = test.dbg.CreateTarget(exe) + test.assertTrue(target, "Target: %s is not valid."%(exe_name)) + + # Set the breakpoints + breakpoint = target.BreakpointCreateBySourceRegex( + bkpt_pattern, source_spec) + test.assertTrue(breakpoint.GetNumLocations() > 0, + 'No locations found for source breakpoint: "%s"'%(bkpt_pattern)) + + # Launch the process, and do not stop at the entry point. + if not launch_info: + launch_info = lldb.SBLaunchInfo(None) + launch_info.SetWorkingDirectory(test.get_process_working_directory()) + + error = lldb.SBError() + process = target.Launch(launch_info, error) + + test.assertTrue(process, "Could not create a valid process for %s: %s"%(exe_name, error.GetCString())) + + # Frame #0 should be at our breakpoint. + threads = get_threads_stopped_at_breakpoint( + process, breakpoint) + + test.assertTrue(len(threads) == 1, "Expected 1 thread to stop at breakpoint, %d did."%(len(threads))) + thread = threads[0] + return (target, process, thread, breakpoint) def continue_to_breakpoint(process, bkpt): """ Continues the process, if it stops, returns the threads stopped at bkpt; otherwise, returns None""" diff --git a/packages/Python/lldbsuite/test/make/Android.rules b/packages/Python/lldbsuite/test/make/Android.rules index 0a725494d354..058401f425ad 100644 --- a/packages/Python/lldbsuite/test/make/Android.rules +++ b/packages/Python/lldbsuite/test/make/Android.rules @@ -90,7 +90,3 @@ else ARCH_LDFLAGS += $(NDK_ROOT)/sources/cxx-stl/gnu-libstdc++/4.9/libs/$(STL_ARCH)/libgnustl_static.a endif - -ifeq "$(ARCH)" "i386" - ARCH_CFLAGS += -mstackrealign -endif diff --git a/packages/Python/lldbsuite/test/sample_test/TestSampleTest.py b/packages/Python/lldbsuite/test/sample_test/TestSampleTest.py index bb34727ff81b..9a1748bbabb5 100644 --- a/packages/Python/lldbsuite/test/sample_test/TestSampleTest.py +++ b/packages/Python/lldbsuite/test/sample_test/TestSampleTest.py @@ -25,6 +25,7 @@ class RenameThisSampleTestTestCase(TestBase): def test_sample_rename_this(self): """There can be many tests in a test case - describe this test here.""" self.build() + self.main_source_file = lldb.SBFileSpec("main.c") self.sample_test() def setUp(self): @@ -33,40 +34,15 @@ def setUp(self): def sample_test(self): """You might use the test implementation in several ways, say so here.""" - exe = os.path.join(os.getcwd(), "a.out") - # Create a target by the debugger. - target = self.dbg.CreateTarget(exe) - self.assertTrue(target, VALID_TARGET) + # This function starts a process, "a.out" by default, sets a source + # breakpoint, runs to it, and returns the thread, process & target. + # It optionally takes an SBLaunchOption argument if you want to pass + # arguments or environment variables. + (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self, + "Set a breakpoint here", self.main_source_file) - # Now create a breakpoint in main.c at the source matching - # "Set a breakpoint here" - breakpoint = target.BreakpointCreateBySourceRegex( - "Set a breakpoint here", lldb.SBFileSpec("main.c")) - self.assertTrue(breakpoint and - breakpoint.GetNumLocations() >= 1, - VALID_BREAKPOINT) - - error = lldb.SBError() - # This is the launch info. If you want to launch with arguments or - # environment variables, add them using SetArguments or - # SetEnvironmentEntries - - launch_info = lldb.SBLaunchInfo(None) - process = target.Launch(launch_info, error) - self.assertTrue(process, PROCESS_IS_VALID) - - # Did we hit our breakpoint? - from lldbsuite.test.lldbutil import get_threads_stopped_at_breakpoint - threads = get_threads_stopped_at_breakpoint(process, breakpoint) - self.assertTrue( - len(threads) == 1, - "There should be a thread stopped at our breakpoint") - - # The hit count for the breakpoint should be 1. - self.assertTrue(breakpoint.GetHitCount() == 1) - - frame = threads[0].GetFrameAtIndex(0) + frame = thread.GetFrameAtIndex(0) test_var = frame.FindVariable("test_var") self.assertTrue(test_var.GetError().Success(), "Failed to fetch test_var") test_value = test_var.GetValueAsUnsigned() diff --git a/source/Commands/CommandObjectThread.cpp b/source/Commands/CommandObjectThread.cpp index 687187b26ccd..6a933df43e14 100644 --- a/source/Commands/CommandObjectThread.cpp +++ b/source/Commands/CommandObjectThread.cpp @@ -161,9 +161,9 @@ class CommandObjectIterateOverThreads : public CommandObjectParsed { // List the common thread ID's const std::vector &thread_index_ids = stack.GetUniqueThreadIndexIDs(); - strm.Printf("%lu thread(s) ", thread_index_ids.size()); + strm.Format("{0} thread(s) ", thread_index_ids.size()); for (const uint32_t &thread_index_id : thread_index_ids) { - strm.Printf("#%u ", thread_index_id); + strm.Format("#{0} ", thread_index_id); } strm.EOL(); @@ -209,7 +209,7 @@ class CommandObjectIterateOverThreads : public CommandObjectParsed { Process *process = m_exe_ctx.GetProcessPtr(); Thread *thread = process->GetThreadList().FindThreadByID(tid).get(); if (thread == nullptr) { - result.AppendErrorWithFormat("Failed to process thread# %llu.\n", tid); + result.AppendErrorWithFormatv("Failed to process thread #{0}.\n", tid); result.SetStatus(eReturnStatusFailed); return false; } diff --git a/source/Core/DumpDataExtractor.cpp b/source/Core/DumpDataExtractor.cpp index 2b7abd60f8bc..c2a9115c3068 100644 --- a/source/Core/DumpDataExtractor.cpp +++ b/source/Core/DumpDataExtractor.cpp @@ -154,7 +154,8 @@ lldb::offset_t lldb_private::DumpDataExtractor( target_sp = exe_scope->CalculateTarget(); if (target_sp) { DisassemblerSP disassembler_sp(Disassembler::FindPlugin( - target_sp->GetArchitecture(), nullptr, nullptr)); + target_sp->GetArchitecture(), + target_sp->GetDisassemblyFlavor(), nullptr)); if (disassembler_sp) { lldb::addr_t addr = base_addr + start_offset; lldb_private::Address so_addr; diff --git a/source/Host/common/File.cpp b/source/Host/common/File.cpp index 3de93ebc220b..90a4462c6ca9 100644 --- a/source/Host/common/File.cpp +++ b/source/Host/common/File.cpp @@ -24,10 +24,12 @@ #endif #include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/Errno.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Process.h" // for llvm::sys::Process::FileDescriptorHasColors() #include "lldb/Host/Config.h" +#include "lldb/Host/Host.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/Log.h" @@ -133,9 +135,8 @@ FILE *File::GetStream() { m_should_close_fd = true; } - do { - m_stream = ::fdopen(m_descriptor, mode); - } while (m_stream == NULL && errno == EINTR); + m_stream = + llvm::sys::RetryAfterSignal(nullptr, ::fdopen, m_descriptor, mode); // If we got a stream, then we own the stream and should no // longer own the descriptor because fclose() will close it for us @@ -157,6 +158,19 @@ void File::SetStream(FILE *fh, bool transfer_ownership) { m_own_stream = transfer_ownership; } +static int DoOpen(const char *path, int flags, int mode) { +#ifdef _MSC_VER + std::wstring wpath; + if (!llvm::ConvertUTF8toWide(path, wpath)) + return -1; + int result; + ::_wsopen_s(&result, wpath.c_str(), flags, _SH_DENYNO, mode); + return result; +#else + return ::open(path, flags, mode); +#endif +} + Status File::Open(const char *path, uint32_t options, uint32_t permissions) { Status error; if (IsValid()) @@ -222,20 +236,7 @@ Status File::Open(const char *path, uint32_t options, uint32_t permissions) { mode |= S_IXOTH; } - do { -#ifdef _MSC_VER - std::wstring wpath; - if (!llvm::ConvertUTF8toWide(path, wpath)) { - m_descriptor = -1; - error.SetErrorString("Error converting path to UTF-16"); - return error; - } - ::_wsopen_s(&m_descriptor, wpath.c_str(), oflag, _SH_DENYNO, mode); -#else - m_descriptor = ::open(path, oflag, mode); -#endif - } while (m_descriptor < 0 && errno == EINTR); - + m_descriptor = llvm::sys::RetryAfterSignal(-1, DoOpen, path, oflag, mode); if (!DescriptorIsValid()) error.SetErrorToErrno(); else { @@ -421,12 +422,7 @@ off_t File::SeekFromEnd(off_t offset, Status *error_ptr) { Status File::Flush() { Status error; if (StreamIsValid()) { - int err = 0; - do { - err = ::fflush(m_stream); - } while (err == EOF && errno == EINTR); - - if (err == EOF) + if (llvm::sys::RetryAfterSignal(EOF, ::fflush, m_stream) == EOF) error.SetErrorToErrno(); } else if (!DescriptorIsValid()) { error.SetErrorString("invalid file handle"); @@ -442,12 +438,7 @@ Status File::Sync() { if (err == 0) error.SetErrorToGenericError(); #else - int err = 0; - do { - err = ::fsync(m_descriptor); - } while (err == -1 && errno == EINTR); - - if (err == -1) + if (llvm::sys::RetryAfterSignal(-1, ::fsync, m_descriptor) == -1) error.SetErrorToErrno(); #endif } else { @@ -497,10 +488,7 @@ Status File::Read(void *buf, size_t &num_bytes) { ssize_t bytes_read = -1; if (DescriptorIsValid()) { - do { - bytes_read = ::read(m_descriptor, buf, num_bytes); - } while (bytes_read < 0 && errno == EINTR); - + bytes_read = llvm::sys::RetryAfterSignal(-1, ::read, m_descriptor, buf, num_bytes); if (bytes_read == -1) { error.SetErrorToErrno(); num_bytes = 0; @@ -559,10 +547,8 @@ Status File::Write(const void *buf, size_t &num_bytes) { ssize_t bytes_written = -1; if (DescriptorIsValid()) { - do { - bytes_written = ::write(m_descriptor, buf, num_bytes); - } while (bytes_written < 0 && errno == EINTR); - + bytes_written = + llvm::sys::RetryAfterSignal(-1, ::write, m_descriptor, buf, num_bytes); if (bytes_written == -1) { error.SetErrorToErrno(); num_bytes = 0; @@ -624,11 +610,8 @@ Status File::Read(void *buf, size_t &num_bytes, off_t &offset) { #ifndef _WIN32 int fd = GetDescriptor(); if (fd != kInvalidDescriptor) { - ssize_t bytes_read = -1; - do { - bytes_read = ::pread(fd, buf, num_bytes, offset); - } while (bytes_read < 0 && errno == EINTR); - + ssize_t bytes_read = + llvm::sys::RetryAfterSignal(-1, ::pread, fd, buf, num_bytes, offset); if (bytes_read < 0) { num_bytes = 0; error.SetErrorToErrno(); @@ -730,11 +713,8 @@ Status File::Write(const void *buf, size_t &num_bytes, off_t &offset) { int fd = GetDescriptor(); if (fd != kInvalidDescriptor) { #ifndef _WIN32 - ssize_t bytes_written = -1; - do { - bytes_written = ::pwrite(m_descriptor, buf, num_bytes, offset); - } while (bytes_written < 0 && errno == EINTR); - + ssize_t bytes_written = + llvm::sys::RetryAfterSignal(-1, ::pwrite, m_descriptor, buf, num_bytes, offset); if (bytes_written < 0) { num_bytes = 0; error.SetErrorToErrno(); diff --git a/source/Host/common/MainLoop.cpp b/source/Host/common/MainLoop.cpp index 7de6f7fa865d..c0c4471e735f 100644 --- a/source/Host/common/MainLoop.cpp +++ b/source/Host/common/MainLoop.cpp @@ -193,10 +193,16 @@ Status MainLoop::RunImpl::Poll() { void MainLoop::RunImpl::ProcessEvents() { #ifdef FORCE_PSELECT - for (const auto &fd : loop.m_read_fds) { - if (!FD_ISSET(fd.first, &read_fd_set)) - continue; - IOObject::WaitableHandle handle = fd.first; + // Collect first all readable file descriptors into a separate vector and then + // iterate over it to invoke callbacks. Iterating directly over + // loop.m_read_fds is not possible because the callbacks can modify the + // container which could invalidate the iterator. + std::vector fds; + for (const auto &fd : loop.m_read_fds) + if (FD_ISSET(fd.first, &read_fd_set)) + fds.push_back(fd.first); + + for (const auto &handle : fds) { #else for (const auto &fd : read_fds) { if ((fd.revents & POLLIN) == 0) @@ -209,13 +215,16 @@ void MainLoop::RunImpl::ProcessEvents() { loop.ProcessReadObject(handle); } - for (const auto &entry : loop.m_signals) { + std::vector signals; + for (const auto &entry : loop.m_signals) + if (g_signal_flags[entry.first] != 0) + signals.push_back(entry.first); + + for (const auto &signal : signals) { if (loop.m_terminate_request) return; - if (g_signal_flags[entry.first] == 0) - continue; // No signal - g_signal_flags[entry.first] = 0; - loop.ProcessSignal(entry.first); + g_signal_flags[signal] = 0; + loop.ProcessSignal(signal); } } #endif diff --git a/source/Host/common/NativeProcessProtocol.cpp b/source/Host/common/NativeProcessProtocol.cpp index 341c301dc9c5..b5b6e9d8b923 100644 --- a/source/Host/common/NativeProcessProtocol.cpp +++ b/source/Host/common/NativeProcessProtocol.cpp @@ -29,11 +29,13 @@ using namespace lldb_private; // NativeProcessProtocol Members // ----------------------------------------------------------------------------- -NativeProcessProtocol::NativeProcessProtocol(lldb::pid_t pid) - : m_pid(pid), m_threads(), m_current_thread_id(LLDB_INVALID_THREAD_ID), - m_threads_mutex(), m_state(lldb::eStateInvalid), m_state_mutex(), - m_delegates_mutex(), m_delegates(), m_breakpoint_list(), - m_watchpoint_list(), m_terminal_fd(-1), m_stop_id(0) {} +NativeProcessProtocol::NativeProcessProtocol(lldb::pid_t pid, int terminal_fd, + NativeDelegate &delegate) + : m_pid(pid), m_terminal_fd(terminal_fd) { + bool registered = RegisterNativeDelegate(delegate); + assert(registered); + (void)registered; +} lldb_private::Status NativeProcessProtocol::Interrupt() { Status error; @@ -488,23 +490,4 @@ Status NativeProcessProtocol::ResolveProcessArchitecture(lldb::pid_t pid, "failed to retrieve a valid architecture from the exe module"); } -#if !defined(__linux__) && !defined(__NetBSD__) -// These need to be implemented to support lldb-gdb-server on a given platform. -// Stubs are -// provided to make the rest of the code link on non-supported platforms. - -Status NativeProcessProtocol::Launch(ProcessLaunchInfo &launch_info, - NativeDelegate &native_delegate, - MainLoop &mainloop, - NativeProcessProtocolSP &process_sp) { - llvm_unreachable("Platform has no NativeProcessProtocol support"); -} - -Status NativeProcessProtocol::Attach(lldb::pid_t pid, - NativeDelegate &native_delegate, - MainLoop &mainloop, - NativeProcessProtocolSP &process_sp) { - llvm_unreachable("Platform has no NativeProcessProtocol support"); -} - -#endif +NativeProcessProtocol::Factory::~Factory() = default; diff --git a/source/Host/common/SocketAddress.cpp b/source/Host/common/SocketAddress.cpp index 440ae5d9027f..41150fa7fd74 100644 --- a/source/Host/common/SocketAddress.cpp +++ b/source/Host/common/SocketAddress.cpp @@ -201,7 +201,7 @@ const SocketAddress &SocketAddress:: operator=(const struct addrinfo *addr_info) { Clear(); if (addr_info && addr_info->ai_addr && addr_info->ai_addrlen > 0 && - addr_info->ai_addrlen <= sizeof m_socket_addr) { + size_t(addr_info->ai_addrlen) <= sizeof m_socket_addr) { ::memcpy(&m_socket_addr, addr_info->ai_addr, addr_info->ai_addrlen); } return *this; diff --git a/source/Host/macosx/Host.mm b/source/Host/macosx/Host.mm index bbf70cd4c4b3..75624ef21f43 100644 --- a/source/Host/macosx/Host.mm +++ b/source/Host/macosx/Host.mm @@ -74,6 +74,7 @@ #include "lldb/Utility/StructuredData.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Errno.h" #include "cfcpp/CFCBundle.h" #include "cfcpp/CFCMutableArray.h" @@ -1663,10 +1664,7 @@ HostThread Host::StartMonitoringChildProcess( int wait_pid = 0; bool cancel = false; bool exited = false; - do { - wait_pid = ::waitpid(pid, &status, 0); - } while (wait_pid < 0 && errno == EINTR); - + wait_pid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &status, 0); if (wait_pid >= 0) { int signal = 0; int exit_status = 0; diff --git a/source/Host/posix/ConnectionFileDescriptorPosix.cpp b/source/Host/posix/ConnectionFileDescriptorPosix.cpp index 6b0f069c35a9..105ef0f23d46 100644 --- a/source/Host/posix/ConnectionFileDescriptorPosix.cpp +++ b/source/Host/posix/ConnectionFileDescriptorPosix.cpp @@ -245,11 +245,7 @@ ConnectionStatus ConnectionFileDescriptor::Connect(llvm::StringRef path, } else if ((addr = GetURLAddress(path, FILE_SCHEME))) { std::string addr_str = addr->str(); // file:///PATH - int fd = -1; - do { - fd = ::open(addr_str.c_str(), O_RDWR); - } while (fd == -1 && errno == EINTR); - + int fd = llvm::sys::RetryAfterSignal(-1, ::open, addr_str.c_str(), O_RDWR); if (fd == -1) { if (error_ptr) error_ptr->SetErrorToErrno(); @@ -620,20 +616,17 @@ ConnectionFileDescriptor::BytesAvailable(const Timeout &timeout, if (select_helper.FDIsSetRead(pipe_fd)) { // There is an interrupt or exit command in the command pipe // Read the data from that pipe: - char buffer[1]; + char c; - ssize_t bytes_read; - - do { - bytes_read = ::read(pipe_fd, buffer, sizeof(buffer)); - } while (bytes_read < 0 && errno == EINTR); - - switch (buffer[0]) { + ssize_t bytes_read = llvm::sys::RetryAfterSignal(-1, ::read, pipe_fd, &c, 1); + assert(bytes_read == 1); + (void)bytes_read; + switch (c) { case 'q': if (log) log->Printf("%p ConnectionFileDescriptor::BytesAvailable() " "got data: %c from the command channel.", - static_cast(this), buffer[0]); + static_cast(this), c); return eConnectionStatusEndOfFile; case 'i': // Interrupt the current read diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp b/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp index d385b78e0ec4..5dbb3bb4ef7e 100644 --- a/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp +++ b/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp @@ -63,10 +63,10 @@ void AuxVector::ParseAuxv(DataExtractor &data) { if (!ParseAuxvEntry(data, entry, &offset, byte_size)) break; - if (entry.type == AT_NULL) + if (entry.type == AUXV_AT_NULL) break; - if (entry.type == AT_IGNORE) + if (entry.type == AUXV_AT_IGNORE) continue; m_auxv.push_back(entry); @@ -110,43 +110,43 @@ void AuxVector::DumpToLog(Log *log) const { const char *AuxVector::GetEntryName(EntryType type) { const char *name = "AT_???"; -#define ENTRY_NAME(_type) \ - _type: \ - name = #_type +#define ENTRY_NAME(_type) \ + _type: \ + name = #_type + 5 switch (type) { - case ENTRY_NAME(AT_NULL); break; - case ENTRY_NAME(AT_IGNORE); break; - case ENTRY_NAME(AT_EXECFD); break; - case ENTRY_NAME(AT_PHDR); break; - case ENTRY_NAME(AT_PHENT); break; - case ENTRY_NAME(AT_PHNUM); break; - case ENTRY_NAME(AT_PAGESZ); break; - case ENTRY_NAME(AT_BASE); break; - case ENTRY_NAME(AT_FLAGS); break; - case ENTRY_NAME(AT_ENTRY); break; - case ENTRY_NAME(AT_NOTELF); break; - case ENTRY_NAME(AT_UID); break; - case ENTRY_NAME(AT_EUID); break; - case ENTRY_NAME(AT_GID); break; - case ENTRY_NAME(AT_EGID); break; - case ENTRY_NAME(AT_CLKTCK); break; - case ENTRY_NAME(AT_PLATFORM); break; - case ENTRY_NAME(AT_HWCAP); break; - case ENTRY_NAME(AT_FPUCW); break; - case ENTRY_NAME(AT_DCACHEBSIZE); break; - case ENTRY_NAME(AT_ICACHEBSIZE); break; - case ENTRY_NAME(AT_UCACHEBSIZE); break; - case ENTRY_NAME(AT_IGNOREPPC); break; - case ENTRY_NAME(AT_SECURE); break; - case ENTRY_NAME(AT_BASE_PLATFORM); break; - case ENTRY_NAME(AT_RANDOM); break; - case ENTRY_NAME(AT_EXECFN); break; - case ENTRY_NAME(AT_SYSINFO); break; - case ENTRY_NAME(AT_SYSINFO_EHDR); break; - case ENTRY_NAME(AT_L1I_CACHESHAPE); break; - case ENTRY_NAME(AT_L1D_CACHESHAPE); break; - case ENTRY_NAME(AT_L2_CACHESHAPE); break; - case ENTRY_NAME(AT_L3_CACHESHAPE); break; + case ENTRY_NAME(AUXV_AT_NULL); break; + case ENTRY_NAME(AUXV_AT_IGNORE); break; + case ENTRY_NAME(AUXV_AT_EXECFD); break; + case ENTRY_NAME(AUXV_AT_PHDR); break; + case ENTRY_NAME(AUXV_AT_PHENT); break; + case ENTRY_NAME(AUXV_AT_PHNUM); break; + case ENTRY_NAME(AUXV_AT_PAGESZ); break; + case ENTRY_NAME(AUXV_AT_BASE); break; + case ENTRY_NAME(AUXV_AT_FLAGS); break; + case ENTRY_NAME(AUXV_AT_ENTRY); break; + case ENTRY_NAME(AUXV_AT_NOTELF); break; + case ENTRY_NAME(AUXV_AT_UID); break; + case ENTRY_NAME(AUXV_AT_EUID); break; + case ENTRY_NAME(AUXV_AT_GID); break; + case ENTRY_NAME(AUXV_AT_EGID); break; + case ENTRY_NAME(AUXV_AT_CLKTCK); break; + case ENTRY_NAME(AUXV_AT_PLATFORM); break; + case ENTRY_NAME(AUXV_AT_HWCAP); break; + case ENTRY_NAME(AUXV_AT_FPUCW); break; + case ENTRY_NAME(AUXV_AT_DCACHEBSIZE); break; + case ENTRY_NAME(AUXV_AT_ICACHEBSIZE); break; + case ENTRY_NAME(AUXV_AT_UCACHEBSIZE); break; + case ENTRY_NAME(AUXV_AT_IGNOREPPC); break; + case ENTRY_NAME(AUXV_AT_SECURE); break; + case ENTRY_NAME(AUXV_AT_BASE_PLATFORM); break; + case ENTRY_NAME(AUXV_AT_RANDOM); break; + case ENTRY_NAME(AUXV_AT_EXECFN); break; + case ENTRY_NAME(AUXV_AT_SYSINFO); break; + case ENTRY_NAME(AUXV_AT_SYSINFO_EHDR); break; + case ENTRY_NAME(AUXV_AT_L1I_CACHESHAPE); break; + case ENTRY_NAME(AUXV_AT_L1D_CACHESHAPE); break; + case ENTRY_NAME(AUXV_AT_L2_CACHESHAPE); break; + case ENTRY_NAME(AUXV_AT_L3_CACHESHAPE); break; } #undef ENTRY_NAME diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.h b/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.h index 9c3e1b002a24..cf9da0808357 100644 --- a/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.h +++ b/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.h @@ -42,41 +42,42 @@ class AuxVector { /// Constants describing the type of entry. /// On Linux, running "LD_SHOW_AUXV=1 ./executable" will spew AUX information. + /// Added AUXV prefix to avoid potential conflicts with system-defined macros enum EntryType { - AT_NULL = 0, ///< End of auxv. - AT_IGNORE = 1, ///< Ignore entry. - AT_EXECFD = 2, ///< File descriptor of program. - AT_PHDR = 3, ///< Program headers. - AT_PHENT = 4, ///< Size of program header. - AT_PHNUM = 5, ///< Number of program headers. - AT_PAGESZ = 6, ///< Page size. - AT_BASE = 7, ///< Interpreter base address. - AT_FLAGS = 8, ///< Flags. - AT_ENTRY = 9, ///< Program entry point. - AT_NOTELF = 10, ///< Set if program is not an ELF. - AT_UID = 11, ///< UID. - AT_EUID = 12, ///< Effective UID. - AT_GID = 13, ///< GID. - AT_EGID = 14, ///< Effective GID. - AT_CLKTCK = 17, ///< Clock frequency (e.g. times(2)). - AT_PLATFORM = 15, ///< String identifying platform. - AT_HWCAP = 16, ///< Machine dependent hints about processor capabilities. - AT_FPUCW = 18, ///< Used FPU control word. - AT_DCACHEBSIZE = 19, ///< Data cache block size. - AT_ICACHEBSIZE = 20, ///< Instruction cache block size. - AT_UCACHEBSIZE = 21, ///< Unified cache block size. - AT_IGNOREPPC = 22, ///< Entry should be ignored. - AT_SECURE = 23, ///< Boolean, was exec setuid-like? - AT_BASE_PLATFORM = 24, ///< String identifying real platforms. - AT_RANDOM = 25, ///< Address of 16 random bytes. - AT_EXECFN = 31, ///< Filename of executable. - AT_SYSINFO = 32, ///< Pointer to the global system page used for system - ///calls and other nice things. - AT_SYSINFO_EHDR = 33, - AT_L1I_CACHESHAPE = 34, ///< Shapes of the caches. - AT_L1D_CACHESHAPE = 35, - AT_L2_CACHESHAPE = 36, - AT_L3_CACHESHAPE = 37, + AUXV_AT_NULL = 0, ///< End of auxv. + AUXV_AT_IGNORE = 1, ///< Ignore entry. + AUXV_AT_EXECFD = 2, ///< File descriptor of program. + AUXV_AT_PHDR = 3, ///< Program headers. + AUXV_AT_PHENT = 4, ///< Size of program header. + AUXV_AT_PHNUM = 5, ///< Number of program headers. + AUXV_AT_PAGESZ = 6, ///< Page size. + AUXV_AT_BASE = 7, ///< Interpreter base address. + AUXV_AT_FLAGS = 8, ///< Flags. + AUXV_AT_ENTRY = 9, ///< Program entry point. + AUXV_AT_NOTELF = 10, ///< Set if program is not an ELF. + AUXV_AT_UID = 11, ///< UID. + AUXV_AT_EUID = 12, ///< Effective UID. + AUXV_AT_GID = 13, ///< GID. + AUXV_AT_EGID = 14, ///< Effective GID. + AUXV_AT_CLKTCK = 17, ///< Clock frequency (e.g. times(2)). + AUXV_AT_PLATFORM = 15, ///< String identifying platform. + AUXV_AT_HWCAP = 16, ///< Machine dependent hints about processor capabilities. + AUXV_AT_FPUCW = 18, ///< Used FPU control word. + AUXV_AT_DCACHEBSIZE = 19, ///< Data cache block size. + AUXV_AT_ICACHEBSIZE = 20, ///< Instruction cache block size. + AUXV_AT_UCACHEBSIZE = 21, ///< Unified cache block size. + AUXV_AT_IGNOREPPC = 22, ///< Entry should be ignored. + AUXV_AT_SECURE = 23, ///< Boolean, was exec setuid-like? + AUXV_AT_BASE_PLATFORM = 24, ///< String identifying real platforms. + AUXV_AT_RANDOM = 25, ///< Address of 16 random bytes. + AUXV_AT_EXECFN = 31, ///< Filename of executable. + AUXV_AT_SYSINFO = 32, ///< Pointer to the global system page used for system + ///calls and other nice things. + AUXV_AT_SYSINFO_EHDR = 33, + AUXV_AT_L1I_CACHESHAPE = 34, ///< Shapes of the caches. + AUXV_AT_L1D_CACHESHAPE = 35, + AUXV_AT_L2_CACHESHAPE = 36, + AUXV_AT_L3_CACHESHAPE = 37, }; private: diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp index 0092535648bd..a7afeb6d68c3 100644 --- a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp +++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp @@ -576,7 +576,7 @@ addr_t DynamicLoaderPOSIXDYLD::ComputeLoadOffset() { } void DynamicLoaderPOSIXDYLD::EvalVdsoStatus() { - AuxVector::iterator I = m_auxv->FindEntry(AuxVector::AT_SYSINFO_EHDR); + AuxVector::iterator I = m_auxv->FindEntry(AuxVector::AUXV_AT_SYSINFO_EHDR); if (I != m_auxv->end()) m_vdso_base = I->value; @@ -589,7 +589,7 @@ addr_t DynamicLoaderPOSIXDYLD::GetEntryPoint() { if (m_auxv.get() == NULL) return LLDB_INVALID_ADDRESS; - AuxVector::iterator I = m_auxv->FindEntry(AuxVector::AT_ENTRY); + AuxVector::iterator I = m_auxv->FindEntry(AuxVector::AUXV_AT_ENTRY); if (I == m_auxv->end()) return LLDB_INVALID_ADDRESS; diff --git a/source/Plugins/InstrumentationRuntime/ASan/ASanRuntime.cpp b/source/Plugins/InstrumentationRuntime/ASan/ASanRuntime.cpp index af242d786a5f..9a6e39be0bfd 100644 --- a/source/Plugins/InstrumentationRuntime/ASan/ASanRuntime.cpp +++ b/source/Plugins/InstrumentationRuntime/ASan/ASanRuntime.cpp @@ -247,12 +247,16 @@ bool AddressSanitizerRuntime::NotifyBreakpointHit( AddressSanitizerRuntime *const instance = static_cast(baton); + ProcessSP process_sp = instance->GetProcessSP(); + + if (process_sp->GetModIDRef().IsLastResumeForUserExpression()) + return false; + StructuredData::ObjectSP report = instance->RetrieveReportData(); std::string description; if (report) { description = instance->FormatDescription(report); } - ProcessSP process_sp = instance->GetProcessSP(); // Make sure this is the right process if (process_sp && process_sp == context->exe_ctx_ref.GetProcessSP()) { ThreadSP thread_sp = context->exe_ctx_ref.GetThreadSP(); diff --git a/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp b/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp index 3c22b81df7a4..eb238419ab18 100644 --- a/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp +++ b/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp @@ -141,7 +141,7 @@ MainThreadCheckerRuntime::RetrieveReportData(ExecutionContextRef exe_ctx_ref) { d->AddStringItem("class_name", className); d->AddStringItem("selector", selector); d->AddStringItem("description", - apiName + " must be called from main thread only"); + apiName + " must be used from main thread only"); d->AddIntegerItem("tid", thread_sp->GetIndexID()); d->AddItem("trace", trace_sp); return dict_sp; @@ -163,6 +163,9 @@ bool MainThreadCheckerRuntime::NotifyBreakpointHit( process_sp != context->exe_ctx_ref.GetProcessSP()) return false; + if (process_sp->GetModIDRef().IsLastResumeForUserExpression()) + return false; + StructuredData::ObjectSP report = instance->RetrieveReportData(context->exe_ctx_ref); diff --git a/source/Plugins/InstrumentationRuntime/TSan/TSanRuntime.cpp b/source/Plugins/InstrumentationRuntime/TSan/TSanRuntime.cpp index f60df0463346..cf9ba60c7b60 100644 --- a/source/Plugins/InstrumentationRuntime/TSan/TSanRuntime.cpp +++ b/source/Plugins/InstrumentationRuntime/TSan/TSanRuntime.cpp @@ -803,6 +803,11 @@ bool ThreadSanitizerRuntime::NotifyBreakpointHit( ThreadSanitizerRuntime *const instance = static_cast(baton); + ProcessSP process_sp = instance->GetProcessSP(); + + if (process_sp->GetModIDRef().IsLastResumeForUserExpression()) + return false; + StructuredData::ObjectSP report = instance->RetrieveReportData(context->exe_ctx_ref); std::string stop_reason_description; @@ -851,7 +856,6 @@ bool ThreadSanitizerRuntime::NotifyBreakpointHit( all_addresses_are_same); } - ProcessSP process_sp = instance->GetProcessSP(); // Make sure this is the right process if (process_sp && process_sp == context->exe_ctx_ref.GetProcessSP()) { ThreadSP thread_sp = context->exe_ctx_ref.GetThreadSP(); diff --git a/source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.cpp b/source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.cpp index 023af84179aa..28c28e41ef44 100644 --- a/source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.cpp +++ b/source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.cpp @@ -217,6 +217,9 @@ bool UndefinedBehaviorSanitizerRuntime::NotifyBreakpointHit( process_sp != context->exe_ctx_ref.GetProcessSP()) return false; + if (process_sp->GetModIDRef().IsLastResumeForUserExpression()) + return false; + StructuredData::ObjectSP report = instance->RetrieveReportData(context->exe_ctx_ref); diff --git a/source/Plugins/Language/ObjC/Cocoa.cpp b/source/Plugins/Language/ObjC/Cocoa.cpp index 2ba005e02ad4..8f4997533212 100644 --- a/source/Plugins/Language/ObjC/Cocoa.cpp +++ b/source/Plugins/Language/ObjC/Cocoa.cpp @@ -543,6 +543,7 @@ bool lldb_private::formatters::NSNumberSummaryProvider( } uint64_t value = 0; + bool success = false; switch (type_code) { case TypeCodes::sint8: value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 1, 0, @@ -550,6 +551,7 @@ bool lldb_private::formatters::NSNumberSummaryProvider( if (error.Fail()) return false; NSNumber_FormatChar(valobj, stream, (char)value, options.GetLanguage()); + success = true; break; case TypeCodes::sint16: value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 2, 0, @@ -558,6 +560,7 @@ bool lldb_private::formatters::NSNumberSummaryProvider( return false; NSNumber_FormatShort(valobj, stream, (short)value, options.GetLanguage()); + success = true; break; case TypeCodes::sint32: value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, @@ -565,6 +568,7 @@ bool lldb_private::formatters::NSNumberSummaryProvider( if (error.Fail()) return false; NSNumber_FormatInt(valobj, stream, (int)value, options.GetLanguage()); + success = true; break; case TypeCodes::sint64: value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, @@ -572,6 +576,7 @@ bool lldb_private::formatters::NSNumberSummaryProvider( if (error.Fail()) return false; NSNumber_FormatLong(valobj, stream, value, options.GetLanguage()); + success = true; break; case TypeCodes::f32: { @@ -582,6 +587,7 @@ bool lldb_private::formatters::NSNumberSummaryProvider( float flt_value = 0.0f; memcpy(&flt_value, &flt_as_int, sizeof(flt_as_int)); NSNumber_FormatFloat(valobj, stream, flt_value, options.GetLanguage()); + success = true; break; } case TypeCodes::f64: @@ -593,6 +599,7 @@ bool lldb_private::formatters::NSNumberSummaryProvider( double dbl_value = 0.0; memcpy(&dbl_value, &dbl_as_lng, sizeof(dbl_as_lng)); NSNumber_FormatDouble(valobj, stream, dbl_value, options.GetLanguage()); + success = true; break; } case TypeCodes::sint128: // internally, this is the same @@ -608,12 +615,11 @@ bool lldb_private::formatters::NSNumberSummaryProvider( return false; llvm::APInt i128_value(128, words); NSNumber_FormatInt128(valobj, stream, i128_value, options.GetLanguage()); + success = true; break; } - default: - return false; } - return true; + return success; } } diff --git a/source/Plugins/Platform/Android/PlatformAndroid.cpp b/source/Plugins/Platform/Android/PlatformAndroid.cpp index d896a9f99e63..0f37da60d5d6 100644 --- a/source/Plugins/Platform/Android/PlatformAndroid.cpp +++ b/source/Plugins/Platform/Android/PlatformAndroid.cpp @@ -366,13 +366,17 @@ bool PlatformAndroid::GetRemoteOSVersion() { return m_major_os_version != 0; } -const char *PlatformAndroid::GetLibdlFunctionDeclarations() const { - return R"( +llvm::StringRef PlatformAndroid::GetLibdlFunctionDeclarations() { + // Older platform versions have the dl function symbols mangled + if (GetSdkVersion() < 26) + return R"( extern "C" void* dlopen(const char*, int) asm("__dl_dlopen"); extern "C" void* dlsym(void*, const char*) asm("__dl_dlsym"); extern "C" int dlclose(void*) asm("__dl_dlclose"); extern "C" char* dlerror(void) asm("__dl_dlerror"); )"; + + return PlatformPOSIX::GetLibdlFunctionDeclarations(); } AdbClient::SyncService *PlatformAndroid::GetSyncService(Status &error) { diff --git a/source/Plugins/Platform/Android/PlatformAndroid.h b/source/Plugins/Platform/Android/PlatformAndroid.h index 8fb4cc71a69f..638dba973369 100644 --- a/source/Plugins/Platform/Android/PlatformAndroid.h +++ b/source/Plugins/Platform/Android/PlatformAndroid.h @@ -76,7 +76,7 @@ class PlatformAndroid : public platform_linux::PlatformLinux { Status DownloadSymbolFile(const lldb::ModuleSP &module_sp, const FileSpec &dst_file_spec) override; - const char *GetLibdlFunctionDeclarations() const override; + llvm::StringRef GetLibdlFunctionDeclarations() override; private: AdbClient::SyncService *GetSyncService(Status &error); diff --git a/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp b/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp index f4cf22ad7583..013c33def13b 100644 --- a/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp +++ b/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp @@ -884,7 +884,7 @@ void PlatformPOSIX::CalculateTrapHandlerSymbolNames() { Status PlatformPOSIX::EvaluateLibdlExpression( lldb_private::Process *process, const char *expr_cstr, - const char *expr_prefix, lldb::ValueObjectSP &result_valobj_sp) { + llvm::StringRef expr_prefix, lldb::ValueObjectSP &result_valobj_sp) { DynamicLoader *loader = process->GetDynamicLoader(); if (loader) { Status error = loader->CanLoadImage(); @@ -944,7 +944,7 @@ uint32_t PlatformPOSIX::DoLoadImage(lldb_private::Process *process, the_result; )", path); - const char *prefix = GetLibdlFunctionDeclarations(); + llvm::StringRef prefix = GetLibdlFunctionDeclarations(); lldb::ValueObjectSP result_valobj_sp; error = EvaluateLibdlExpression(process, expr.GetData(), prefix, result_valobj_sp); @@ -992,7 +992,7 @@ Status PlatformPOSIX::UnloadImage(lldb_private::Process *process, StreamString expr; expr.Printf("dlclose((void *)0x%" PRIx64 ")", image_addr); - const char *prefix = GetLibdlFunctionDeclarations(); + llvm::StringRef prefix = GetLibdlFunctionDeclarations(); lldb::ValueObjectSP result_valobj_sp; Status error = EvaluateLibdlExpression(process, expr.GetData(), prefix, result_valobj_sp); @@ -1024,7 +1024,7 @@ lldb::ProcessSP PlatformPOSIX::ConnectProcess(llvm::StringRef connect_url, error); } -const char *PlatformPOSIX::GetLibdlFunctionDeclarations() const { +llvm::StringRef PlatformPOSIX::GetLibdlFunctionDeclarations() { return R"( extern "C" void* dlopen(const char*, int); extern "C" void* dlsym(void*, const char*); diff --git a/source/Plugins/Platform/POSIX/PlatformPOSIX.h b/source/Plugins/Platform/POSIX/PlatformPOSIX.h index 742702b07b88..ebc36c2461db 100644 --- a/source/Plugins/Platform/POSIX/PlatformPOSIX.h +++ b/source/Plugins/Platform/POSIX/PlatformPOSIX.h @@ -198,10 +198,10 @@ class PlatformPOSIX : public lldb_private::Platform { lldb_private::Status EvaluateLibdlExpression(lldb_private::Process *process, const char *expr_cstr, - const char *expr_prefix, + llvm::StringRef expr_prefix, lldb::ValueObjectSP &result_valobj_sp); - virtual const char *GetLibdlFunctionDeclarations() const; + virtual llvm::StringRef GetLibdlFunctionDeclarations(); private: DISALLOW_COPY_AND_ASSIGN(PlatformPOSIX); diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp index 10dd14753914..a4f5f02dde62 100644 --- a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp +++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp @@ -746,15 +746,9 @@ ProcessMonitor::ProcessMonitor( if (!error.Success()) return; -WAIT_AGAIN: - // Wait for the operation thread to initialize. - if (sem_wait(&args->m_semaphore)) { - if (errno == EINTR) - goto WAIT_AGAIN; - else { - error.SetErrorToErrno(); - return; - } + if (llvm::sys::RetryAfterSignal(-1, sem_wait, &args->m_semaphore) == -1) { + error.SetErrorToErrno(); + return; } // Check that the launch was a success. @@ -790,15 +784,9 @@ ProcessMonitor::ProcessMonitor(ProcessFreeBSD *process, lldb::pid_t pid, if (!error.Success()) return; -WAIT_AGAIN: - // Wait for the operation thread to initialize. - if (sem_wait(&args->m_semaphore)) { - if (errno == EINTR) - goto WAIT_AGAIN; - else { - error.SetErrorToErrno(); - return; - } + if (llvm::sys::RetryAfterSignal(-1, sem_wait, &args->m_semaphore) == -1) { + error.SetErrorToErrno(); + return; } // Check that the attach was a success. diff --git a/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/source/Plugins/Process/Linux/NativeProcessLinux.cpp index 8e378802de9c..d988ee93a2bc 100644 --- a/source/Plugins/Process/Linux/NativeProcessLinux.cpp +++ b/source/Plugins/Process/Linux/NativeProcessLinux.cpp @@ -214,207 +214,122 @@ static Status EnsureFDFlags(int fd, int flags) { // Public Static Methods // ----------------------------------------------------------------------------- -Status NativeProcessProtocol::Launch( - ProcessLaunchInfo &launch_info, - NativeProcessProtocol::NativeDelegate &native_delegate, MainLoop &mainloop, - NativeProcessProtocolSP &native_process_sp) { +llvm::Expected +NativeProcessLinux::Factory::Launch(ProcessLaunchInfo &launch_info, + NativeDelegate &native_delegate, + MainLoop &mainloop) const { Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - Status error; + MaybeLogLaunchInfo(launch_info); - // Verify the working directory is valid if one was specified. - FileSpec working_dir{launch_info.GetWorkingDirectory()}; - if (working_dir && (!working_dir.ResolvePath() || - !llvm::sys::fs::is_directory(working_dir.GetPath()))) { - error.SetErrorStringWithFormat("No such file or directory: %s", - working_dir.GetCString()); - return error; + Status status; + ::pid_t pid = ProcessLauncherPosixFork() + .LaunchProcess(launch_info, status) + .GetProcessId(); + LLDB_LOG(log, "pid = {0:x}", pid); + if (status.Fail()) { + LLDB_LOG(log, "failed to launch process: {0}", status); + return status.ToError(); } - // Create the NativeProcessLinux in launch mode. - native_process_sp.reset(new NativeProcessLinux()); + // Wait for the child process to trap on its call to execve. + int wstatus; + ::pid_t wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &wstatus, 0); + assert(wpid == pid); + (void)wpid; + if (!WIFSTOPPED(wstatus)) { + LLDB_LOG(log, "Could not sync with inferior process: wstatus={1}", + WaitStatus::Decode(wstatus)); + return llvm::make_error("Could not sync with inferior process", + llvm::inconvertibleErrorCode()); + } + LLDB_LOG(log, "inferior started, now in stopped state"); - if (!native_process_sp->RegisterNativeDelegate(native_delegate)) { - native_process_sp.reset(); - error.SetErrorStringWithFormat("failed to register the native delegate"); - return error; + ArchSpec arch; + if ((status = ResolveProcessArchitecture(pid, arch)).Fail()) + return status.ToError(); + + // Set the architecture to the exe architecture. + LLDB_LOG(log, "pid = {0:x}, detected architecture {1}", pid, + arch.GetArchitectureName()); + + status = SetDefaultPtraceOpts(pid); + if (status.Fail()) { + LLDB_LOG(log, "failed to set default ptrace options: {0}", status); + return status.ToError(); } - error = std::static_pointer_cast(native_process_sp) - ->LaunchInferior(mainloop, launch_info); - - if (error.Fail()) { - native_process_sp.reset(); - LLDB_LOG(log, "failed to launch process: {0}", error); - return error; - } - - launch_info.SetProcessID(native_process_sp->GetID()); - - return error; + std::shared_ptr process_sp(new NativeProcessLinux( + pid, launch_info.GetPTY().ReleaseMasterFileDescriptor(), native_delegate, + arch, mainloop)); + process_sp->InitializeThreads({pid}); + return process_sp; } -Status NativeProcessProtocol::Attach( +llvm::Expected NativeProcessLinux::Factory::Attach( lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate, - MainLoop &mainloop, NativeProcessProtocolSP &native_process_sp) { + MainLoop &mainloop) const { Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); LLDB_LOG(log, "pid = {0:x}", pid); // Retrieve the architecture for the running process. - ArchSpec process_arch; - Status error = ResolveProcessArchitecture(pid, process_arch); - if (!error.Success()) - return error; + ArchSpec arch; + Status status = ResolveProcessArchitecture(pid, arch); + if (!status.Success()) + return status.ToError(); - std::shared_ptr native_process_linux_sp( - new NativeProcessLinux()); + auto tids_or = NativeProcessLinux::Attach(pid); + if (!tids_or) + return tids_or.takeError(); - if (!native_process_linux_sp->RegisterNativeDelegate(native_delegate)) { - error.SetErrorStringWithFormat("failed to register the native delegate"); - return error; - } - - native_process_linux_sp->AttachToInferior(mainloop, pid, error); - if (!error.Success()) - return error; - - native_process_sp = native_process_linux_sp; - return error; + std::shared_ptr process_sp( + new NativeProcessLinux(pid, -1, native_delegate, arch, mainloop)); + process_sp->InitializeThreads(*tids_or); + return process_sp; } // ----------------------------------------------------------------------------- // Public Instance Methods // ----------------------------------------------------------------------------- -NativeProcessLinux::NativeProcessLinux() - : NativeProcessProtocol(LLDB_INVALID_PROCESS_ID), m_arch(), - m_supports_mem_region(eLazyBoolCalculate), m_mem_region_cache(), - m_pending_notification_tid(LLDB_INVALID_THREAD_ID), - m_pt_proces_trace_id(LLDB_INVALID_UID) {} - -void NativeProcessLinux::AttachToInferior(MainLoop &mainloop, lldb::pid_t pid, - Status &error) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - LLDB_LOG(log, "pid = {0:x}", pid); +NativeProcessLinux::NativeProcessLinux(::pid_t pid, int terminal_fd, + NativeDelegate &delegate, + const ArchSpec &arch, MainLoop &mainloop) + : NativeProcessProtocol(pid, terminal_fd, delegate), m_arch(arch) { + if (m_terminal_fd != -1) { + Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK); + assert(status.Success()); + } + Status status; m_sigchld_handle = mainloop.RegisterSignal( - SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, error); - if (!m_sigchld_handle) - return; - - error = ResolveProcessArchitecture(pid, m_arch); - if (!error.Success()) - return; - - // Set the architecture to the exe architecture. - LLDB_LOG(log, "pid = {0:x}, detected architecture {1}", pid, - m_arch.GetArchitectureName()); - m_pid = pid; - SetState(eStateAttaching); - - Attach(pid, error); + SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, status); + assert(m_sigchld_handle && status.Success()); } -Status NativeProcessLinux::LaunchInferior(MainLoop &mainloop, - ProcessLaunchInfo &launch_info) { - Status error; - m_sigchld_handle = mainloop.RegisterSignal( - SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, error); - if (!m_sigchld_handle) - return error; - - SetState(eStateLaunching); - - MaybeLogLaunchInfo(launch_info); - - ::pid_t pid = - ProcessLauncherPosixFork().LaunchProcess(launch_info, error).GetProcessId(); - if (error.Fail()) - return error; - - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - - // Wait for the child process to trap on its call to execve. - ::pid_t wpid; - int status; - if ((wpid = waitpid(pid, &status, 0)) < 0) { - error.SetErrorToErrno(); - LLDB_LOG(log, "waitpid for inferior failed with %s", error); - - // Mark the inferior as invalid. - // FIXME this could really use a new state - eStateLaunchFailure. For now, - // using eStateInvalid. - SetState(StateType::eStateInvalid); - - return error; +void NativeProcessLinux::InitializeThreads(llvm::ArrayRef<::pid_t> tids) { + for (const auto &tid : tids) { + NativeThreadLinuxSP thread_sp = AddThread(tid); + assert(thread_sp && "AddThread() returned a nullptr thread"); + thread_sp->SetStoppedBySignal(SIGSTOP); + ThreadWasCreated(*thread_sp); } - assert(WIFSTOPPED(status) && (wpid == static_cast<::pid_t>(pid)) && - "Could not sync with inferior process."); - - LLDB_LOG(log, "inferior started, now in stopped state"); - error = SetDefaultPtraceOpts(pid); - if (error.Fail()) { - LLDB_LOG(log, "failed to set default ptrace options: {0}", error); - - // Mark the inferior as invalid. - // FIXME this could really use a new state - eStateLaunchFailure. For now, - // using eStateInvalid. - SetState(StateType::eStateInvalid); - - return error; - } - - // Release the master terminal descriptor and pass it off to the - // NativeProcessLinux instance. Similarly stash the inferior pid. - m_terminal_fd = launch_info.GetPTY().ReleaseMasterFileDescriptor(); - m_pid = pid; - launch_info.SetProcessID(pid); - - if (m_terminal_fd != -1) { - error = EnsureFDFlags(m_terminal_fd, O_NONBLOCK); - if (error.Fail()) { - LLDB_LOG(log, - "inferior EnsureFDFlags failed for ensuring terminal " - "O_NONBLOCK setting: {0}", - error); - - // Mark the inferior as invalid. - // FIXME this could really use a new state - eStateLaunchFailure. For - // now, using eStateInvalid. - SetState(StateType::eStateInvalid); - - return error; - } - } - - LLDB_LOG(log, "adding pid = {0}", pid); - ResolveProcessArchitecture(m_pid, m_arch); - NativeThreadLinuxSP thread_sp = AddThread(pid); - assert(thread_sp && "AddThread() returned a nullptr thread"); - thread_sp->SetStoppedBySignal(SIGSTOP); - ThreadWasCreated(*thread_sp); // Let our process instance know the thread has stopped. - SetCurrentThreadID(thread_sp->GetID()); - SetState(StateType::eStateStopped); + SetCurrentThreadID(tids[0]); + SetState(StateType::eStateStopped, false); - if (error.Fail()) - LLDB_LOG(log, "inferior launching failed {0}", error); - return error; + // Proccess any signals we received before installing our handler + SigchldHandler(); } -::pid_t NativeProcessLinux::Attach(lldb::pid_t pid, Status &error) { +llvm::Expected> NativeProcessLinux::Attach(::pid_t pid) { Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + Status status; // Use a map to keep track of the threads which we have attached/need to // attach. Host::TidMap tids_to_attach; - if (pid <= 1) { - error.SetErrorToGenericError(); - error.SetErrorString("Attaching to process 1 is not allowed."); - return -1; - } - while (Host::FindProcessThreads(pid, tids_to_attach)) { for (Host::TidMap::iterator it = tids_to_attach.begin(); it != tids_to_attach.end();) { @@ -423,48 +338,36 @@ ::pid_t NativeProcessLinux::Attach(lldb::pid_t pid, Status &error) { // Attach to the requested process. // An attach will cause the thread to stop with a SIGSTOP. - error = PtraceWrapper(PTRACE_ATTACH, tid); - if (error.Fail()) { + if ((status = PtraceWrapper(PTRACE_ATTACH, tid)).Fail()) { // No such thread. The thread may have exited. // More error handling may be needed. - if (error.GetError() == ESRCH) { + if (status.GetError() == ESRCH) { it = tids_to_attach.erase(it); continue; - } else - return -1; + } + return status.ToError(); } - int status; + int wpid = + llvm::sys::RetryAfterSignal(-1, ::waitpid, tid, nullptr, __WALL); // Need to use __WALL otherwise we receive an error with errno=ECHLD // At this point we should have a thread stopped if waitpid succeeds. - if ((status = waitpid(tid, NULL, __WALL)) < 0) { + if (wpid < 0) { // No such thread. The thread may have exited. // More error handling may be needed. if (errno == ESRCH) { it = tids_to_attach.erase(it); continue; - } else { - error.SetErrorToErrno(); - return -1; } + return llvm::errorCodeToError( + std::error_code(errno, std::generic_category())); } - error = SetDefaultPtraceOpts(tid); - if (error.Fail()) - return -1; + if ((status = SetDefaultPtraceOpts(tid)).Fail()) + return status.ToError(); LLDB_LOG(log, "adding tid = {0}", tid); it->second = true; - - // Create the thread, mark it as stopped. - NativeThreadLinuxSP thread_sp(AddThread(static_cast(tid))); - assert(thread_sp && "AddThread() returned a nullptr"); - - // This will notify this is a new thread and tell the system it is - // stopped. - thread_sp->SetStoppedBySignal(SIGSTOP); - ThreadWasCreated(*thread_sp); - SetCurrentThreadID(thread_sp->GetID()); } // move the loop forward @@ -472,17 +375,16 @@ ::pid_t NativeProcessLinux::Attach(lldb::pid_t pid, Status &error) { } } - if (tids_to_attach.size() > 0) { - m_pid = pid; - // Let our process instance know the thread has stopped. - SetState(StateType::eStateStopped); - } else { - error.SetErrorToGenericError(); - error.SetErrorString("No such process."); - return -1; - } + size_t tid_count = tids_to_attach.size(); + if (tid_count == 0) + return llvm::make_error("No such process", + llvm::inconvertibleErrorCode()); - return pid; + std::vector<::pid_t> tids; + tids.reserve(tid_count); + for (const auto &p : tids_to_attach) + tids.push_back(p.first); + return std::move(tids); } Status NativeProcessLinux::SetDefaultPtraceOpts(lldb::pid_t pid) { @@ -662,14 +564,11 @@ void NativeProcessLinux::WaitForNewThread(::pid_t tid) { // The thread is not tracked yet, let's wait for it to appear. int status = -1; - ::pid_t wait_pid; - do { - LLDB_LOG(log, - "received thread creation event for tid {0}. tid not tracked " - "yet, waiting for thread to appear...", - tid); - wait_pid = waitpid(tid, &status, __WALL); - } while (wait_pid == -1 && errno == EINTR); + LLDB_LOG(log, + "received thread creation event for tid {0}. tid not tracked " + "yet, waiting for thread to appear...", + tid); + ::pid_t wait_pid = llvm::sys::RetryAfterSignal(-1, ::waitpid, tid, &status, __WALL); // Since we are waiting on a specific tid, this must be the creation event. // But let's do some checks just in case. if (wait_pid != tid) { @@ -897,11 +796,9 @@ void NativeProcessLinux::MonitorSIGTRAP(const siginfo_t &info, break; default: - LLDB_LOG( - log, - "received unknown SIGTRAP stop event ({0}, pid {1} tid {2}, resuming", - info.si_code, GetID(), thread.GetID()); - llvm_unreachable("Unexpected SIGTRAP code!"); + LLDB_LOG(log, "received unknown SIGTRAP stop event ({0}, pid {1} tid {2}", + info.si_code, GetID(), thread.GetID()); + MonitorSignal(info, thread, false); break; } } @@ -2363,15 +2260,13 @@ void NativeProcessLinux::SigchldHandler() { // Process all pending waitpid notifications. while (true) { int status = -1; - ::pid_t wait_pid = waitpid(-1, &status, __WALL | __WNOTHREAD | WNOHANG); + ::pid_t wait_pid = llvm::sys::RetryAfterSignal(-1, ::waitpid, -1, &status, + __WALL | __WNOTHREAD | WNOHANG); if (wait_pid == 0) break; // We are done. if (wait_pid == -1) { - if (errno == EINTR) - continue; - Status error(errno, eErrorTypePOSIX); LLDB_LOG(log, "waitpid (-1, &status, _) failed: {0}", error); break; diff --git a/source/Plugins/Process/Linux/NativeProcessLinux.h b/source/Plugins/Process/Linux/NativeProcessLinux.h index 6bf093f6a39a..9584713d3654 100644 --- a/source/Plugins/Process/Linux/NativeProcessLinux.h +++ b/source/Plugins/Process/Linux/NativeProcessLinux.h @@ -39,15 +39,18 @@ namespace process_linux { /// /// Changes in the inferior process state are broadcasted. class NativeProcessLinux : public NativeProcessProtocol { - friend Status NativeProcessProtocol::Launch( - ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate, - MainLoop &mainloop, NativeProcessProtocolSP &process_sp); - - friend Status NativeProcessProtocol::Attach( - lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate, - MainLoop &mainloop, NativeProcessProtocolSP &process_sp); - public: + class Factory : public NativeProcessProtocol::Factory { + public: + llvm::Expected + Launch(ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate, + MainLoop &mainloop) const override; + + llvm::Expected + Attach(lldb::pid_t pid, NativeDelegate &native_delegate, + MainLoop &mainloop) const override; + }; + // --------------------------------------------------------------------- // NativeProcessProtocol Interface // --------------------------------------------------------------------- @@ -144,10 +147,10 @@ class NativeProcessLinux : public NativeProcessProtocol { MainLoop::SignalHandleUP m_sigchld_handle; ArchSpec m_arch; - LazyBool m_supports_mem_region; + LazyBool m_supports_mem_region = eLazyBoolCalculate; std::vector> m_mem_region_cache; - lldb::tid_t m_pending_notification_tid; + lldb::tid_t m_pending_notification_tid = LLDB_INVALID_THREAD_ID; // List of thread ids stepping with a breakpoint with the address of // the relevan breakpoint @@ -156,19 +159,15 @@ class NativeProcessLinux : public NativeProcessProtocol { // --------------------------------------------------------------------- // Private Instance Methods // --------------------------------------------------------------------- - NativeProcessLinux(); + NativeProcessLinux(::pid_t pid, int terminal_fd, NativeDelegate &delegate, + const ArchSpec &arch, MainLoop &mainloop); - Status LaunchInferior(MainLoop &mainloop, ProcessLaunchInfo &launch_info); - - /// Attaches to an existing process. Forms the - /// implementation of Process::DoAttach - void AttachToInferior(MainLoop &mainloop, lldb::pid_t pid, Status &error); - - ::pid_t Attach(lldb::pid_t pid, Status &error); + // Returns a list of process threads that we have attached to. + static llvm::Expected> Attach(::pid_t pid); static Status SetDefaultPtraceOpts(const lldb::pid_t); - static void *MonitorThread(void *baton); + void InitializeThreads(llvm::ArrayRef<::pid_t> tids); void MonitorCallback(lldb::pid_t pid, bool exited, WaitStatus status); @@ -280,7 +279,7 @@ class NativeProcessLinux : public NativeProcessProtocol { // same process user id. llvm::DenseSet m_pt_traced_thread_group; - lldb::user_id_t m_pt_proces_trace_id; + lldb::user_id_t m_pt_proces_trace_id = LLDB_INVALID_UID; TraceOptions m_pt_process_trace_config; }; diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp index c3b58f16256a..1a5b304ac697 100644 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp @@ -680,7 +680,7 @@ Status NativeRegisterContextLinux_arm64::ClearAllHardwareWatchpoints() { return error; lldb::addr_t tempAddr = 0; - uint32_t tempControl = 0, tempRefCount = 0; + uint32_t tempControl = 0; for (uint32_t i = 0; i < m_max_hwp_supported; i++) { if (m_hwp_regs[i].control & 0x01) { @@ -858,7 +858,7 @@ Status NativeRegisterContextLinux_arm64::DoReadRegisterValue( RegisterValue &value) { Status error; if (offset > sizeof(struct user_pt_regs)) { - uintptr_t offset = offset - sizeof(struct user_pt_regs); + offset -= sizeof(struct user_pt_regs); if (offset > sizeof(struct user_fpsimd_state)) { error.SetErrorString("invalid offset value"); return error; @@ -905,7 +905,7 @@ Status NativeRegisterContextLinux_arm64::DoWriteRegisterValue( Status error; ::pid_t tid = m_thread.GetID(); if (offset > sizeof(struct user_pt_regs)) { - uintptr_t offset = offset - sizeof(struct user_pt_regs); + offset -= sizeof(struct user_pt_regs); if (offset > sizeof(struct user_fpsimd_state)) { error.SetErrorString("invalid offset value"); return error; diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp index 59dc9e9f7d45..e44e03b46b5c 100755 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp @@ -646,13 +646,6 @@ Status NativeRegisterContextLinux_x86_64::ReadAllRegisterValues( Status error; data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); - if (!data_sp) { - error.SetErrorStringWithFormat( - "failed to allocate DataBufferHeap instance of size %" PRIu64, - REG_CONTEXT_SIZE); - return error; - } - error = ReadGPR(); if (error.Fail()) return error; @@ -662,13 +655,6 @@ Status NativeRegisterContextLinux_x86_64::ReadAllRegisterValues( return error; uint8_t *dst = data_sp->GetBytes(); - if (dst == nullptr) { - error.SetErrorStringWithFormat("DataBufferHeap instance of size %" PRIu64 - " returned a null pointer", - REG_CONTEXT_SIZE); - return error; - } - ::memcpy(dst, &m_gpr_x86_64, GetRegisterInfoInterface().GetGPRSize()); dst += GetRegisterInfoInterface().GetGPRSize(); if (m_xstate_type == XStateType::FXSAVE) @@ -741,10 +727,9 @@ Status NativeRegisterContextLinux_x86_64::WriteAllRegisterValues( } if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { - error.SetErrorStringWithFormat( - "NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched " - "data size, expected %" PRIu64 ", actual %" PRIu64, - __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); + error.SetErrorStringWithFormatv( + "data_sp contained mismatched data size, expected {0}, actual {1}", + REG_CONTEXT_SIZE, data_sp->GetByteSize()); return error; } diff --git a/source/Plugins/Process/Linux/ProcessorTrace.cpp b/source/Plugins/Process/Linux/ProcessorTrace.cpp index 7043d50256e6..505c526ab70d 100644 --- a/source/Plugins/Process/Linux/ProcessorTrace.cpp +++ b/source/Plugins/Process/Linux/ProcessorTrace.cpp @@ -46,13 +46,11 @@ Status ProcessorTraceMonitor::GetTraceConfig(TraceOptions &config) const { Status ProcessorTraceMonitor::StartTrace(lldb::pid_t pid, lldb::tid_t tid, const TraceOptions &config) { - Status error; - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); - LLDB_LOG(log, "{0}", config.getThreadID()); - #ifndef PERF_ATTR_SIZE_VER5 llvm_unreachable("perf event not supported"); #else + Status error; + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); LLDB_LOG(log, "called thread id {0}", tid); uint64_t page_size = getpagesize(); @@ -61,12 +59,11 @@ Status ProcessorTraceMonitor::StartTrace(lldb::pid_t pid, lldb::tid_t tid, uint64_t numpages = static_cast( llvm::PowerOf2Floor((bufsize + page_size - 1) / page_size)); - numpages = std::max(1ul, numpages); + numpages = std::max(1, numpages); bufsize = page_size * numpages; numpages = static_cast( llvm::PowerOf2Floor((metabufsize + page_size - 1) / page_size)); - numpages = std::max(0ul, numpages); metabufsize = page_size * numpages; perf_event_attr attr; @@ -117,7 +114,7 @@ Status ProcessorTraceMonitor::StartTrace(lldb::pid_t pid, lldb::tid_t tid, return error; } - m_fd = std::move(std::unique_ptr(new int(fd), file_close())); + m_fd = std::unique_ptr(new int(fd), file_close()); errno = 0; auto base = @@ -129,9 +126,9 @@ Status ProcessorTraceMonitor::StartTrace(lldb::pid_t pid, lldb::tid_t tid, return error; } - m_mmap_meta = std::move(std::unique_ptr( + m_mmap_meta = std::unique_ptr( reinterpret_cast(base), - munmap_delete(metabufsize + page_size))); + munmap_delete(metabufsize + page_size)); m_mmap_meta->aux_offset = m_mmap_meta->data_offset + m_mmap_meta->data_size; m_mmap_meta->aux_size = bufsize; @@ -145,10 +142,10 @@ Status ProcessorTraceMonitor::StartTrace(lldb::pid_t pid, lldb::tid_t tid, error.SetErrorString("Trace buffer allocation failed"); return error; } - m_mmap_aux = std::move(std::unique_ptr( - reinterpret_cast(mmap_aux), munmap_delete(bufsize))); -#endif + m_mmap_aux = std::unique_ptr( + reinterpret_cast(mmap_aux), munmap_delete(bufsize)); return error; +#endif } llvm::MutableArrayRef ProcessorTraceMonitor::GetDataBuffer() { @@ -251,14 +248,14 @@ ProcessorTraceMonitor::Create(lldb::pid_t pid, lldb::tid_t tid, Status error; if (tid == LLDB_INVALID_THREAD_ID) { error.SetErrorString("thread not specified"); - return std::move(error.ToError()); + return error.ToError(); } ProcessorTraceMonitorUP pt_monitor_up(new ProcessorTraceMonitor); error = pt_monitor_up->StartTrace(pid, tid, config); if (error.Fail()) - return std::move(error.ToError()); + return error.ToError(); pt_monitor_up->SetThreadID(tid); @@ -274,13 +271,11 @@ ProcessorTraceMonitor::Create(lldb::pid_t pid, lldb::tid_t tid, Status ProcessorTraceMonitor::ReadPerfTraceAux(llvm::MutableArrayRef &buffer, size_t offset) { - - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); - Status error; - #ifndef PERF_ATTR_SIZE_VER5 llvm_unreachable("perf event not supported"); #else + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); + Status error; uint64_t head = m_mmap_meta->aux_head; LLDB_LOG(log, "Aux size -{0} , Head - {1}", m_mmap_meta->aux_size, head); @@ -306,12 +301,12 @@ ProcessorTraceMonitor::ReadPerfTraceAux(llvm::MutableArrayRef &buffer, Status ProcessorTraceMonitor::ReadPerfTraceData(llvm::MutableArrayRef &buffer, size_t offset) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); - uint64_t bytes_remaining = buffer.size(); - Status error; #ifndef PERF_ATTR_SIZE_VER5 llvm_unreachable("perf event not supported"); #else + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); + uint64_t bytes_remaining = buffer.size(); + Status error; uint64_t head = m_mmap_meta->data_head; diff --git a/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp b/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp index a4d775860a65..b9ef02efa65d 100644 --- a/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp +++ b/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp @@ -21,6 +21,7 @@ #include "lldb/Host/common/NativeRegisterContext.h" #include "lldb/Host/posix/ProcessLauncherPosixFork.h" #include "lldb/Target/Process.h" +#include "llvm/Support/Errno.h" // System includes - They have to be included after framework includes because // they define some @@ -63,81 +64,101 @@ static Status EnsureFDFlags(int fd, int flags) { // Public Static Methods // ----------------------------------------------------------------------------- -Status NativeProcessProtocol::Launch( - ProcessLaunchInfo &launch_info, - NativeProcessProtocol::NativeDelegate &native_delegate, MainLoop &mainloop, - NativeProcessProtocolSP &native_process_sp) { +llvm::Expected +NativeProcessNetBSD::Factory::Launch(ProcessLaunchInfo &launch_info, + NativeDelegate &native_delegate, + MainLoop &mainloop) const { Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - Status error; - - // Verify the working directory is valid if one was specified. - FileSpec working_dir{launch_info.GetWorkingDirectory()}; - if (working_dir && (!working_dir.ResolvePath() || - !llvm::sys::fs::is_directory(working_dir.GetPath()))) { - error.SetErrorStringWithFormat("No such file or directory: %s", - working_dir.GetCString()); - return error; + Status status; + ::pid_t pid = ProcessLauncherPosixFork() + .LaunchProcess(launch_info, status) + .GetProcessId(); + LLDB_LOG(log, "pid = {0:x}", pid); + if (status.Fail()) { + LLDB_LOG(log, "failed to launch process: {0}", status); + return status.ToError(); } - // Create the NativeProcessNetBSD in launch mode. - native_process_sp.reset(new NativeProcessNetBSD()); - - if (!native_process_sp->RegisterNativeDelegate(native_delegate)) { - native_process_sp.reset(); - error.SetErrorStringWithFormat("failed to register the native delegate"); - return error; + // Wait for the child process to trap on its call to execve. + int wstatus; + ::pid_t wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &wstatus, 0); + assert(wpid == pid); + (void)wpid; + if (!WIFSTOPPED(wstatus)) { + LLDB_LOG(log, "Could not sync with inferior process: wstatus={1}", + WaitStatus::Decode(wstatus)); + return llvm::make_error("Could not sync with inferior process", + llvm::inconvertibleErrorCode()); } + LLDB_LOG(log, "inferior started, now in stopped state"); - error = std::static_pointer_cast(native_process_sp) - ->LaunchInferior(mainloop, launch_info); + ArchSpec arch; + if ((status = ResolveProcessArchitecture(pid, arch)).Fail()) + return status.ToError(); - if (error.Fail()) { - native_process_sp.reset(); - LLDB_LOG(log, "failed to launch process: {0}", error); - return error; + // Set the architecture to the exe architecture. + LLDB_LOG(log, "pid = {0:x}, detected architecture {1}", pid, + arch.GetArchitectureName()); + + std::shared_ptr process_sp(new NativeProcessNetBSD( + pid, launch_info.GetPTY().ReleaseMasterFileDescriptor(), native_delegate, + arch, mainloop)); + + status = process_sp->ReinitializeThreads(); + if (status.Fail()) + return status.ToError(); + + for (const auto &thread_sp : process_sp->m_threads) { + static_pointer_cast(thread_sp)->SetStoppedBySignal( + SIGSTOP); } + process_sp->SetState(StateType::eStateStopped); - launch_info.SetProcessID(native_process_sp->GetID()); - - return error; + return process_sp; } -Status NativeProcessProtocol::Attach( +llvm::Expected NativeProcessNetBSD::Factory::Attach( lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate, - MainLoop &mainloop, NativeProcessProtocolSP &native_process_sp) { + MainLoop &mainloop) const { Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); LLDB_LOG(log, "pid = {0:x}", pid); // Retrieve the architecture for the running process. - ArchSpec process_arch; - Status error = ResolveProcessArchitecture(pid, process_arch); - if (!error.Success()) - return error; + ArchSpec arch; + Status status = ResolveProcessArchitecture(pid, arch); + if (!status.Success()) + return status.ToError(); - std::shared_ptr native_process_netbsd_sp( - new NativeProcessNetBSD()); + std::shared_ptr process_sp( + new NativeProcessNetBSD(pid, -1, native_delegate, arch, mainloop)); - if (!native_process_netbsd_sp->RegisterNativeDelegate(native_delegate)) { - error.SetErrorStringWithFormat("failed to register the native delegate"); - return error; - } + status = process_sp->Attach(); + if (!status.Success()) + return status.ToError(); - native_process_netbsd_sp->AttachToInferior(mainloop, pid, error); - if (!error.Success()) - return error; - - native_process_sp = native_process_netbsd_sp; - return error; + return process_sp; } // ----------------------------------------------------------------------------- // Public Instance Methods // ----------------------------------------------------------------------------- -NativeProcessNetBSD::NativeProcessNetBSD() - : NativeProcessProtocol(LLDB_INVALID_PROCESS_ID), m_arch(), - m_supports_mem_region(eLazyBoolCalculate), m_mem_region_cache() {} +NativeProcessNetBSD::NativeProcessNetBSD(::pid_t pid, int terminal_fd, + NativeDelegate &delegate, + const ArchSpec &arch, + MainLoop &mainloop) + : NativeProcessProtocol(pid, terminal_fd, delegate), m_arch(arch) { + if (m_terminal_fd != -1) { + Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK); + assert(status.Success()); + } + + Status status; + m_sigchld_handle = mainloop.RegisterSignal( + SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, status); + assert(m_sigchld_handle && status.Success()); +} // Handles all waitpid events from the inferior process. void NativeProcessNetBSD::MonitorCallback(lldb::pid_t pid, int signal) { @@ -709,126 +730,17 @@ Status NativeProcessNetBSD::GetFileLoadAddress(const llvm::StringRef &file_name, return Status(); } -Status NativeProcessNetBSD::LaunchInferior(MainLoop &mainloop, - ProcessLaunchInfo &launch_info) { - Status error; - m_sigchld_handle = mainloop.RegisterSignal( - SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, error); - if (!m_sigchld_handle) - return error; - - SetState(eStateLaunching); - - ::pid_t pid = ProcessLauncherPosixFork() - .LaunchProcess(launch_info, error) - .GetProcessId(); - if (error.Fail()) - return error; - - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - - // Wait for the child process to trap on its call to execve. - ::pid_t wpid; - int status; - if ((wpid = waitpid(pid, &status, 0)) < 0) { - error.SetErrorToErrno(); - LLDB_LOG(log, "waitpid for inferior failed with %s", error); - - // Mark the inferior as invalid. - // FIXME this could really use a new state - eStateLaunchFailure. For - // now, using eStateInvalid. - SetState(StateType::eStateInvalid); - - return error; - } - assert(WIFSTOPPED(status) && (wpid == static_cast<::pid_t>(pid)) && - "Could not sync with inferior process."); - - LLDB_LOG(log, "inferior started, now in stopped state"); - - // Release the master terminal descriptor and pass it off to the - // NativeProcessNetBSD instance. Similarly stash the inferior pid. - m_terminal_fd = launch_info.GetPTY().ReleaseMasterFileDescriptor(); - m_pid = pid; - launch_info.SetProcessID(pid); - - if (m_terminal_fd != -1) { - error = EnsureFDFlags(m_terminal_fd, O_NONBLOCK); - if (error.Fail()) { - LLDB_LOG(log, - "inferior EnsureFDFlags failed for ensuring terminal " - "O_NONBLOCK setting: {0}", - error); - - // Mark the inferior as invalid. - // FIXME this could really use a new state - eStateLaunchFailure. For - // now, using eStateInvalid. - SetState(StateType::eStateInvalid); - - return error; - } - } - - LLDB_LOG(log, "adding pid = {0}", pid); - - ResolveProcessArchitecture(m_pid, m_arch); - - error = ReinitializeThreads(); - if (error.Fail()) { - SetState(StateType::eStateInvalid); - return error; - } - - for (const auto &thread_sp : m_threads) { - static_pointer_cast(thread_sp)->SetStoppedBySignal( - SIGSTOP); - } - - /* Set process stopped */ - SetState(StateType::eStateStopped); - - if (error.Fail()) - LLDB_LOG(log, "inferior launching failed {0}", error); - return error; -} - -void NativeProcessNetBSD::AttachToInferior(MainLoop &mainloop, lldb::pid_t pid, - Status &error) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - LLDB_LOG(log, "pid = {0:x}", pid); - - m_sigchld_handle = mainloop.RegisterSignal( - SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, error); - if (!m_sigchld_handle) - return; - - error = ResolveProcessArchitecture(pid, m_arch); - if (!error.Success()) - return; - - // Set the architecture to the exe architecture. - LLDB_LOG(log, "pid = {0:x}, detected architecture {1}", pid, - m_arch.GetArchitectureName()); - - m_pid = pid; - SetState(eStateAttaching); - - Attach(pid, error); -} - void NativeProcessNetBSD::SigchldHandler() { Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); // Process all pending waitpid notifications. int status; - ::pid_t wait_pid = waitpid(GetID(), &status, WALLSIG | WNOHANG); + ::pid_t wait_pid = + llvm::sys::RetryAfterSignal(-1, waitpid, GetID(), &status, WALLSIG | WNOHANG); if (wait_pid == 0) return; // We are done. if (wait_pid == -1) { - if (errno == EINTR) - return; - Status error(errno, eErrorTypePOSIX); LLDB_LOG(log, "waitpid ({0}, &status, _) failed: {1}", GetID(), error); } @@ -880,33 +792,23 @@ NativeThreadNetBSDSP NativeProcessNetBSD::AddThread(lldb::tid_t thread_id) { return thread_sp; } -::pid_t NativeProcessNetBSD::Attach(lldb::pid_t pid, Status &error) { - if (pid <= 1) { - error.SetErrorToGenericError(); - error.SetErrorString("Attaching to process 1 is not allowed."); - return -1; - } - +Status NativeProcessNetBSD::Attach() { // Attach to the requested process. // An attach will cause the thread to stop with a SIGSTOP. - error = PtraceWrapper(PT_ATTACH, pid); - if (error.Fail()) - return -1; + Status status = PtraceWrapper(PT_ATTACH, m_pid); + if (status.Fail()) + return status; - int status; + int wstatus; // Need to use WALLSIG otherwise we receive an error with errno=ECHLD // At this point we should have a thread stopped if waitpid succeeds. - if ((status = waitpid(pid, NULL, WALLSIG)) < 0) - return -1; - - m_pid = pid; + if ((wstatus = waitpid(m_pid, NULL, WALLSIG)) < 0) + return Status(errno, eErrorTypePOSIX); /* Initialize threads */ - error = ReinitializeThreads(); - if (error.Fail()) { - SetState(StateType::eStateInvalid); - return -1; - } + status = ReinitializeThreads(); + if (status.Fail()) + return status; for (const auto &thread_sp : m_threads) { static_pointer_cast(thread_sp)->SetStoppedBySignal( @@ -915,8 +817,7 @@ ::pid_t NativeProcessNetBSD::Attach(lldb::pid_t pid, Status &error) { // Let our process instance know the thread has stopped. SetState(StateType::eStateStopped); - - return pid; + return Status(); } Status NativeProcessNetBSD::ReadMemory(lldb::addr_t addr, void *buf, diff --git a/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h b/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h index 7a1303faea68..34b892f1fc88 100644 --- a/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h +++ b/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h @@ -31,15 +31,18 @@ namespace process_netbsd { /// /// Changes in the inferior process state are broadcasted. class NativeProcessNetBSD : public NativeProcessProtocol { - friend Status NativeProcessProtocol::Launch( - ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate, - MainLoop &mainloop, NativeProcessProtocolSP &process_sp); - - friend Status NativeProcessProtocol::Attach( - lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate, - MainLoop &mainloop, NativeProcessProtocolSP &process_sp); - public: + class Factory : public NativeProcessProtocol::Factory { + public: + llvm::Expected + Launch(ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate, + MainLoop &mainloop) const override; + + llvm::Expected + Attach(lldb::pid_t pid, NativeDelegate &native_delegate, + MainLoop &mainloop) const override; + }; + // --------------------------------------------------------------------- // NativeProcessProtocol Interface // --------------------------------------------------------------------- @@ -107,21 +110,19 @@ class NativeProcessNetBSD : public NativeProcessProtocol { private: MainLoop::SignalHandleUP m_sigchld_handle; ArchSpec m_arch; - LazyBool m_supports_mem_region; + LazyBool m_supports_mem_region = eLazyBoolCalculate; std::vector> m_mem_region_cache; // --------------------------------------------------------------------- // Private Instance Methods // --------------------------------------------------------------------- - NativeProcessNetBSD(); + NativeProcessNetBSD(::pid_t pid, int terminal_fd, NativeDelegate &delegate, + const ArchSpec &arch, MainLoop &mainloop); bool HasThreadNoLock(lldb::tid_t thread_id); NativeThreadNetBSDSP AddThread(lldb::tid_t thread_id); - Status LaunchInferior(MainLoop &mainloop, ProcessLaunchInfo &launch_info); - void AttachToInferior(MainLoop &mainloop, lldb::pid_t pid, Status &error); - void MonitorCallback(lldb::pid_t pid, int signal); void MonitorExited(lldb::pid_t pid, WaitStatus status); void MonitorSIGSTOP(lldb::pid_t pid); @@ -133,8 +134,7 @@ class NativeProcessNetBSD : public NativeProcessProtocol { Status PopulateMemoryRegionCache(); void SigchldHandler(); - ::pid_t Attach(lldb::pid_t pid, Status &error); - + Status Attach(); Status ReinitializeThreads(); }; diff --git a/source/Plugins/Process/gdb-remote/CMakeLists.txt b/source/Plugins/Process/gdb-remote/CMakeLists.txt index 3d008f42499d..5e51feef1d3f 100644 --- a/source/Plugins/Process/gdb-remote/CMakeLists.txt +++ b/source/Plugins/Process/gdb-remote/CMakeLists.txt @@ -7,14 +7,6 @@ set(LLDB_PLUGINS lldbPluginPlatformMacOSX ) -if(CMAKE_SYSTEM_NAME MATCHES "Linux|Android") - list(APPEND LLDB_PLUGINS lldbPluginProcessLinux) -endif() - -if(CMAKE_SYSTEM_NAME MATCHES "NetBSD") - list(APPEND LLDB_PLUGINS lldbPluginProcessNetBSD) -endif() - add_lldb_library(lldbPluginProcessGDBRemote PLUGIN GDBRemoteClientBase.cpp GDBRemoteCommunication.cpp diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 33aed7a43c4a..e6fd386b903b 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -86,6 +86,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient() m_supports_jLoadedDynamicLibrariesInfos(eLazyBoolCalculate), m_supports_jGetSharedCacheInfo(eLazyBoolCalculate), m_supports_QPassSignals(eLazyBoolCalculate), + m_supports_error_string_reply(eLazyBoolCalculate), m_supports_qProcessInfoPID(true), m_supports_qfProcessInfo(true), m_supports_qUserName(true), m_supports_qGroupName(true), m_supports_qThreadStopInfo(true), m_supports_z0(true), @@ -596,6 +597,21 @@ bool GDBRemoteCommunicationClient::GetThreadExtendedInfoSupported() { return m_supports_jThreadExtendedInfo; } +void GDBRemoteCommunicationClient::EnableErrorStringInPacket() { + if (m_supports_error_string_reply == eLazyBoolCalculate) { + StringExtractorGDBRemote response; + // We try to enable error strings in remote packets + // but if we fail, we just work in the older way. + m_supports_error_string_reply = eLazyBoolNo; + if (SendPacketAndWaitForResponse("QEnableErrorStrings", response, false) == + PacketResult::Success) { + if (response.IsOKResponse()) { + m_supports_error_string_reply = eLazyBoolYes; + } + } + } +} + bool GDBRemoteCommunicationClient::GetLoadedDynamicLibrariesInfosSupported() { if (m_supports_jLoadedDynamicLibrariesInfos == eLazyBoolCalculate) { StringExtractorGDBRemote response; @@ -3181,8 +3197,8 @@ GDBRemoteCommunicationClient::SendStartTracePacket(const TraceOptions &options, true) == GDBRemoteCommunication::PacketResult::Success) { if (!response.IsNormalResponse()) { - error.SetError(response.GetError(), eErrorTypeGeneric); - LLDB_LOG(log, "Target does not support Tracing"); + error = response.GetStatus(); + LLDB_LOG(log, "Target does not support Tracing , error {0}", error); } else { ret_uid = response.GetHexMaxU64(false, LLDB_INVALID_UID); } @@ -3219,7 +3235,7 @@ GDBRemoteCommunicationClient::SendStopTracePacket(lldb::user_id_t uid, true) == GDBRemoteCommunication::PacketResult::Success) { if (!response.IsOKResponse()) { - error.SetError(response.GetError(), eErrorTypeGeneric); + error = response.GetStatus(); LLDB_LOG(log, "stop tracing failed"); } } else { @@ -3234,6 +3250,7 @@ GDBRemoteCommunicationClient::SendStopTracePacket(lldb::user_id_t uid, Status GDBRemoteCommunicationClient::SendGetDataPacket( lldb::user_id_t uid, lldb::tid_t thread_id, llvm::MutableArrayRef &buffer, size_t offset) { + StreamGDBRemote escaped_packet; escaped_packet.PutCString("jTraceBufferRead:"); return SendGetTraceDataPacket(escaped_packet, uid, thread_id, buffer, offset); @@ -3242,6 +3259,7 @@ Status GDBRemoteCommunicationClient::SendGetDataPacket( Status GDBRemoteCommunicationClient::SendGetMetaDataPacket( lldb::user_id_t uid, lldb::tid_t thread_id, llvm::MutableArrayRef &buffer, size_t offset) { + StreamGDBRemote escaped_packet; escaped_packet.PutCString("jTraceMetaRead:"); return SendGetTraceDataPacket(escaped_packet, uid, thread_id, buffer, offset); @@ -3308,7 +3326,7 @@ GDBRemoteCommunicationClient::SendGetTraceConfigPacket(lldb::user_id_t uid, custom_params_sp)); } } else { - error.SetError(response.GetError(), eErrorTypeGeneric); + error = response.GetStatus(); } } else { LLDB_LOG(log, "failed to send packet"); @@ -3344,7 +3362,7 @@ Status GDBRemoteCommunicationClient::SendGetTraceDataPacket( size_t filled_size = response.GetHexBytesAvail(buffer); buffer = llvm::MutableArrayRef(buffer.data(), filled_size); } else { - error.SetError(response.GetError(), eErrorTypeGeneric); + error = response.GetStatus(); buffer = buffer.slice(buffer.size()); } } else { diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index a38110faaec6..712d85eed082 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -340,6 +340,8 @@ class GDBRemoteCommunicationClient : public GDBRemoteClientBase { bool GetQXferAuxvReadSupported(); + void EnableErrorStringInPacket(); + bool GetQXferLibrariesReadSupported(); bool GetQXferLibrariesSVR4ReadSupported(); @@ -549,6 +551,7 @@ class GDBRemoteCommunicationClient : public GDBRemoteClientBase { LazyBool m_supports_jLoadedDynamicLibrariesInfos; LazyBool m_supports_jGetSharedCacheInfo; LazyBool m_supports_QPassSignals; + LazyBool m_supports_error_string_reply; bool m_supports_qProcessInfoPID : 1, m_supports_qfProcessInfo : 1, m_supports_qUserName : 1, m_supports_qGroupName : 1, diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp index dac675ee9432..4be92b79fd1a 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp @@ -20,6 +20,7 @@ // Project includes #include "ProcessGDBRemoteLog.h" #include "Utility/StringExtractorGDBRemote.h" +#include "lldb/Utility/StreamString.h" using namespace lldb; using namespace lldb_private; @@ -27,7 +28,12 @@ using namespace lldb_private::process_gdb_remote; GDBRemoteCommunicationServer::GDBRemoteCommunicationServer( const char *comm_name, const char *listener_name) - : GDBRemoteCommunication(comm_name, listener_name), m_exit_now(false) {} + : GDBRemoteCommunication(comm_name, listener_name), m_exit_now(false) { + RegisterPacketHandler( + StringExtractorGDBRemote::eServerPacketType_QEnableErrorStrings, + [this](StringExtractorGDBRemote packet, Status &error, bool &interrupt, + bool &quit) { return this->Handle_QErrorStringEnable(packet); }); +} GDBRemoteCommunicationServer::~GDBRemoteCommunicationServer() {} @@ -99,6 +105,24 @@ GDBRemoteCommunicationServer::SendErrorResponse(uint8_t err) { return SendPacketNoLock(llvm::StringRef(packet, packet_len)); } +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::SendErrorResponse(const Status &error) { + if (m_send_error_strings) { + lldb_private::StreamString packet; + packet.Printf("E%2.2x;", static_cast(error.GetError())); + packet.PutCStringAsRawHex8(error.AsCString()); + return SendPacketNoLock(packet.GetString()); + } else + return SendErrorResponse(error.GetError()); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::Handle_QErrorStringEnable( + StringExtractorGDBRemote &packet) { + m_send_error_strings = true; + return SendOKResponse(); +} + GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::SendIllFormedResponse( const StringExtractorGDBRemote &failed_packet, const char *message) { diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h index 6eb25f8b9f98..a35352480040 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h @@ -57,6 +57,13 @@ class GDBRemoteCommunicationServer : public GDBRemoteCommunication { bool m_exit_now; // use in asynchronous handling to indicate process should // exit. + bool m_send_error_strings; // If the client enables this then + // we will send error strings as well. + + PacketResult Handle_QErrorStringEnable(StringExtractorGDBRemote &packet); + + PacketResult SendErrorResponse(const Status &error); + PacketResult SendUnimplementedResponse(const char *packet); PacketResult SendErrorResponse(uint8_t error); diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp index de2400c51ba3..f53db502be93 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp @@ -1046,14 +1046,9 @@ GDBRemoteCommunicationServerCommon::Handle_A(StringExtractorGDBRemote &packet) { if (success) { m_process_launch_error = LaunchProcess(); - if (m_process_launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) { + if (m_process_launch_error.Success()) return SendOKResponse(); - } else { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf("LLGSPacketHandler::%s failed to launch exe: %s", - __FUNCTION__, m_process_launch_error.AsCString()); - } + LLDB_LOG(log, "failed to launch exe: {0}", m_process_launch_error); } return SendErrorResponse(8); } diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index 7523260c13e4..a7fe4ee3b147 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -73,15 +73,11 @@ enum GDBRemoteServerError { // GDBRemoteCommunicationServerLLGS constructor //---------------------------------------------------------------------- GDBRemoteCommunicationServerLLGS::GDBRemoteCommunicationServerLLGS( - MainLoop &mainloop) + MainLoop &mainloop, const NativeProcessProtocol::Factory &process_factory) : GDBRemoteCommunicationServerCommon("gdb-remote.server", "gdb-remote.server.rx_packet"), - m_mainloop(mainloop), m_current_tid(LLDB_INVALID_THREAD_ID), - m_continue_tid(LLDB_INVALID_THREAD_ID), m_debugged_process_mutex(), - m_debugged_process_sp(), m_stdio_communication("process.stdio"), - m_inferior_prev_state(StateType::eStateInvalid), - m_saved_registers_map(), m_next_saved_registers_id(1), - m_handshake_completed(false) { + m_mainloop(mainloop), m_process_factory(process_factory), + m_stdio_communication("process.stdio") { RegisterPacketHandlers(); } @@ -241,19 +237,20 @@ Status GDBRemoteCommunicationServerLLGS::LaunchProcess() { const bool default_to_use_pty = true; m_process_launch_info.FinalizeFileActions(nullptr, default_to_use_pty); - Status error; { std::lock_guard guard(m_debugged_process_mutex); assert(!m_debugged_process_sp && "lldb-server creating debugged " "process but one already exists"); - error = NativeProcessProtocol::Launch(m_process_launch_info, *this, - m_mainloop, m_debugged_process_sp); - } - - if (!error.Success()) { - fprintf(stderr, "%s: failed to launch executable %s", __FUNCTION__, - m_process_launch_info.GetArguments().GetArgumentAtIndex(0)); - return error; + auto process_or = + m_process_factory.Launch(m_process_launch_info, *this, m_mainloop); + if (!process_or) { + Status status(process_or.takeError()); + llvm::errs() << llvm::formatv( + "failed to launch executable `{0}`: {1}", + m_process_launch_info.GetArguments().GetArgumentAtIndex(0), status); + return status; + } + m_debugged_process_sp = *process_or; } // Handle mirroring of inferior stdout/stderr over the gdb-remote protocol @@ -279,9 +276,9 @@ Status GDBRemoteCommunicationServerLLGS::LaunchProcess() { log->Printf("ProcessGDBRemoteCommunicationServerLLGS::%s setting " "inferior STDIO fd to %d", __FUNCTION__, terminal_fd); - error = SetSTDIOFileDescriptor(terminal_fd); - if (error.Fail()) - return error; + Status status = SetSTDIOFileDescriptor(terminal_fd); + if (status.Fail()) + return status; } else { if (log) log->Printf("ProcessGDBRemoteCommunicationServerLLGS::%s ignoring " @@ -298,14 +295,12 @@ Status GDBRemoteCommunicationServerLLGS::LaunchProcess() { printf("Launched '%s' as process %" PRIu64 "...\n", m_process_launch_info.GetArguments().GetArgumentAtIndex(0), - m_process_launch_info.GetProcessID()); + m_debugged_process_sp->GetID()); - return error; + return Status(); } Status GDBRemoteCommunicationServerLLGS::AttachToProcess(lldb::pid_t pid) { - Status error; - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); if (log) log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64, @@ -321,13 +316,14 @@ Status GDBRemoteCommunicationServerLLGS::AttachToProcess(lldb::pid_t pid) { pid, m_debugged_process_sp->GetID()); // Try to attach. - error = NativeProcessProtocol::Attach(pid, *this, m_mainloop, - m_debugged_process_sp); - if (!error.Success()) { - fprintf(stderr, "%s: failed to attach to process %" PRIu64 ": %s", - __FUNCTION__, pid, error.AsCString()); - return error; + auto process_or = m_process_factory.Attach(pid, *this, m_mainloop); + if (!process_or) { + Status status(process_or.takeError()); + llvm::errs() << llvm::formatv("failed to attach to process {0}: {1}", pid, + status); + return status; } + m_debugged_process_sp = *process_or; // Setup stdout/stderr mapping from inferior. auto terminal_fd = m_debugged_process_sp->GetTerminalFileDescriptor(); @@ -336,9 +332,9 @@ Status GDBRemoteCommunicationServerLLGS::AttachToProcess(lldb::pid_t pid) { log->Printf("ProcessGDBRemoteCommunicationServerLLGS::%s setting " "inferior STDIO fd to %d", __FUNCTION__, terminal_fd); - error = SetSTDIOFileDescriptor(terminal_fd); - if (error.Fail()) - return error; + Status status = SetSTDIOFileDescriptor(terminal_fd); + if (status.Fail()) + return status; } else { if (log) log->Printf("ProcessGDBRemoteCommunicationServerLLGS::%s ignoring " @@ -347,8 +343,7 @@ Status GDBRemoteCommunicationServerLLGS::AttachToProcess(lldb::pid_t pid) { } printf("Attached to process %" PRIu64 "...\n", pid); - - return error; + return Status(); } void GDBRemoteCommunicationServerLLGS::InitializeDelegate( @@ -1128,7 +1123,7 @@ GDBRemoteCommunicationServerLLGS::Handle_jTraceStart( uid = m_debugged_process_sp->StartTrace(options, error); LLDB_LOG(log, "uid is {0} , error is {1}", uid, error.GetError()); if (error.Fail()) - return SendErrorResponse(error.GetError()); + return SendErrorResponse(error); StreamGDBRemote response; response.Printf("%" PRIx64, uid); @@ -1165,7 +1160,7 @@ GDBRemoteCommunicationServerLLGS::Handle_jTraceStop( Status error = m_debugged_process_sp->StopTrace(uid, tid); if (error.Fail()) - return SendErrorResponse(error.GetError()); + return SendErrorResponse(error); return SendOKResponse(); } @@ -1208,7 +1203,7 @@ GDBRemoteCommunicationServerLLGS::Handle_jTraceConfigRead( Status error = m_debugged_process_sp->GetTraceConfig(uid, options); if (error.Fail()) - return SendErrorResponse(error.GetError()); + return SendErrorResponse(error); StreamGDBRemote escaped_response; StructuredData::Dictionary json_packet; @@ -1284,7 +1279,7 @@ GDBRemoteCommunicationServerLLGS::Handle_jTraceRead( error = m_debugged_process_sp->GetMetaData(uid, tid, buf, offset); if (error.Fail()) - return SendErrorResponse(error.GetError()); + return SendErrorResponse(error); for (auto i : buf) response.PutHex8(i); diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h index a7d7850d454f..b065642d4aed 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h @@ -39,7 +39,9 @@ class GDBRemoteCommunicationServerLLGS //------------------------------------------------------------------ // Constructors and Destructors //------------------------------------------------------------------ - GDBRemoteCommunicationServerLLGS(MainLoop &mainloop); + GDBRemoteCommunicationServerLLGS( + MainLoop &mainloop, + const NativeProcessProtocol::Factory &process_factory); //------------------------------------------------------------------ /// Specify the program to launch and its arguments. @@ -108,20 +110,21 @@ class GDBRemoteCommunicationServerLLGS protected: MainLoop &m_mainloop; MainLoop::ReadHandleUP m_network_handle_up; - lldb::tid_t m_current_tid; - lldb::tid_t m_continue_tid; + const NativeProcessProtocol::Factory &m_process_factory; + lldb::tid_t m_current_tid = LLDB_INVALID_THREAD_ID; + lldb::tid_t m_continue_tid = LLDB_INVALID_THREAD_ID; std::recursive_mutex m_debugged_process_mutex; NativeProcessProtocolSP m_debugged_process_sp; Communication m_stdio_communication; MainLoop::ReadHandleUP m_stdio_handle_up; - lldb::StateType m_inferior_prev_state; + lldb::StateType m_inferior_prev_state = lldb::StateType::eStateInvalid; std::unique_ptr m_active_auxv_buffer_up; std::mutex m_saved_registers_mutex; std::unordered_map m_saved_registers_map; - uint32_t m_next_saved_registers_id; - bool m_handshake_completed : 1; + uint32_t m_next_saved_registers_id = 1; + bool m_handshake_completed = false; PacketResult SendONotification(const char *buffer, uint32_t len); diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 042c96111bb3..8a66f3865ebc 100644 --- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -1031,6 +1031,7 @@ Status ProcessGDBRemote::ConnectToDebugserver(llvm::StringRef connect_url) { m_gdb_comm.GetHostInfo(); m_gdb_comm.GetVContSupported('c'); m_gdb_comm.GetVAttachOrWaitSupported(); + m_gdb_comm.EnableErrorStringInPacket(); // Ask the remote server for the default thread id if (GetTarget().GetNonStopModeEnabled()) diff --git a/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp index b7fbd7347d08..6c39690268c6 100644 --- a/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ b/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -1857,14 +1857,12 @@ StructuredData::DictionarySP ScriptInterpreterPython::GetDynamicSettings( return StructuredData::DictionarySP(); PythonObject reply_pyobj; - { - Locker py_lock(this, - Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); - TargetSP target_sp(target->shared_from_this()); - reply_pyobj.Reset(PyRefType::Owned, - (PyObject *)g_swig_plugin_get(generic->GetValue(), - setting_name, target_sp)); - } + Locker py_lock(this, + Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + TargetSP target_sp(target->shared_from_this()); + reply_pyobj.Reset(PyRefType::Owned, + (PyObject *)g_swig_plugin_get(generic->GetValue(), + setting_name, target_sp)); PythonDictionary py_dict(PyRefType::Borrowed, reply_pyobj.get()); return py_dict.CreateStructuredDictionary(); diff --git a/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp b/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp index 9d79a411faad..aa15063ac0dc 100644 --- a/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp +++ b/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp @@ -604,9 +604,10 @@ uint32_t x86AssemblyInspectionEngine::extract_4(uint8_t *b) { } bool x86AssemblyInspectionEngine::instruction_length(uint8_t *insn_p, - int &length) { + int &length, + uint32_t buffer_remaining_bytes) { - const uint32_t max_op_byte_size = m_arch.GetMaximumOpcodeByteSize(); + uint32_t max_op_byte_size = std::min(buffer_remaining_bytes, m_arch.GetMaximumOpcodeByteSize()); llvm::SmallVector opcode_data; opcode_data.resize(max_op_byte_size); @@ -698,8 +699,9 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly( bool row_updated = false; // The UnwindPlan::Row 'row' has been updated m_cur_insn = data + current_func_text_offset; - if (!instruction_length(m_cur_insn, insn_len) || insn_len == 0 || - insn_len > kMaxInstructionByteSize) { + if (!instruction_length(m_cur_insn, insn_len, size - current_func_text_offset) + || insn_len == 0 + || insn_len > kMaxInstructionByteSize) { // An unrecognized/junk instruction break; } @@ -1002,8 +1004,9 @@ bool x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite( while (offset < size) { m_cur_insn = data + offset; int insn_len; - if (!instruction_length(m_cur_insn, insn_len) || insn_len == 0 || - insn_len > kMaxInstructionByteSize) { + if (!instruction_length(m_cur_insn, insn_len, size - offset) + || insn_len == 0 + || insn_len > kMaxInstructionByteSize) { // An unrecognized/junk instruction. break; } @@ -1214,8 +1217,9 @@ bool x86AssemblyInspectionEngine::FindFirstNonPrologueInstruction( int scratch; m_cur_insn = data + offset; - if (!instruction_length(m_cur_insn, insn_len) || - insn_len > kMaxInstructionByteSize || insn_len == 0) { + if (!instruction_length(m_cur_insn, insn_len, size - offset) + || insn_len > kMaxInstructionByteSize + || insn_len == 0) { // An error parsing the instruction, i.e. probably data/garbage - stop // scanning break; diff --git a/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h b/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h index 2e7875966cb6..97441d362973 100644 --- a/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h +++ b/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h @@ -113,7 +113,7 @@ class x86AssemblyInspectionEngine { bool ret_pattern_p(); uint32_t extract_4(uint8_t *b); - bool instruction_length(uint8_t *insn, int &length); + bool instruction_length(uint8_t *insn, int &length, uint32_t buffer_remaining_bytes); bool machine_regno_to_lldb_regno(int machine_regno, uint32_t &lldb_regno); diff --git a/source/Utility/StringExtractorGDBRemote.cpp b/source/Utility/StringExtractorGDBRemote.cpp index 3473a9e96689..8e50c0106a48 100644 --- a/source/Utility/StringExtractorGDBRemote.cpp +++ b/source/Utility/StringExtractorGDBRemote.cpp @@ -19,8 +19,18 @@ StringExtractorGDBRemote::GetResponseType() const { switch (m_packet[0]) { case 'E': - if (m_packet.size() == 3 && isxdigit(m_packet[1]) && isxdigit(m_packet[2])) - return eError; + if (isxdigit(m_packet[1]) && isxdigit(m_packet[2])) { + if (m_packet.size() == 3) + return eError; + llvm::StringRef packet_ref(m_packet); + if (packet_ref[3] == ';') { + auto err_string = packet_ref.substr(4); + for (auto e : err_string) + if (!isxdigit(e)) + return eResponse; + return eError; + } + } break; case 'O': @@ -86,6 +96,8 @@ StringExtractorGDBRemote::GetServerPacketType() const { return eServerPacketType_QEnvironment; if (PACKET_STARTS_WITH("QEnvironmentHexEncoded:")) return eServerPacketType_QEnvironmentHexEncoded; + if (PACKET_STARTS_WITH("QEnableErrorStrings")) + return eServerPacketType_QEnableErrorStrings; break; case 'P': @@ -438,8 +450,8 @@ bool StringExtractorGDBRemote::IsNormalResponse() const { } bool StringExtractorGDBRemote::IsErrorResponse() const { - return GetResponseType() == eError && m_packet.size() == 3 && - isxdigit(m_packet[1]) && isxdigit(m_packet[2]); + return GetResponseType() == eError && isxdigit(m_packet[1]) && + isxdigit(m_packet[2]); } uint8_t StringExtractorGDBRemote::GetError() { @@ -450,6 +462,23 @@ uint8_t StringExtractorGDBRemote::GetError() { return 0; } +lldb_private::Status StringExtractorGDBRemote::GetStatus() { + lldb_private::Status error; + if (GetResponseType() == eError) { + SetFilePos(1); + uint8_t errc = GetHexU8(255); + error.SetError(errc, lldb::eErrorTypeGeneric); + + error.SetErrorStringWithFormat("Error %u", errc); + std::string error_messg; + if (GetChar() == ';') { + GetHexByteString(error_messg); + error.SetErrorString(error_messg); + } + } + return error; +} + size_t StringExtractorGDBRemote::GetEscapedBinaryData(std::string &str) { // Just get the data bytes in the string as // GDBRemoteCommunication::CheckForPacket() diff --git a/source/Utility/StringExtractorGDBRemote.h b/source/Utility/StringExtractorGDBRemote.h index 473cab04f800..f4ed642a706e 100644 --- a/source/Utility/StringExtractorGDBRemote.h +++ b/source/Utility/StringExtractorGDBRemote.h @@ -10,6 +10,7 @@ #ifndef utility_StringExtractorGDBRemote_h_ #define utility_StringExtractorGDBRemote_h_ +#include "lldb/Utility/Status.h" #include "lldb/Utility/StringExtractor.h" #include "llvm/ADT/StringRef.h" // for StringRef @@ -72,6 +73,7 @@ class StringExtractorGDBRemote : public StringExtractor { eServerPacketType_qGetWorkingDir, eServerPacketType_qFileLoadAddress, eServerPacketType_QEnvironment, + eServerPacketType_QEnableErrorStrings, eServerPacketType_QLaunchArch, eServerPacketType_QSetDisableASLR, eServerPacketType_QSetDetachOnError, @@ -190,6 +192,8 @@ class StringExtractorGDBRemote : public StringExtractor { // digits. Otherwise the error encoded in XX is returned. uint8_t GetError(); + lldb_private::Status GetStatus(); + size_t GetEscapedBinaryData(std::string &str); protected: diff --git a/tools/lldb-server/CMakeLists.txt b/tools/lldb-server/CMakeLists.txt index 4f76ebd6881c..f8c57cb9488f 100644 --- a/tools/lldb-server/CMakeLists.txt +++ b/tools/lldb-server/CMakeLists.txt @@ -59,6 +59,16 @@ if (LLVM_BUILD_STATIC) endif() endif() +set(LLDB_PLUGINS) + +if(CMAKE_SYSTEM_NAME MATCHES "Linux|Android") + list(APPEND LLDB_PLUGINS lldbPluginProcessLinux) +endif() + +if(CMAKE_SYSTEM_NAME MATCHES "NetBSD") + list(APPEND LLDB_PLUGINS lldbPluginProcessNetBSD) +endif() + add_lldb_tool(lldb-server INCLUDE_IN_FRAMEWORK Acceptor.cpp lldb-gdbserver.cpp @@ -72,7 +82,7 @@ add_lldb_tool(lldb-server INCLUDE_IN_FRAMEWORK lldbHost lldbInitialization lldbInterpreter - ${EXTRA_LLDB_LIBS} + ${LLDB_PLUGINS} ${LLDB_SYSTEM_LIBS} LINK_COMPONENTS diff --git a/tools/lldb-server/lldb-gdbserver.cpp b/tools/lldb-server/lldb-gdbserver.cpp index 412d775e8394..337f244c2c2d 100644 --- a/tools/lldb-server/lldb-gdbserver.cpp +++ b/tools/lldb-server/lldb-gdbserver.cpp @@ -33,10 +33,17 @@ #include "lldb/Host/Pipe.h" #include "lldb/Host/Socket.h" #include "lldb/Host/StringConvert.h" +#include "lldb/Host/common/NativeProcessProtocol.h" #include "lldb/Utility/Status.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Errno.h" +#if defined(__linux__) +#include "Plugins/Process/Linux/NativeProcessLinux.h" +#elif defined(__NetBSD__) +#include "Plugins/Process/NetBSD/NativeProcessNetBSD.h" +#endif + #ifndef LLGS_PROGRAM_NAME #define LLGS_PROGRAM_NAME "lldb-server" #endif @@ -51,6 +58,30 @@ using namespace lldb_private; using namespace lldb_private::lldb_server; using namespace lldb_private::process_gdb_remote; +namespace { +#if defined(__linux__) +typedef process_linux::NativeProcessLinux::Factory NativeProcessFactory; +#elif defined(__NetBSD__) +typedef process_netbsd::NativeProcessNetBSD::Factory NativeProcessFactory; +#else +// Dummy implementation to make sure the code compiles +class NativeProcessFactory : public NativeProcessProtocol::Factory { +public: + llvm::Expected + Launch(ProcessLaunchInfo &launch_info, + NativeProcessProtocol::NativeDelegate &delegate, + MainLoop &mainloop) const override { + llvm_unreachable("Not implemented"); + } + llvm::Expected + Attach(lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &delegate, + MainLoop &mainloop) const override { + llvm_unreachable("Not implemented"); + } +}; +#endif +} + //---------------------------------------------------------------------- // option descriptors for getopt_long_only() //---------------------------------------------------------------------- @@ -446,7 +477,8 @@ int main_gdbserver(int argc, char *argv[]) { exit(255); } - GDBRemoteCommunicationServerLLGS gdb_server(mainloop); + NativeProcessFactory factory; + GDBRemoteCommunicationServerLLGS gdb_server(mainloop, factory); const char *const host_and_port = argv[0]; argc -= 1; diff --git a/tools/lldb-server/lldb-platform.cpp b/tools/lldb-server/lldb-platform.cpp index 8d45682566b9..ec5b781dac48 100644 --- a/tools/lldb-server/lldb-platform.cpp +++ b/tools/lldb-server/lldb-platform.cpp @@ -197,46 +197,41 @@ int main_platform(int argc, char *argv[]) { break; case 'p': { - char *end = NULL; - long tmp_port_offset = strtoul(optarg, &end, 0); - if (end && *end == '\0') { - if (LOW_PORT <= tmp_port_offset && tmp_port_offset <= HIGH_PORT) { - port_offset = (uint16_t)tmp_port_offset; - } else { - fprintf(stderr, "error: port offset %li is not in the valid user " - "port range of %u - %u\n", - tmp_port_offset, LOW_PORT, HIGH_PORT); - option_error = 5; - } - } else { - fprintf(stderr, "error: invalid port offset string %s\n", optarg); + if (!llvm::to_integer(optarg, port_offset)) { + llvm::errs() << "error: invalid port offset string " << optarg << "\n"; option_error = 4; + break; + } + if (port_offset < LOW_PORT || port_offset > HIGH_PORT) { + llvm::errs() << llvm::formatv("error: port offset {0} is not in the " + "valid user port range of {1} - {2}\n", + port_offset, LOW_PORT, HIGH_PORT); + option_error = 5; } } break; case 'P': case 'm': case 'M': { - char *end = NULL; - long portnum = strtoul(optarg, &end, 0); - if (end && *end == '\0') { - if (LOW_PORT <= portnum && portnum <= HIGH_PORT) { - if (ch == 'P') - gdbserver_portmap[(uint16_t)portnum] = LLDB_INVALID_PROCESS_ID; - else if (ch == 'm') - min_gdbserver_port = portnum; - else - max_gdbserver_port = portnum; - } else { - fprintf(stderr, "error: port number %li is not in the valid user " - "port range of %u - %u\n", - portnum, LOW_PORT, HIGH_PORT); - option_error = 1; - } - } else { - fprintf(stderr, "error: invalid port number string %s\n", optarg); + uint16_t portnum; + if (!llvm::to_integer(optarg, portnum)) { + llvm::errs() << "error: invalid port number string " << optarg << "\n"; option_error = 2; + break; } + if (portnum < LOW_PORT || portnum > HIGH_PORT) { + llvm::errs() << llvm::formatv("error: port number {0} is not in the " + "valid user port range of {1} - {2}\n", + portnum, LOW_PORT, HIGH_PORT); + option_error = 1; + break; + } + if (ch == 'P') + gdbserver_portmap[portnum] = LLDB_INVALID_PROCESS_ID; + else if (ch == 'm') + min_gdbserver_port = portnum; + else + max_gdbserver_port = portnum; } break; case 'h': /* fall-through is intentional */ diff --git a/unittests/Process/Linux/ProcessorTraceTest.cpp b/unittests/Process/Linux/ProcessorTraceTest.cpp index b732934d014d..67381b6ddca3 100644 --- a/unittests/Process/Linux/ProcessorTraceTest.cpp +++ b/unittests/Process/Linux/ProcessorTraceTest.cpp @@ -30,42 +30,40 @@ size_t ReadCylicBufferWrapper(void *buf, size_t buf_size, void *cyc_buf, } TEST(CyclicBuffer, EdgeCases) { - size_t bytes_read = 0; + size_t bytes_read; uint8_t cyclic_buffer[6] = {'l', 'i', 'c', 'c', 'y', 'c'}; // We will always leave the last bytes untouched // so that string comparisions work. - char bigger_buffer[10] = {}; - char equal_size_buffer[7] = {}; char smaller_buffer[4] = {}; // empty buffer to read into bytes_read = ReadCylicBufferWrapper(smaller_buffer, 0, cyclic_buffer, sizeof(cyclic_buffer), 3, 0); - ASSERT_EQ(0, bytes_read); + ASSERT_EQ(0u, bytes_read); // empty cyclic buffer bytes_read = ReadCylicBufferWrapper(smaller_buffer, sizeof(smaller_buffer), cyclic_buffer, 0, 3, 0); - ASSERT_EQ(0, bytes_read); + ASSERT_EQ(0u, bytes_read); // bigger offset bytes_read = ReadCylicBufferWrapper(smaller_buffer, sizeof(smaller_buffer), cyclic_buffer, sizeof(cyclic_buffer), 3, 6); - ASSERT_EQ(0, bytes_read); + ASSERT_EQ(0u, bytes_read); // wrong offset bytes_read = ReadCylicBufferWrapper(smaller_buffer, sizeof(smaller_buffer), cyclic_buffer, sizeof(cyclic_buffer), 3, 7); - ASSERT_EQ(0, bytes_read); + ASSERT_EQ(0u, bytes_read); // wrong start bytes_read = ReadCylicBufferWrapper(smaller_buffer, sizeof(smaller_buffer), cyclic_buffer, sizeof(cyclic_buffer), 3, 7); - ASSERT_EQ(0, bytes_read); + ASSERT_EQ(0u, bytes_read); } TEST(CyclicBuffer, EqualSizeBuffer) { @@ -73,7 +71,7 @@ TEST(CyclicBuffer, EqualSizeBuffer) { uint8_t cyclic_buffer[6] = {'l', 'i', 'c', 'c', 'y', 'c'}; char cyclic[] = "cyclic"; - for (int i = 0; i < sizeof(cyclic); i++) { + for (size_t i = 0; i < sizeof(cyclic); i++) { // We will always leave the last bytes untouched // so that string comparisions work. char equal_size_buffer[7] = {}; @@ -86,7 +84,7 @@ TEST(CyclicBuffer, EqualSizeBuffer) { } TEST(CyclicBuffer, SmallerSizeBuffer) { - size_t bytes_read = 0; + size_t bytes_read; uint8_t cyclic_buffer[6] = {'l', 'i', 'c', 'c', 'y', 'c'}; // We will always leave the last bytes untouched @@ -95,25 +93,25 @@ TEST(CyclicBuffer, SmallerSizeBuffer) { bytes_read = ReadCylicBufferWrapper(smaller_buffer, (sizeof(smaller_buffer) - 1), cyclic_buffer, sizeof(cyclic_buffer), 3, 0); - ASSERT_EQ(3, bytes_read); + ASSERT_EQ(3u, bytes_read); ASSERT_STREQ(smaller_buffer, "cyc"); bytes_read = ReadCylicBufferWrapper(smaller_buffer, (sizeof(smaller_buffer) - 1), cyclic_buffer, sizeof(cyclic_buffer), 3, 1); - ASSERT_EQ(3, bytes_read); + ASSERT_EQ(3u, bytes_read); ASSERT_STREQ(smaller_buffer, "ycl"); bytes_read = ReadCylicBufferWrapper(smaller_buffer, (sizeof(smaller_buffer) - 1), cyclic_buffer, sizeof(cyclic_buffer), 3, 2); - ASSERT_EQ(3, bytes_read); + ASSERT_EQ(3u, bytes_read); ASSERT_STREQ(smaller_buffer, "cli"); bytes_read = ReadCylicBufferWrapper(smaller_buffer, (sizeof(smaller_buffer) - 1), cyclic_buffer, sizeof(cyclic_buffer), 3, 3); - ASSERT_EQ(3, bytes_read); + ASSERT_EQ(3u, bytes_read); ASSERT_STREQ(smaller_buffer, "lic"); { @@ -121,7 +119,7 @@ TEST(CyclicBuffer, SmallerSizeBuffer) { bytes_read = ReadCylicBufferWrapper(smaller_buffer, (sizeof(smaller_buffer) - 1), cyclic_buffer, sizeof(cyclic_buffer), 3, 4); - ASSERT_EQ(2, bytes_read); + ASSERT_EQ(2u, bytes_read); ASSERT_STREQ(smaller_buffer, "ic"); } { @@ -129,7 +127,7 @@ TEST(CyclicBuffer, SmallerSizeBuffer) { bytes_read = ReadCylicBufferWrapper(smaller_buffer, (sizeof(smaller_buffer) - 1), cyclic_buffer, sizeof(cyclic_buffer), 3, 5); - ASSERT_EQ(1, bytes_read); + ASSERT_EQ(1u, bytes_read); ASSERT_STREQ(smaller_buffer, "c"); } } @@ -139,7 +137,7 @@ TEST(CyclicBuffer, BiggerSizeBuffer) { uint8_t cyclic_buffer[6] = {'l', 'i', 'c', 'c', 'y', 'c'}; char cyclic[] = "cyclic"; - for (int i = 0; i < sizeof(cyclic); i++) { + for (size_t i = 0; i < sizeof(cyclic); i++) { // We will always leave the last bytes untouched // so that string comparisions work. char bigger_buffer[10] = {}; diff --git a/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp b/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp index e97760967197..c3591b2d73e1 100644 --- a/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp +++ b/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp @@ -2415,3 +2415,28 @@ TEST_F(Testx86AssemblyInspectionEngine, TestStackRealign32BitDisp_x86_64) { EXPECT_EQ(rsp_plus_8, plan.GetRowForFunctionOffset(sizeof(data) - 1)->GetCFAValue()); } + +// Give the disassembler random bytes to test that it doesn't exceed +// the bounds of the array when run under clang's address sanitizer. +TEST_F(Testx86AssemblyInspectionEngine, TestDisassemblyJunkBytes) { + AddressRange sample_range; + UnwindPlan unwind_plan(eRegisterKindLLDB); + std::unique_ptr engine32 = Geti386Inspector(); + std::unique_ptr engine64 = Getx86_64Inspector(); + + uint8_t data[] = { + 0x10, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; + + sample_range = AddressRange(0x1000, sizeof(data)); + + EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly( + data, sizeof(data), sample_range, unwind_plan)); + + unwind_plan.Clear(); + + EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly( + data, sizeof(data), sample_range, unwind_plan)); + +} + diff --git a/www/architecture.html b/www/architecture.html deleted file mode 100755 index eb178febde54..000000000000 --- a/www/architecture.html +++ /dev/null @@ -1,294 +0,0 @@ - - - - - -LLDB Architecture - - - -
- The LLDB Debugger -
- -
-
- - - -
-
-

Architecture

-
- -

LLDB is a large and complex codebase. This section will help you become more familiar with - the pieces that make up LLDB and give a general overview of the general architecture.

-
- -
-
-

Code Layout

-
- -

LLDB has many code groupings that makeup the source base:

- -
- -
- -
-

API

-
- -

The API folder contains the public interface to LLDB.

-

We are currently vending a C++ API. In order to be able to add - methods to this API and allow people to link to our classes, - we have certain rules that we must follow:

-
    -
  • Classes can't inherit from any other classes.
  • -
  • Classes can't contain virtual methods.
  • -
  • Classes should be compatible with script bridging utilities like swig.
  • -
  • Classes should be lightweight and be backed by a single member. Pointers (or shared pointers) are the preferred choice since they allow changing the contents of the backend without affecting the public object layout.
  • -
  • The interface should be as minimal as possible in order to give a complete API.
  • -
-

By adhering to these rules we should be able to continue to - vend a C++ API, and make changes to the API as any additional - methods added to these classes will just be a dynamic loader - lookup and they won't affect the class layout (since they - aren't virtual methods, and no members can be added to the - class).

-
- -
- -
-

Breakpoint

-
- -

A collection of classes that implement our breakpoint classes. - Breakpoints are resolved symbolically and always continue to - resolve themselves as your program runs. Whether settings breakpoints - by file and line, by symbol name, by symbol regular expression, - or by address, breakpoints will keep trying to resolve new locations - each time shared libraries are loaded. Breakpoints will of course - unresolve themselves when shared libraries are unloaded. Breakpoints - can also be scoped to be set only in a specific shared library. By - default, breakpoints can be set in any shared library and will continue - to attempt to be resolved with each shared library load.

-

Breakpoint options can be set on the breakpoint, - or on the individual locations. This allows flexibility when dealing - with breakpoints and allows us to do what the user wants.

-
- -
- -
-

Commands

-
- -

The command source files represent objects that implement - the functionality for all textual commands available - in our command line interface.

-

Every command is backed by a lldb_private::CommandObject - or lldb_private::CommandObjectMultiword object.

-

lldb_private::CommandObjectMultiword are commands that - have subcommands and allow command line commands to be - logically grouped into a hierarchy.

-

lldb_private::CommandObject command line commands - are the objects that implement the functionality of the - command. They can optionally define - options for themselves, as well as group those options into - logical groups that can go together. The help system is - tied into these objects and can extract the syntax and - option groupings to display appropriate help for each - command.

-
- -
- -
-

Core

-
- -

The Core source files contain basic functionality that - is required in the debugger. A wide variety of classes - are implemented:

- -
    -
  • Address (section offset addressing)
  • -
  • AddressRange
  • -
  • Architecture specification
  • -
  • Broadcaster / Event / Listener
  • -
  • Communication classes that use Connection objects
  • -
  • Uniqued C strings
  • -
  • Data extraction
  • -
  • File specifications
  • -
  • Mangled names
  • -
  • Regular expressions
  • -
  • Source manager
  • -
  • Streams
  • -
  • Value objects
  • -
-
- -
- -
-

DataFormatters

-
- -

A collection of classes that implement the data formatters subsystem.

- -

For a general user-level introduction to data formatters, you can look here. -

A 10,000 foot view of the data formatters is based upon the DataVisualization class. - DataVisualization is the very high level entry point into the data formatters. It vends a stable interface in face of changing internals - and is the recommended entry point for components of LLDB that need to ask questions of the data formatters. - The main questions one can ask of DataVisualization are: -

    -
  • given a ValueObject, retrieve the formatters to be used for it
  • -
  • given a type, retrieve the formatters to be used for it. This is not an "exact" question, - i.e. one can retrieve a formatter from a type name which would not be used to then format ValueObjects of that type
  • -
  • given a name, retrieve a category of that name, optionally creating it if needed - more generally, categories management
  • -
  • given an identifier and a summary, store it as a named summary - more generally, named summary management
  • -
- -

For people actively maintaining the data formatters subsystem itself, however, the FormatManager class is the relevant point of entry. - This class is subject to more frequent changes as the formatters evolve. Currently, it provides a thin caching layer on top of a list of categories - that each export a group of formatters. -

-

From an end-user perspective, the "type" LLDB command is the point of access to the data formatters. A large group of generally-useful formatters - is provided by default and loaded upon debugger startup. -

- -
- -
-

Expression

-
- -

Expression parsing files cover everything from evaluating - DWARF expressions, to evaluating expressions using - Clang.

-

The DWARF expression parser has been heavily modified to - support type promotion, new opcodes needed for evaluating - expressions with symbolic variable references (expression local variables, - program variables), and other operators required by - typical expressions such as assign, address of, float/double/long - double floating point values, casting, and more. The - DWARF expression parser uses a stack of lldb_private::Value - objects. These objects know how to do the standard C type - promotion, and allow for symbolic references to variables - in the program and in the LLDB process (expression local - and expression global variables).

-

The expression parser uses a full instance of the Clang - compiler in order to accurately evaluate expressions. - Hooks have been put into Clang so that the compiler knows - to ask about identifiers it doesn't know about. Once - expressions have be compiled into an AST, we can then - traverse this AST and either generate a DWARF expression - that contains simple opcodes that can be quickly re-evaluated - each time an expression needs to be evaluated, or JIT'ed - up into code that can be run on the process being debugged.

-
- -
- -
-

Host

-
- -

LLDB tries to abstract itself from the host upon which - it is currently running by providing a host abstraction - layer. This layer involves everything from spawning, detaching, - joining and killing native in-process threads, to getting - current information about the current host.

-

Host functionality includes abstraction layers for:

-
    -
  • Mutexes
  • -
  • Conditions
  • -
  • Timing functions
  • -
  • Thread functions
  • -
  • Host target triple
  • -
  • Host child process notifications
  • -
  • Host specific types
  • -
-
- -
- -
-

Interpreter

-
- -

The interpreter classes are the classes responsible for - being the base classes needed for each command object, - and is responsible for tracking and running command line - commands.

-
- -
- -
-

Symbol

-
-

Symbol classes involve everything needed in order to parse - object files and debug symbols. All the needed classes - for compilation units (code and debug info for a source file), - functions, lexical blocks within functions, inlined - functions, types, declaration locations, and variables - are in this section.

-
- -
- -
-

Target

-
- -

Classes that are related to a debug target include:

-
    -
  • Target
  • -
  • Process
  • -
  • Thread
  • -
  • Stack frames
  • -
  • Stack frame registers
  • -
  • ABI for function calling in process being debugged
  • -
  • Execution context batons
  • -
-
- -
- -
-

Utility

-
- -

Utility files should be as stand alone as possible and - available for LLDB, plug-ins or related - applications to use.

-

Files found in the Utility section include:

-
    -
  • Pseudo-terminal support
  • -
  • Register numbering for specific architectures.
  • -
  • String data extractors
  • -
-
- -
-
-
-
- - diff --git a/www/architecture/index.html b/www/architecture/index.html index fd75603f6405..312476fe6edf 100755 --- a/www/architecture/index.html +++ b/www/architecture/index.html @@ -119,30 +119,26 @@
-

Core

-
- -

The Core source files contain basic functionality that - is required in the debugger. A wide variety of classes - are implemented:

- -
    -
  • Address (section offset addressing)
  • -
  • AddressRange
  • -
  • Architecture specification
  • -
  • Broadcaster / Event / Listener
  • -
  • Communication classes that use Connection objects
  • -
  • Uniqued C strings
  • -
  • Data extraction
  • -
  • File specifications
  • -
  • Mangled names
  • -
  • Regular expressions
  • -
  • Source manager
  • -
  • Streams
  • -
  • Value objects
  • -
-
- +

Core

+
+

+ The Core source files contain basic functionality + that is required in the debugger as well as the + class represeting the debugger it self (Debugger). A + wide variety of classes are implemented: +

+
    +
  • Address (section offset addressing)
  • +
  • AddressRange
  • +
  • Architecture specification
  • +
  • Broadcaster / Event / Listener
  • +
  • Communication classes that use Connection objects
  • +
  • Mangled names
  • +
  • Source manager
  • +
  • Value objects
  • +
+
+
@@ -193,26 +189,27 @@
-

Host

-
- -

LLDB tries to abstract itself from the host upon which - it is currently running by providing a host abstraction - layer. This layer involves everything from spawning, detaching, - joining and killing native in-process threads, to getting - current information about the current host.

-

Host functionality includes abstraction layers for:

-
    -
  • Mutexes
  • -
  • Conditions
  • -
  • Timing functions
  • -
  • Thread functions
  • -
  • Host target triple
  • -
  • Host child process notifications
  • -
  • Host specific types
  • -
-
- +

Host

+
+

+ LLDB tries to abstract itself from the host upon which + it is currently running by providing a host abstraction + layer. This layer includes functionality, whose + implementation varies wildly from host to host. +

+

Host functionality includes abstraction layers for:

+
    +
  • Information about the host system (triple, list of running processes, etc.)
  • +
  • Launching processes
  • +
  • Various OS primitives like pipes and sockets
  • +
+

+ It also includes the base classes of the + NativeProcess/Thread hierarchy, which is used by + lldb-server. +

+
+
@@ -259,20 +256,40 @@
-

Utility

-
- -

Utility files should be as stand alone as possible and - available for LLDB, plug-ins or related - applications to use.

-

Files found in the Utility section include:

-
    -
  • Pseudo-terminal support
  • -
  • Register numbering for specific architectures.
  • -
  • String data extractors
  • -
-
- +

Utility

+
+

+ This module contains the lowest layers of LLDB. A + lot of these classes don't really have anything to + do with debugging -- they are just there because the + higher layers of the debugger use these clasess + to implement their functionality. Others are data + structures used in many other parts of the debugger + (TraceOptions). Most of the functionality in this + module could be useful in an application that is + not a debugger; however, providing + a general purpose C++ library is an explicit + non-goal of this module. +

+

+ This module provides following functionality: +

+
    +
  • Abstract path manipulation (FileSpec)
  • +
  • Data buffers (DataBuffer, DataEncoder, DataExtractor)
  • +
  • Logging
  • +
  • Structured data manipulation (JSON)
  • +
  • Streams
  • +
  • Timers
  • +
  • etc.
  • +
+

+ For historic reasons, some of this functionality + overlaps that which is provided by the LLVM support + library. +

+
+
diff --git a/www/sidebar.incl b/www/sidebar.incl index 184a022790e2..8c5cca373653 100644 --- a/www/sidebar.incl +++ b/www/sidebar.incl @@ -49,7 +49,7 @@
  • Build
  • Test
  • SB API Coding Rules
  • -
  • Bug Reports
  • +
  • Bug Reports
  • Browse SVN
  • Browse ViewVC
  • From 97a708bebca0e58714a1e005445ff28d0c1c2ca5 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Wed, 19 Jul 2017 07:02:49 +0000 Subject: [PATCH 03/10] Vendor import of libc++ trunk r308421: https://llvm.org/svn/llvm-project/libcxx/trunk@308421 --- docs/DesignDocs/VisibilityMacros.rst | 11 ++-- include/__config | 14 ++--- include/algorithm | 7 --- include/string | 9 +-- include/vector | 7 --- lib/CMakeLists.txt | 2 +- test/support/test_macros.h | 5 +- www/cxx1z_status.html | 8 +++ www/cxx2a_status.html | 90 ++++++++++++++++++++++++++++ www/index.html | 2 + www/upcoming_meeting.html | 6 +- 11 files changed, 123 insertions(+), 38 deletions(-) create mode 100644 www/cxx2a_status.html diff --git a/docs/DesignDocs/VisibilityMacros.rst b/docs/DesignDocs/VisibilityMacros.rst index 694882dd2638..993ce2cca5fd 100644 --- a/docs/DesignDocs/VisibilityMacros.rst +++ b/docs/DesignDocs/VisibilityMacros.rst @@ -90,20 +90,21 @@ Visibility Macros The macro has an empty definition with GCC. **Windows Behavior**: `extern template` and `dllexport` are fundamentally - incompatible *on a template class* on Windows; the former suppresses + incompatible *on a class template* on Windows; the former suppresses instantiation, while the latter forces it. Specifying both on the same - declaration makes the template class be instantiated, which is not desirable + declaration makes the class template be instantiated, which is not desirable inside headers. This macro therefore expands to `dllimport` outside of libc++ but nothing inside of it (rather than expanding to `dllexport`); instead, the explicit instantiations themselves are marked as exported. Note that this - applies *only* to extern template *classes*. Extern template *functions* obey + applies *only* to extern *class* templates. Extern *function* templates obey regular import/export semantics, and applying `dllexport` directly to the - extern template declaration is the correct thing to do for them. + extern template declaration (i.e. using `_LIBCPP_FUNC_VIS`) is the correct + thing to do for them. **_LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS** Mark the member functions, typeinfo, and vtable of an explicit instantiation of a class template as being exported by the libc++ library. This attribute - must be specified on all template class explicit instantiations. + must be specified on all class template explicit instantiations. It is only necessary to mark the explicit instantiation itself (as opposed to the extern template declaration) as exported on Windows, as discussed above. diff --git a/include/__config b/include/__config index 003e1ea60c60..f15d2d06e564 100644 --- a/include/__config +++ b/include/__config @@ -229,8 +229,9 @@ # define _LIBCPP_SHORT_WCHAR 1 // Both MinGW and native MSVC provide a "MSVC"-like enviroment # define _LIBCPP_MSVCRT_LIKE -// If mingw not explicitly detected, assume using MS C runtime only. -# ifndef __MINGW32__ +// If mingw not explicitly detected, assume using MS C runtime only if +// a MS compatibility version is specified. +# if defined(_MSC_VER) && !defined(__MINGW32__) # define _LIBCPP_MSVCRT // Using Microsoft's C Runtime library # endif # if (defined(_M_AMD64) || defined(__x86_64__)) || (defined(_M_ARM) || defined(__arm__)) @@ -625,7 +626,6 @@ namespace std { #define _LIBCPP_HIDDEN #define _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS #define _LIBCPP_TEMPLATE_VIS -#define _LIBCPP_FUNC_VIS_ONLY #define _LIBCPP_ENUM_VIS #if defined(_LIBCPP_COMPILER_MSVC) @@ -684,10 +684,6 @@ namespace std { # endif #endif -#ifndef _LIBCPP_FUNC_VIS_ONLY -# define _LIBCPP_FUNC_VIS_ONLY _LIBCPP_FUNC_VIS -#endif - #ifndef _LIBCPP_EXTERN_VIS # define _LIBCPP_EXTERN_VIS #endif @@ -925,8 +921,10 @@ template struct __static_assert_check {}; # define _LIBCPP_STD_VER 11 # elif __cplusplus <= 201402L # define _LIBCPP_STD_VER 14 +# elif __cplusplus <= 201703L +# define _LIBCPP_STD_VER 17 # else -# define _LIBCPP_STD_VER 16 // current year, or date of c++17 ratification +# define _LIBCPP_STD_VER 18 // current year, or date of c++2a ratification # endif #endif // _LIBCPP_STD_VER diff --git a/include/algorithm b/include/algorithm index 9fe0361e577d..4542275adfda 100644 --- a/include/algorithm +++ b/include/algorithm @@ -4234,10 +4234,6 @@ sort(__wrap_iter<_Tp*> __first, __wrap_iter<_Tp*> __last, _Compare __comp) _VSTD::sort<_Tp*, _Comp_ref>(__first.base(), __last.base(), __comp); } -#ifdef _LIBCPP_MSVC -#pragma warning( push ) -#pragma warning( disable: 4231) -#endif // _LIBCPP_MSVC _LIBCPP_EXTERN_TEMPLATE(_LIBCPP_FUNC_VIS void __sort<__less&, char*>(char*, char*, __less&)) _LIBCPP_EXTERN_TEMPLATE(_LIBCPP_FUNC_VIS void __sort<__less&, wchar_t*>(wchar_t*, wchar_t*, __less&)) _LIBCPP_EXTERN_TEMPLATE(_LIBCPP_FUNC_VIS void __sort<__less&, signed char*>(signed char*, signed char*, __less&)) @@ -4271,9 +4267,6 @@ _LIBCPP_EXTERN_TEMPLATE(_LIBCPP_FUNC_VIS bool __insertion_sort_incomplete<__less _LIBCPP_EXTERN_TEMPLATE(_LIBCPP_FUNC_VIS bool __insertion_sort_incomplete<__less&, long double*>(long double*, long double*, __less&)) _LIBCPP_EXTERN_TEMPLATE(_LIBCPP_FUNC_VIS unsigned __sort5<__less&, long double*>(long double*, long double*, long double*, long double*, long double*, __less&)) -#ifdef _LIBCPP_MSVC -#pragma warning( pop ) -#endif // _LIBCPP_MSVC // lower_bound diff --git a/include/string b/include/string index 010a4c7816ea..cf42f529c701 100644 --- a/include/string +++ b/include/string @@ -578,14 +578,7 @@ __basic_string_common<__b>::__throw_out_of_range() const _VSTD::__throw_out_of_range("basic_string"); } -#ifdef _LIBCPP_MSVC -#pragma warning( push ) -#pragma warning( disable: 4231 ) -#endif // _LIBCPP_MSVC _LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS __basic_string_common) -#ifdef _LIBCPP_MSVC -#pragma warning( pop ) -#endif // _LIBCPP_MSVC #ifdef _LIBCPP_NO_EXCEPTIONS template @@ -4006,7 +3999,7 @@ basic_string<_CharT, _Traits, _Allocator>::__subscriptable(const const_iterator* _LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS basic_string) _LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS basic_string) -_LIBCPP_EXTERN_TEMPLATE(string operator+, allocator >(char const*, string const&)) +_LIBCPP_EXTERN_TEMPLATE(_LIBCPP_FUNC_VIS string operator+, allocator >(char const*, string const&)) #if _LIBCPP_STD_VER > 11 // Literal suffixes for basic_string [basic.string.literals] diff --git a/include/vector b/include/vector index ee19fb7081a2..6e9920a0f80f 100644 --- a/include/vector +++ b/include/vector @@ -310,14 +310,7 @@ __vector_base_common<__b>::__throw_out_of_range() const _VSTD::__throw_out_of_range("vector"); } -#ifdef _LIBCPP_MSVC -#pragma warning( push ) -#pragma warning( disable: 4231 ) -#endif // _LIBCPP_MSVC _LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS __vector_base_common) -#ifdef _LIBCPP_MSVC -#pragma warning( pop ) -#endif // _LIBCPP_MSVC template class __vector_base diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 9fc0d1394336..578651423f3b 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -258,7 +258,7 @@ if (LIBCXX_ENABLE_STATIC) set(MERGE_ARCHIVES_SEARCH_PATHS "-L${LIBCXX_CXX_ABI_LIBRARY_PATH}") endif() if ((TARGET ${LIBCXX_CXX_ABI_LIBRARY}) OR - (${LIBCXX_CXX_ABI_LIBRARY} STREQUAL "cxxabi(_static|_shared)?" AND HAVE_LIBCXXABI)) + (${LIBCXX_CXX_ABI_LIBRARY} MATCHES "cxxabi(_static|_shared)?" AND HAVE_LIBCXXABI)) set(MERGE_ARCHIVES_ABI_TARGET "$") else() set(MERGE_ARCHIVES_ABI_TARGET diff --git a/test/support/test_macros.h b/test/support/test_macros.h index cc2918a0875a..95270e437905 100644 --- a/test/support/test_macros.h +++ b/test/support/test_macros.h @@ -81,8 +81,11 @@ # define TEST_STD_VER 11 #elif __cplusplus <= 201402L # define TEST_STD_VER 14 +#elif __cplusplus <= 201703L +# define TEST_STD_VER 17 #else -# define TEST_STD_VER 16 // current year; greater than current standard +# define TEST_STD_VER 99 // greater than current standard +// This is deliberately different than _LIBCPP_STD_VER to discourage matching them up. #endif #endif diff --git a/www/cxx1z_status.html b/www/cxx1z_status.html index bd33b6e3c574..d9c44fc297ac 100644 --- a/www/cxx1z_status.html +++ b/www/cxx1z_status.html @@ -161,6 +161,9 @@ P0607R0LWGInline Variables for the Standard LibraryKona P0618R0LWGDeprecating <codecvt>Kona P0623R0LWGFinal C++17 Parallel Algorithms FixesKona + + P0682R1LWGRepairing elementary string conversionsToronto + P0739R0LWGSome improvements to class template argument deduction integration into the standard libraryToronto @@ -483,6 +486,11 @@ 2911An is_aggregate type trait is neededKonaComplete 2921packaged_task and type-erased allocatorsKona 2934optional<const T> doesn't compare with TKonaComplete + + 2901Variants cannot properly support allocatorsTorontoComplete + 2955to_chars / from_chars depend on std::stringTorontoResolved by P0682R1 + 2956filesystem::canonical() still defined in terms of absolute(p, base)TorontoComplete + diff --git a/www/cxx2a_status.html b/www/cxx2a_status.html new file mode 100644 index 000000000000..2c9f878b623f --- /dev/null +++ b/www/cxx2a_status.html @@ -0,0 +1,90 @@ + + + + + + libc++ C++2a Status + + + + + + + +
    + +

    libc++ C++2a Status

    + + +

    In July 2017, the C++ standard committee created a draft for the next version of the C++ standard, known here as "C++2a" (probably to be C++20).

    +

    This page shows the status of libc++; the status of clang's support of the language features is here.

    + +

    The groups that have contributed papers: +

      +
    • LWG - Library working group
    • +
    • CWG - Core Language Working group
    • +
    • SG1 - Study group #1 (Concurrency working group)
    • +
    +

    + +

    Paper Status

    + + + + + + + +
    Paper #GroupPaper NameMeetingStatusFirst released version
    P0463R1LWGEndian just EndianToronto
    P0674R1LWGExtending make_shared to Support ArraysToronto
    + +

    [ Note: "Nothing to do" means that no library changes were needed to implement this change -- end note]

    + +

    Library Working group Issues Status

    + + + + + + + + + + + + + + + + + + + +
    Issue #Issue NameMeetingStatus
    2070allocate_shared should use allocator_traits<A>::constructTorontoResolved by P0674R1
    2444Inconsistent complexity for std::sort_heapToronto
    2593Moved-from state of AllocatorsToronto
    2597std::log misspecified for complex numbersToronto
    2783stack::emplace() and queue::emplace() should return decltype(auto)Toronto
    2932Constraints on parallel algorithm implementations are underspecifiedToronto
    2937Is equivalent("existing_thing", "not_existing_thing") an errorTorontoComplete
    2940result_of specification also needs a little cleanupToronto
    2942LWG 2873's resolution missed weak_ptr::owner_beforeToronto
    2954Specialization of the convenience variable templates should be prohibitedToronto
    2961Bad postcondition for set_default_resourceToronto
    2966Incomplete resolution of US 74TorontoNothing to do
    2974Diagnose out of bounds tuple_element/variant_alternativeTorontoComplete
    + +

    Last Updated: 16-Jul-2017

    +
    + + diff --git a/www/index.html b/www/index.html index 5dc13858d400..2e707dcb2137 100644 --- a/www/index.html +++ b/www/index.html @@ -138,6 +138,8 @@ C++14 can be found here.

    A list of features and changes for the next C++ standard, known here as "C++1z" (probably to be C++17) can be found here.

    +

    A list of features and changes for the C++ standard beyond C++17, known here as + "C++2a" (probably to be C++20) can be found here.

    Implementation of the post-c++14 Technical Specifications is in progress. A list of features and the current status of these features can be found here.

    diff --git a/www/upcoming_meeting.html b/www/upcoming_meeting.html index f1a99fdef2d8..f90f4661266d 100644 --- a/www/upcoming_meeting.html +++ b/www/upcoming_meeting.html @@ -73,7 +73,11 @@ 2974Diagnose out of bounds tuple_element/variant_alternativeToronto
    Priority 1 Bugs
    - 2665remove_filename() post condition is incorrectKonaWe do this already + 2665remove_filename() post condition is incorrectTorontoWe do this already + +
    Immediate Issues in Toronto
    + 2901Variants cannot properly support allocatorsTorontoWe do this already + 2956filesystem::canonical() still defined in terms of absolute(p, base)Toronto From da06c7cfa0388de29a4024d8d386e48f2fb13ed6 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Wed, 19 Jul 2017 07:02:58 +0000 Subject: [PATCH 04/10] Vendor import of lld trunk r308421: https://llvm.org/svn/llvm-project/lld/trunk@308421 --- COFF/Chunks.cpp | 10 +- COFF/Chunks.h | 5 +- COFF/Config.h | 1 + COFF/Driver.cpp | 37 +- COFF/PDB.cpp | 424 ++++++++++++------ ELF/Arch/ARM.cpp | 45 ++ ELF/Arch/MipsArchTree.cpp | 6 +- ELF/Config.h | 1 + ELF/Driver.cpp | 4 + ELF/EhFrame.h | 4 +- ELF/Filesystem.h | 4 +- ELF/GdbIndex.h | 2 +- ELF/ICF.h | 2 +- ELF/InputFiles.h | 4 +- ELF/LTO.h | 6 +- ELF/LinkerScript.cpp | 19 +- ELF/MapFile.cpp | 2 +- ELF/MapFile.h | 4 +- ELF/Memory.h | 4 +- ELF/Options.td | 7 +- ELF/OutputSections.cpp | 8 +- ELF/OutputSections.h | 7 +- ELF/Relocations.cpp | 81 ++-- ELF/Relocations.h | 11 +- ELF/ScriptParser.cpp | 10 + ELF/Strings.cpp | 23 - ELF/Strings.h | 7 +- ELF/SymbolTable.cpp | 43 +- ELF/Symbols.cpp | 2 +- ELF/SyntheticSections.cpp | 29 +- ELF/Target.cpp | 5 + ELF/Target.h | 5 +- ELF/Threads.h | 4 +- ELF/Thunks.cpp | 18 +- ELF/Thunks.h | 2 +- ELF/Writer.cpp | 6 +- ELF/Writer.h | 4 +- docs/windows_support.rst | 5 +- test/COFF/Inputs/default.def | 2 + test/COFF/Inputs/extension.def | 3 + test/COFF/Inputs/named.def | 3 + test/COFF/Inputs/object.s | 13 + .../COFF/Inputs/pdb-type-server-simple-a.yaml | 255 +++++++++++ .../COFF/Inputs/pdb-type-server-simple-b.yaml | 173 +++++++ .../Inputs/pdb-type-server-simple-ts.yaml | 147 ++++++ test/COFF/common.test | 1 + test/COFF/conflict.test | 1 + test/COFF/constant.test | 1 + test/COFF/def-export-stdcall.s | 1 + test/COFF/delayimports32.test | 1 + test/COFF/entry-mangled.test | 1 + test/COFF/entrylib.ll | 1 + test/COFF/implib-name.test | 71 +++ test/COFF/imports.test | 1 + test/COFF/include-lto.ll | 1 + test/COFF/msvclto-archive.ll | 1 + test/COFF/msvclto-order.ll | 1 + test/COFF/msvclto.ll | 1 + test/COFF/pdb-comdat.test | 4 +- test/COFF/pdb-lib.s | 1 + test/COFF/pdb-symbol-types.yaml | 2 +- test/COFF/pdb-type-server-missing.yaml | 132 ++++++ test/COFF/pdb-type-server-simple.test | 91 ++++ test/COFF/reloc-discarded-dwarf.s | 15 + test/COFF/reloc-oob.yaml | 62 +++ test/COFF/savetemps.ll | 1 + test/COFF/thinlto-archives.ll | 1 + test/COFF/thinlto-mangled.ll | 1 + test/COFF/thinlto.ll | 1 + test/ELF/Inputs/ctors_dtors_priority1.s | 4 +- test/ELF/Inputs/ctors_dtors_priority2.s | 4 +- test/ELF/Inputs/ctors_dtors_priority3.s | 4 +- test/ELF/Inputs/gdb-index-a.elf | Bin 3040 -> 0 bytes test/ELF/Inputs/gdb-index-b.elf | Bin 3048 -> 0 bytes test/ELF/Inputs/gdb-index.s | 73 +++ test/ELF/Inputs/symver-archive1.s | 6 - test/ELF/Inputs/symver-archive2.s | 1 - test/ELF/allow-shlib-undefined.s | 1 + test/ELF/as-needed-no-reloc.s | 2 +- test/ELF/as-needed.s | 12 +- test/ELF/auxiliary.s | 1 + test/ELF/compressed-debug-input.s | 2 +- test/ELF/ctors_dtors_priority.s | 31 +- test/ELF/debug-gnu-pubnames.s | 24 +- test/ELF/dynamic-reloc.s | 2 +- test/ELF/filter.s | 15 + test/ELF/gc-sections-shared.s | 2 +- test/ELF/gdb-index-empty.s | 1 + test/ELF/gdb-index-gc-sections.s | 1 + test/ELF/gdb-index.s | 113 +++-- test/ELF/i386-reloc-large-addend.s | 1 + test/ELF/i386-reloc-range.s | 1 + test/ELF/invalid/tls-symbol.s | 4 +- test/ELF/linkerscript/exidx-crash.s | 7 + test/ELF/linkerscript/got-write-offset.s | 23 + test/ELF/linkerscript/output-too-large.s | 1 + test/ELF/lto/available-externally.ll | 1 + test/ELF/lto/comdat2.ll | 1 + test/ELF/lto/common2.ll | 1 + test/ELF/lto/common3.ll | 1 + test/ELF/lto/discard-value-names.ll | 1 + test/ELF/lto/opt-level.ll | 1 + test/ELF/lto/opt-remarks.ll | 1 + test/ELF/lto/relax-relocs.ll | 1 + test/ELF/lto/thin-archivecollision.ll | 1 + test/ELF/lto/thinlto.ll | 1 + test/ELF/lto/type-merge2.ll | 1 + test/ELF/lto/unnamed-addr-comdat.ll | 1 + test/ELF/lto/unnamed-addr-drop.ll | 1 + test/ELF/lto/unnamed-addr.ll | 1 + test/ELF/many-alloc-sections.s | 1 + test/ELF/many-sections.s | 1 + test/ELF/map-gc-sections.s | 9 + test/ELF/merge-section-types.s | 1 + test/ELF/new-dtags.test | 1 + test/ELF/no-obj.s | 1 + test/ELF/no-soname.s | 9 +- test/ELF/no-symtab.s | 1 + test/ELF/no-undefined.s | 1 + test/ELF/pie-weak.s | 1 + test/ELF/progname.s | 1 + test/ELF/relative-dynamic-reloc-pie.s | 1 + test/ELF/relative-dynamic-reloc.s | 1 + test/ELF/relocatable-compressed-input.s | 2 +- test/ELF/relocatable-reloc.s | 1 + test/ELF/relocatable-section-symbol.s | 1 + test/ELF/relocatable-sections.s | 1 + test/ELF/relocatable-tls.s | 1 + test/ELF/relocation-shared.s | 1 + test/ELF/shared-be.s | 2 +- test/ELF/shared.s | 2 +- test/ELF/soname.s | 2 +- test/ELF/soname2.s | 2 +- test/ELF/symver-archive.s | 15 - test/ELF/version-script-twice.s | 14 + 135 files changed, 1878 insertions(+), 396 deletions(-) create mode 100644 test/COFF/Inputs/default.def create mode 100644 test/COFF/Inputs/extension.def create mode 100644 test/COFF/Inputs/named.def create mode 100644 test/COFF/Inputs/object.s create mode 100644 test/COFF/Inputs/pdb-type-server-simple-a.yaml create mode 100644 test/COFF/Inputs/pdb-type-server-simple-b.yaml create mode 100644 test/COFF/Inputs/pdb-type-server-simple-ts.yaml create mode 100644 test/COFF/implib-name.test create mode 100644 test/COFF/pdb-type-server-missing.yaml create mode 100644 test/COFF/pdb-type-server-simple.test create mode 100644 test/COFF/reloc-discarded-dwarf.s create mode 100644 test/COFF/reloc-oob.yaml delete mode 100644 test/ELF/Inputs/gdb-index-a.elf delete mode 100644 test/ELF/Inputs/gdb-index-b.elf create mode 100644 test/ELF/Inputs/gdb-index.s delete mode 100644 test/ELF/Inputs/symver-archive1.s delete mode 100644 test/ELF/Inputs/symver-archive2.s create mode 100644 test/ELF/filter.s create mode 100644 test/ELF/linkerscript/exidx-crash.s create mode 100644 test/ELF/linkerscript/got-write-offset.s create mode 100644 test/ELF/map-gc-sections.s delete mode 100644 test/ELF/symver-archive.s create mode 100644 test/ELF/version-script-twice.s diff --git a/COFF/Chunks.cpp b/COFF/Chunks.cpp index c0996f55f9d1..7d93c28c86c8 100644 --- a/COFF/Chunks.cpp +++ b/COFF/Chunks.cpp @@ -210,7 +210,15 @@ void SectionChunk::writeTo(uint8_t *Buf) const { memcpy(Buf + OutputSectionOff, A.data(), A.size()); // Apply relocations. + size_t InputSize = getSize(); for (const coff_relocation &Rel : Relocs) { + // Check for an invalid relocation offset. This check isn't perfect, because + // we don't have the relocation size, which is only known after checking the + // machine and relocation type. As a result, a relocation may overwrite the + // beginning of the following input section. + if (Rel.VirtualAddress >= InputSize) + fatal("relocation points beyond the end of its parent section"); + uint8_t *Off = Buf + OutputSectionOff + Rel.VirtualAddress; // Get the output section of the symbol for this relocation. The output @@ -227,7 +235,7 @@ void SectionChunk::writeTo(uint8_t *Buf) const { // sections are not GC roots and can end up with these kinds of relocations. // Skip these relocations. if (!OS && !isa(Sym) && !isa(Sym)) { - if (isCodeView()) + if (isCodeView() || isDWARF()) continue; fatal("relocation against symbol in discarded section: " + Sym->getName()); diff --git a/COFF/Chunks.h b/COFF/Chunks.h index fc3f5d0df4b6..ece5419e255e 100644 --- a/COFF/Chunks.h +++ b/COFF/Chunks.h @@ -112,7 +112,7 @@ class Chunk { }; // A chunk corresponding a section of an input file. -class SectionChunk : public Chunk { +class SectionChunk final : public Chunk { // Identical COMDAT Folding feature accesses section internal data. friend class ICF; @@ -188,6 +188,9 @@ class SectionChunk : public Chunk { return SectionName == ".debug" || SectionName.startswith(".debug$"); } + // True if this is a DWARF debug info chunk. + bool isDWARF() const { return SectionName.startswith(".debug_"); } + // Allow iteration over the bodies of this chunk's relocated symbols. llvm::iterator_range symbols() const { return llvm::make_range(symbol_iterator(File, Relocs.begin()), diff --git a/COFF/Config.h b/COFF/Config.h index 25fdc7abd67b..a58e7d5585f2 100644 --- a/COFF/Config.h +++ b/COFF/Config.h @@ -82,6 +82,7 @@ struct Configuration { SymbolBody *Entry = nullptr; bool NoEntry = false; std::string OutputFile; + std::string ImportName; bool ColorDiagnostics; bool DoGC = true; bool DoICF = true; diff --git a/COFF/Driver.cpp b/COFF/Driver.cpp index 3620297b8b94..35f4a04866c5 100644 --- a/COFF/Driver.cpp +++ b/COFF/Driver.cpp @@ -429,7 +429,32 @@ static std::string getImplibPath() { return Out.str(); } -static void createImportLibrary() { +// +// The import name is caculated as the following: +// +// | LIBRARY w/ ext | LIBRARY w/o ext | no LIBRARY +// -----+----------------+---------------------+------------------ +// LINK | {value} | {value}.{.dll/.exe} | {output name} +// LIB | {value} | {value}.dll | {output name}.dll +// +static std::string getImportName(bool AsLib) { + SmallString<128> Out; + + if (Config->ImportName.empty()) { + Out.assign(sys::path::filename(Config->OutputFile)); + if (AsLib) + sys::path::replace_extension(Out, ".dll"); + } else { + Out.assign(Config->ImportName); + if (!sys::path::has_extension(Out)) + sys::path::replace_extension(Out, + (Config->DLL || AsLib) ? ".dll" : ".exe"); + } + + return Out.str(); +} + +static void createImportLibrary(bool AsLib) { std::vector Exports; for (Export &E1 : Config->Exports) { COFFShortExport E2; @@ -444,9 +469,8 @@ static void createImportLibrary() { Exports.push_back(E2); } - std::string DLLName = sys::path::filename(Config->OutputFile); - std::string Path = getImplibPath(); - writeImportLibrary(DLLName, Path, Exports, Config->Machine); + writeImportLibrary(getImportName(AsLib), getImplibPath(), Exports, + Config->Machine); } static void parseModuleDefs(StringRef Path) { @@ -457,6 +481,7 @@ static void parseModuleDefs(StringRef Path) { if (Config->OutputFile.empty()) Config->OutputFile = Saver.save(M.OutputFile); + Config->ImportName = Saver.save(M.ImportName); if (M.ImageBase) Config->ImageBase = M.ImageBase; if (M.StackReserve) @@ -992,7 +1017,7 @@ void LinkerDriver::link(ArrayRef ArgsArr) { // Handle generation of import library from a def file. if (!Args.hasArgNoClaim(OPT_INPUT)) { fixupExports(); - createImportLibrary(); + createImportLibrary(/*AsLib=*/true); exit(0); } @@ -1117,7 +1142,7 @@ void LinkerDriver::link(ArrayRef ArgsArr) { // need to create a .lib file. if (!Config->Exports.empty() || Config->DLL) { fixupExports(); - createImportLibrary(); + createImportLibrary(/*AsLib=*/false); assignExportOrdinals(); } diff --git a/COFF/PDB.cpp b/COFF/PDB.cpp index 508f59e3af1f..89462da93454 100644 --- a/COFF/PDB.cpp +++ b/COFF/PDB.cpp @@ -14,28 +14,29 @@ #include "SymbolTable.h" #include "Symbols.h" #include "llvm/DebugInfo/CodeView/CVDebugRecord.h" -#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" -#include "llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h" #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" #include "llvm/DebugInfo/CodeView/SymbolSerializer.h" +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" #include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h" #include "llvm/DebugInfo/CodeView/TypeStreamMerger.h" #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" #include "llvm/DebugInfo/MSF/MSFBuilder.h" #include "llvm/DebugInfo/MSF/MSFCommon.h" +#include "llvm/DebugInfo/PDB/GenericError.h" #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h" #include "llvm/DebugInfo/PDB/Native/DbiStream.h" #include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h" #include "llvm/DebugInfo/PDB/Native/InfoStream.h" #include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h" #include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h" -#include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h" #include "llvm/DebugInfo/PDB/Native/TpiStream.h" #include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" +#include "llvm/DebugInfo/PDB/PDB.h" #include "llvm/Object/COFF.h" #include "llvm/Support/BinaryByteStream.h" #include "llvm/Support/Endian.h" @@ -53,8 +54,81 @@ using llvm::object::coff_section; static ExitOnError ExitOnErr; +namespace { +/// Map from type index and item index in a type server PDB to the +/// corresponding index in the destination PDB. +struct CVIndexMap { + SmallVector TPIMap; + SmallVector IPIMap; + bool IsTypeServerMap = false; +}; + +class PDBLinker { +public: + PDBLinker(SymbolTable *Symtab) + : Alloc(), Symtab(Symtab), Builder(Alloc), TypeTable(Alloc), + IDTable(Alloc) {} + + /// Emit the basic PDB structure: initial streams, headers, etc. + void initialize(const llvm::codeview::DebugInfo *DI); + + /// Link CodeView from each object file in the symbol table into the PDB. + void addObjectsToPDB(); + + /// Link CodeView from a single object file into the PDB. + void addObjectFile(ObjectFile *File); + + /// Produce a mapping from the type and item indices used in the object + /// file to those in the destination PDB. + /// + /// If the object file uses a type server PDB (compiled with /Zi), merge TPI + /// and IPI from the type server PDB and return a map for it. Each unique type + /// server PDB is merged at most once, so this may return an existing index + /// mapping. + /// + /// If the object does not use a type server PDB (compiled with /Z7), we merge + /// all the type and item records from the .debug$S stream and fill in the + /// caller-provided ObjectIndexMap. + const CVIndexMap &mergeDebugT(ObjectFile *File, CVIndexMap &ObjectIndexMap); + + const CVIndexMap &maybeMergeTypeServerPDB(ObjectFile *File, + TypeServer2Record &TS); + + /// Add the section map and section contributions to the PDB. + void addSections(ArrayRef SectionTable); + + /// Write the PDB to disk. + void commit(); + +private: + BumpPtrAllocator Alloc; + + SymbolTable *Symtab; + + pdb::PDBFileBuilder Builder; + + /// Type records that will go into the PDB TPI stream. + TypeTableBuilder TypeTable; + + /// Item records that will go into the PDB IPI stream. + TypeTableBuilder IDTable; + + /// PDBs use a single global string table for filenames in the file checksum + /// table. + DebugStringTableSubsection PDBStrTab; + + llvm::SmallString<128> NativePath; + + std::vector SectionMap; + + /// Type index mappings of type server PDBs that we've loaded so far. + std::map TypeServerIndexMappings; +}; +} + // Returns a list of all SectionChunks. -static void addSectionContribs(SymbolTable *Symtab, pdb::DbiStreamBuilder &DbiBuilder) { +static void addSectionContribs(SymbolTable *Symtab, + pdb::DbiStreamBuilder &DbiBuilder) { for (Chunk *C : Symtab->getChunks()) if (auto *SC = dyn_cast(C)) DbiBuilder.addSectionContrib(SC->File->ModuleDBI, SC->Header); @@ -96,24 +170,115 @@ static void addTypeInfo(pdb::TpiStreamBuilder &TpiBuilder, }); } -static void mergeDebugT(ObjectFile *File, - TypeTableBuilder &IDTable, - TypeTableBuilder &TypeTable, - SmallVectorImpl &TypeIndexMap, - pdb::PDBTypeServerHandler &Handler) { +static Optional +maybeReadTypeServerRecord(CVTypeArray &Types) { + auto I = Types.begin(); + if (I == Types.end()) + return None; + const CVType &Type = *I; + if (Type.kind() != LF_TYPESERVER2) + return None; + TypeServer2Record TS; + if (auto EC = TypeDeserializer::deserializeAs(const_cast(Type), TS)) + fatal(EC, "error reading type server record"); + return std::move(TS); +} + +const CVIndexMap &PDBLinker::mergeDebugT(ObjectFile *File, + CVIndexMap &ObjectIndexMap) { ArrayRef Data = getDebugSection(File, ".debug$T"); if (Data.empty()) - return; + return ObjectIndexMap; BinaryByteStream Stream(Data, support::little); CVTypeArray Types; BinaryStreamReader Reader(Stream); - Handler.addSearchPath(sys::path::parent_path(File->getName())); if (auto EC = Reader.readArray(Types, Reader.getLength())) fatal(EC, "Reader::readArray failed"); + + // Look through type servers. If we've already seen this type server, don't + // merge any type information. + if (Optional TS = maybeReadTypeServerRecord(Types)) + return maybeMergeTypeServerPDB(File, *TS); + + // This is a /Z7 object. Fill in the temporary, caller-provided + // ObjectIndexMap. if (auto Err = mergeTypeAndIdRecords(IDTable, TypeTable, - TypeIndexMap, &Handler, Types)) - fatal(Err, "codeview::mergeTypeStreams failed"); + ObjectIndexMap.TPIMap, Types)) + fatal(Err, "codeview::mergeTypeAndIdRecords failed"); + return ObjectIndexMap; +} + +static Expected> +tryToLoadPDB(const GUID &GuidFromObj, StringRef TSPath) { + std::unique_ptr ThisSession; + if (auto EC = + pdb::loadDataForPDB(pdb::PDB_ReaderType::Native, TSPath, ThisSession)) + return std::move(EC); + + std::unique_ptr NS( + static_cast(ThisSession.release())); + pdb::PDBFile &File = NS->getPDBFile(); + auto ExpectedInfo = File.getPDBInfoStream(); + // All PDB Files should have an Info stream. + if (!ExpectedInfo) + return ExpectedInfo.takeError(); + + // Just because a file with a matching name was found and it was an actual + // PDB file doesn't mean it matches. For it to match the InfoStream's GUID + // must match the GUID specified in the TypeServer2 record. + if (ExpectedInfo->getGuid() != GuidFromObj) + return make_error( + pdb::generic_error_code::type_server_not_found, TSPath); + + return std::move(NS); +} + +const CVIndexMap &PDBLinker::maybeMergeTypeServerPDB(ObjectFile *File, + TypeServer2Record &TS) { + // First, check if we already loaded a PDB with this GUID. Return the type + // index mapping if we have it. + auto Insertion = TypeServerIndexMappings.insert({TS.getGuid(), CVIndexMap()}); + CVIndexMap &IndexMap = Insertion.first->second; + if (!Insertion.second) + return IndexMap; + + // Mark this map as a type server map. + IndexMap.IsTypeServerMap = true; + + // Check for a PDB at: + // 1. The given file path + // 2. Next to the object file or archive file + auto ExpectedSession = tryToLoadPDB(TS.getGuid(), TS.getName()); + if (!ExpectedSession) { + consumeError(ExpectedSession.takeError()); + StringRef LocalPath = + !File->ParentName.empty() ? File->ParentName : File->getName(); + SmallString<128> Path = sys::path::parent_path(LocalPath); + sys::path::append( + Path, sys::path::filename(TS.getName(), sys::path::Style::windows)); + ExpectedSession = tryToLoadPDB(TS.getGuid(), Path); + } + if (auto E = ExpectedSession.takeError()) + fatal(E, "Type server PDB was not found"); + + // Merge TPI first, because the IPI stream will reference type indices. + auto ExpectedTpi = (*ExpectedSession)->getPDBFile().getPDBTpiStream(); + if (auto E = ExpectedTpi.takeError()) + fatal(E, "Type server does not have TPI stream"); + if (auto Err = mergeTypeRecords(TypeTable, IndexMap.TPIMap, + ExpectedTpi->typeArray())) + fatal(Err, "codeview::mergeTypeRecords failed"); + + // Merge IPI. + auto ExpectedIpi = (*ExpectedSession)->getPDBFile().getPDBIpiStream(); + if (auto E = ExpectedIpi.takeError()) + fatal(E, "Type server does not have TPI stream"); + if (auto Err = mergeIdRecords(IDTable, IndexMap.TPIMap, IndexMap.IPIMap, + ExpectedIpi->typeArray())) + fatal(Err, "codeview::mergeIdRecords failed"); + + return IndexMap; } static bool remapTypeIndex(TypeIndex &TI, ArrayRef TypeIndexMap) { @@ -127,16 +292,22 @@ static bool remapTypeIndex(TypeIndex &TI, ArrayRef TypeIndexMap) { static void remapTypesInSymbolRecord(ObjectFile *File, MutableArrayRef Contents, - ArrayRef TypeIndexMap, + const CVIndexMap &IndexMap, ArrayRef TypeRefs) { for (const TiReference &Ref : TypeRefs) { unsigned ByteSize = Ref.Count * sizeof(TypeIndex); if (Contents.size() < Ref.Offset + ByteSize) fatal("symbol record too short"); + + // This can be an item index or a type index. Choose the appropriate map. + ArrayRef TypeOrItemMap = IndexMap.TPIMap; + if (Ref.Kind == TiRefKind::IndexRef && IndexMap.IsTypeServerMap) + TypeOrItemMap = IndexMap.IPIMap; + MutableArrayRef TIs( reinterpret_cast(Contents.data() + Ref.Offset), Ref.Count); for (TypeIndex &TI : TIs) { - if (!remapTypeIndex(TI, TypeIndexMap)) { + if (!remapTypeIndex(TI, TypeOrItemMap)) { TI = TypeIndex(SimpleTypeKind::NotTranslated); log("ignoring symbol record in " + File->getName() + " with bad type index 0x" + utohexstr(TI.getIndex())); @@ -241,7 +412,7 @@ static void scopeStackClose(SmallVectorImpl &Stack, } static void mergeSymbolRecords(BumpPtrAllocator &Alloc, ObjectFile *File, - ArrayRef TypeIndexMap, + const CVIndexMap &IndexMap, BinaryStreamRef SymData) { // FIXME: Improve error recovery by warning and skipping records when // possible. @@ -264,7 +435,7 @@ static void mergeSymbolRecords(BumpPtrAllocator &Alloc, ObjectFile *File, // Re-map all the type index references. MutableArrayRef Contents = NewData.drop_front(sizeof(RecordPrefix)); - remapTypesInSymbolRecord(File, Contents, TypeIndexMap, TypeRefs); + remapTypesInSymbolRecord(File, Contents, IndexMap, TypeRefs); // Fill in "Parent" and "End" fields by maintaining a stack of scopes. CVSymbol NewSym(Sym.kind(), NewData); @@ -289,110 +460,105 @@ static ArrayRef relocateDebugChunk(BumpPtrAllocator &Alloc, ".debug$S"); } -// Add all object files to the PDB. Merge .debug$T sections into IpiData and -// TpiData. -static void addObjectsToPDB(BumpPtrAllocator &Alloc, SymbolTable *Symtab, - pdb::PDBFileBuilder &Builder, - TypeTableBuilder &TypeTable, - TypeTableBuilder &IDTable) { - // Follow type servers. If the same type server is encountered more than - // once for this instance of `PDBTypeServerHandler` (for example if many - // object files reference the same TypeServer), the types from the - // TypeServer will only be visited once. - pdb::PDBTypeServerHandler Handler; +void PDBLinker::addObjectFile(ObjectFile *File) { + // Add a module descriptor for every object file. We need to put an absolute + // path to the object into the PDB. If this is a plain object, we make its + // path absolute. If it's an object in an archive, we make the archive path + // absolute. + bool InArchive = !File->ParentName.empty(); + SmallString<128> Path = InArchive ? File->ParentName : File->getName(); + sys::fs::make_absolute(Path); + sys::path::native(Path, sys::path::Style::windows); + StringRef Name = InArchive ? File->getName() : StringRef(Path); - // PDBs use a single global string table for filenames in the file checksum - // table. - auto PDBStrTab = std::make_shared(); + File->ModuleDBI = &ExitOnErr(Builder.getDbiBuilder().addModuleInfo(Name)); + File->ModuleDBI->setObjFileName(Path); - // Visit all .debug$T sections to add them to Builder. - for (ObjectFile *File : Symtab->ObjectFiles) { - // Add a module descriptor for every object file. We need to put an absolute - // path to the object into the PDB. If this is a plain object, we make its - // path absolute. If it's an object in an archive, we make the archive path - // absolute. - bool InArchive = !File->ParentName.empty(); - SmallString<128> Path = InArchive ? File->ParentName : File->getName(); - sys::fs::make_absolute(Path); - sys::path::native(Path, llvm::sys::path::Style::windows); - StringRef Name = InArchive ? File->getName() : StringRef(Path); + // Before we can process symbol substreams from .debug$S, we need to process + // type information, file checksums, and the string table. Add type info to + // the PDB first, so that we can get the map from object file type and item + // indices to PDB type and item indices. + CVIndexMap ObjectIndexMap; + const CVIndexMap &IndexMap = mergeDebugT(File, ObjectIndexMap); - File->ModuleDBI = &ExitOnErr(Builder.getDbiBuilder().addModuleInfo(Name)); - File->ModuleDBI->setObjFileName(Path); + // Now do all live .debug$S sections. + for (SectionChunk *DebugChunk : File->getDebugChunks()) { + if (!DebugChunk->isLive() || DebugChunk->getSectionName() != ".debug$S") + continue; - // Before we can process symbol substreams from .debug$S, we need to process - // type information, file checksums, and the string table. Add type info to - // the PDB first, so that we can get the map from object file type and item - // indices to PDB type and item indices. - SmallVector TypeIndexMap; - mergeDebugT(File, IDTable, TypeTable, TypeIndexMap, Handler); + ArrayRef RelocatedDebugContents = + relocateDebugChunk(Alloc, DebugChunk); + if (RelocatedDebugContents.empty()) + continue; - // Now do all line info. - for (SectionChunk *DebugChunk : File->getDebugChunks()) { - if (!DebugChunk->isLive() || DebugChunk->getSectionName() != ".debug$S") - continue; + DebugSubsectionArray Subsections; + BinaryStreamReader Reader(RelocatedDebugContents, support::little); + ExitOnErr(Reader.readArray(Subsections, RelocatedDebugContents.size())); - ArrayRef RelocatedDebugContents = - relocateDebugChunk(Alloc, DebugChunk); - if (RelocatedDebugContents.empty()) - continue; - - DebugSubsectionArray Subsections; - BinaryStreamReader Reader(RelocatedDebugContents, support::little); - ExitOnErr(Reader.readArray(Subsections, RelocatedDebugContents.size())); - - DebugStringTableSubsectionRef CVStrTab; - DebugChecksumsSubsectionRef Checksums; - for (const DebugSubsectionRecord &SS : Subsections) { - switch (SS.kind()) { - case DebugSubsectionKind::StringTable: - ExitOnErr(CVStrTab.initialize(SS.getRecordData())); - break; - case DebugSubsectionKind::FileChecksums: - ExitOnErr(Checksums.initialize(SS.getRecordData())); - break; - case DebugSubsectionKind::Lines: - // We can add the relocated line table directly to the PDB without - // modification because the file checksum offsets will stay the same. - File->ModuleDBI->addDebugSubsection(SS); - break; - case DebugSubsectionKind::Symbols: - mergeSymbolRecords(Alloc, File, TypeIndexMap, SS.getRecordData()); - break; - default: - // FIXME: Process the rest of the subsections. - break; - } - } - - if (Checksums.valid()) { - // Make a new file checksum table that refers to offsets in the PDB-wide - // string table. Generally the string table subsection appears after the - // checksum table, so we have to do this after looping over all the - // subsections. - if (!CVStrTab.valid()) - fatal(".debug$S sections must have both a string table subsection " - "and a checksum subsection table or neither"); - auto NewChecksums = - make_unique(*PDBStrTab); - for (FileChecksumEntry &FC : Checksums) { - StringRef FileName = ExitOnErr(CVStrTab.getString(FC.FileNameOffset)); - ExitOnErr(Builder.getDbiBuilder().addModuleSourceFile( - *File->ModuleDBI, FileName)); - NewChecksums->addChecksum(FileName, FC.Kind, FC.Checksum); - } - File->ModuleDBI->addDebugSubsection(std::move(NewChecksums)); + DebugStringTableSubsectionRef CVStrTab; + DebugChecksumsSubsectionRef Checksums; + for (const DebugSubsectionRecord &SS : Subsections) { + switch (SS.kind()) { + case DebugSubsectionKind::StringTable: + ExitOnErr(CVStrTab.initialize(SS.getRecordData())); + break; + case DebugSubsectionKind::FileChecksums: + ExitOnErr(Checksums.initialize(SS.getRecordData())); + break; + case DebugSubsectionKind::Lines: + // We can add the relocated line table directly to the PDB without + // modification because the file checksum offsets will stay the same. + File->ModuleDBI->addDebugSubsection(SS); + break; + case DebugSubsectionKind::Symbols: + mergeSymbolRecords(Alloc, File, IndexMap, SS.getRecordData()); + break; + default: + // FIXME: Process the rest of the subsections. + break; } } - } - Builder.getStringTableBuilder().setStrings(*PDBStrTab); + if (Checksums.valid()) { + // Make a new file checksum table that refers to offsets in the PDB-wide + // string table. Generally the string table subsection appears after the + // checksum table, so we have to do this after looping over all the + // subsections. + if (!CVStrTab.valid()) + fatal(".debug$S sections must have both a string table subsection " + "and a checksum subsection table or neither"); + auto NewChecksums = make_unique(PDBStrTab); + for (FileChecksumEntry &FC : Checksums) { + StringRef FileName = ExitOnErr(CVStrTab.getString(FC.FileNameOffset)); + ExitOnErr(Builder.getDbiBuilder().addModuleSourceFile(*File->ModuleDBI, + FileName)); + NewChecksums->addChecksum(FileName, FC.Kind, FC.Checksum); + } + File->ModuleDBI->addDebugSubsection(std::move(NewChecksums)); + } + } +} + +// Add all object files to the PDB. Merge .debug$T sections into IpiData and +// TpiData. +void PDBLinker::addObjectsToPDB() { + for (ObjectFile *File : Symtab->ObjectFiles) + addObjectFile(File); + + Builder.getStringTableBuilder().setStrings(PDBStrTab); // Construct TPI stream contents. addTypeInfo(Builder.getTpiBuilder(), TypeTable); // Construct IPI stream contents. addTypeInfo(Builder.getIpiBuilder(), IDTable); + + // Add public and symbol records stream. + + // For now we don't actually write any thing useful to the publics stream, but + // the act of "getting" it also creates it lazily so that we write an empty + // stream. + (void)Builder.getPublicsBuilder(); } static void addLinkerModuleSymbols(StringRef Path, @@ -423,7 +589,7 @@ static void addLinkerModuleSymbols(StringRef Path, std::string ArgStr = llvm::join(Args, " "); EBS.Fields.push_back("cwd"); SmallString<64> cwd; - llvm::sys::fs::current_path(cwd); + sys::fs::current_path(cwd); EBS.Fields.push_back(cwd); EBS.Fields.push_back("exe"); EBS.Fields.push_back(Config->Argv[0]); @@ -442,8 +608,14 @@ static void addLinkerModuleSymbols(StringRef Path, // Creates a PDB file. void coff::createPDB(SymbolTable *Symtab, ArrayRef SectionTable, const llvm::codeview::DebugInfo *DI) { - BumpPtrAllocator Alloc; - pdb::PDBFileBuilder Builder(Alloc); + PDBLinker PDB(Symtab); + PDB.initialize(DI); + PDB.addObjectsToPDB(); + PDB.addSections(SectionTable); + PDB.commit(); +} + +void PDBLinker::initialize(const llvm::codeview::DebugInfo *DI) { ExitOnErr(Builder.initialize(4096)); // 4096 is blocksize // Create streams in MSF for predefined streams, namely @@ -455,12 +627,7 @@ void coff::createPDB(SymbolTable *Symtab, ArrayRef SectionTable, auto &InfoBuilder = Builder.getInfoBuilder(); InfoBuilder.setAge(DI ? DI->PDB70.Age : 0); - llvm::SmallString<128> NativePath(Config->PDBPath.begin(), - Config->PDBPath.end()); - llvm::sys::fs::make_absolute(NativePath); - llvm::sys::path::native(NativePath, llvm::sys::path::Style::windows); - - pdb::PDB_UniqueId uuid{}; + GUID uuid{}; if (DI) memcpy(&uuid, &DI->PDB70.Signature, sizeof(uuid)); InfoBuilder.setGuid(uuid); @@ -471,32 +638,25 @@ void coff::createPDB(SymbolTable *Symtab, ArrayRef SectionTable, pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder(); DbiBuilder.setVersionHeader(pdb::PdbDbiV70); ExitOnErr(DbiBuilder.addDbgStream(pdb::DbgHeaderType::NewFPO, {})); +} - // It's not entirely clear what this is, but the * Linker * module uses it. - uint32_t PdbFilePathNI = DbiBuilder.addECName(NativePath); - - TypeTableBuilder TypeTable(BAlloc); - TypeTableBuilder IDTable(BAlloc); - addObjectsToPDB(Alloc, Symtab, Builder, TypeTable, IDTable); - - // Add public and symbol records stream. - - // For now we don't actually write any thing useful to the publics stream, but - // the act of "getting" it also creates it lazily so that we write an empty - // stream. - (void)Builder.getPublicsBuilder(); - +void PDBLinker::addSections(ArrayRef SectionTable) { // Add Section Contributions. + pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder(); addSectionContribs(Symtab, DbiBuilder); // Add Section Map stream. ArrayRef Sections = { (const object::coff_section *)SectionTable.data(), SectionTable.size() / sizeof(object::coff_section)}; - std::vector SectionMap = - pdb::DbiStreamBuilder::createSectionMap(Sections); + SectionMap = pdb::DbiStreamBuilder::createSectionMap(Sections); DbiBuilder.setSectionMap(SectionMap); + // It's not entirely clear what this is, but the * Linker * module uses it. + NativePath = Config->PDBPath; + sys::fs::make_absolute(NativePath); + sys::path::native(NativePath, sys::path::Style::windows); + uint32_t PdbFilePathNI = DbiBuilder.addECName(NativePath); auto &LinkerModule = ExitOnErr(DbiBuilder.addModuleInfo("* Linker *")); LinkerModule.setPdbFilePathNI(PdbFilePathNI); addLinkerModuleSymbols(NativePath, LinkerModule, Alloc); @@ -504,7 +664,9 @@ void coff::createPDB(SymbolTable *Symtab, ArrayRef SectionTable, // Add COFF section header stream. ExitOnErr( DbiBuilder.addDbgStream(pdb::DbgHeaderType::SectionHdr, SectionTable)); +} +void PDBLinker::commit() { // Write to a file. ExitOnErr(Builder.commit(Config->PDBPath)); } diff --git a/ELF/Arch/ARM.cpp b/ELF/Arch/ARM.cpp index e4b06ade4487..106021de7d32 100644 --- a/ELF/Arch/ARM.cpp +++ b/ELF/Arch/ARM.cpp @@ -40,6 +40,8 @@ class ARM final : public TargetInfo { void addPltHeaderSymbols(InputSectionBase *ISD) const override; bool needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File, const SymbolBody &S) const override; + bool inBranchRange(uint32_t RelocType, uint64_t Src, + uint64_t Dst) const override; void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; }; } // namespace @@ -218,6 +220,49 @@ bool ARM::needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File, return false; } +bool ARM::inBranchRange(uint32_t RelocType, uint64_t Src, uint64_t Dst) const { + uint64_t Range; + uint64_t InstrSize; + + switch (RelocType) { + case R_ARM_PC24: + case R_ARM_PLT32: + case R_ARM_JUMP24: + case R_ARM_CALL: + Range = 0x2000000; + InstrSize = 4; + break; + case R_ARM_THM_JUMP19: + Range = 0x100000; + InstrSize = 2; + break; + case R_ARM_THM_JUMP24: + case R_ARM_THM_CALL: + Range = 0x1000000; + InstrSize = 2; + break; + default: + return true; + } + // PC at Src is 2 instructions ahead, immediate of branch is signed + if (Src > Dst) + Range -= 2 * InstrSize; + else + Range += InstrSize; + + if ((Dst & 0x1) == 0) + // Destination is ARM, if ARM caller then Src is already 4-byte aligned. + // If Thumb Caller (BLX) the Src address has bottom 2 bits cleared to ensure + // destination will be 4 byte aligned. + Src &= ~0x3; + else + // Bit 0 == 1 denotes Thumb state, it is not part of the range + Dst &= ~0x1; + + uint64_t Distance = (Src > Dst) ? Src - Dst : Dst - Src; + return Distance <= Range; +} + void ARM::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { switch (Type) { case R_ARM_ABS32: diff --git a/ELF/Arch/MipsArchTree.cpp b/ELF/Arch/MipsArchTree.cpp index ed183e9a3061..3d1dc1daf0c1 100644 --- a/ELF/Arch/MipsArchTree.cpp +++ b/ELF/Arch/MipsArchTree.cpp @@ -37,7 +37,7 @@ struct FileFlags { StringRef Filename; uint32_t Flags; }; -} +} // namespace static StringRef getAbiName(uint32_t Flags) { switch (Flags) { @@ -337,8 +337,8 @@ uint8_t elf::getMipsFpAbiFlag(uint8_t OldFlag, uint8_t NewFlag, return NewFlag; if (compareMipsFpAbi(OldFlag, NewFlag) < 0) error("target floating point ABI '" + getMipsFpAbiName(OldFlag) + - "' is incompatible with '" + getMipsFpAbiName(NewFlag) + "': " + - FileName); + "' is incompatible with '" + getMipsFpAbiName(NewFlag) + + "': " + FileName); return OldFlag; } diff --git a/ELF/Config.h b/ELF/Config.h index 5e3b77637316..23627dd812db 100644 --- a/ELF/Config.h +++ b/ELF/Config.h @@ -99,6 +99,7 @@ struct Configuration { std::vector VersionDefinitions; std::vector Argv; std::vector AuxiliaryList; + std::vector FilterList; std::vector SearchPaths; std::vector SymbolOrderingFile; std::vector Undefined; diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp index 10ad13f214d5..4630e110bcd8 100644 --- a/ELF/Driver.cpp +++ b/ELF/Driver.cpp @@ -259,6 +259,9 @@ static void checkOptions(opt::InputArgList &Args) { if (Config->Pie && Config->Shared) error("-shared and -pie may not be used together"); + if (!Config->Shared && !Config->FilterList.empty()) + error("-F may not be used without -shared"); + if (!Config->Shared && !Config->AuxiliaryList.empty()) error("-f may not be used without -shared"); @@ -631,6 +634,7 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { getArg(Args, OPT_export_dynamic, OPT_no_export_dynamic, false); Config->FatalWarnings = getArg(Args, OPT_fatal_warnings, OPT_no_fatal_warnings, false); + Config->FilterList = getArgs(Args, OPT_filter); Config->Fini = Args.getLastArgValue(OPT_fini, "_fini"); Config->GcSections = getArg(Args, OPT_gc_sections, OPT_no_gc_sections, false); Config->GdbIndex = Args.hasArg(OPT_gdb_index); diff --git a/ELF/EhFrame.h b/ELF/EhFrame.h index 4e2b6f83a294..07d1aaa3cbb3 100644 --- a/ELF/EhFrame.h +++ b/ELF/EhFrame.h @@ -19,7 +19,7 @@ struct EhSectionPiece; template size_t readEhRecordSize(InputSectionBase *S, size_t Off); template uint8_t getFdeEncoding(EhSectionPiece *P); -} -} +} // namespace elf +} // namespace lld #endif diff --git a/ELF/Filesystem.h b/ELF/Filesystem.h index d56d067f7378..dbeadac5a96b 100644 --- a/ELF/Filesystem.h +++ b/ELF/Filesystem.h @@ -16,7 +16,7 @@ namespace lld { namespace elf { void unlinkAsync(StringRef Path); std::error_code tryCreateFile(StringRef Path); -} -} +} // namespace elf +} // namespace lld #endif diff --git a/ELF/GdbIndex.h b/ELF/GdbIndex.h index c49f8946e199..bc024e6689ef 100644 --- a/ELF/GdbIndex.h +++ b/ELF/GdbIndex.h @@ -11,8 +11,8 @@ #define LLD_ELF_GDB_INDEX_H #include "InputFiles.h" -#include "llvm/Object/ELF.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/Object/ELF.h" namespace lld { namespace elf { diff --git a/ELF/ICF.h b/ELF/ICF.h index 502e128c8109..24219855fc17 100644 --- a/ELF/ICF.h +++ b/ELF/ICF.h @@ -14,6 +14,6 @@ namespace lld { namespace elf { template void doIcf(); } -} +} // namespace lld #endif diff --git a/ELF/InputFiles.h b/ELF/InputFiles.h index 544a0b009b39..f6d3f907850c 100644 --- a/ELF/InputFiles.h +++ b/ELF/InputFiles.h @@ -11,8 +11,8 @@ #define LLD_ELF_INPUT_FILES_H #include "Config.h" -#include "InputSection.h" #include "Error.h" +#include "InputSection.h" #include "Symbols.h" #include "lld/Core/LLVM.h" @@ -34,7 +34,7 @@ struct DILineInfo; namespace lto { class InputFile; } -} +} // namespace llvm namespace lld { namespace elf { diff --git a/ELF/LTO.h b/ELF/LTO.h index 28afa0e83add..d19923c90a99 100644 --- a/ELF/LTO.h +++ b/ELF/LTO.h @@ -30,7 +30,7 @@ namespace llvm { namespace lto { class LTO; } -} +} // namespace llvm namespace lld { namespace elf { @@ -51,7 +51,7 @@ class BitcodeCompiler { std::vector> Buff; std::vector> Files; }; -} -} +} // namespace elf +} // namespace lld #endif diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp index a182d5a3a096..8bdbd8db20ad 100644 --- a/ELF/LinkerScript.cpp +++ b/ELF/LinkerScript.cpp @@ -229,6 +229,19 @@ bool LinkerScript::shouldKeep(InputSectionBase *S) { return false; } +// If an input string is in the form of "foo.N" where N is a number, +// return N. Otherwise, returns 65536, which is one greater than the +// lowest priority. +static int getPriority(StringRef S) { + size_t Pos = S.rfind('.'); + if (Pos == StringRef::npos) + return 65536; + int V; + if (!to_integer(S.substr(Pos + 1), V, 10)) + return 65536; + return V; +} + // A helper function for the SORT() command. static std::function getComparator(SortSectionPolicy K) { @@ -449,7 +462,7 @@ void LinkerScript::fabricateDefaultCommands() { // The Sections with -T
    have been sorted in order of ascending // address. We must lower StartAddr if the lowest -T
    as // calls to setDot() must be monotonically increasing. - for (auto& KV : Config->SectionStartMap) + for (auto &KV : Config->SectionStartMap) StartAddr = std::min(StartAddr, KV.second); Commands.push_back(make( @@ -739,7 +752,7 @@ void LinkerScript::adjustSectionsAfterSorting() { Cmd->MemRegion = findMemoryRegion(Cmd); // Handle align (e.g. ".foo : ALIGN(16) { ... }"). if (Cmd->AlignExpr) - Cmd->Sec->updateAlignment(Cmd->AlignExpr().getValue()); + Cmd->Sec->updateAlignment(Cmd->AlignExpr().getValue()); } } @@ -1071,7 +1084,7 @@ template void OutputSectionCommand::finalize() { } if ((Sec->Flags & SHF_LINK_ORDER)) { - std::sort(Sections.begin(), Sections.end(), compareByFilePosition); + std::stable_sort(Sections.begin(), Sections.end(), compareByFilePosition); for (int I = 0, N = Sections.size(); I < N; ++I) *ScriptSections[I] = Sections[I]; diff --git a/ELF/MapFile.cpp b/ELF/MapFile.cpp index e0c7d8cd8b1b..2b2a95c47cf9 100644 --- a/ELF/MapFile.cpp +++ b/ELF/MapFile.cpp @@ -55,7 +55,7 @@ template std::vector getSymbols() { for (SymbolBody *B : File->getSymbols()) if (B->File == File && !B->isSection()) if (auto *Sym = dyn_cast(B)) - if (Sym->Section) + if (Sym->Section && Sym->Section->Live) V.push_back(Sym); return V; } diff --git a/ELF/MapFile.h b/ELF/MapFile.h index 68d8ba8d4a04..460848ff24d3 100644 --- a/ELF/MapFile.h +++ b/ELF/MapFile.h @@ -17,7 +17,7 @@ namespace elf { struct OutputSectionCommand; template void writeMapFile(llvm::ArrayRef Script); -} -} +} // namespace elf +} // namespace lld #endif diff --git a/ELF/Memory.h b/ELF/Memory.h index e5a04ed1e5a8..4000f2f9f1c9 100644 --- a/ELF/Memory.h +++ b/ELF/Memory.h @@ -61,7 +61,7 @@ inline void freeArena() { Alloc->reset(); BAlloc.Reset(); } -} -} +} // namespace elf +} // namespace lld #endif diff --git a/ELF/Options.td b/ELF/Options.td index 29e14c530c6a..9c78608118cc 100644 --- a/ELF/Options.td +++ b/ELF/Options.td @@ -104,6 +104,8 @@ def export_dynamic_symbol: S<"export-dynamic-symbol">, def fatal_warnings: F<"fatal-warnings">, HelpText<"Treat warnings as errors">; +def filter: J<"filter=">, HelpText<"Set DT_FILTER field to the specified name">; + def fini: S<"fini">, MetaVarName<"">, HelpText<"Specify a finalizer function">; @@ -305,6 +307,7 @@ def alias_exclude_libs: J<"exclude-libs=">, Alias; def alias_export_dynamic_E: Flag<["-"], "E">, Alias; def alias_export_dynamic_symbol: J<"export-dynamic-symbol=">, Alias; +def alias_filter: Separate<["-"], "F">, Alias; def alias_fini_fini: J<"fini=">, Alias; def alias_format_b: S<"b">, Alias; def alias_hash_style_hash_style: J<"hash-style=">, Alias; @@ -339,6 +342,7 @@ def alias_Ttext_segment: S<"Ttext-segment">, Alias; def alias_Ttext_segment_eq: J<"Ttext-segment=">, Alias; def alias_undefined_eq: J<"undefined=">, Alias; def alias_undefined_u: JoinedOrSeparate<["-"], "u">, Alias; +def alias_version_script_eq: J<"version-script=">, Alias; def alias_version_V: Flag<["-"], "V">, Alias; def alias_wrap_wrap: J<"wrap=">, Alias; @@ -406,6 +410,3 @@ def EL : F<"EL">; def G: JoinedOrSeparate<["-"], "G">; def Qy : F<"Qy">; -// Aliases for ignored options -def alias_version_script_version_script: J<"version-script=">, - Alias; diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp index d6ae5dcae167..abe548165866 100644 --- a/ELF/OutputSections.cpp +++ b/ELF/OutputSections.cpp @@ -222,16 +222,16 @@ void OutputSectionFactory::addInputSec(InputSectionBase *IS, if (Sec) { if (getIncompatibleFlags(Sec->Flags) != getIncompatibleFlags(IS->Flags)) - error("incompatible section flags for " + Sec->Name + - "\n>>> " + toString(IS) + ": 0x" + utohexstr(IS->Flags) + + error("incompatible section flags for " + Sec->Name + "\n>>> " + + toString(IS) + ": 0x" + utohexstr(IS->Flags) + "\n>>> output section " + Sec->Name + ": 0x" + utohexstr(Sec->Flags)); if (Sec->Type != IS->Type) { if (canMergeToProgbits(Sec->Type) && canMergeToProgbits(IS->Type)) Sec->Type = SHT_PROGBITS; else - error("section type mismatch for " + IS->Name + - "\n>>> " + toString(IS) + ": " + + error("section type mismatch for " + IS->Name + "\n>>> " + + toString(IS) + ": " + getELFSectionTypeName(Config->EMachine, IS->Type) + "\n>>> output section " + Sec->Name + ": " + getELFSectionTypeName(Config->EMachine, Sec->Type)); diff --git a/ELF/OutputSections.h b/ELF/OutputSections.h index 68ee066a13da..68b46ebf6a7b 100644 --- a/ELF/OutputSections.h +++ b/ELF/OutputSections.h @@ -111,8 +111,8 @@ struct SectionKey { uint64_t Flags; uint32_t Alignment; }; -} -} +} // namespace elf +} // namespace lld namespace llvm { template <> struct DenseMapInfo { static lld::elf::SectionKey getEmptyKey(); @@ -121,7 +121,7 @@ template <> struct DenseMapInfo { static bool isEqual(const lld::elf::SectionKey &LHS, const lld::elf::SectionKey &RHS); }; -} +} // namespace llvm namespace lld { namespace elf { @@ -150,5 +150,4 @@ extern std::vector OutputSectionCommands; } // namespace elf } // namespace lld - #endif diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp index 52dbe4b583d0..e5fcb2dcc582 100644 --- a/ELF/Relocations.cpp +++ b/ELF/Relocations.cpp @@ -276,7 +276,7 @@ handleTlsRelocation(uint32_t Type, SymbolBody &Body, InputSectionBase &C, } else { C.Relocations.push_back( {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_LE), Type, - Offset, Addend, &Body}); + Offset, Addend, &Body}); } return Target->TlsGdRelaxSkip; } @@ -1000,16 +1000,20 @@ void ThunkCreator::mergeThunks() { } } -ThunkSection *ThunkCreator::getOSThunkSec(OutputSection *OS, +static uint32_t findEndOfFirstNonExec(OutputSectionCommand &Cmd) { + for (BaseCommand *Base : Cmd.Commands) + if (auto *ISD = dyn_cast(Base)) + for (auto *IS : ISD->Sections) + if ((IS->Flags & SHF_EXECINSTR) == 0) + return IS->OutSecOff + IS->getSize(); + return 0; +} + +ThunkSection *ThunkCreator::getOSThunkSec(OutputSectionCommand *Cmd, std::vector *ISR) { if (CurTS == nullptr) { - uint32_t Off = 0; - for (auto *IS : OS->Sections) { - Off = IS->OutSecOff + IS->getSize(); - if ((IS->Flags & SHF_EXECINSTR) == 0) - break; - } - CurTS = addThunkSection(OS, ISR, Off); + uint32_t Off = findEndOfFirstNonExec(*Cmd); + CurTS = addThunkSection(Cmd->Sec, ISR, Off); } return CurTS; } @@ -1024,7 +1028,7 @@ ThunkSection *ThunkCreator::getISThunkSec(InputSection *IS, OutputSection *OS) { OutputSectionCommand *C = Script->getCmd(TOS); std::vector *Range = nullptr; for (BaseCommand *BC : C->Commands) - if (auto *ISD = dyn_cast (BC)) { + if (auto *ISD = dyn_cast(BC)) { InputSection *first = ISD->Sections.front(); InputSection *last = ISD->Sections.back(); if (IS->OutSecOff >= first->OutSecOff && @@ -1046,7 +1050,6 @@ ThunkSection *ThunkCreator::addThunkSection(OutputSection *OS, return TS; } - std::pair ThunkCreator::getThunk(SymbolBody &Body, uint32_t Type) { auto Res = ThunkedSymbols.insert({&Body, std::vector()}); @@ -1066,7 +1069,7 @@ std::pair ThunkCreator::getThunk(SymbolBody &Body, // InputSectionDescription::Sections. void ThunkCreator::forEachExecInputSection( ArrayRef OutputSections, - std::function *, + std::function *, InputSection *)> Fn) { for (OutputSectionCommand *Cmd : OutputSections) { @@ -1077,7 +1080,7 @@ void ThunkCreator::forEachExecInputSection( if (auto *ISD = dyn_cast(BC)) { CurTS = nullptr; for (InputSection *IS : ISD->Sections) - Fn(OS, &ISD->Sections, IS); + Fn(Cmd, &ISD->Sections, IS); } } } @@ -1103,32 +1106,32 @@ bool ThunkCreator::createThunks( // We separate the creation of ThunkSections from the insertion of the // ThunkSections back into the OutputSection as ThunkSections are not always // inserted into the same OutputSection as the caller. - forEachExecInputSection( - OutputSections, [&](OutputSection *OS, std::vector *ISR, - InputSection *IS) { - for (Relocation &Rel : IS->Relocations) { - SymbolBody &Body = *Rel.Sym; - if (Thunks.find(&Body) != Thunks.end() || - !Target->needsThunk(Rel.Expr, Rel.Type, IS->File, Body)) - continue; - Thunk *T; - bool IsNew; - std::tie(T, IsNew) = getThunk(Body, Rel.Type); - if (IsNew) { - // Find or create a ThunkSection for the new Thunk - ThunkSection *TS; - if (auto *TIS = T->getTargetInputSection()) - TS = getISThunkSec(TIS, OS); - else - TS = getOSThunkSec(OS, ISR); - TS->addThunk(T); - Thunks[T->ThunkSym] = T; - } - // Redirect relocation to Thunk, we never go via the PLT to a Thunk - Rel.Sym = T->ThunkSym; - Rel.Expr = fromPlt(Rel.Expr); - } - }); + forEachExecInputSection(OutputSections, [&](OutputSectionCommand *Cmd, + std::vector *ISR, + InputSection *IS) { + for (Relocation &Rel : IS->Relocations) { + SymbolBody &Body = *Rel.Sym; + if (Thunks.find(&Body) != Thunks.end() || + !Target->needsThunk(Rel.Expr, Rel.Type, IS->File, Body)) + continue; + Thunk *T; + bool IsNew; + std::tie(T, IsNew) = getThunk(Body, Rel.Type); + if (IsNew) { + // Find or create a ThunkSection for the new Thunk + ThunkSection *TS; + if (auto *TIS = T->getTargetInputSection()) + TS = getISThunkSec(TIS, Cmd->Sec); + else + TS = getOSThunkSec(Cmd, ISR); + TS->addThunk(T); + Thunks[T->ThunkSym] = T; + } + // Redirect relocation to Thunk, we never go via the PLT to a Thunk + Rel.Sym = T->ThunkSym; + Rel.Expr = fromPlt(Rel.Expr); + } + }); // Merge all created synthetic ThunkSections back into OutputSection mergeThunks(); ++Pass; diff --git a/ELF/Relocations.h b/ELF/Relocations.h index fc3e3444ac24..ea046d248474 100644 --- a/ELF/Relocations.h +++ b/ELF/Relocations.h @@ -103,7 +103,8 @@ struct RelExprMaskBuilder { // RelExpr's as a constant bit mask and test for membership with a // couple cheap bitwise operations. template bool isRelExprOneOf(RelExpr Expr) { - assert(0 <= Expr && (int)Expr < 64 && "RelExpr is too large for 64-bit mask!"); + assert(0 <= Expr && (int)Expr < 64 && + "RelExpr is too large for 64-bit mask!"); return (uint64_t(1) << Expr) & RelExprMaskBuilder::build(); } @@ -133,12 +134,12 @@ class ThunkCreator { private: void mergeThunks(); - ThunkSection *getOSThunkSec(OutputSection *OS, + ThunkSection *getOSThunkSec(OutputSectionCommand *Cmd, std::vector *ISR); ThunkSection *getISThunkSec(InputSection *IS, OutputSection *OS); void forEachExecInputSection( ArrayRef OutputSections, - std::function *, + std::function *, InputSection *)> Fn); std::pair getThunk(SymbolBody &Body, uint32_t Type); @@ -178,7 +179,7 @@ template static inline int64_t getAddend(const typename ELFT::Rela &Rel) { return Rel.r_addend; } -} -} +} // namespace elf +} // namespace lld #endif diff --git a/ELF/ScriptParser.cpp b/ELF/ScriptParser.cpp index 72940ca0cfd4..b3847081697c 100644 --- a/ELF/ScriptParser.cpp +++ b/ELF/ScriptParser.cpp @@ -113,6 +113,12 @@ class ScriptParser final : ScriptLexer { }; } // namespace +static StringRef unquote(StringRef S) { + if (S.startswith("\"")) + return S.substr(1, S.size() - 2); + return S; +} + static bool isUnderSysroot(StringRef Path) { if (Config->Sysroot == "") return false; @@ -1103,6 +1109,10 @@ void ScriptParser::readVersionDeclaration(StringRef VerStr) { expect(";"); } +static bool hasWildcard(StringRef S) { + return S.find_first_of("?*[") != StringRef::npos; +} + // Reads a list of symbols, e.g. "{ global: foo; bar; local: *; };". std::pair, std::vector> ScriptParser::readSymbols() { diff --git a/ELF/Strings.cpp b/ELF/Strings.cpp index 2e88bfba0fc1..bca86384002d 100644 --- a/ELF/Strings.cpp +++ b/ELF/Strings.cpp @@ -38,29 +38,6 @@ bool StringMatcher::match(StringRef S) const { return false; } -// If an input string is in the form of "foo.N" where N is a number, -// return N. Otherwise, returns 65536, which is one greater than the -// lowest priority. -int elf::getPriority(StringRef S) { - size_t Pos = S.rfind('.'); - if (Pos == StringRef::npos) - return 65536; - int V; - if (!to_integer(S.substr(Pos + 1), V, 10)) - return 65536; - return V; -} - -bool elf::hasWildcard(StringRef S) { - return S.find_first_of("?*[") != StringRef::npos; -} - -StringRef elf::unquote(StringRef S) { - if (!S.startswith("\"")) - return S; - return S.substr(1, S.size() - 2); -} - // Converts a hex string (e.g. "deadbeef") to a vector. std::vector elf::parseHex(StringRef S) { std::vector Hex; diff --git a/ELF/Strings.h b/ELF/Strings.h index fd1aa40539d2..68ccafa2ff17 100644 --- a/ELF/Strings.h +++ b/ELF/Strings.h @@ -21,11 +21,8 @@ namespace lld { namespace elf { -int getPriority(StringRef S); -bool hasWildcard(StringRef S); std::vector parseHex(StringRef S); bool isValidCIdentifier(StringRef S); -StringRef unquote(StringRef S); // This is a lazy version of StringRef. String size is computed lazily // when it is needed. It is more efficient than StringRef to instantiate @@ -76,7 +73,7 @@ llvm::Optional demangle(StringRef Name); inline ArrayRef toArrayRef(StringRef S) { return {(const uint8_t *)S.data(), S.size()}; } -} -} +} // namespace elf +} // namespace lld #endif diff --git a/ELF/SymbolTable.cpp b/ELF/SymbolTable.cpp index c802d74b8ff8..83091057ebed 100644 --- a/ELF/SymbolTable.cpp +++ b/ELF/SymbolTable.cpp @@ -172,8 +172,8 @@ template void SymbolTable::addSymbolWrap(StringRef Name) { } // Creates alias for symbol. Used to implement --defsym=ALIAS=SYM. -template void SymbolTable::addSymbolAlias(StringRef Alias, - StringRef Name) { +template +void SymbolTable::addSymbolAlias(StringRef Alias, StringRef Name) { SymbolBody *B = find(Name); if (!B) { error("-defsym: undefined symbol: " + Name); @@ -211,13 +211,6 @@ static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) { // Find an existing symbol or create and insert a new one. template std::pair SymbolTable::insert(StringRef Name) { - // @@ means the symbol is the default version. In that - // case symbol must exist and @@ will be used to - // resolve references to . - size_t Pos = Name.find("@@"); - if (Pos != StringRef::npos) - Name = Name.take_front(Pos); - auto P = Symtab.insert( {CachedHashStringRef(Name), SymIndex((int)SymVector.size(), false)}); SymIndex &V = P.first->second; @@ -400,9 +393,8 @@ static void warnOrError(const Twine &Msg) { } static void reportDuplicate(SymbolBody *Sym, InputFile *NewFile) { - warnOrError("duplicate symbol: " + toString(*Sym) + - "\n>>> defined in " + toString(Sym->File) + - "\n>>> defined in " + toString(NewFile)); + warnOrError("duplicate symbol: " + toString(*Sym) + "\n>>> defined in " + + toString(Sym->File) + "\n>>> defined in " + toString(NewFile)); } template @@ -680,7 +672,8 @@ template void SymbolTable::handleAnonymousVersion() { // Set symbol versions to symbols. This function handles patterns // containing no wildcard characters. template -void SymbolTable::assignExactVersion(SymbolVersion Ver, uint16_t VersionId, +void SymbolTable::assignExactVersion(SymbolVersion Ver, + uint16_t VersionId, StringRef VersionName) { if (Ver.HasWildcard) return; @@ -724,13 +717,35 @@ void SymbolTable::assignWildcardVersion(SymbolVersion Ver, B->symbol()->VersionId = VersionId; } +static bool isDefaultVersion(SymbolBody *B) { + return B->isInCurrentDSO() && B->getName().find("@@") != StringRef::npos; +} + // This function processes version scripts by updating VersionId // member of symbols. template void SymbolTable::scanVersionScript() { + // Symbol themselves might know their versions because symbols + // can contain versions in the form of @. + // Let them parse and update their names to exclude version suffix. + for (Symbol *Sym : SymVector) { + SymbolBody *Body = Sym->body(); + bool IsDefault = isDefaultVersion(Body); + Body->parseSymbolVersion(); + + if (!IsDefault) + continue; + + // @@ means the symbol is the default version. If that's the + // case, the symbol is not used only to resolve of version + // but also undefined unversioned symbols with name . + SymbolBody *S = find(Body->getName()); + if (S && S->isUndefined()) + S->copy(Body); + } + // Handle edge cases first. handleAnonymousVersion(); - // Now we have version definitions, so we need to set version ids to symbols. // Each version definition has a glob pattern, and all symbols that match // with the pattern get that version. diff --git a/ELF/Symbols.cpp b/ELF/Symbols.cpp index 1d17f57f0c30..c69007e781a6 100644 --- a/ELF/Symbols.cpp +++ b/ELF/Symbols.cpp @@ -94,7 +94,7 @@ static uint64_t getSymVA(const SymbolBody &Body, int64_t &Addend) { if (D.isTls() && !Config->Relocatable) { if (!Out::TlsPhdr) fatal(toString(D.File) + - " has a STT_TLS symbol but doesn't have a PT_TLS section"); + " has an STT_TLS symbol but doesn't have an SHF_TLS section"); return VA - Out::TlsPhdr->p_vaddr; } return VA; diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp index fd724fac327c..4bbec4ab34bd 100644 --- a/ELF/SyntheticSections.cpp +++ b/ELF/SyntheticSections.cpp @@ -662,7 +662,12 @@ bool GotSection::empty() const { return NumEntries == 0 && !HasGotOffRel; } -void GotSection::writeTo(uint8_t *Buf) { relocateAlloc(Buf, Buf + Size); } +void GotSection::writeTo(uint8_t *Buf) { + // Buf points to the start of this section's buffer, + // whereas InputSectionBase::relocateAlloc() expects its argument + // to point to the start of the output section. + relocateAlloc(Buf - OutSecOff, Buf - OutSecOff + Size); +} MipsGotSection::MipsGotSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL, SHT_PROGBITS, 16, @@ -812,9 +817,7 @@ unsigned MipsGotSection::getLocalEntriesNum() const { LocalEntries32.size(); } -void MipsGotSection::finalizeContents() { - updateAllocSize(); -} +void MipsGotSection::finalizeContents() { updateAllocSize(); } void MipsGotSection::updateAllocSize() { PageEntriesNum = 0; @@ -838,9 +841,7 @@ bool MipsGotSection::empty() const { return Config->Relocatable; } -uint64_t MipsGotSection::getGp() const { - return ElfSym::MipsGp->getVA(0); -} +uint64_t MipsGotSection::getGp() const { return ElfSym::MipsGp->getVA(0); } static uint64_t readUint(uint8_t *Buf) { if (Config->Is64) @@ -1019,6 +1020,8 @@ DynamicSection::DynamicSection() template void DynamicSection::addEntries() { // Add strings to .dynstr early so that .dynstr's size will be // fixed early. + for (StringRef S : Config->FilterList) + add({DT_FILTER, InX::DynStrTab->addString(S)}); for (StringRef S : Config->AuxiliaryList) add({DT_AUXILIARY, InX::DynStrTab->addString(S)}); if (!Config->Rpath.empty()) @@ -1607,7 +1610,7 @@ HashTableSection::HashTableSection() template void HashTableSection::finalizeContents() { getParent()->Link = InX::DynSymTab->getParent()->SectionIndex; - unsigned NumEntries = 2; // nbucket and nchain. + unsigned NumEntries = 2; // nbucket and nchain. NumEntries += InX::DynSymTab->getNumSymbols(); // The chain entries. // Create as many buckets as there are symbols. @@ -1926,9 +1929,7 @@ void GdbIndexSection::writeTo(uint8_t *Buf) { StringPool.write(Buf); } -bool GdbIndexSection::empty() const { - return !Out::DebugInfo; -} +bool GdbIndexSection::empty() const { return !Out::DebugInfo; } template EhFrameHeader::EhFrameHeader() @@ -2211,9 +2212,7 @@ void MergeSyntheticSection::finalizeContents() { finalizeNoTailMerge(); } -size_t MergeSyntheticSection::getSize() const { - return Builder.getSize(); -} +size_t MergeSyntheticSection::getSize() const { return Builder.getSize(); } // This function decompresses compressed sections and scans over the input // sections to create mergeable synthetic sections. It removes @@ -2312,7 +2311,7 @@ ThunkSection::ThunkSection(OutputSection *OS, uint64_t Off) } void ThunkSection::addThunk(Thunk *T) { - uint64_t Off = alignTo(Size, T->alignment); + uint64_t Off = alignTo(Size, T->Alignment); T->Offset = Off; Thunks.push_back(T); T->addSymbols(*this); diff --git a/ELF/Target.cpp b/ELF/Target.cpp index c886419971bc..11986efc746f 100644 --- a/ELF/Target.cpp +++ b/ELF/Target.cpp @@ -128,6 +128,11 @@ bool TargetInfo::needsThunk(RelExpr Expr, uint32_t RelocType, return false; } +bool TargetInfo::inBranchRange(uint32_t RelocType, uint64_t Src, + uint64_t Dst) const { + return true; +} + void TargetInfo::writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const { writeGotPlt(Buf, S); } diff --git a/ELF/Target.h b/ELF/Target.h index 5914d9bbb7ef..1658a81c9b71 100644 --- a/ELF/Target.h +++ b/ELF/Target.h @@ -51,6 +51,9 @@ class TargetInfo { // targeting S. virtual bool needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File, const SymbolBody &S) const; + // Return true if we can reach Dst from Src with Relocation RelocType + virtual bool inBranchRange(uint32_t RelocType, uint64_t Src, + uint64_t Dst) const; virtual RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const = 0; virtual void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const = 0; @@ -154,6 +157,6 @@ static void checkAlignment(uint8_t *Loc, uint64_t V, uint32_t Type) { lld::toString(Type)); } } // namespace elf -} +} // namespace lld #endif diff --git a/ELF/Threads.h b/ELF/Threads.h index e01afd4d3fc9..9feb8683976c 100644 --- a/ELF/Threads.h +++ b/ELF/Threads.h @@ -82,7 +82,7 @@ inline void parallelForEachN(size_t Begin, size_t End, else for_each_n(llvm::parallel::seq, Begin, End, Fn); } -} -} +} // namespace elf +} // namespace lld #endif diff --git a/ELF/Thunks.cpp b/ELF/Thunks.cpp index cae31027e557..07289d0efdf1 100644 --- a/ELF/Thunks.cpp +++ b/ELF/Thunks.cpp @@ -72,9 +72,7 @@ class ARMV7PILongThunk final : public Thunk { class ThumbV7ABSLongThunk final : public Thunk { public: - ThumbV7ABSLongThunk(const SymbolBody &Dest) : Thunk(Dest) { - alignment = 2; - } + ThumbV7ABSLongThunk(const SymbolBody &Dest) : Thunk(Dest) { Alignment = 2; } uint32_t size() const override { return 10; } void writeTo(uint8_t *Buf, ThunkSection &IS) const override; @@ -84,9 +82,7 @@ class ThumbV7ABSLongThunk final : public Thunk { class ThumbV7PILongThunk final : public Thunk { public: - ThumbV7PILongThunk(const SymbolBody &Dest) : Thunk(Dest) { - alignment = 2; - } + ThumbV7PILongThunk(const SymbolBody &Dest) : Thunk(Dest) { Alignment = 2; } uint32_t size() const override { return 12; } void writeTo(uint8_t *Buf, ThunkSection &IS) const override; @@ -218,10 +214,10 @@ bool ThumbV7PILongThunk::isCompatibleWith(uint32_t RelocType) const { // Write MIPS LA25 thunk code to call PIC function from the non-PIC one. void MipsThunk::writeTo(uint8_t *Buf, ThunkSection &) const { uint64_t S = Destination.getVA(); - write32(Buf, 0x3c190000, Config->Endianness); // lui $25, %hi(func) + write32(Buf, 0x3c190000, Config->Endianness); // lui $25, %hi(func) write32(Buf + 4, 0x08000000 | (S >> 2), Config->Endianness); // j func - write32(Buf + 8, 0x27390000, Config->Endianness); // addiu $25, $25, %lo(func) - write32(Buf + 12, 0x00000000, Config->Endianness); // nop + write32(Buf + 8, 0x27390000, Config->Endianness); // addiu $25, $25, %lo(func) + write32(Buf + 12, 0x00000000, Config->Endianness); // nop Target->relocateOne(Buf, R_MIPS_HI16, S); Target->relocateOne(Buf + 8, R_MIPS_LO16, S); } @@ -262,9 +258,7 @@ static Thunk *addThunkArm(uint32_t Reloc, SymbolBody &S) { fatal("unrecognized relocation type"); } -static Thunk *addThunkMips(SymbolBody &S) { - return make(S); -} +static Thunk *addThunkMips(SymbolBody &S) { return make(S); } Thunk *addThunk(uint32_t RelocType, SymbolBody &S) { if (Config->EMachine == EM_ARM) diff --git a/ELF/Thunks.h b/ELF/Thunks.h index 00b6b2cf2994..21eba699fe4f 100644 --- a/ELF/Thunks.h +++ b/ELF/Thunks.h @@ -50,7 +50,7 @@ class Thunk { const SymbolBody &Destination; SymbolBody *ThunkSym; uint64_t Offset; - uint32_t alignment = 4; + uint32_t Alignment = 4; }; // For a Relocation to symbol S create a Thunk to be added to a synthetic diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp index bf43ee5c5f91..1853f99bc600 100644 --- a/ELF/Writer.cpp +++ b/ELF/Writer.cpp @@ -257,7 +257,6 @@ template void Writer::run() { if (ErrorCount) return; - // Handle -Map option. writeMapFile(OutputSectionCommands); if (ErrorCount) @@ -1331,7 +1330,7 @@ template void Writer::addPredefinedSections() { // ARM ABI requires .ARM.exidx to be terminated by some piece of data. // We have the terminater synthetic section class. Add that at the end. OutputSectionCommand *Cmd = findSectionCommand(".ARM.exidx"); - if (!Cmd || Cmd->Commands.empty() || Config->Relocatable) + if (!Cmd || !Cmd->Sec || Config->Relocatable) return; auto *Sentinel = make(); @@ -1392,7 +1391,8 @@ OutputSectionCommand *Writer::findSectionCommand(StringRef Name) { return nullptr; } -template OutputSection *Writer::findSectionInScript(StringRef Name) { +template +OutputSection *Writer::findSectionInScript(StringRef Name) { if (OutputSectionCommand *Cmd = findSectionCommand(Name)) return Cmd->Sec; return nullptr; diff --git a/ELF/Writer.h b/ELF/Writer.h index e935b6419de6..7fa56bea1c35 100644 --- a/ELF/Writer.h +++ b/ELF/Writer.h @@ -55,7 +55,7 @@ uint8_t getMipsFpAbiFlag(uint8_t OldFlag, uint8_t NewFlag, llvm::StringRef FileName); bool isMipsN32Abi(const InputFile *F); -} -} +} // namespace elf +} // namespace lld #endif diff --git a/docs/windows_support.rst b/docs/windows_support.rst index 56df45b32633..6b06d29afafd 100644 --- a/docs/windows_support.rst +++ b/docs/windows_support.rst @@ -29,8 +29,6 @@ Development status Driver :good:`Mostly done`. Some exotic command line options that are not usually used for application develompent, such as ``/DRIVER``, are not supported. - Options for Windows 8 app store are not recognized too - (e.g. ``/APPCONTAINER``). Linking against DLL :good:`Done`. LLD can read import libraries needed to link against DLL. Both @@ -44,8 +42,7 @@ Creating DLL :good:`Done`. LLD creates a DLL if ``/DLL`` option is given. Exported functions can be specified either via command line (``/EXPORT``) or via module-definition file (.def). Both export-by-name and export-by-ordinal are - supported. LLD uses Microsoft ``lib.exe`` tool to create an import library - file. + supported. Windows resource files support :good:`Done`. If an ``.res`` file is given, LLD converts the file to a COFF diff --git a/test/COFF/Inputs/default.def b/test/COFF/Inputs/default.def new file mode 100644 index 000000000000..1d59beebbb26 --- /dev/null +++ b/test/COFF/Inputs/default.def @@ -0,0 +1,2 @@ +EXPORTS + f diff --git a/test/COFF/Inputs/extension.def b/test/COFF/Inputs/extension.def new file mode 100644 index 000000000000..d93f0dc1ecce --- /dev/null +++ b/test/COFF/Inputs/extension.def @@ -0,0 +1,3 @@ +LIBRARY library.ext +EXPORTS + f diff --git a/test/COFF/Inputs/named.def b/test/COFF/Inputs/named.def new file mode 100644 index 000000000000..07c8622189db --- /dev/null +++ b/test/COFF/Inputs/named.def @@ -0,0 +1,3 @@ +LIBRARY library +EXPORTS + f diff --git a/test/COFF/Inputs/object.s b/test/COFF/Inputs/object.s new file mode 100644 index 000000000000..b70599385591 --- /dev/null +++ b/test/COFF/Inputs/object.s @@ -0,0 +1,13 @@ + + .text + + .def f + .scl 2 + .type 32 + .endef + .global f +f: + retq $0 + + .section .drectve,"rd" + .ascii " /EXPORT:f" diff --git a/test/COFF/Inputs/pdb-type-server-simple-a.yaml b/test/COFF/Inputs/pdb-type-server-simple-a.yaml new file mode 100644 index 000000000000..78c68168127b --- /dev/null +++ b/test/COFF/Inputs/pdb-type-server-simple-a.yaml @@ -0,0 +1,255 @@ +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ ] +sections: + - Name: .drectve + Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ] + Alignment: 1 + SectionData: 2020202F44454641554C544C49423A224C4942434D5422202F44454641554C544C49423A224F4C444E414D45532220 + - Name: '.debug$S' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + Subsections: + - !Symbols + Records: + - Kind: S_OBJNAME + ObjNameSym: + Signature: 0 + ObjectName: 'C:\src\llvm-project\build\a.obj' + - Kind: S_COMPILE3 + Compile3Sym: + Flags: [ SecurityChecks, HotPatch ] + Machine: X64 + FrontendMajor: 19 + FrontendMinor: 0 + FrontendBuild: 24215 + FrontendQFE: 1 + BackendMajor: 19 + BackendMinor: 0 + BackendBuild: 24215 + BackendQFE: 1 + Version: 'Microsoft (R) Optimizing Compiler' + - !Symbols + Records: + - Kind: S_GPROC32_ID + ProcSym: + CodeSize: 27 + DbgStart: 4 + DbgEnd: 22 + FunctionType: 4098 + Flags: [ ] + DisplayName: main + - Kind: S_FRAMEPROC + FrameProcSym: + TotalFrameBytes: 56 + PaddingFrameBytes: 0 + OffsetToPadding: 0 + BytesOfCalleeSavedRegisters: 0 + OffsetOfExceptionHandler: 0 + SectionIdOfExceptionHandler: 0 + Flags: [ AsynchronousExceptionHandling, OptimizedForSpeed ] + - Kind: S_REGREL32 + RegRelativeSym: + Offset: 32 + Type: 4102 + Register: RSP + VarName: f + - Kind: S_PROC_ID_END + ScopeEndSym: + - !Lines + CodeSize: 27 + Flags: [ ] + RelocOffset: 0 + RelocSegment: 0 + Blocks: + - FileName: 'c:\src\llvm-project\build\a.c' + Lines: + - Offset: 0 + LineStart: 3 + IsStatement: true + EndDelta: 0 + - Offset: 4 + LineStart: 4 + IsStatement: true + EndDelta: 0 + - Offset: 12 + LineStart: 5 + IsStatement: true + EndDelta: 0 + - Offset: 22 + LineStart: 6 + IsStatement: true + EndDelta: 0 + Columns: + - !Symbols + Records: + - Kind: S_UDT + UDTSym: + Type: 4102 + UDTName: Foo + - !FileChecksums + Checksums: + - FileName: 'c:\src\llvm-project\build\a.c' + Kind: MD5 + Checksum: BF69E7E933074E1B7ED1FE8FB395965B + - !StringTable + Strings: + - 'c:\src\llvm-project\build\a.c' + - !Symbols + Records: + - Kind: S_BUILDINFO + BuildInfoSym: + BuildId: 4107 + Relocations: + - VirtualAddress: 152 + SymbolName: main + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 156 + SymbolName: main + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 224 + SymbolName: main + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 228 + SymbolName: main + Type: IMAGE_REL_AMD64_SECTION + - Name: '.debug$T' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + Types: + - Kind: LF_TYPESERVER2 + TypeServer2: + Guid: '{41414141-4141-4141-4141-414141414141}' + Age: 1 + Name: 'C:\src\llvm-project\build\ts.pdb' + - Name: '.text$mn' + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: 4883EC38C74424202A000000488D4C2420E8000000004883C438C3 + Relocations: + - VirtualAddress: 18 + SymbolName: g + Type: IMAGE_REL_AMD64_REL32 + - Name: .xdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: '0104010004620000' + - Name: .pdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: 000000001B00000000000000 + Relocations: + - VirtualAddress: 0 + SymbolName: '$LN3' + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 4 + SymbolName: '$LN3' + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 8 + SymbolName: '$unwind$main' + Type: IMAGE_REL_AMD64_ADDR32NB +symbols: + - Name: .drectve + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 47 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.debug$S' + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 388 + NumberOfRelocations: 4 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.debug$T' + Value: 0 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 64 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.text$mn' + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 27 + NumberOfRelocations: 1 + NumberOfLinenumbers: 0 + CheckSum: 1939996292 + Number: 0 + - Name: g + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: main + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: '$LN3' + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_LABEL + - Name: .xdata + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 8 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 931692337 + Number: 0 + - Name: '$unwind$main' + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .pdata + Value: 0 + SectionNumber: 6 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 12 + NumberOfRelocations: 3 + NumberOfLinenumbers: 0 + CheckSum: 567356797 + Number: 0 + - Name: '$pdata$main' + Value: 0 + SectionNumber: 6 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC +... diff --git a/test/COFF/Inputs/pdb-type-server-simple-b.yaml b/test/COFF/Inputs/pdb-type-server-simple-b.yaml new file mode 100644 index 000000000000..56e97d530894 --- /dev/null +++ b/test/COFF/Inputs/pdb-type-server-simple-b.yaml @@ -0,0 +1,173 @@ +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ ] +sections: + - Name: .drectve + Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ] + Alignment: 1 + SectionData: 2020202F44454641554C544C49423A224C4942434D5422202F44454641554C544C49423A224F4C444E414D45532220 + - Name: '.debug$S' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + Subsections: + - !Symbols + Records: + - Kind: S_OBJNAME + ObjNameSym: + Signature: 0 + ObjectName: 'C:\src\llvm-project\build\b.obj' + - Kind: S_COMPILE3 + Compile3Sym: + Flags: [ SecurityChecks, HotPatch ] + Machine: X64 + FrontendMajor: 19 + FrontendMinor: 0 + FrontendBuild: 24215 + FrontendQFE: 1 + BackendMajor: 19 + BackendMinor: 0 + BackendBuild: 24215 + BackendQFE: 1 + Version: 'Microsoft (R) Optimizing Compiler' + - !Symbols + Records: + - Kind: S_GPROC32_ID + ProcSym: + CodeSize: 13 + DbgStart: 5 + DbgEnd: 12 + FunctionType: 4099 + Flags: [ ] + DisplayName: g + - Kind: S_FRAMEPROC + FrameProcSym: + TotalFrameBytes: 0 + PaddingFrameBytes: 0 + OffsetToPadding: 0 + BytesOfCalleeSavedRegisters: 0 + OffsetOfExceptionHandler: 0 + SectionIdOfExceptionHandler: 0 + Flags: [ AsynchronousExceptionHandling, OptimizedForSpeed ] + - Kind: S_REGREL32 + RegRelativeSym: + Offset: 8 + Type: 4097 + Register: RSP + VarName: p + - Kind: S_PROC_ID_END + ScopeEndSym: + - !Lines + CodeSize: 13 + Flags: [ ] + RelocOffset: 0 + RelocSegment: 0 + Blocks: + - FileName: 'c:\src\llvm-project\build\b.c' + Lines: + - Offset: 0 + LineStart: 2 + IsStatement: true + EndDelta: 0 + Columns: + - !Symbols + Records: + - Kind: S_UDT + UDTSym: + Type: 4102 + UDTName: Foo + - !FileChecksums + Checksums: + - FileName: 'c:\src\llvm-project\build\b.c' + Kind: MD5 + Checksum: DDF8FD35CD67990C5D4147516BE10D0C + - !StringTable + Strings: + - 'c:\src\llvm-project\build\b.c' + - !Symbols + Records: + - Kind: S_BUILDINFO + BuildInfoSym: + BuildId: 4111 + Relocations: + - VirtualAddress: 152 + SymbolName: g + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 156 + SymbolName: g + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 220 + SymbolName: g + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 224 + SymbolName: g + Type: IMAGE_REL_AMD64_SECTION + - Name: '.debug$T' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + Types: + - Kind: LF_TYPESERVER2 + TypeServer2: + Guid: '{41414141-4141-4141-4141-414141414141}' + Age: 1 + Name: 'C:\src\llvm-project\build\ts.pdb' + - Name: '.text$mn' + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: 48894C2408488B4424088B00C3 +symbols: + - Name: .drectve + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 47 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.debug$S' + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 360 + NumberOfRelocations: 4 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.debug$T' + Value: 0 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 64 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.text$mn' + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 13 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 3246683207 + Number: 0 + - Name: g + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/test/COFF/Inputs/pdb-type-server-simple-ts.yaml b/test/COFF/Inputs/pdb-type-server-simple-ts.yaml new file mode 100644 index 000000000000..73496571ac72 --- /dev/null +++ b/test/COFF/Inputs/pdb-type-server-simple-ts.yaml @@ -0,0 +1,147 @@ +--- +MSF: + SuperBlock: + BlockSize: 4096 + FreeBlockMap: 1 + NumBlocks: 19 + NumDirectoryBytes: 64 + Unknown1: 0 + BlockMapAddr: 17 + NumDirectoryBlocks: 1 + DirectoryBlocks: [ 16 ] + NumStreams: 0 + FileSize: 77824 +PdbStream: + Age: 1 + Guid: '{41414141-4141-4141-4141-414141414141}' + Signature: 1500053944 + Features: [ VC140 ] + Version: VC70 +TpiStream: + Version: VC80 + Records: + - Kind: LF_STRUCTURE + Class: + MemberCount: 0 + Options: [ None, ForwardReference, HasUniqueName ] + FieldList: 0 + Name: Foo + UniqueName: '.?AUFoo@@' + DerivationList: 0 + VTableShape: 0 + Size: 0 + - Kind: LF_POINTER + Pointer: + ReferentType: 4096 + Attrs: 65548 + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 4097 ] + - Kind: LF_PROCEDURE + Procedure: + ReturnType: 116 + CallConv: NearC + Options: [ None ] + ParameterCount: 1 + ArgumentList: 4098 + - Kind: LF_POINTER + Pointer: + ReferentType: 4099 + Attrs: 65548 + - Kind: LF_FIELDLIST + FieldList: + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 116 + FieldOffset: 0 + Name: x + - Kind: LF_STRUCTURE + Class: + MemberCount: 1 + Options: [ None, HasUniqueName ] + FieldList: 4101 + Name: Foo + UniqueName: '.?AUFoo@@' + DerivationList: 0 + VTableShape: 0 + Size: 4 + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 0 ] + - Kind: LF_PROCEDURE + Procedure: + ReturnType: 116 + CallConv: NearC + Options: [ None ] + ParameterCount: 0 + ArgumentList: 4103 +IpiStream: + Version: VC80 + Records: + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'c:\src\llvm-project\build\a.c' + - Kind: LF_UDT_SRC_LINE + UdtSourceLine: + UDT: 4102 + SourceFile: 4096 + LineNumber: 1 + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4104 + Name: main + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4099 + Name: g + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'C:\src\llvm-project\build' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'C:\PROGRA~2\MICROS~1.0\VC\Bin\amd64\cl.exe' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: '-c -Zi -MT -IC:\PROGRA~2\MICROS~1.0\VC\include -IC:\PROGRA~2\MICROS~1.0\VC\atlmfc\include -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\ucrt -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\shared -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\um' + - Kind: LF_SUBSTR_LIST + StringList: + StringIndices: [ 4102 ] + - Kind: LF_STRING_ID + StringId: + Id: 4103 + String: ' -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\winrt -TC -X' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: a.c + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'C:\src\llvm-project\build\ts.pdb' + - Kind: LF_BUILDINFO + BuildInfo: + ArgIndices: [ 4100, 4101, 4105, 4106, 4104 ] + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'c:\src\llvm-project\build\b.c' + - Kind: LF_UDT_SRC_LINE + UdtSourceLine: + UDT: 4102 + SourceFile: 4108 + LineNumber: 1 + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: b.c + - Kind: LF_BUILDINFO + BuildInfo: + ArgIndices: [ 4100, 4101, 4110, 4106, 4104 ] +... diff --git a/test/COFF/common.test b/test/COFF/common.test index 007cfcfb6f92..4a00153f3e93 100644 --- a/test/COFF/common.test +++ b/test/COFF/common.test @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: yaml2obj %s > %t.obj # RUN: lld-link /out:%t.exe /entry:main %t.obj %t.obj # RUN: llvm-objdump -d %t.exe | FileCheck %s diff --git a/test/COFF/conflict.test b/test/COFF/conflict.test index a634c7185675..ae8e6c8ad327 100644 --- a/test/COFF/conflict.test +++ b/test/COFF/conflict.test @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: yaml2obj < %s > %t1.obj # RUN: yaml2obj < %s > %t2.obj # RUN: not lld-link /out:%t.exe %t1.obj %t2.obj >& %t.log diff --git a/test/COFF/constant.test b/test/COFF/constant.test index 3c8956beac9c..02d6b3e2ccae 100644 --- a/test/COFF/constant.test +++ b/test/COFF/constant.test @@ -1,3 +1,4 @@ +REQUIRES: x86 RUN: mkdir -p %t RUN: llvm-mc -triple i686-unknown-windows-msvc -filetype obj -o %t/import.o %S/Inputs/constant-import.s RUN: llc -mtriple i686-unknown-windows-msvc -filetype obj -o %t/export.o %S/Inputs/constant-export.ll diff --git a/test/COFF/def-export-stdcall.s b/test/COFF/def-export-stdcall.s index cdca7ae76acf..d7700d9e9535 100644 --- a/test/COFF/def-export-stdcall.s +++ b/test/COFF/def-export-stdcall.s @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=i686-windows-msvc %s -o %t.obj # RUN: echo -e "LIBRARY foo\nEXPORTS\n stdcall" > %t.def # RUN: lld-link -entry:dllmain -dll -def:%t.def %t.obj -out:%t.dll -implib:%t.lib diff --git a/test/COFF/delayimports32.test b/test/COFF/delayimports32.test index 9c4fcae5b6a5..53aadbb6a185 100644 --- a/test/COFF/delayimports32.test +++ b/test/COFF/delayimports32.test @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: yaml2obj < %p/Inputs/hello32.yaml > %t.obj # RUN: lld-link %t.obj %p/Inputs/std32.lib /subsystem:console \ # RUN: /entry:main@0 /alternatename:___delayLoadHelper2@8=_main@0 \ diff --git a/test/COFF/entry-mangled.test b/test/COFF/entry-mangled.test index acf54ba07973..1140e8298fbc 100644 --- a/test/COFF/entry-mangled.test +++ b/test/COFF/entry-mangled.test @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: yaml2obj < %s > %t.obj # RUN: lld-link /out:%t.exe /entry:main %t.obj # RUN: llvm-as -o %t.lto.obj %S/Inputs/entry-mangled.ll diff --git a/test/COFF/entrylib.ll b/test/COFF/entrylib.ll index 4ffa42c44a3e..602b4ff63336 100644 --- a/test/COFF/entrylib.ll +++ b/test/COFF/entrylib.ll @@ -1,3 +1,4 @@ +; REQUIRES: x86 ; RUN: llvm-as -o %t.obj %s ; RUN: rm -f %t.lib ; RUN: llvm-ar cru %t.lib %t.obj diff --git a/test/COFF/implib-name.test b/test/COFF/implib-name.test new file mode 100644 index 000000000000..81b5b258483f --- /dev/null +++ b/test/COFF/implib-name.test @@ -0,0 +1,71 @@ +# RUN: mkdir -p %T +# RUN: llvm-mc -triple x86_64-unknown-windows-msvc -filetype obj -o %T/object.obj %S/Inputs/object.s + +# RUN: lld-link /dll /machine:x64 /def:%S/Inputs/named.def /out:%T/library.dll %T/object.obj /entry:f /subsystem:CONSOLE +# RUN: llvm-ar t %T/library.lib | FileCheck %s -check-prefix CHECK-DEFAULT-DLL-EXT + +# RUN: lld-link /machine:x64 /def:%S/Inputs/named.def /out:%T/library.lib +# RUN: llvm-ar t %T/library.lib | FileCheck %s -check-prefix CHECK-DEFAULT-DLL-EXT + +CHECK-DEFAULT-DLL-EXT: library.dll +CHECK-DEFAULT-DLL-EXT: library.dll +CHECK-DEFAULT-DLL-EXT: library.dll +CHECK-DEFAULT-DLL-EXT: library.dll + +# RUN: lld-link /machine:x64 /def:%S/Inputs/named.def /out:%T/library.exe %T/object.obj /entry:f /subsystem:CONSOLE +# RUN: llvm-ar t %T/library.lib | FileCheck %s -check-prefix CHECK-DEFAULT-EXE-EXT + +CHECK-DEFAULT-EXE-EXT: library.exe +CHECK-DEFAULT-EXE-EXT: library.exe +CHECK-DEFAULT-EXE-EXT: library.exe +CHECK-DEFAULT-EXE-EXT: library.exe + +# RUN: lld-link /dll /machine:x64 /def:%S/Inputs/extension.def /out:%T/extension.dll /entry:f /subsystem:CONSOLE +# RUN: llvm-ar t %T/extension.lib | FileCheck %s -check-prefix CHECK-EXTENSION + +# RUN: lld-link /machine:x64 /def:%S/Inputs/extension.def /out:%T/extension.exe /entry:f /subsystem:CONSOLE +# RUN: llvm-ar t %T/extension.lib | FileCheck %s -check-prefix CHECK-EXTENSION + +# RUN: lld-link /machine:x64 /def:%S/Inputs/extension.def /out:%T/extension.lib +# RUN: llvm-ar t %T/extension.lib | FileCheck %s -check-prefix CHECK-EXTENSION + +CHECK-EXTENSION: library.ext +CHECK-EXTENSION: library.ext +CHECK-EXTENSION: library.ext +CHECK-EXTENSION: library.ext + +# RUN: lld-link /dll /machine:x64 /def:%S/Inputs/default.def /out:%T/default.dll /entry:f /subsystem:CONSOLE +# RUN: llvm-ar t %T/default.lib | FileCheck %s -check-prefix CHECK-OUTPUT-NAME-DLL + +# RUN: lld-link /machine:x64 /def:%S/Inputs/default.def /out:%T/default.lib +# RUN: llvm-ar t %T/default.lib | FileCheck %s -check-prefix CHECK-OUTPUT-NAME-DLL + +CHECK-OUTPUT-NAME-DLL: default.dll +CHECK-OUTPUT-NAME-DLL: default.dll +CHECK-OUTPUT-NAME-DLL: default.dll +CHECK-OUTPUT-NAME-DLL: default.dll + +# RUN: lld-link /machine:x64 /def:%S/Inputs/default.def /out:%T/default.exe %T/object.obj /entry:f /subsystem:CONSOLE +# RUN: llvm-ar t %T/default.lib | FileCheck %s -check-prefix CHECK-OUTPUT-NAME-EXE + +CHECK-OUTPUT-NAME-EXE: default.exe +CHECK-OUTPUT-NAME-EXE: default.exe +CHECK-OUTPUT-NAME-EXE: default.exe +CHECK-OUTPUT-NAME-EXE: default.exe + +# RUN: lld-link /machine:x64 /out:%T/default.exe %T/object.obj /entry:f /subsystem:CONSOLE +# RUN: llvm-ar t %T/default.lib | FileCheck %s -check-prefix CHECK-NODEF-EXE + +CHECK-NODEF-EXE: default.exe +CHECK-NODEF-EXE: default.exe +CHECK-NODEF-EXE: default.exe +CHECK-NODEF-EXE: default.exe + +# RUN: lld-link /machine:x64 /dll /out:%T/default.dll %T/object.obj /entry:f /subsystem:CONSOLE +# RUN: llvm-ar t %T/default.lib | FileCheck %s -check-prefix CHECK-NODEF-DLL + +CHECK-NODEF-DLL: default.dll +CHECK-NODEF-DLL: default.dll +CHECK-NODEF-DLL: default.dll +CHECK-NODEF-DLL: default.dll + diff --git a/test/COFF/imports.test b/test/COFF/imports.test index 584c24eb1b76..326bfbebbb05 100644 --- a/test/COFF/imports.test +++ b/test/COFF/imports.test @@ -1,3 +1,4 @@ +# REQUIRES: x86 # Verify that the lld can handle .lib files and emit .idata sections. # # RUN: lld-link /out:%t.exe /entry:main /subsystem:console \ diff --git a/test/COFF/include-lto.ll b/test/COFF/include-lto.ll index 6ca32fa71ad1..d5ae546ab719 100644 --- a/test/COFF/include-lto.ll +++ b/test/COFF/include-lto.ll @@ -1,3 +1,4 @@ +; REQUIRES: x86 ; RUN: llvm-as -o %t.obj %s ; RUN: lld-link /dll /out:%t.dll %t.obj ; RUN: llvm-objdump -d %t.dll | FileCheck %s diff --git a/test/COFF/msvclto-archive.ll b/test/COFF/msvclto-archive.ll index 047b19e76ddf..334565a1bef7 100644 --- a/test/COFF/msvclto-archive.ll +++ b/test/COFF/msvclto-archive.ll @@ -1,3 +1,4 @@ +; REQUIRES: x86 ;; Make sure we re-create archive files to strip bitcode files. ;; Do not create empty archives because the MSVC linker diff --git a/test/COFF/msvclto-order.ll b/test/COFF/msvclto-order.ll index 8991dce4a8d5..6f569af4af0c 100644 --- a/test/COFF/msvclto-order.ll +++ b/test/COFF/msvclto-order.ll @@ -1,3 +1,4 @@ +; REQUIRES: x86 ; RUN: opt -thinlto-bc %s -o %t.obj ; RUN: llc -filetype=obj %S/Inputs/msvclto-order-a.ll -o %T/msvclto-order-a.obj ; RUN: llvm-ar crs %T/msvclto-order-a.lib %T/msvclto-order-a.obj diff --git a/test/COFF/msvclto.ll b/test/COFF/msvclto.ll index 7fa9c54711b4..66fabeb80c74 100644 --- a/test/COFF/msvclto.ll +++ b/test/COFF/msvclto.ll @@ -1,3 +1,4 @@ +; REQUIRES: x86 ; RUN: llvm-as -o %t.obj %s ; RUN: mkdir -p %t.dir ; RUN: llvm-mc -triple=x86_64-pc-windows-msvc -filetype=obj -o %t.dir/bitcode.obj %p/Inputs/msvclto.s diff --git a/test/COFF/pdb-comdat.test b/test/COFF/pdb-comdat.test index ea691aec87ad..f85dacdbf4bb 100644 --- a/test/COFF/pdb-comdat.test +++ b/test/COFF/pdb-comdat.test @@ -56,7 +56,7 @@ CHECK: flags = has async eh | opt speed CHECK: 196 | S_END [size = 4] CHECK: 200 | S_GDATA32 [size = 24] `global` CHECK: type = 0x0074 (int), addr = 0000:0000 -CHECK: 224 | S_BUILDINFO [size = 8] BuildId = `4106` +CHECK: 224 | S_BUILDINFO [size = 8] BuildId = `0x100A` CHECK: 232 | S_GPROC32_ID [size = 44] `foo` CHECK: parent = 0, end = 308, addr = 0002:0032, code size = 15 CHECK: debug start = 0, debug end = 14, flags = none @@ -81,7 +81,7 @@ CHECK: flags = has async eh | opt speed CHECK: 196 | S_END [size = 4] CHECK: 200 | S_GDATA32 [size = 24] `global` CHECK: type = 0x0074 (int), addr = 0000:0000 -CHECK: 224 | S_BUILDINFO [size = 8] BuildId = `4109` +CHECK: 224 | S_BUILDINFO [size = 8] BuildId = `0x100D` CHECK-NOT: S_GPROC32_ID {{.*}} `foo` CHECK-LABEL: Mod 0002 | `* Linker *`: diff --git a/test/COFF/pdb-lib.s b/test/COFF/pdb-lib.s index ab95f82a2a91..74d987eac814 100644 --- a/test/COFF/pdb-lib.s +++ b/test/COFF/pdb-lib.s @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: rm -rf %t && mkdir -p %t && cd %t # RUN: llvm-mc -filetype=obj -triple=i686-windows-msvc %s -o foo.obj # RUN: llc %S/Inputs/bar.ll -filetype=obj -mtriple=i686-windows-msvc -o bar.obj diff --git a/test/COFF/pdb-symbol-types.yaml b/test/COFF/pdb-symbol-types.yaml index 8abbc365b34e..2ad6f5b07bf4 100644 --- a/test/COFF/pdb-symbol-types.yaml +++ b/test/COFF/pdb-symbol-types.yaml @@ -35,7 +35,7 @@ # CHECK: original type = 0x1004 # CHECK: 240 | S_UDT [size = 12] `Foo` # CHECK: original type = 0x1004 -# CHECK: 252 | S_BUILDINFO [size = 8] BuildId = `4106` +# CHECK: 252 | S_BUILDINFO [size = 8] BuildId = `0x100A` # CHECK-LABEL: Mod 0001 | `* Linker *`: --- !COFF diff --git a/test/COFF/pdb-type-server-missing.yaml b/test/COFF/pdb-type-server-missing.yaml new file mode 100644 index 000000000000..91bb04f5622f --- /dev/null +++ b/test/COFF/pdb-type-server-missing.yaml @@ -0,0 +1,132 @@ +# This is an object compiled with /Zi (see the LF_TYPESERVER2 record) without an +# adjacent type server PDB. Test that LLD fails gracefully on it. + +# FIXME: Ideally we'd do what MSVC does, which is to warn and drop all debug +# info in the object with the missing PDB. + +# RUN: yaml2obj %s -o %t.obj +# RUN: not lld-link %t.obj -out:%t.exe -debug -pdb:%t.pdb -nodefaultlib -entry:main 2>&1 | FileCheck %s + +# CHECK: error: Type server PDB was not found + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ ] +sections: + - Name: '.debug$S' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + Subsections: + - !Symbols + Records: + - Kind: S_GPROC32_ID + ProcSym: + CodeSize: 3 + DbgStart: 0 + DbgEnd: 2 + FunctionType: 4199 + Flags: [ ] + DisplayName: main + - Kind: S_FRAMEPROC + FrameProcSym: + TotalFrameBytes: 0 + PaddingFrameBytes: 0 + OffsetToPadding: 0 + BytesOfCalleeSavedRegisters: 0 + OffsetOfExceptionHandler: 0 + SectionIdOfExceptionHandler: 0 + Flags: [ AsynchronousExceptionHandling, OptimizedForSpeed ] + - Kind: S_PROC_ID_END + ScopeEndSym: + - !Lines + CodeSize: 3 + Flags: [ ] + RelocOffset: 0 + RelocSegment: 0 + Blocks: + - FileName: 'c:\src\llvm-project\build\t.c' + Lines: + - Offset: 0 + LineStart: 1 + IsStatement: true + EndDelta: 0 + Columns: + - !FileChecksums + Checksums: + - FileName: 'c:\src\llvm-project\build\t.c' + Kind: MD5 + Checksum: 270A878DCC1B845655B162F56C4F5020 + - !StringTable + Strings: + - 'c:\src\llvm-project\build\t.c' + Relocations: + - VirtualAddress: 44 + SymbolName: main + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 48 + SymbolName: main + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 100 + SymbolName: main + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 104 + SymbolName: main + Type: IMAGE_REL_AMD64_SECTION + - Name: '.debug$T' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + Types: + - Kind: LF_TYPESERVER2 + TypeServer2: + Guid: '{01DF191B-22BF-6B42-96CE-5258B8329FE5}' + Age: 18 + Name: 'C:\src\llvm-project\build\definitely_not_found_for_sure.pdb' + - Name: '.text$mn' + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: 33C0C3 +symbols: + - Name: '.debug$S' + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 328 + NumberOfRelocations: 4 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.debug$T' + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 564 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.text$mn' + Value: 0 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 3 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 4021952397 + Number: 0 + - Name: main + Value: 0 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/test/COFF/pdb-type-server-simple.test b/test/COFF/pdb-type-server-simple.test new file mode 100644 index 000000000000..c0de4e390914 --- /dev/null +++ b/test/COFF/pdb-type-server-simple.test @@ -0,0 +1,91 @@ +Replicate this scenario: + +$ cat a.c +struct Foo { int x; }; +int g(struct Foo *p); +int main() { + struct Foo f = {42}; + return g(&f); +} + +$ cat b.c +struct Foo { int x; }; +int g(struct Foo *p) { return p->x; } + +$ cl -c a.c b.c -Zi -Fdts.pdb + +$ lld-link a.obj b.obj -debug -entry:main -nodefaultlib -out:t.exe + +RUN: rm -rf %t && mkdir -p %t && cd %t +RUN: yaml2obj %S/Inputs/pdb-type-server-simple-a.yaml -o a.obj +RUN: yaml2obj %S/Inputs/pdb-type-server-simple-b.yaml -o b.obj +RUN: llvm-pdbutil yaml2pdb %S/Inputs/pdb-type-server-simple-ts.yaml -pdb ts.pdb +RUN: lld-link a.obj b.obj -entry:main -debug -out:t.exe -pdb:t.pdb -nodefaultlib +RUN: llvm-pdbutil dump -symbols -types -ids %t/t.pdb | FileCheck %s + + +CHECK-LABEL: Types (TPI Stream) +CHECK: ============================================================ + +CHECK: [[FOO_DECL:[^ ]*]] | LF_STRUCTURE [size = 36] `Foo` + +CHECK: [[FOO_PTR:[^ ]*]] | LF_POINTER [size = 12] +CHECK-NEXT: referent = [[FOO_DECL]] + +CHECK: [[G_ARGS:[^ ]*]] | LF_ARGLIST [size = 12] +CHECK-NEXT: [[FOO_PTR]]: `Foo*` + +CHECK: [[G_PROTO:[^ ]*]] | LF_PROCEDURE [size = 16] +CHECK-NEXT: return type = 0x0074 (int), # args = 1, param list = [[G_ARGS]] +CHECK-NEXT: calling conv = cdecl, options = None + +CHECK: [[FOO_COMPLETE:[^ ]*]] | LF_STRUCTURE [size = 36] `Foo` +CHECK-NEXT: unique name: `.?AUFoo@@` +CHECK-NEXT: vtable: , base list: , field list: 0x{{.*}} +CHECK: options: has unique name +CHECK: [[MAIN_PROTO:[^ ]*]] | LF_PROCEDURE [size = 16] +CHECK: return type = 0x0074 (int), # args = 0, param list = 0x{{.*}} +CHECK: calling conv = cdecl, options = None + + +CHECK-LABEL: Types (IPI Stream) +CHECK: ============================================================ +CHECK: [[MAIN_ID:[^ ]*]] | LF_FUNC_ID [size = 20] +CHECK: name = main, type = [[MAIN_PROTO]], parent scope = +CHECK: [[G_ID:[^ ]*]] | LF_FUNC_ID [size = 16] +CHECK: name = g, type = [[G_PROTO]], parent scope = +CHECK: [[A_BUILD:[^ ]*]] | LF_BUILDINFO [size = 28] +CHECK: {{.*}}: `a.c` +CHECK: [[B_BUILD:[^ ]*]] | LF_BUILDINFO [size = 28] +CHECK: {{.*}}: `b.c` + +CHECK-LABEL: Symbols +CHECK: ============================================================ +CHECK-LABEL: Mod 0000 | `{{.*}}a.obj`: +CHECK: 4 | S_OBJNAME [size = 40] sig=0, `C:\src\llvm-project\build\a.obj` +CHECK: 104 | S_GPROC32_ID [size = 44] `main` +CHECK: parent = 0, end = 196, addr = 0002:0000, code size = 27 +CHECK: type = {{.*}}, debug start = 4, debug end = 22, flags = none +CHECK: 200 | S_UDT [size = 12] `Foo` +CHECK: original type = [[FOO_COMPLETE]] +CHECK: 212 | S_BUILDINFO [size = 8] BuildId = `[[A_BUILD]]` +CHECK-LABEL: Mod 0001 | `{{.*}}b.obj`: +CHECK: 4 | S_OBJNAME [size = 40] sig=0, `C:\src\llvm-project\build\b.obj` +CHECK: 44 | S_COMPILE3 [size = 60] +CHECK: machine = intel x86-x64, Ver = Microsoft (R) Optimizing Compiler, language = c +CHECK: frontend = 19.0.24215.1, backend = 19.0.24215.1 +CHECK: flags = security checks | hot patchable +CHECK: 104 | S_GPROC32_ID [size = 44] `g` +CHECK: parent = 0, end = 196, addr = 0002:0032, code size = 13 +CHECK: type = {{.*}}, debug start = 5, debug end = 12, flags = none +CHECK: 148 | S_FRAMEPROC [size = 32] +CHECK: size = 0, padding size = 0, offset to padding = 0 +CHECK: bytes of callee saved registers = 0, exception handler addr = 0000:0000 +CHECK: flags = has async eh | opt speed +CHECK: 180 | S_REGREL32 [size = 16] `p` +CHECK: type = [[FOO_PTR]] (Foo*), register = rsp, offset = 8 +CHECK: 196 | S_END [size = 4] +CHECK: 200 | S_UDT [size = 12] `Foo` +CHECK: original type = [[FOO_COMPLETE]] +CHECK: 212 | S_BUILDINFO [size = 8] BuildId = `[[B_BUILD]]` +CHECK-LABEL: Mod 0002 | `* Linker *`: diff --git a/test/COFF/reloc-discarded-dwarf.s b/test/COFF/reloc-discarded-dwarf.s new file mode 100644 index 000000000000..d779d2f5b8fc --- /dev/null +++ b/test/COFF/reloc-discarded-dwarf.s @@ -0,0 +1,15 @@ +# RUN: llvm-mc -triple=x86_64-windows-msvc -filetype=obj -o %t1.obj %s +# RUN: llvm-mc -triple=x86_64-windows-msvc -filetype=obj -o %t2.obj %s + +# LLD should not error on relocations in DWARF debug sections against symbols in +# discarded sections. +# RUN: lld-link -entry:main -debug %t1.obj %t2.obj + + .section .text,"xr",discard,main + .globl main +main: +f: + retq + + .section .debug_info,"dr" + .quad f diff --git a/test/COFF/reloc-oob.yaml b/test/COFF/reloc-oob.yaml new file mode 100644 index 000000000000..0ed4c4d57976 --- /dev/null +++ b/test/COFF/reloc-oob.yaml @@ -0,0 +1,62 @@ +# Make sure LLD does some light relocation bounds checking. + +# RUN: yaml2obj %s -o %t.obj +# RUN: not lld-link %t.obj -entry:main -nodefaultlib -out:%t.exe 2>&1 | FileCheck %s + +# CHECK: error: relocation points beyond the end of its parent section + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_I386 + Characteristics: [ ] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: 5589E550C745FC00000000A10000000083C4045DC3 + Relocations: + - VirtualAddress: 24 + SymbolName: _g + Type: IMAGE_REL_I386_DIR32 + - Name: .data + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 4 + SectionData: 2A000000 +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 21 + NumberOfRelocations: 1 + NumberOfLinenumbers: 0 + CheckSum: 662775349 + Number: 1 + - Name: .data + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 4 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 3482275674 + Number: 2 + - Name: _main + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: _g + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/test/COFF/savetemps.ll b/test/COFF/savetemps.ll index 4e59812441a9..7f2e11c17715 100644 --- a/test/COFF/savetemps.ll +++ b/test/COFF/savetemps.ll @@ -1,3 +1,4 @@ +; REQUIRES: x86 ; RUN: rm -fr %T/savetemps ; RUN: mkdir %T/savetemps ; RUN: llvm-as -o %T/savetemps/savetemps.obj %s diff --git a/test/COFF/thinlto-archives.ll b/test/COFF/thinlto-archives.ll index 7a5e36aa1fb9..9a47a3a6feb6 100644 --- a/test/COFF/thinlto-archives.ll +++ b/test/COFF/thinlto-archives.ll @@ -1,3 +1,4 @@ +; REQUIRES: x86 ; RUN: rm -fr %T/thinlto-archives ; RUN: mkdir %T/thinlto-archives %T/thinlto-archives/a %T/thinlto-archives/b ; RUN: opt -thinlto-bc -o %T/thinlto-archives/main.obj %s diff --git a/test/COFF/thinlto-mangled.ll b/test/COFF/thinlto-mangled.ll index efcd9c3d2d0a..8c901cbd70ba 100644 --- a/test/COFF/thinlto-mangled.ll +++ b/test/COFF/thinlto-mangled.ll @@ -1,3 +1,4 @@ +; REQUIRES: x86 ; RUN: opt -thinlto-bc %s -o %t.obj ; RUN: opt -thinlto-bc %S/Inputs/thinlto-mangled-qux.ll -o %T/thinlto-mangled-qux.obj ; RUN: lld-link -out:%t.exe -entry:main %t.obj %T/thinlto-mangled-qux.obj diff --git a/test/COFF/thinlto.ll b/test/COFF/thinlto.ll index 11b689d6327e..f01d0d802289 100644 --- a/test/COFF/thinlto.ll +++ b/test/COFF/thinlto.ll @@ -1,3 +1,4 @@ +; REQUIRES: x86 ; RUN: rm -fr %T/thinlto ; RUN: mkdir %T/thinlto ; RUN: opt -thinlto-bc -o %T/thinlto/main.obj %s diff --git a/test/ELF/Inputs/ctors_dtors_priority1.s b/test/ELF/Inputs/ctors_dtors_priority1.s index 2eb19d7edad9..2102dba278dc 100644 --- a/test/ELF/Inputs/ctors_dtors_priority1.s +++ b/test/ELF/Inputs/ctors_dtors_priority1.s @@ -1,5 +1,5 @@ .section .ctors, "aw", @progbits - .byte 0xA1 + .quad 0xA1 .section .dtors, "aw", @progbits - .byte 0xA2 + .quad 0xA2 diff --git a/test/ELF/Inputs/ctors_dtors_priority2.s b/test/ELF/Inputs/ctors_dtors_priority2.s index fb85ce87c5c5..e94b15e2b894 100644 --- a/test/ELF/Inputs/ctors_dtors_priority2.s +++ b/test/ELF/Inputs/ctors_dtors_priority2.s @@ -1,5 +1,5 @@ .section .ctors, "aw", @progbits - .byte 0xB1 + .quad 0xB1 .section .dtors, "aw", @progbits - .byte 0xB2 + .quad 0xB2 diff --git a/test/ELF/Inputs/ctors_dtors_priority3.s b/test/ELF/Inputs/ctors_dtors_priority3.s index 96418d351a85..7bba90cc70f8 100644 --- a/test/ELF/Inputs/ctors_dtors_priority3.s +++ b/test/ELF/Inputs/ctors_dtors_priority3.s @@ -1,5 +1,5 @@ .section .ctors, "aw", @progbits - .byte 0xC1 + .quad 0xC1 .section .dtors, "aw", @progbits - .byte 0xC2 + .quad 0xC2 diff --git a/test/ELF/Inputs/gdb-index-a.elf b/test/ELF/Inputs/gdb-index-a.elf deleted file mode 100644 index 9b90b0dc233e9740e22834ba1cddf320a28c0a1a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3040 zcmbtW&rcIU6rSxO1%+DBh=_?bF^W;PEf5rqrj`gs4F?U02Til33pCPg({2?ws3(8K z#E^L5VuD`usKEm<(TfNF1UYyxF?#pl$%DQ(J8#)OrylerJ2UTl-<$94%TLz=}N_)qus9tndc)>Aj)vzW?3ZX$|WaRFXfX6 z)smw_waR?aD>(W3tPm4pVJJKS)|I!6b?am8f zstw>dCPZ{*s_o}7Q?znO`lirVY>M_KeElw(qO%EqdlS5?3BIEVPP@?DuB4s0+)Nb|)xG~u*9XbCrs2K8`7+pm zh0hB5$PL?ma1i59`h_qlH0Jq-Acjx(zvkmhkk5&7q|e_RoQvlQKSmk2!gfa$gr65Q z{FES%<|8}{7@rd$aTy!1VZRGn&OHSYo&Ji_Usjo@k9)-RCjsMgV#+;i!1nlE&~mN~ z5so4Gsmh@DhI0SlUWI_J{(c0(Xq~Wre24J*mjKi0zXco(&u7>;w+=y_enz8@XPN6i z28_>%dK=h);m=CgIQJ0*b^2G7KIP;6Z3s0hu@KjnW=`AkMUAp#3<_>;;L<&ud5eh9a)09`)jIaeaKIbovzq J@;@7{{~H(av9$mI diff --git a/test/ELF/Inputs/gdb-index-b.elf b/test/ELF/Inputs/gdb-index-b.elf deleted file mode 100644 index b3356d8c773b20ef283c3ac4d8ee0d73c39b738a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3048 zcmbtWJ8u&~5T5e^NgxSMc!Us;jD!S8=lDo0;3BFzqqLD`Pu&0Z7W%~xG0IJjpB1sv+m5tG8%6(NOSb=7-{b>lh=!cu zp7hAe!r<88o5JYp!pN&a53@)4NyT21+-~A0SM@95L=25^yKLOe+EOKqViT0a)En!% z=~l_Un4jU+aefXCa2wAGzkx$h(2OR$xq3Yb(wD>q^<=7tnTfr8twz~}S~bYFs--Nj zW_JIcW__^|m4i}ip6K|@%z@0#*-|TvTA3+t!pn{CX~kMTe=9%blk z%xAme<-Jrqzc=2=S50TEPkVduSkKsM9^*J@=~n~E*Lwo|c1|8=6d$A75=*|4qhZOor$k8W!wNQzW;=MqB<9mi*Yu zGXEpSWK87yf`$b@Ev88BLpIv-UsCzCKi(g=kj(#_F&UE~>QmrBD27PxGq&0CFInCn zx1G%YnlZ%Gb@DKlqbd>3rztwW?y*ib|3yXUw*R&NN9Awk!1#$K2!n*bvK?4T@U%aE z-%Qc(udz=&u+85K%lzS%*Zz86<4-|;yAb=m^8XIS5Lv&icF;d7;$zh#Uz#78A7{#z NzplUyY&S*b{|)b5v6%n> diff --git a/test/ELF/Inputs/gdb-index.s b/test/ELF/Inputs/gdb-index.s new file mode 100644 index 000000000000..907a66d350b0 --- /dev/null +++ b/test/ELF/Inputs/gdb-index.s @@ -0,0 +1,73 @@ +.text +.Ltext0: +.globl main2 +.type main2, @function +main2: + nop + nop +.Letext0: + +.section .debug_info,"",@progbits +.long 0x30 +.value 0x4 +.long 0 +.byte 0x8 +.uleb128 0x1 +.quad .Ltext0 +.quad .Letext0-.Ltext0 +.long 0 +.long 0 +.long 0 +.long 0 +.byte 0x63 +.byte 0x88 +.byte 0xb4 +.byte 0x61 +.byte 0xaa +.byte 0xb6 +.byte 0xb0 +.byte 0x67 + +.section .debug_abbrev,"",@progbits +.uleb128 0x1 +.uleb128 0x11 +.byte 0 +.uleb128 0x11 +.uleb128 0x1 +.uleb128 0x12 +.uleb128 0x7 +.uleb128 0x10 +.uleb128 0x17 +.uleb128 0x2130 +.uleb128 0xe +.uleb128 0x1b +.uleb128 0xe +.uleb128 0x2134 +.uleb128 0x19 +.uleb128 0x2133 +.uleb128 0x17 +.uleb128 0x2131 +.uleb128 0x7 +.byte 0 +.byte 0 +.byte 0 + +.section .debug_gnu_pubnames,"",@progbits +.long 0x18 +.value 0x2 +.long 0 +.long 0x33 +.long 0x18 +.byte 0x30 +.string "main2" +.long 0 + +.section .debug_gnu_pubtypes,"",@progbits +.long 0x17 +.value 0x2 +.long 0 +.long 0x33 +.long 0x2b +.byte 0x90 +.string "int" +.long 0 diff --git a/test/ELF/Inputs/symver-archive1.s b/test/ELF/Inputs/symver-archive1.s deleted file mode 100644 index be7c64494215..000000000000 --- a/test/ELF/Inputs/symver-archive1.s +++ /dev/null @@ -1,6 +0,0 @@ -.text -.globl x -.type x, @function -x: - -.symver x, xx@@VER diff --git a/test/ELF/Inputs/symver-archive2.s b/test/ELF/Inputs/symver-archive2.s deleted file mode 100644 index a9b9d0b0a35b..000000000000 --- a/test/ELF/Inputs/symver-archive2.s +++ /dev/null @@ -1 +0,0 @@ -call xx@PLT diff --git a/test/ELF/allow-shlib-undefined.s b/test/ELF/allow-shlib-undefined.s index 2d068b0f60ed..abb0351db723 100644 --- a/test/ELF/allow-shlib-undefined.s +++ b/test/ELF/allow-shlib-undefined.s @@ -1,3 +1,4 @@ +# REQUIRES: x86 # --allow-shlib-undefined and --no-allow-shlib-undefined are fully # ignored in linker implementation. # --allow-shlib-undefined is set by default diff --git a/test/ELF/as-needed-no-reloc.s b/test/ELF/as-needed-no-reloc.s index 68f03d782c24..f8c34f80a595 100644 --- a/test/ELF/as-needed-no-reloc.s +++ b/test/ELF/as-needed-no-reloc.s @@ -16,7 +16,7 @@ # CHECK-NEXT: Other: 0 # CHECK-NEXT: Section: Undefined -# CHECK: NEEDED SharedLibrary ({{.*}}as-needed-no-reloc{{.*}}2.so) +# CHECK: NEEDED Shared library: [{{.*}}as-needed-no-reloc{{.*}}2.so] .globl _start _start: diff --git a/test/ELF/as-needed.s b/test/ELF/as-needed.s index 4f1a48abac36..37c6103b0ed0 100644 --- a/test/ELF/as-needed.s +++ b/test/ELF/as-needed.s @@ -28,13 +28,13 @@ // RUN: ld.lld %t.o %t.script -o %t2 // RUN: llvm-readobj -dynamic-table %t2 | FileCheck -check-prefix=CHECK2 %s -// CHECK: NEEDED SharedLibrary (shared1) -// CHECK: NEEDED SharedLibrary (shared2) -// CHECK: NEEDED SharedLibrary (shared3) +// CHECK: NEEDED Shared library: [shared1] +// CHECK: NEEDED Shared library: [shared2] +// CHECK: NEEDED Shared library: [shared3] -// CHECK2: NEEDED SharedLibrary (shared1) -// CHECK2-NOT: NEEDED SharedLibrary (shared2) -// CHECK2-NOT: NEEDED SharedLibrary (shared3) +// CHECK2: NEEDED Shared library: [shared1] +// CHECK2-NOT: NEEDED Shared library: [shared2] +// CHECK2-NOT: NEEDED Shared library: [shared3] .global _start _start: diff --git a/test/ELF/auxiliary.s b/test/ELF/auxiliary.s index 236d0a421d4f..18fbdf05f9ec 100644 --- a/test/ELF/auxiliary.s +++ b/test/ELF/auxiliary.s @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o # RUN: ld.lld %t.o -shared -f aaa --auxiliary bbb -o %t # RUN: llvm-readobj --dynamic-table %t | FileCheck %s diff --git a/test/ELF/compressed-debug-input.s b/test/ELF/compressed-debug-input.s index fbd5b02a07f0..d96ebdcb30b4 100644 --- a/test/ELF/compressed-debug-input.s +++ b/test/ELF/compressed-debug-input.s @@ -1,4 +1,4 @@ -# REQUIRES: zlib +# REQUIRES: zlib, x86 # RUN: llvm-mc -compress-debug-sections=zlib -filetype=obj -triple=x86_64-unknown-linux %s -o %t # RUN: llvm-readobj -sections %t | FileCheck -check-prefix=ZLIB %s diff --git a/test/ELF/ctors_dtors_priority.s b/test/ELF/ctors_dtors_priority.s index 10d6471f953a..fcddcbb020f3 100644 --- a/test/ELF/ctors_dtors_priority.s +++ b/test/ELF/ctors_dtors_priority.s @@ -14,28 +14,35 @@ _start: nop .section .ctors, "aw", @progbits - .byte 1 + .quad 1 .section .ctors.100, "aw", @progbits - .byte 2 + .quad 2 .section .ctors.005, "aw", @progbits - .byte 3 + .quad 3 .section .ctors, "aw", @progbits - .byte 4 + .quad 4 .section .ctors, "aw", @progbits - .byte 5 + .quad 5 .section .dtors, "aw", @progbits - .byte 0x11 + .quad 0x11 .section .dtors.100, "aw", @progbits - .byte 0x12 + .quad 0x12 .section .dtors.005, "aw", @progbits - .byte 0x13 + .quad 0x13 .section .dtors, "aw", @progbits - .byte 0x14 + .quad 0x14 .section .dtors, "aw", @progbits - .byte 0x15 + .quad 0x15 // CHECK: Contents of section .ctors: -// CHECK-NEXT: a1010405 b10302c1 +// CHECK-NEXT: 202000 a1000000 00000000 01000000 00000000 +// CHECK-NEXT: 202010 04000000 00000000 05000000 00000000 +// CHECK-NEXT: 202020 b1000000 00000000 03000000 00000000 +// CHECK-NEXT: 202030 02000000 00000000 c1000000 00000000 + // CHECK: Contents of section .dtors: -// CHECK-NEXT: a2111415 b21312c2 +// CHECK-NEXT: 202040 a2000000 00000000 11000000 00000000 +// CHECK-NEXT: 202050 14000000 00000000 15000000 00000000 +// CHECK-NEXT: 202060 b2000000 00000000 13000000 00000000 +// CHECK-NEXT: 202070 12000000 00000000 c2000000 00000000 diff --git a/test/ELF/debug-gnu-pubnames.s b/test/ELF/debug-gnu-pubnames.s index 0a8693c97eb8..aebfdfd0fb91 100644 --- a/test/ELF/debug-gnu-pubnames.s +++ b/test/ELF/debug-gnu-pubnames.s @@ -1,10 +1,18 @@ # REQUIRES: x86 -# RUN: ld.lld -e main %p/Inputs/gdb-index-a.elf %p/Inputs/gdb-index-b.elf -o %t1.exe -# RUN: llvm-readobj -sections %t1.exe | FileCheck -check-prefix=CHECK1 %s -# CHECK1: Name: .debug_gnu_pubnames -# CHECK1: Name: .debug_gnu_pubtypes +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -# RUN: ld.lld -gdb-index -e main %p/Inputs/gdb-index-a.elf %p/Inputs/gdb-index-b.elf -o %t2.exe -# RUN: llvm-readobj -sections %t2.exe | FileCheck -check-prefix=CHECK2 %s -# CHECK2-NOT: Name: .debug_gnu_pubnames -# CHECK2-NOT: Name: .debug_gnu_pubtypes +# RUN: ld.lld %t.o -o %t1.exe +# RUN: llvm-readobj -sections %t1.exe | FileCheck %s +# CHECK: .debug_gnu_pubnames +# CHECK: .debug_gnu_pubtypes + +# RUN: ld.lld -gdb-index %t.o -o %t2.exe +# RUN: llvm-readobj -sections %t2.exe | FileCheck %s --check-prefix=GDB +# GDB-NOT: .debug_gnu_pubnames +# GDB-NOT: .debug_gnu_pubtypes + +.section .debug_gnu_pubnames,"",@progbits +.long 0 + +.section .debug_gnu_pubtypes,"",@progbits +.long 0 diff --git a/test/ELF/dynamic-reloc.s b/test/ELF/dynamic-reloc.s index 8fda0b45abea..939093c17b41 100644 --- a/test/ELF/dynamic-reloc.s +++ b/test/ELF/dynamic-reloc.s @@ -43,7 +43,7 @@ // CHECK: DynamicSection [ // CHECK-NEXT: Tag Type Name/Value -// CHECK-NEXT: 0x0000000000000001 NEEDED SharedLibrary ({{.*}}2.so) +// CHECK-NEXT: 0x0000000000000001 NEEDED Shared library: [{{.*}}2.so] // CHECK-NEXT: 0x0000000000000015 DEBUG 0x0 // CHECK-NEXT: 0x0000000000000017 JMPREL // CHECK-NEXT: 0x0000000000000002 PLTRELSZ 24 (bytes) diff --git a/test/ELF/filter.s b/test/ELF/filter.s new file mode 100644 index 000000000000..fa8e5267b18b --- /dev/null +++ b/test/ELF/filter.s @@ -0,0 +1,15 @@ +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: ld.lld %t.o -shared -F foo.so -F boo.so -o %t1 +# RUN: llvm-readobj --dynamic-table %t1 | FileCheck %s + +# Test alias. +# RUN: ld.lld %t.o -shared --filter=foo.so --filter=boo.so -o %t2 +# RUN: llvm-readobj --dynamic-table %t2 | FileCheck %s + +# CHECK: DynamicSection [ +# CHECK-NEXT: Tag Type Name/Value +# CHECK-NEXT: 0x000000007FFFFFFF FILTER Filter library: [foo.so] +# CHECK-NEXT: 0x000000007FFFFFFF FILTER Filter library: [boo.so] + +# RUN: not ld.lld %t.o -F x -o %t 2>&1 | FileCheck -check-prefix=ERR %s +# ERR: -F may not be used without -shared diff --git a/test/ELF/gc-sections-shared.s b/test/ELF/gc-sections-shared.s index a88f2b443479..efb21faee6bd 100644 --- a/test/ELF/gc-sections-shared.s +++ b/test/ELF/gc-sections-shared.s @@ -38,7 +38,7 @@ # CHECK-NEXT: } # CHECK-NEXT: ] -# CHECK: NEEDED SharedLibrary ({{.*}}.so) +# CHECK: NEEDED Shared library: [{{.*}}.so] .section .text.foo, "ax" .globl foo diff --git a/test/ELF/gdb-index-empty.s b/test/ELF/gdb-index-empty.s index 24f20803a008..0158357c9bfd 100644 --- a/test/ELF/gdb-index-empty.s +++ b/test/ELF/gdb-index-empty.s @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux -o %t %s # RUN: ld.lld --gdb-index --gc-sections -o %t2 %t # RUN: llvm-dwarfdump -debug-dump=gdb_index %t2 | FileCheck %s diff --git a/test/ELF/gdb-index-gc-sections.s b/test/ELF/gdb-index-gc-sections.s index 70a14754656c..58c47ae5e987 100644 --- a/test/ELF/gdb-index-gc-sections.s +++ b/test/ELF/gdb-index-gc-sections.s @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux -o %t %s # RUN: ld.lld --gdb-index --gc-sections -o %t2 %t # RUN: llvm-dwarfdump -debug-dump=gdb_index %t2 | FileCheck %s diff --git a/test/ELF/gdb-index.s b/test/ELF/gdb-index.s index b7d8a708ace5..e04845e022c3 100644 --- a/test/ELF/gdb-index.s +++ b/test/ELF/gdb-index.s @@ -1,32 +1,19 @@ -## gdb-index-a.elf and gdb-index-b.elf are a test.o and test2.o renamed, -## were generated in this way: -## test.cpp: -## int main() { return 0; } -## test2.cpp: -## int main2() { return 0; } -## Compiled with: -## gcc -gsplit-dwarf -c test.cpp test2.cpp -## gcc version 5.3.1 20160413 -## Info about gdb-index: https://sourceware.org/gdb/onlinedocs/gdb/Index-Section-Format.html - # REQUIRES: x86 -# RUN: ld.lld --gdb-index -e main %p/Inputs/gdb-index-a.elf %p/Inputs/gdb-index-b.elf -o %t +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/gdb-index.s -o %t2.o +# RUN: ld.lld --gdb-index -e main %t1.o %t2.o -o %t # RUN: llvm-dwarfdump -debug-dump=gdb_index %t | FileCheck %s # RUN: llvm-objdump -d %t | FileCheck %s --check-prefix=DISASM # DISASM: Disassembly of section .text: # DISASM: main: -# DISASM-CHECK: 11000: 55 pushq %rbp -# DISASM-CHECK: 11001: 48 89 e5 movq %rsp, %rbp -# DISASM-CHECK: 11004: b8 00 00 00 00 movl $0, %eax -# DISASM-CHECK: 11009: 5d popq %rbp -# DISASM-CHECK: 1100a: c3 retq -# DISASM: _Z5main2v: -# DISASM-CHECK: 1100b: 55 pushq %rbp -# DISASM-CHECK: 1100c: 48 89 e5 movq %rsp, %rbp -# DISASM-CHECK: 1100f: b8 00 00 00 00 movl $0, %eax -# DISASM-CHECK: 11014: 5d popq %rbp -# DISASM-CHECK: 11015: c3 retq +# DISASM-CHECK: 201000: 90 nop +# DISASM-CHECK: 201001: cc int3 +# DISASM-CHECK: 201002: cc int3 +# DISASM-CHECK: 201003: cc int3 +# DISASM: main2: +# DISASM-CHECK: 201004: 90 nop +# DISASM-CHECK: 201005: 90 nop # CHECK: .gnu_index contents: # CHECK-NEXT: Version = 7 @@ -34,8 +21,8 @@ # CHECK-NEXT: 0: Offset = 0x0, Length = 0x34 # CHECK-NEXT: 1: Offset = 0x34, Length = 0x34 # CHECK: Address area offset = 0x38, has 2 entries: -# CHECK-NEXT: Low/High address = [0x201000, 0x20100b) (Size: 0xb), CU id = 0 -# CHECK-NEXT: Low/High address = [0x20100b, 0x201016) (Size: 0xb), CU id = 1 +# CHECK-NEXT: Low/High address = [0x201000, 0x201001) (Size: 0x1), CU id = 0 +# CHECK-NEXT: Low/High address = [0x201004, 0x201006) (Size: 0x2), CU id = 1 # CHECK: Symbol table offset = 0x60, size = 1024, filled slots: # CHECK-NEXT: 489: Name offset = 0x1d, CU vector offset = 0x0 # CHECK-NEXT: String name: main, CU vector index: 0 @@ -47,3 +34,79 @@ # CHECK-NEXT: 0(0x0): 0x30000000 # CHECK-NEXT: 1(0x8): 0x90000000 0x90000001 # CHECK-NEXT: 2(0x14): 0x30000001 + +## The following section contents are created by this using gcc 7.1.0: +## echo 'int main() { return 0; }' | gcc -gsplit-dwarf -xc++ -S -o- - + +.text +.Ltext0: +.globl main +.type main, @function +main: + nop +.Letext0: + +.section .debug_info,"",@progbits +.long 0x30 +.value 0x4 +.long 0 +.byte 0x8 +.uleb128 0x1 +.quad .Ltext0 +.quad .Letext0-.Ltext0 +.long 0 +.long 0 +.long 0 +.long 0 +.byte 0x63 +.byte 0x88 +.byte 0xb4 +.byte 0x61 +.byte 0xaa +.byte 0xb6 +.byte 0xb0 +.byte 0x67 + +.section .debug_abbrev,"",@progbits +.uleb128 0x1 +.uleb128 0x11 +.byte 0 +.uleb128 0x11 +.uleb128 0x1 +.uleb128 0x12 +.uleb128 0x7 +.uleb128 0x10 +.uleb128 0x17 +.uleb128 0x2130 +.uleb128 0xe +.uleb128 0x1b +.uleb128 0xe +.uleb128 0x2134 +.uleb128 0x19 +.uleb128 0x2133 +.uleb128 0x17 +.uleb128 0x2131 +.uleb128 0x7 +.byte 0 +.byte 0 +.byte 0 + +.section .debug_gnu_pubnames,"",@progbits +.long 0x18 +.value 0x2 +.long 0 +.long 0x33 +.long 0x18 +.byte 0x30 +.string "main" +.long 0 + +.section .debug_gnu_pubtypes,"",@progbits +.long 0x17 +.value 0x2 +.long 0 +.long 0x33 +.long 0x2b +.byte 0x90 +.string "int" +.long 0 diff --git a/test/ELF/i386-reloc-large-addend.s b/test/ELF/i386-reloc-large-addend.s index b644640404e2..5af584475562 100644 --- a/test/ELF/i386-reloc-large-addend.s +++ b/test/ELF/i386-reloc-large-addend.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc %s -o %t.o -triple i386-pc-linux-code16 -filetype=obj // RUN: echo ".global foo; foo = 0x1" > %t1.s diff --git a/test/ELF/i386-reloc-range.s b/test/ELF/i386-reloc-range.s index 47447d0efa32..4fb5325e5434 100644 --- a/test/ELF/i386-reloc-range.s +++ b/test/ELF/i386-reloc-range.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc %s -o %t.o -triple i386-pc-linux-code16 -filetype=obj // RUN: echo ".global foo; foo = 0x10202" > %t1.s diff --git a/test/ELF/invalid/tls-symbol.s b/test/ELF/invalid/tls-symbol.s index 7c65c6c9f2c7..354ca573d5c0 100644 --- a/test/ELF/invalid/tls-symbol.s +++ b/test/ELF/invalid/tls-symbol.s @@ -1,5 +1,5 @@ # REQUIRES: x86 -## The test file contains a STT_TLS symbol but has no TLS section. +## The test file contains an STT_TLS symbol but has no TLS section. # RUN: not ld.lld %S/Inputs/tls-symbol.elf -o %t 2>&1 | FileCheck %s -# CHECK: has a STT_TLS symbol but doesn't have a PT_TLS section +# CHECK: has an STT_TLS symbol but doesn't have an SHF_TLS section diff --git a/test/ELF/linkerscript/exidx-crash.s b/test/ELF/linkerscript/exidx-crash.s new file mode 100644 index 000000000000..c29d0135414d --- /dev/null +++ b/test/ELF/linkerscript/exidx-crash.s @@ -0,0 +1,7 @@ +# REQUIRES: aarch64 + +# We used to crash on this. + +# RUN: llvm-mc %s -o %t.o -filetype=obj -triple=aarch64-pc-linux +# RUN: echo "SECTIONS { .ARM.exidx : { *(.foo) } }" > %t.script +# RUN: ld.lld -T %t.script %t.o -o %t diff --git a/test/ELF/linkerscript/got-write-offset.s b/test/ELF/linkerscript/got-write-offset.s new file mode 100644 index 000000000000..323da7b4a46b --- /dev/null +++ b/test/ELF/linkerscript/got-write-offset.s @@ -0,0 +1,23 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux-gnu %s -o %t +# RUN: echo "SECTIONS { \ +# RUN: .data 0x1000 : { *(.data) } \ +# RUN: .got 0x2000 : { \ +# RUN: LONG(0) \ +# RUN: *(.got) \ +# RUN: } \ +# RUN: };" > %t.script +# RUN: ld.lld -shared -o %t.out --script %t.script %t +# RUN: llvm-objdump -s %t.out | FileCheck %s +.text +.global foo +foo: + movl bar@GOT, %eax +.data +.local bar +bar: + .zero 4 +# CHECK: Contents of section .data: +# CHECK-NEXT: 1000 00000000 +# CHECK: Contents of section .got: +# CHECK-NEXT: 2000 00000000 00100000 diff --git a/test/ELF/linkerscript/output-too-large.s b/test/ELF/linkerscript/output-too-large.s index db021eaa99e0..c892a88a947e 100644 --- a/test/ELF/linkerscript/output-too-large.s +++ b/test/ELF/linkerscript/output-too-large.s @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o # RUN: echo "SECTIONS { .text : { . = 0xffffffff; *(.text*); } }" > %t.script # RUN: not ld.lld --script %t.script %t.o -o %t 2>&1 | FileCheck %s diff --git a/test/ELF/lto/available-externally.ll b/test/ELF/lto/available-externally.ll index 181042b9d1e1..315e710ec87c 100644 --- a/test/ELF/lto/available-externally.ll +++ b/test/ELF/lto/available-externally.ll @@ -1,3 +1,4 @@ +; REQUIRES: x86 ; RUN: llvm-as %s -o %t1.o ; RUN: llvm-as %p/Inputs/available-externally.ll -o %t2.o ; RUN: ld.lld %t1.o %t2.o -m elf_x86_64 -o %t.so -shared -save-temps diff --git a/test/ELF/lto/comdat2.ll b/test/ELF/lto/comdat2.ll index 1509585f1553..283182155ae6 100644 --- a/test/ELF/lto/comdat2.ll +++ b/test/ELF/lto/comdat2.ll @@ -1,3 +1,4 @@ +; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o ; RUN: llvm-mc -triple=x86_64-pc-linux %p/Inputs/comdat.s -o %t2.o -filetype=obj ; RUN: ld.lld -m elf_x86_64 %t.o %t2.o -o %t.so -shared diff --git a/test/ELF/lto/common2.ll b/test/ELF/lto/common2.ll index b44bbac4fda3..2345a203b24c 100644 --- a/test/ELF/lto/common2.ll +++ b/test/ELF/lto/common2.ll @@ -1,3 +1,4 @@ +; REQUIRES: x86 ; RUN: llvm-as %s -o %t1.o ; RUN: ld.lld -m elf_x86_64 %t1.o -o %t -shared -save-temps ; RUN: llvm-dis < %t.0.2.internalize.bc | FileCheck %s diff --git a/test/ELF/lto/common3.ll b/test/ELF/lto/common3.ll index 6d40de547fcd..aea33f443f4c 100644 --- a/test/ELF/lto/common3.ll +++ b/test/ELF/lto/common3.ll @@ -1,3 +1,4 @@ +; REQUIRES: x86 ; RUN: llvm-as %s -o %t1.o ; RUN: llvm-as %S/Inputs/common3.ll -o %t2.o ; RUN: ld.lld -m elf_x86_64 %t1.o %t2.o -o %t -shared -save-temps diff --git a/test/ELF/lto/discard-value-names.ll b/test/ELF/lto/discard-value-names.ll index c71dc386113d..f1e95fe75000 100644 --- a/test/ELF/lto/discard-value-names.ll +++ b/test/ELF/lto/discard-value-names.ll @@ -1,3 +1,4 @@ +; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o ; RUN: ld.lld -m elf_x86_64 -shared -save-temps %t.o -o %t2.o diff --git a/test/ELF/lto/opt-level.ll b/test/ELF/lto/opt-level.ll index 934bf01b6c32..1065ca775751 100644 --- a/test/ELF/lto/opt-level.ll +++ b/test/ELF/lto/opt-level.ll @@ -1,3 +1,4 @@ +; REQUIRES: x86 ; RUN: llvm-as -o %t.o %s ; RUN: ld.lld -o %t0 -m elf_x86_64 -e main --lto-O0 %t.o ; RUN: llvm-nm %t0 | FileCheck --check-prefix=CHECK-O0 %s diff --git a/test/ELF/lto/opt-remarks.ll b/test/ELF/lto/opt-remarks.ll index 88304205caba..e29cc72bb3cc 100644 --- a/test/ELF/lto/opt-remarks.ll +++ b/test/ELF/lto/opt-remarks.ll @@ -1,3 +1,4 @@ +; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o ; RUN: rm -f %t.yaml diff --git a/test/ELF/lto/relax-relocs.ll b/test/ELF/lto/relax-relocs.ll index 929e124b2d8e..8e8d9d165787 100644 --- a/test/ELF/lto/relax-relocs.ll +++ b/test/ELF/lto/relax-relocs.ll @@ -1,3 +1,4 @@ +; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o ; RUN: ld.lld -m elf_x86_64 -save-temps -shared %t.o -o %t.so ; RUN: llvm-readobj -r %t.so.lto.o | FileCheck %s diff --git a/test/ELF/lto/thin-archivecollision.ll b/test/ELF/lto/thin-archivecollision.ll index f1dd5ae4d85f..554c2b02fc40 100644 --- a/test/ELF/lto/thin-archivecollision.ll +++ b/test/ELF/lto/thin-archivecollision.ll @@ -1,3 +1,4 @@ +; REQUIRES: x86 ; RUN: opt -module-summary %s -o %t.o ; RUN: mkdir -p %t1 %t2 ; RUN: opt -module-summary %p/Inputs/thin1.ll -o %t1/t.coll.o diff --git a/test/ELF/lto/thinlto.ll b/test/ELF/lto/thinlto.ll index 2036c554a76d..99dd19130d28 100644 --- a/test/ELF/lto/thinlto.ll +++ b/test/ELF/lto/thinlto.ll @@ -1,3 +1,4 @@ +; REQUIRES: x86 ; Basic ThinLTO tests. ; RUN: opt -module-summary %s -o %t.o ; RUN: opt -module-summary %p/Inputs/thinlto.ll -o %t2.o diff --git a/test/ELF/lto/type-merge2.ll b/test/ELF/lto/type-merge2.ll index 45777a7e6a48..6ebbf778dd8e 100644 --- a/test/ELF/lto/type-merge2.ll +++ b/test/ELF/lto/type-merge2.ll @@ -1,3 +1,4 @@ +; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o ; RUN: llvm-as %p/Inputs/type-merge2.ll -o %t2.o ; RUN: ld.lld -m elf_x86_64 %t.o %t2.o -o %t.so -shared -save-temps diff --git a/test/ELF/lto/unnamed-addr-comdat.ll b/test/ELF/lto/unnamed-addr-comdat.ll index ed48f3ba5e04..29a59415851b 100644 --- a/test/ELF/lto/unnamed-addr-comdat.ll +++ b/test/ELF/lto/unnamed-addr-comdat.ll @@ -1,3 +1,4 @@ +; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o ; RUN: ld.lld -m elf_x86_64 %t.o %t.o -o %t.so -save-temps -shared ; RUN: llvm-dis %t.so.0.2.internalize.bc -o - | FileCheck %s diff --git a/test/ELF/lto/unnamed-addr-drop.ll b/test/ELF/lto/unnamed-addr-drop.ll index 9142537fe57d..e827cbb435e6 100644 --- a/test/ELF/lto/unnamed-addr-drop.ll +++ b/test/ELF/lto/unnamed-addr-drop.ll @@ -1,3 +1,4 @@ +; REQUIRES: x86 ; RUN: llvm-as %s -o %t1.o ; RUN: llvm-as %S/Inputs/unnamed-addr-drop.ll -o %t2.o ; RUN: ld.lld -m elf_x86_64 %t1.o %t2.o -o %t.so -save-temps -shared diff --git a/test/ELF/lto/unnamed-addr.ll b/test/ELF/lto/unnamed-addr.ll index 6a6dd73dad86..56fe148b0995 100644 --- a/test/ELF/lto/unnamed-addr.ll +++ b/test/ELF/lto/unnamed-addr.ll @@ -1,3 +1,4 @@ +; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o ; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -save-temps -shared ; RUN: llvm-dis %t.so.0.4.opt.bc -o - | FileCheck %s diff --git a/test/ELF/many-alloc-sections.s b/test/ELF/many-alloc-sections.s index 441e5ff32d08..648ab8250286 100644 --- a/test/ELF/many-alloc-sections.s +++ b/test/ELF/many-alloc-sections.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o %t.o // RUN: echo "SECTIONS { . = SIZEOF_HEADERS; .text : { *(.text) } }" > %t.script // FIXME: threads are disable because the test is too slow with them (PR32942). diff --git a/test/ELF/many-sections.s b/test/ELF/many-sections.s index ae923889ddc1..7ef0f7ceaac4 100644 --- a/test/ELF/many-sections.s +++ b/test/ELF/many-sections.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o %t // RUN: llvm-readobj -t %t | FileCheck %s diff --git a/test/ELF/map-gc-sections.s b/test/ELF/map-gc-sections.s new file mode 100644 index 000000000000..717ab819889d --- /dev/null +++ b/test/ELF/map-gc-sections.s @@ -0,0 +1,9 @@ +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +// RUN: ld.lld %t.o -o %t -Map=- --gc-sections | FileCheck %s + +.section .tbss,"awT",@nobits +// CHECK-NOT: foo +.globl foo +foo: +.align 8 +.long 0 diff --git a/test/ELF/merge-section-types.s b/test/ELF/merge-section-types.s index ee80fe177fe0..f8462824684f 100644 --- a/test/ELF/merge-section-types.s +++ b/test/ELF/merge-section-types.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o // RUN: ld.lld -shared %t.o -o %t // RUN: llvm-readobj -s %t | FileCheck %s diff --git a/test/ELF/new-dtags.test b/test/ELF/new-dtags.test index 334d477622a7..1ae328c6b502 100644 --- a/test/ELF/new-dtags.test +++ b/test/ELF/new-dtags.test @@ -1,3 +1,4 @@ +# REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o // RUN: ld.lld %t.o -rpath=/somepath -shared --disable-new-dtags -o %t // RUN: ld.lld %t.o -rpath=/somepath -shared --enable-new-dtags -o %t2 diff --git a/test/ELF/no-obj.s b/test/ELF/no-obj.s index eea10a45d879..693cdf1e9d3f 100644 --- a/test/ELF/no-obj.s +++ b/test/ELF/no-obj.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o // RUN: llvm-ar rcs %t.a %t.o // RUN: not ld.lld -o %t2 -u _start %t.a 2>&1 | FileCheck %s diff --git a/test/ELF/no-soname.s b/test/ELF/no-soname.s index d2c15ed8f9cd..e3869ff5a03c 100644 --- a/test/ELF/no-soname.s +++ b/test/ELF/no-soname.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o // RUN: mkdir -p %T/no-soname // RUN: ld.lld %t.o -shared -o %T/no-soname/libfoo.so @@ -5,26 +6,26 @@ // RUN: ld.lld %t.o %T/no-soname/libfoo.so -o %t // RUN: llvm-readobj --dynamic-table %t | FileCheck %s -// CHECK: 0x0000000000000001 NEEDED SharedLibrary ({{.*}}/no-soname/libfoo.so) +// CHECK: 0x0000000000000001 NEEDED Shared library: [{{.*}}/no-soname/libfoo.so] // CHECK-NOT: NEEDED // RUN: ld.lld %t.o %T/no-soname/../no-soname/libfoo.so -o %t // RUN: llvm-readobj --dynamic-table %t | FileCheck %s --check-prefix=CHECK2 -// CHECK2: 0x0000000000000001 NEEDED SharedLibrary ({{.*}}/no-soname/../no-soname/libfoo.so) +// CHECK2: 0x0000000000000001 NEEDED Shared library: [{{.*}}/no-soname/../no-soname/libfoo.so] // CHECK2-NOT: NEEDED // RUN: ld.lld %t.o -L%T/no-soname/../no-soname -lfoo -o %t // RUN: llvm-readobj --dynamic-table %t | FileCheck %s --check-prefix=CHECK3 -// CHECK3: 0x0000000000000001 NEEDED SharedLibrary (libfoo.so) +// CHECK3: 0x0000000000000001 NEEDED Shared library: [libfoo.so] // CHECK3-NOT: NEEDED // RUN: ld.lld %t.o -shared -soname libbar.so -o %T/no-soname/libbar.so // RUN: ld.lld %t.o %T/no-soname/libbar.so -o %t // RUN: llvm-readobj --dynamic-table %t | FileCheck %s --check-prefix=CHECK4 -// CHECK4: 0x0000000000000001 NEEDED SharedLibrary (libbar.so) +// CHECK4: 0x0000000000000001 NEEDED Shared library: [libbar.so] // CHECK4-NOT: NEEDED .global _start diff --git a/test/ELF/no-symtab.s b/test/ELF/no-symtab.s index 158bd727f251..af9df13e9768 100644 --- a/test/ELF/no-symtab.s +++ b/test/ELF/no-symtab.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o // RUN: ld.lld %t.o %p/Inputs/no-symtab.o -o %t .global _start diff --git a/test/ELF/no-undefined.s b/test/ELF/no-undefined.s index fa4d5e928763..493a38987091 100644 --- a/test/ELF/no-undefined.s +++ b/test/ELF/no-undefined.s @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t # RUN: not ld.lld --no-undefined -shared %t -o %t.so # RUN: ld.lld -shared %t -o %t1.so diff --git a/test/ELF/pie-weak.s b/test/ELF/pie-weak.s index e74bcdfc09c0..99dbd47488fc 100644 --- a/test/ELF/pie-weak.s +++ b/test/ELF/pie-weak.s @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: llvm-mc -filetype=obj -relax-relocations=false -triple=x86_64-unknown-linux %s -o %t.o # RUN: ld.lld -pie %t.o -o %t # RUN: llvm-readobj -r %t | FileCheck --check-prefix=RELOCS %s diff --git a/test/ELF/progname.s b/test/ELF/progname.s index 6d91823c9481..be8ab9e31c4f 100644 --- a/test/ELF/progname.s +++ b/test/ELF/progname.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o // RUN: echo .global __progname > %t2.s // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %t2.s -o %t2.o diff --git a/test/ELF/relative-dynamic-reloc-pie.s b/test/ELF/relative-dynamic-reloc-pie.s index 25b3e0ac2333..f7c8b3c1516c 100644 --- a/test/ELF/relative-dynamic-reloc-pie.s +++ b/test/ELF/relative-dynamic-reloc-pie.s @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o # RUN: ld.lld -pie %t.o -o %t.pie # RUN: llvm-readobj -r -dyn-symbols %t.pie | FileCheck %s diff --git a/test/ELF/relative-dynamic-reloc.s b/test/ELF/relative-dynamic-reloc.s index 39382124e889..0ed7e40f7436 100644 --- a/test/ELF/relative-dynamic-reloc.s +++ b/test/ELF/relative-dynamic-reloc.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o // RUN: ld.lld -shared %t.o -o %t.so // RUN: llvm-readobj -t -r -dyn-symbols %t.so | FileCheck %s diff --git a/test/ELF/relocatable-compressed-input.s b/test/ELF/relocatable-compressed-input.s index bdfb2073a1e0..3c0199c33f7d 100644 --- a/test/ELF/relocatable-compressed-input.s +++ b/test/ELF/relocatable-compressed-input.s @@ -1,4 +1,4 @@ -# REQUIRES: zlib +# REQUIRES: x86, zlib # RUN: llvm-mc -compress-debug-sections=zlib-gnu -filetype=obj -triple=x86_64-unknown-linux %s -o %t1 # RUN: llvm-readobj -sections %t1 | FileCheck -check-prefix=GNU %s diff --git a/test/ELF/relocatable-reloc.s b/test/ELF/relocatable-reloc.s index c576073a7510..7c699b9bf314 100644 --- a/test/ELF/relocatable-reloc.s +++ b/test/ELF/relocatable-reloc.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj %s -o %t.o -triple=x86_64-pc-linux // RUN: ld.lld %t.o %t.o -r -o %t2.o // RUN: llvm-readobj -r %t2.o | FileCheck %s diff --git a/test/ELF/relocatable-section-symbol.s b/test/ELF/relocatable-section-symbol.s index 9ac3a91d2c24..57a75ab92f11 100644 --- a/test/ELF/relocatable-section-symbol.s +++ b/test/ELF/relocatable-section-symbol.s @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o # RUN: ld.lld -r -o %t %t.o %t.o # RUN: llvm-readobj -r %t | FileCheck --check-prefix=RELA %s diff --git a/test/ELF/relocatable-sections.s b/test/ELF/relocatable-sections.s index d6a922fba482..75ede137293c 100644 --- a/test/ELF/relocatable-sections.s +++ b/test/ELF/relocatable-sections.s @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o # RUN: ld.lld -r %t1.o -o %t # RUN: llvm-objdump -section-headers %t | FileCheck %s diff --git a/test/ELF/relocatable-tls.s b/test/ELF/relocatable-tls.s index 88d38c2ae4b4..ff04dd2dfccb 100644 --- a/test/ELF/relocatable-tls.s +++ b/test/ELF/relocatable-tls.s @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \ # RUN: %S/Inputs/relocatable-tls.s -o %t2.o diff --git a/test/ELF/relocation-shared.s b/test/ELF/relocation-shared.s index e1850944c459..4fba7a5683b0 100644 --- a/test/ELF/relocation-shared.s +++ b/test/ELF/relocation-shared.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o // RUN: ld.lld %t.o -shared -o %t.so // RUN: llvm-readobj -r -s -section-data %t.so | FileCheck %s diff --git a/test/ELF/shared-be.s b/test/ELF/shared-be.s index c969793d9d21..0b941d373720 100644 --- a/test/ELF/shared-be.s +++ b/test/ELF/shared-be.s @@ -21,7 +21,7 @@ // CHECK: DynamicSection [ // CHECK-NEXT: Tag Type Name/Value // CHECK-NEXT: 0x000000000000001D RUNPATH foo:bar -// CHECK-NEXT: 0x0000000000000001 NEEDED SharedLibrary ({{.*}}2.so) +// CHECK-NEXT: 0x0000000000000001 NEEDED Shared library: [{{.*}}2.so] // CHECK-NEXT: 0x0000000000000015 DEBUG 0x0 // CHECK-NEXT: 0x0000000000000007 RELA [[RELADDR]] // CHECK-NEXT: 0x0000000000000008 RELASZ [[RELSIZE]] (bytes) diff --git a/test/ELF/shared.s b/test/ELF/shared.s index 350ef5c602d0..d4c79d914ffb 100644 --- a/test/ELF/shared.s +++ b/test/ELF/shared.s @@ -254,7 +254,7 @@ // CHECK: DynamicSection [ // CHECK-NEXT: Tag Type Name/Value // CHECK-NEXT: 0x0000001D RUNPATH foo:bar -// CHECK-NEXT: 0x00000001 NEEDED SharedLibrary ({{.*}}2.so) +// CHECK-NEXT: 0x00000001 NEEDED Shared library: [{{.*}}2.so] // CHECK-NEXT: 0x00000015 DEBUG 0x0 // CHECK-NEXT: 0x00000011 REL [[RELADDR]] // CHECK-NEXT: 0x00000012 RELSZ [[RELSIZE]] (bytes) diff --git a/test/ELF/soname.s b/test/ELF/soname.s index 65e95ce85add..a26bb30f7a17 100644 --- a/test/ELF/soname.s +++ b/test/ELF/soname.s @@ -4,7 +4,7 @@ // RUN: ld.lld %t.o %t.so %t2.so -o %t // RUN: llvm-readobj --dynamic-table %t | FileCheck %s -// CHECK: 0x0000000000000001 NEEDED SharedLibrary (bar) +// CHECK: 0x0000000000000001 NEEDED Shared library: [bar] // CHECK-NOT: NEEDED .global _start diff --git a/test/ELF/soname2.s b/test/ELF/soname2.s index d446766a799d..9fb8da519bfb 100644 --- a/test/ELF/soname2.s +++ b/test/ELF/soname2.s @@ -2,7 +2,7 @@ // RUN: ld.lld %t.o -shared -soname=foo.so -o %t // RUN: llvm-readobj --dynamic-table %t | FileCheck %s -// CHECK: 0x000000000000000E SONAME LibrarySoname (foo.so) +// CHECK: 0x000000000000000E SONAME Library soname: [foo.so] .global _start _start: diff --git a/test/ELF/symver-archive.s b/test/ELF/symver-archive.s deleted file mode 100644 index be50503a3f5d..000000000000 --- a/test/ELF/symver-archive.s +++ /dev/null @@ -1,15 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1 -# RUN: rm -f %t.a -# RUN: llvm-ar rcs %t.a %t1 -# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/symver-archive1.s -o %t2.o -# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/symver-archive2.s -o %t3.o -# RUN: ld.lld -o %t.out %t2.o %t3.o %t.a - -.text -.globl x -.type x, @function -x: - -.globl xx -xx = x diff --git a/test/ELF/version-script-twice.s b/test/ELF/version-script-twice.s new file mode 100644 index 000000000000..3aeedd5b5ddc --- /dev/null +++ b/test/ELF/version-script-twice.s @@ -0,0 +1,14 @@ +# REQUIRES: x86 + +# RUN: echo "FBSD_1.1 {}; FBSD_1.2 {};" > %t.ver +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: ld.lld -shared %t.o -o %t.so --version-script=%t.ver +# RUN: llvm-readobj --dyn-symbols --elf-output-style=GNU %t.so | FileCheck %s + + .weak openat +openat: +openat@FBSD_1.1 = openat +openat@@FBSD_1.2 = openat + +# CHECK-DAG: openat@FBSD_1.1 +# CHECK-DAG: openat@@FBSD_1.2 From a884e649599e13d58ce6d2b2a0ce8091ceb48dac Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Wed, 19 Jul 2017 07:03:07 +0000 Subject: [PATCH 05/10] Vendor import of lldb trunk r308421: https://llvm.org/svn/llvm-project/lldb/trunk@308421 --- cmake/modules/LLDBConfig.cmake | 34 +- cmake/modules/LLDBStandalone.cmake | 1 - include/lldb/Host/MainLoop.h | 2 +- include/lldb/Host/PosixApi.h | 2 + include/lldb/Host/SocketAddress.h | 5 + .../lldb/Host/common/NativeProcessProtocol.h | 7 +- .../lldb/Host/common/NativeThreadProtocol.h | 6 +- include/lldb/Interpreter/CommandInterpreter.h | 2 +- include/lldb/Utility/DataExtractor.h | 1 + include/lldb/lldb-private-forward.h | 4 - include/lldb/lldb-types.h | 24 - .../unwind_expression/TestUnwindExpression.py | 28 +- .../TestBadAddressBreakpoints.py | 39 +- .../TestConsecutiveBreakpoints.py | 24 +- source/Host/CMakeLists.txt | 4 + source/Host/common/File.cpp | 1 + source/Host/common/Host.cpp | 1 + source/Host/common/MainLoop.cpp | 1 + source/Host/common/NativeRegisterContext.cpp | 65 +- source/Host/common/NativeThreadProtocol.cpp | 8 +- source/Host/common/Socket.cpp | 1 + source/Host/common/SocketAddress.cpp | 7 + source/Host/common/TCPSocket.cpp | 1 + source/Host/linux/Host.cpp | 1 + source/Host/linux/HostInfoLinux.cpp | 1 + .../posix/ConnectionFileDescriptorPosix.cpp | 1 + source/Host/posix/FileSystem.cpp | 1 + source/Host/posix/HostProcessPosix.cpp | 2 + source/Host/posix/LockFilePosix.cpp | 1 + .../Host/posix/ProcessLauncherPosixFork.cpp | 2 + source/Interpreter/CommandInterpreter.cpp | 2 +- .../DynamicLoader/POSIX-DYLD/AuxVector.cpp | 14 +- .../Clang/ClangModulesDeclVendor.cpp | 8 +- .../CPlusPlus/CPlusPlusNameParser.cpp | 31 + .../Language/CPlusPlus/CPlusPlusNameParser.h | 3 + .../gdb-server/PlatformRemoteGDBServer.cpp | 1 + .../Process/Linux/NativeProcessLinux.cpp | 24 +- .../Process/Linux/NativeProcessLinux.h | 11 +- .../Linux/NativeRegisterContextLinux.cpp | 6 +- .../NativeRegisterContextLinux_arm64.cpp | 4 +- .../NativeRegisterContextLinux_mips64.cpp | 4 +- .../Process/Linux/NativeThreadLinux.cpp | 24 +- .../Plugins/Process/Linux/NativeThreadLinux.h | 3 +- source/Plugins/Process/Linux/ProcessorTrace.h | 1 + .../Process/NetBSD/NativeProcessNetBSD.cpp | 23 +- .../Process/NetBSD/NativeProcessNetBSD.h | 4 +- .../NetBSD/NativeRegisterContextNetBSD.cpp | 10 +- .../Process/NetBSD/NativeThreadNetBSD.cpp | 8 +- .../Process/NetBSD/NativeThreadNetBSD.h | 3 +- .../GDBRemoteCommunicationServerLLGS.cpp | 560 +++++++----------- .../GDBRemoteCommunicationServerLLGS.h | 2 +- .../Process/gdb-remote/ProcessGDBRemote.cpp | 2 + source/Target/Target.cpp | 1 + test/CMakeLists.txt | 14 +- tools/debugserver/CMakeLists.txt | 19 +- tools/debugserver/source/CMakeLists.txt | 20 +- .../debugserver/source/MacOSX/CMakeLists.txt | 25 +- .../source/MacOSX/DarwinLog/CMakeLists.txt | 2 +- .../source/MacOSX/i386/CMakeLists.txt | 4 - .../source/MacOSX/x86_64/CMakeLists.txt | 8 - tools/debugserver/source/RNBSocket.cpp | 21 +- tools/driver/Driver.cpp | 1 + tools/lldb-mi/MICmnLLDBDebugger.cpp | 1 + tools/lldb-mi/MIDriver.cpp | 2 + tools/lldb-mi/MIDriverMain.cpp | 1 + tools/lldb-server/lldb-gdbserver.cpp | 4 +- .../CPlusPlus/CPlusPlusLanguageTest.cpp | 5 + unittests/debugserver/RNBSocketTest.cpp | 2 + 68 files changed, 508 insertions(+), 647 deletions(-) delete mode 100644 tools/debugserver/source/MacOSX/i386/CMakeLists.txt delete mode 100644 tools/debugserver/source/MacOSX/x86_64/CMakeLists.txt diff --git a/cmake/modules/LLDBConfig.cmake b/cmake/modules/LLDBConfig.cmake index bbf7a0838d26..726552675f47 100644 --- a/cmake/modules/LLDBConfig.cmake +++ b/cmake/modules/LLDBConfig.cmake @@ -10,15 +10,20 @@ if (LLVM_COMPILER_IS_GCC_COMPATIBLE AND NOT "${CMAKE_SYSTEM_NAME}" MATCHES "Darw set(LLDB_LINKER_SUPPORTS_GROUPS ON) endif() +set(LLDB_DEFAULT_DISABLE_PYTHON 0) +set(LLDB_DEFAULT_DISABLE_CURSES 0) + if ( CMAKE_SYSTEM_NAME MATCHES "Windows" ) - set(LLDB_DEFAULT_DISABLE_PYTHON 0) set(LLDB_DEFAULT_DISABLE_CURSES 1) elseif (CMAKE_SYSTEM_NAME MATCHES "Android" ) set(LLDB_DEFAULT_DISABLE_PYTHON 1) set(LLDB_DEFAULT_DISABLE_CURSES 1) -else() - set(LLDB_DEFAULT_DISABLE_PYTHON 0) - set(LLDB_DEFAULT_DISABLE_CURSES 0) +elseif(IOS) + set(LLDB_DEFAULT_DISABLE_PYTHON 1) +endif() + +if(IOS) + add_definitions(-DNO_XPC_SERVICES) endif() set(LLDB_DISABLE_PYTHON ${LLDB_DEFAULT_DISABLE_PYTHON} CACHE BOOL @@ -298,13 +303,15 @@ if (NOT LIBXML2_FOUND AND NOT (CMAKE_SYSTEM_NAME MATCHES "Windows")) endif() # Find libraries or frameworks that may be needed -if (CMAKE_SYSTEM_NAME MATCHES "Darwin") - find_library(CARBON_LIBRARY Carbon) +if (APPLE) + if(NOT IOS) + find_library(CARBON_LIBRARY Carbon) + find_library(CORE_SERVICES_LIBRARY CoreServices) + find_library(DEBUG_SYMBOLS_LIBRARY DebugSymbols PATHS "/System/Library/PrivateFrameworks") + endif() find_library(FOUNDATION_LIBRARY Foundation) find_library(CORE_FOUNDATION_LIBRARY CoreFoundation) - find_library(CORE_SERVICES_LIBRARY CoreServices) find_library(SECURITY_LIBRARY Security) - find_library(DEBUG_SYMBOLS_LIBRARY DebugSymbols PATHS "/System/Library/PrivateFrameworks") set(LLDB_FRAMEWORK_INSTALL_DIR Library/Frameworks CACHE STRING "Output directory for LLDB.framework") set(LLDB_FRAMEWORK_VERSION A CACHE STRING "LLDB.framework version (default is A)") @@ -312,10 +319,13 @@ if (CMAKE_SYSTEM_NAME MATCHES "Darwin") LLDB.framework/Versions/${LLDB_FRAMEWORK_VERSION}/Resources) add_definitions( -DLIBXML2_DEFINED ) - list(APPEND system_libs xml2 ${CURSES_LIBRARIES}) - list(APPEND system_libs ${CARBON_LIBRARY} ${FOUNDATION_LIBRARY} - ${CORE_FOUNDATION_LIBRARY} ${CORE_SERVICES_LIBRARY} ${SECURITY_LIBRARY} - ${DEBUG_SYMBOLS_LIBRARY}) + list(APPEND system_libs xml2 + ${CURSES_LIBRARIES} + ${FOUNDATION_LIBRARY} + ${CORE_FOUNDATION_LIBRARY} + ${CORE_SERVICES_LIBRARY} + ${SECURITY_LIBRARY} + ${DEBUG_SYMBOLS_LIBRARY}) else() if (LIBXML2_FOUND) diff --git a/cmake/modules/LLDBStandalone.cmake b/cmake/modules/LLDBStandalone.cmake index 67e207e59edb..2f959c91fdd7 100644 --- a/cmake/modules/LLDBStandalone.cmake +++ b/cmake/modules/LLDBStandalone.cmake @@ -2,7 +2,6 @@ # standalone project, using LLVM as an external library: if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) project(lldb) - cmake_minimum_required(VERSION 2.8.12.2) if (POLICY CMP0022) cmake_policy(SET CMP0022 NEW) # automatic when 2.8.12 is required diff --git a/include/lldb/Host/MainLoop.h b/include/lldb/Host/MainLoop.h index a722348b8843..5ac145ff865b 100644 --- a/include/lldb/Host/MainLoop.h +++ b/include/lldb/Host/MainLoop.h @@ -12,8 +12,8 @@ #include "lldb/Host/Config.h" #include "lldb/Host/MainLoopBase.h" - #include "llvm/ADT/DenseMap.h" +#include #if !HAVE_PPOLL && !HAVE_SYS_EVENT_H #define SIGNAL_POLLING_UNSUPPORTED 1 diff --git a/include/lldb/Host/PosixApi.h b/include/lldb/Host/PosixApi.h index 02324307dc9e..d5c48dd6d170 100644 --- a/include/lldb/Host/PosixApi.h +++ b/include/lldb/Host/PosixApi.h @@ -16,6 +16,8 @@ #if defined(_WIN32) #include "lldb/Host/windows/PosixApi.h" +#else +#include #endif #endif diff --git a/include/lldb/Host/SocketAddress.h b/include/lldb/Host/SocketAddress.h index 8e9026ba962c..ebc6f4e57ee8 100644 --- a/include/lldb/Host/SocketAddress.h +++ b/include/lldb/Host/SocketAddress.h @@ -151,6 +151,11 @@ class SocketAddress { //------------------------------------------------------------------ bool IsAnyAddr() const; + //------------------------------------------------------------------ + // Returns true if the socket is INADDR_LOOPBACK + //------------------------------------------------------------------ + bool IsLocalhost() const; + //------------------------------------------------------------------ // Direct access to all of the sockaddr structures //------------------------------------------------------------------ diff --git a/include/lldb/Host/common/NativeProcessProtocol.h b/include/lldb/Host/common/NativeProcessProtocol.h index 5f2157510c0a..9671d710fc02 100644 --- a/include/lldb/Host/common/NativeProcessProtocol.h +++ b/include/lldb/Host/common/NativeProcessProtocol.h @@ -33,8 +33,7 @@ class ResumeActionList; //------------------------------------------------------------------ // NativeProcessProtocol //------------------------------------------------------------------ -class NativeProcessProtocol - : public std::enable_shared_from_this { +class NativeProcessProtocol { friend class SoftwareBreakpoint; public: @@ -268,7 +267,7 @@ class NativeProcessProtocol /// A NativeProcessProtocol shared pointer if the operation succeeded or /// an error object if it failed. //------------------------------------------------------------------ - virtual llvm::Expected + virtual llvm::Expected> Launch(ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate, MainLoop &mainloop) const = 0; @@ -292,7 +291,7 @@ class NativeProcessProtocol /// A NativeProcessProtocol shared pointer if the operation succeeded or /// an error object if it failed. //------------------------------------------------------------------ - virtual llvm::Expected + virtual llvm::Expected> Attach(lldb::pid_t pid, NativeDelegate &native_delegate, MainLoop &mainloop) const = 0; }; diff --git a/include/lldb/Host/common/NativeThreadProtocol.h b/include/lldb/Host/common/NativeThreadProtocol.h index 2e6c96a34cf5..d96f71311185 100644 --- a/include/lldb/Host/common/NativeThreadProtocol.h +++ b/include/lldb/Host/common/NativeThreadProtocol.h @@ -23,7 +23,7 @@ namespace lldb_private { class NativeThreadProtocol : public std::enable_shared_from_this { public: - NativeThreadProtocol(NativeProcessProtocol *process, lldb::tid_t tid); + NativeThreadProtocol(NativeProcessProtocol &process, lldb::tid_t tid); virtual ~NativeThreadProtocol() {} @@ -46,7 +46,7 @@ class NativeThreadProtocol lldb::tid_t GetID() const { return m_tid; } - NativeProcessProtocolSP GetProcess(); + NativeProcessProtocol &GetProcess() { return m_process; } // --------------------------------------------------------------------- // Thread-specific watchpoints @@ -64,7 +64,7 @@ class NativeThreadProtocol virtual Status RemoveHardwareBreakpoint(lldb::addr_t addr) = 0; protected: - NativeProcessProtocolWP m_process_wp; + NativeProcessProtocol &m_process; lldb::tid_t m_tid; }; } diff --git a/include/lldb/Interpreter/CommandInterpreter.h b/include/lldb/Interpreter/CommandInterpreter.h index f47411079a3a..73bd7d6e6220 100644 --- a/include/lldb/Interpreter/CommandInterpreter.h +++ b/include/lldb/Interpreter/CommandInterpreter.h @@ -539,7 +539,7 @@ class CommandInterpreter : public Broadcaster, std::string m_repeat_command; // Stores the command that will be executed for // an empty command string. lldb::ScriptInterpreterSP m_script_interpreter_sp; - std::mutex m_script_interpreter_mutex; + std::recursive_mutex m_script_interpreter_mutex; lldb::IOHandlerSP m_command_io_handler_sp; char m_comment_char; bool m_batch_command_mode; diff --git a/include/lldb/Utility/DataExtractor.h b/include/lldb/Utility/DataExtractor.h index 58240d9a5268..4ef78c1af492 100644 --- a/include/lldb/Utility/DataExtractor.h +++ b/include/lldb/Utility/DataExtractor.h @@ -15,6 +15,7 @@ #include "lldb/lldb-forward.h" // for DataBufferSP #include "lldb/lldb-types.h" +#include #include #include diff --git a/include/lldb/lldb-private-forward.h b/include/lldb/lldb-private-forward.h index 69a231132982..296facb1a0bd 100644 --- a/include/lldb/lldb-private-forward.h +++ b/include/lldb/lldb-private-forward.h @@ -30,10 +30,6 @@ class UnixSignals; // SP/WP decls. // --------------------------------------------------------------- typedef std::shared_ptr NativeBreakpointSP; -typedef std::shared_ptr - NativeProcessProtocolSP; -typedef std::weak_ptr - NativeProcessProtocolWP; typedef std::shared_ptr NativeRegisterContextSP; typedef std::shared_ptr diff --git a/include/lldb/lldb-types.h b/include/lldb/lldb-types.h index 07e9f5ac7161..fc445f55a9e5 100644 --- a/include/lldb/lldb-types.h +++ b/include/lldb/lldb-types.h @@ -13,16 +13,10 @@ #include "lldb/lldb-enumerations.h" #include "lldb/lldb-forward.h" -#include -#include #include //---------------------------------------------------------------------- // All host systems must define: -// lldb::condition_t The native condition type (or a substitute class) -// for conditions on the host system. -// lldb::mutex_t The native mutex type for mutex objects on the host -// system. // lldb::thread_t The native thread type for spawned threads on the // system // lldb::thread_arg_t The type of the one any only thread creation @@ -34,32 +28,22 @@ // #define LLDB_INVALID_PROCESS_ID ... // #define LLDB_INVALID_THREAD_ID ... // #define LLDB_INVALID_HOST_THREAD ... -// #define IS_VALID_LLDB_HOST_THREAD ... //---------------------------------------------------------------------- // TODO: Add a bunch of ifdefs to determine the host system and what // things should be defined. Currently MacOSX is being assumed by default // since that is what lldb was first developed for. -#ifndef _MSC_VER -#include -#include -#endif - #ifdef _WIN32 #include namespace lldb { -typedef void *mutex_t; -typedef void *condition_t; typedef void *rwlock_t; typedef void *process_t; // Process type is HANDLE typedef void *thread_t; // Host thread type typedef void *file_t; // Host file type -typedef void *pipe_t; // Host pipe type typedef unsigned int __w64 socket_t; // Host socket type -typedef uint32_t thread_key_t; typedef void *thread_arg_t; // Host thread argument type typedef unsigned thread_result_t; // Host thread result type typedef thread_result_t (*thread_func_t)(void *); // Host thread function type @@ -73,15 +57,11 @@ namespace lldb { //---------------------------------------------------------------------- // MacOSX Types //---------------------------------------------------------------------- -typedef ::pthread_mutex_t mutex_t; -typedef pthread_cond_t condition_t; typedef pthread_rwlock_t rwlock_t; typedef uint64_t process_t; // Process type is just a pid. typedef pthread_t thread_t; // Host thread type typedef int file_t; // Host file type -typedef int pipe_t; // Host pipe type typedef int socket_t; // Host socket type -typedef pthread_key_t thread_key_t; typedef void *thread_arg_t; // Host thread argument type typedef void *thread_result_t; // Host thread result type typedef void *(*thread_func_t)(void *); // Host thread function type @@ -100,10 +80,6 @@ typedef bool (*ExpressionCancelCallback)(ExpressionEvaluationPhase phase, #define LLDB_INVALID_PROCESS ((lldb::process_t)-1) #define LLDB_INVALID_HOST_THREAD ((lldb::thread_t)NULL) -#define IS_VALID_LLDB_HOST_THREAD(t) ((t) != LLDB_INVALID_HOST_THREAD) - -#define LLDB_INVALID_HOST_TIME \ - { 0, 0 } namespace lldb { typedef uint64_t addr_t; diff --git a/packages/Python/lldbsuite/test/expression_command/unwind_expression/TestUnwindExpression.py b/packages/Python/lldbsuite/test/expression_command/unwind_expression/TestUnwindExpression.py index 9cc585b75aa1..3b01d4470de6 100644 --- a/packages/Python/lldbsuite/test/expression_command/unwind_expression/TestUnwindExpression.py +++ b/packages/Python/lldbsuite/test/expression_command/unwind_expression/TestUnwindExpression.py @@ -23,32 +23,8 @@ class UnwindFromExpressionTest(TestBase): def build_and_run_to_bkpt(self): self.build() - exe = os.path.join(os.getcwd(), "a.out") - - target = self.dbg.CreateTarget(exe) - self.assertTrue(target, VALID_TARGET) - - # Create the breakpoint. - breakpoint = target.BreakpointCreateBySourceRegex( - "// Set a breakpoint here to get started", self.main_spec) - self.assertTrue(breakpoint, VALID_BREAKPOINT) - - # Launch the process, and do not stop at the entry point. - process = target.LaunchSimple( - None, None, self.get_process_working_directory()) - - if not process: - self.fail("SBTarget.LaunchProcess() failed") - - if process.GetState() != lldb.eStateStopped: - self.fail("Process should be in the 'stopped' state, " - "instead the actual state is: '%s'" % - lldbutil.state_type_to_str(process.GetState())) - - self.thread = lldbutil.get_one_thread_stopped_at_breakpoint( - process, breakpoint) - self.assertIsNotNone( - self.thread, "Expected one thread to be stopped at the breakpoint") + (target, process, self.thread, bkpt) = lldbutil.run_to_source_breakpoint(self, + "// Set a breakpoint here to get started", self.main_spec) # Next set a breakpoint in this function, set up Expression options to stop on # breakpoint hits, and call the function. diff --git a/packages/Python/lldbsuite/test/functionalities/breakpoint/address_breakpoints/TestBadAddressBreakpoints.py b/packages/Python/lldbsuite/test/functionalities/breakpoint/address_breakpoints/TestBadAddressBreakpoints.py index ca05356f9696..6f06ca7770c8 100644 --- a/packages/Python/lldbsuite/test/functionalities/breakpoint/address_breakpoints/TestBadAddressBreakpoints.py +++ b/packages/Python/lldbsuite/test/functionalities/breakpoint/address_breakpoints/TestBadAddressBreakpoints.py @@ -30,46 +30,13 @@ def setUp(self): def address_breakpoints(self): """Test that breakpoints set on a bad address say they are bad.""" - exe = os.path.join(os.getcwd(), "a.out") - # Create a target by the debugger. - target = self.dbg.CreateTarget(exe) - self.assertTrue(target, VALID_TARGET) - - # Now create a breakpoint on main.c by name 'c'. - breakpoint = target.BreakpointCreateBySourceRegex( - "Set a breakpoint here", lldb.SBFileSpec("main.c")) - self.assertTrue(breakpoint and - breakpoint.GetNumLocations() == 1, - VALID_BREAKPOINT) - - # Get the breakpoint location from breakpoint after we verified that, - # indeed, it has one location. - location = breakpoint.GetLocationAtIndex(0) - self.assertTrue(location and - location.IsEnabled(), - VALID_BREAKPOINT_LOCATION) - - launch_info = lldb.SBLaunchInfo(None) - - error = lldb.SBError() - - process = target.Launch(launch_info, error) - self.assertTrue(process, PROCESS_IS_VALID) - - # Did we hit our breakpoint? - from lldbsuite.test.lldbutil import get_threads_stopped_at_breakpoint - threads = get_threads_stopped_at_breakpoint(process, breakpoint) - self.assertTrue( - len(threads) == 1, - "There should be a thread stopped at our breakpoint") - - # The hit count for the breakpoint should be 1. - self.assertTrue(breakpoint.GetHitCount() == 1) + (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self, + "Set a breakpoint here", lldb.SBFileSpec("main.c")) # Now see if we can read from 0. If I can't do that, I don't have a good way to know # what an illegal address is... - error.Clear() + error = lldb.SBError() ptr = process.ReadPointerFromMemory(0x0, error) diff --git a/packages/Python/lldbsuite/test/functionalities/breakpoint/consecutive_breakpoints/TestConsecutiveBreakpoints.py b/packages/Python/lldbsuite/test/functionalities/breakpoint/consecutive_breakpoints/TestConsecutiveBreakpoints.py index 312f2944102e..6afde150d8d7 100644 --- a/packages/Python/lldbsuite/test/functionalities/breakpoint/consecutive_breakpoints/TestConsecutiveBreakpoints.py +++ b/packages/Python/lldbsuite/test/functionalities/breakpoint/consecutive_breakpoints/TestConsecutiveBreakpoints.py @@ -18,29 +18,9 @@ class ConsecutiveBreakpointsTestCase(TestBase): def prepare_test(self): self.build() - exe = os.path.join(os.getcwd(), "a.out") - # Create a target by the debugger. - self.target = self.dbg.CreateTarget(exe) - self.assertTrue(self.target, VALID_TARGET) - - breakpoint1 = self.target.BreakpointCreateBySourceRegex( - "Set breakpoint here", lldb.SBFileSpec("main.cpp")) - self.assertTrue( - breakpoint1 and breakpoint1.GetNumLocations() == 1, - VALID_BREAKPOINT) - - # Now launch the process, and do not stop at entry point. - self.process = self.target.LaunchSimple( - None, None, self.get_process_working_directory()) - self.assertIsNotNone(self.process, PROCESS_IS_VALID) - - # We should be stopped at the first breakpoint - self.thread = lldbutil.get_one_thread_stopped_at_breakpoint( - self.process, breakpoint1) - self.assertIsNotNone( - self.thread, - "Expected one thread to be stopped at breakpoint 1") + (self.target, self.process, self.thread, bkpt) = lldbutil.run_to_source_breakpoint( + self, "Set breakpoint here", lldb.SBFileSpec("main.cpp")) # Set breakpoint to the next instruction frame = self.thread.GetFrameAtIndex(0) diff --git a/source/Host/CMakeLists.txt b/source/Host/CMakeLists.txt index 73d030e198af..2ee599cf43a2 100644 --- a/source/Host/CMakeLists.txt +++ b/source/Host/CMakeLists.txt @@ -103,6 +103,10 @@ else() macosx/cfcpp/CFCMutableSet.cpp macosx/cfcpp/CFCString.cpp ) + if(IOS) + set_property(SOURCE macosx/Host.mm APPEND PROPERTY + COMPILE_DEFINITIONS "NO_XPC_SERVICES=1") + endif() elseif (CMAKE_SYSTEM_NAME MATCHES "Linux|Android") diff --git a/source/Host/common/File.cpp b/source/Host/common/File.cpp index 90a4462c6ca9..6ee4e894756b 100644 --- a/source/Host/common/File.cpp +++ b/source/Host/common/File.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #endif #include "llvm/Support/ConvertUTF.h" diff --git a/source/Host/common/Host.cpp b/source/Host/common/Host.cpp index 29e5991d31aa..8248aa3c5118 100644 --- a/source/Host/common/Host.cpp +++ b/source/Host/common/Host.cpp @@ -46,6 +46,7 @@ #endif // C++ Includes +#include // Other libraries and framework includes // Project includes diff --git a/source/Host/common/MainLoop.cpp b/source/Host/common/MainLoop.cpp index c0c4471e735f..d0e0d00a3151 100644 --- a/source/Host/common/MainLoop.cpp +++ b/source/Host/common/MainLoop.cpp @@ -10,6 +10,7 @@ #include "llvm/Config/llvm-config.h" #include "lldb/Host/MainLoop.h" +#include "lldb/Host/PosixApi.h" #include "lldb/Utility/Status.h" #include #include diff --git a/source/Host/common/NativeRegisterContext.cpp b/source/Host/common/NativeRegisterContext.cpp index 2ca95d707963..629b0247422d 100644 --- a/source/Host/common/NativeRegisterContext.cpp +++ b/source/Host/common/NativeRegisterContext.cpp @@ -345,17 +345,12 @@ Status NativeRegisterContext::ReadRegisterValueFromMemory( return error; } - NativeProcessProtocolSP process_sp(m_thread.GetProcess()); - if (!process_sp) { - error.SetErrorString("invalid process"); - return error; - } - + NativeProcessProtocol &process = m_thread.GetProcess(); uint8_t src[RegisterValue::kMaxRegisterByteSize]; // Read the memory size_t bytes_read; - error = process_sp->ReadMemory(src_addr, src, src_len, bytes_read); + error = process.ReadMemory(src_addr, src, src_len, bytes_read); if (error.Fail()) return error; @@ -374,7 +369,7 @@ Status NativeRegisterContext::ReadRegisterValueFromMemory( // order of the memory data doesn't match the process. For now we are assuming // they are the same. lldb::ByteOrder byte_order; - if (!process_sp->GetByteOrder(byte_order)) { + if (process.GetByteOrder(byte_order)) { error.SetErrorString("NativeProcessProtocol::GetByteOrder () failed"); return error; } @@ -392,41 +387,37 @@ Status NativeRegisterContext::WriteRegisterValueToMemory( Status error; - NativeProcessProtocolSP process_sp(m_thread.GetProcess()); - if (process_sp) { + NativeProcessProtocol &process = m_thread.GetProcess(); - // TODO: we might need to add a parameter to this function in case the byte - // order of the memory data doesn't match the process. For now we are - // assuming - // they are the same. - lldb::ByteOrder byte_order; - if (!process_sp->GetByteOrder(byte_order)) - return Status("NativeProcessProtocol::GetByteOrder () failed"); + // TODO: we might need to add a parameter to this function in case the byte + // order of the memory data doesn't match the process. For now we are + // assuming + // they are the same. + lldb::ByteOrder byte_order; + if (!process.GetByteOrder(byte_order)) + return Status("NativeProcessProtocol::GetByteOrder () failed"); - const size_t bytes_copied = - reg_value.GetAsMemoryData(reg_info, dst, dst_len, byte_order, error); + const size_t bytes_copied = + reg_value.GetAsMemoryData(reg_info, dst, dst_len, byte_order, error); - if (error.Success()) { - if (bytes_copied == 0) { - error.SetErrorString("byte copy failed."); - } else { - size_t bytes_written; - error = - process_sp->WriteMemory(dst_addr, dst, bytes_copied, bytes_written); - if (error.Fail()) - return error; + if (error.Success()) { + if (bytes_copied == 0) { + error.SetErrorString("byte copy failed."); + } else { + size_t bytes_written; + error = process.WriteMemory(dst_addr, dst, bytes_copied, bytes_written); + if (error.Fail()) + return error; - if (bytes_written != bytes_copied) { - // This might happen if we read _some_ bytes but not all - error.SetErrorStringWithFormat("only wrote %" PRIu64 " of %" PRIu64 - " bytes", - static_cast(bytes_written), - static_cast(bytes_copied)); - } + if (bytes_written != bytes_copied) { + // This might happen if we read _some_ bytes but not all + error.SetErrorStringWithFormat("only wrote %" PRIu64 " of %" PRIu64 + " bytes", + static_cast(bytes_written), + static_cast(bytes_copied)); } } - } else - error.SetErrorString("invalid process"); + } return error; } diff --git a/source/Host/common/NativeThreadProtocol.cpp b/source/Host/common/NativeThreadProtocol.cpp index 29e25bbc5692..54ac96dd3c6f 100644 --- a/source/Host/common/NativeThreadProtocol.cpp +++ b/source/Host/common/NativeThreadProtocol.cpp @@ -16,9 +16,9 @@ using namespace lldb; using namespace lldb_private; -NativeThreadProtocol::NativeThreadProtocol(NativeProcessProtocol *process, +NativeThreadProtocol::NativeThreadProtocol(NativeProcessProtocol &process, lldb::tid_t tid) - : m_process_wp(process->shared_from_this()), m_tid(tid) {} + : m_process(process), m_tid(tid) {} Status NativeThreadProtocol::ReadRegister(uint32_t reg, RegisterValue ®_value) { @@ -62,7 +62,3 @@ Status NativeThreadProtocol::RestoreAllRegisters(lldb::DataBufferSP &data_sp) { return Status("no register context"); return register_context_sp->ReadAllRegisterValues(data_sp); } - -NativeProcessProtocolSP NativeThreadProtocol::GetProcess() { - return m_process_wp.lock(); -} diff --git a/source/Host/common/Socket.cpp b/source/Host/common/Socket.cpp index 0df9dc02c70f..5490e9b30bda 100644 --- a/source/Host/common/Socket.cpp +++ b/source/Host/common/Socket.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #endif #ifdef __linux__ diff --git a/source/Host/common/SocketAddress.cpp b/source/Host/common/SocketAddress.cpp index 41150fa7fd74..def3e0359f01 100644 --- a/source/Host/common/SocketAddress.cpp +++ b/source/Host/common/SocketAddress.cpp @@ -317,6 +317,13 @@ bool SocketAddress::IsAnyAddr() const { : 0 == memcmp(&m_socket_addr.sa_ipv6.sin6_addr, &in6addr_any, 16); } +bool SocketAddress::IsLocalhost() const { + return (GetFamily() == AF_INET) + ? m_socket_addr.sa_ipv4.sin_addr.s_addr == htonl(INADDR_LOOPBACK) + : 0 == memcmp(&m_socket_addr.sa_ipv6.sin6_addr, &in6addr_loopback, + 16); +} + bool SocketAddress::operator==(const SocketAddress &rhs) const { if (GetFamily() != rhs.GetFamily()) return false; diff --git a/source/Host/common/TCPSocket.cpp b/source/Host/common/TCPSocket.cpp index c013334ce23a..a7af93f10a7f 100644 --- a/source/Host/common/TCPSocket.cpp +++ b/source/Host/common/TCPSocket.cpp @@ -34,6 +34,7 @@ #define CLOSE_SOCKET closesocket typedef const char *set_socket_option_arg_type; #else +#include #define CLOSE_SOCKET ::close typedef const void *set_socket_option_arg_type; #endif diff --git a/source/Host/linux/Host.cpp b/source/Host/linux/Host.cpp index 486d4e3f0b81..f43090eadf81 100644 --- a/source/Host/linux/Host.cpp +++ b/source/Host/linux/Host.cpp @@ -16,6 +16,7 @@ #include #include #include +#include // C++ Includes // Other libraries and framework includes diff --git a/source/Host/linux/HostInfoLinux.cpp b/source/Host/linux/HostInfoLinux.cpp index 3ff722d5c109..8d59cda249e8 100644 --- a/source/Host/linux/HostInfoLinux.cpp +++ b/source/Host/linux/HostInfoLinux.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include // std::once diff --git a/source/Host/posix/ConnectionFileDescriptorPosix.cpp b/source/Host/posix/ConnectionFileDescriptorPosix.cpp index 105ef0f23d46..3797650105ce 100644 --- a/source/Host/posix/ConnectionFileDescriptorPosix.cpp +++ b/source/Host/posix/ConnectionFileDescriptorPosix.cpp @@ -30,6 +30,7 @@ #ifndef LLDB_DISABLE_POSIX #include +#include #endif // C++ Includes diff --git a/source/Host/posix/FileSystem.cpp b/source/Host/posix/FileSystem.cpp index e5a99e1aa754..3ece0677f991 100644 --- a/source/Host/posix/FileSystem.cpp +++ b/source/Host/posix/FileSystem.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #ifdef __linux__ #include #include diff --git a/source/Host/posix/HostProcessPosix.cpp b/source/Host/posix/HostProcessPosix.cpp index b5505dbec65b..3c5273f4bd3f 100644 --- a/source/Host/posix/HostProcessPosix.cpp +++ b/source/Host/posix/HostProcessPosix.cpp @@ -13,7 +13,9 @@ #include "llvm/ADT/STLExtras.h" +#include #include +#include using namespace lldb_private; diff --git a/source/Host/posix/LockFilePosix.cpp b/source/Host/posix/LockFilePosix.cpp index 2b7d548a021c..05423062bd44 100644 --- a/source/Host/posix/LockFilePosix.cpp +++ b/source/Host/posix/LockFilePosix.cpp @@ -10,6 +10,7 @@ #include "lldb/Host/posix/LockFilePosix.h" #include +#include using namespace lldb; using namespace lldb_private; diff --git a/source/Host/posix/ProcessLauncherPosixFork.cpp b/source/Host/posix/ProcessLauncherPosixFork.cpp index 0b40c24256ef..66c0229e0dab 100644 --- a/source/Host/posix/ProcessLauncherPosixFork.cpp +++ b/source/Host/posix/ProcessLauncherPosixFork.cpp @@ -19,8 +19,10 @@ #include #include #include +#include #include +#include #ifdef __ANDROID__ #include diff --git a/source/Interpreter/CommandInterpreter.cpp b/source/Interpreter/CommandInterpreter.cpp index 075f2e7b7bd1..986be7ffbf89 100644 --- a/source/Interpreter/CommandInterpreter.cpp +++ b/source/Interpreter/CommandInterpreter.cpp @@ -2475,7 +2475,7 @@ void CommandInterpreter::HandleCommandsFromFile( } ScriptInterpreter *CommandInterpreter::GetScriptInterpreter(bool can_create) { - std::lock_guard locker(m_script_interpreter_mutex); + std::lock_guard locker(m_script_interpreter_mutex); if (!m_script_interpreter_sp) { if (!can_create) return nullptr; diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp b/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp index 5dbb3bb4ef7e..7dd2b57da0cb 100644 --- a/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp +++ b/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp @@ -7,24 +7,12 @@ // //===----------------------------------------------------------------------===// -// C Includes -#include -#include -#include - -// C++ Includes -// Other libraries and framework includes +#include "AuxVector.h" #include "lldb/Target/Process.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Log.h" -#if defined(__linux__) || defined(__FreeBSD__) -#include "Plugins/Process/elf-core/ProcessElfCore.h" -#endif - -#include "AuxVector.h" - using namespace lldb; using namespace lldb_private; diff --git a/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp b/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp index 696bdf7e030d..bce0eaf6d57e 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp @@ -451,16 +451,16 @@ void ClangModulesDeclVendorImpl::ForEachMacro( bool first_arg = true; - for (clang::MacroInfo::arg_iterator ai = macro_info->arg_begin(), - ae = macro_info->arg_end(); - ai != ae; ++ai) { + for (auto pi = macro_info->param_begin(), + pe = macro_info->param_end(); + pi != pe; ++pi) { if (!first_arg) { macro_expansion.append(", "); } else { first_arg = false; } - macro_expansion.append((*ai)->getName().str()); + macro_expansion.append((*pi)->getName().str()); } if (macro_info->isC99Varargs()) { diff --git a/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp b/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp index 5f0596cc9ad2..88bdd68ff301 100644 --- a/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp +++ b/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp @@ -274,6 +274,28 @@ bool CPlusPlusNameParser::ConsumeAnonymousNamespace() { return true; } +bool CPlusPlusNameParser::ConsumeLambda() { + Bookmark start_position = SetBookmark(); + if (!ConsumeToken(tok::l_brace)) { + return false; + } + constexpr llvm::StringLiteral g_lambda("lambda"); + if (HasMoreTokens() && Peek().is(tok::raw_identifier) && + Peek().getRawIdentifier() == g_lambda) { + // Put the matched brace back so we can use ConsumeBrackets + TakeBack(); + } else { + return false; + } + + if (!ConsumeBrackets(tok::l_brace, tok::r_brace)) { + return false; + } + + start_position.Remove(); + return true; +} + bool CPlusPlusNameParser::ConsumeBrackets(tok::TokenKind left, tok::TokenKind right) { Bookmark start_position = SetBookmark(); @@ -502,6 +524,15 @@ CPlusPlusNameParser::ParseFullNameImpl() { state = State::AfterTwoColons; break; } + case tok::l_brace: + if (state == State::Beginning || state == State::AfterTwoColons) { + if (ConsumeLambda()) { + state = State::AfterIdentifier; + break; + } + } + continue_parsing = false; + break; case tok::coloncolon: // Type nesting delimiter. if (state != State::Beginning && state != State::AfterIdentifier && state != State::AfterTemplate) { diff --git a/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h b/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h index f936fb787c94..fe1d46f32c17 100644 --- a/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h +++ b/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h @@ -143,6 +143,9 @@ class CPlusPlusNameParser { // Consumes '(anonymous namespace)' bool ConsumeAnonymousNamespace(); + // Consumes '{lambda ...}' + bool ConsumeLambda(); + // Consumes operator declaration like 'operator *' or 'operator delete []' bool ConsumeOperator(); diff --git a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp index 645bfdfa770d..759ec7fd1d29 100644 --- a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp +++ b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp @@ -23,6 +23,7 @@ #include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" +#include "lldb/Host/PosixApi.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Utility/FileSpec.h" diff --git a/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/source/Plugins/Process/Linux/NativeProcessLinux.cpp index d988ee93a2bc..170d3b100064 100644 --- a/source/Plugins/Process/Linux/NativeProcessLinux.cpp +++ b/source/Plugins/Process/Linux/NativeProcessLinux.cpp @@ -214,7 +214,7 @@ static Status EnsureFDFlags(int fd, int flags) { // Public Static Methods // ----------------------------------------------------------------------------- -llvm::Expected +llvm::Expected> NativeProcessLinux::Factory::Launch(ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate, MainLoop &mainloop) const { @@ -259,14 +259,13 @@ NativeProcessLinux::Factory::Launch(ProcessLaunchInfo &launch_info, return status.ToError(); } - std::shared_ptr process_sp(new NativeProcessLinux( + return std::unique_ptr(new NativeProcessLinux( pid, launch_info.GetPTY().ReleaseMasterFileDescriptor(), native_delegate, - arch, mainloop)); - process_sp->InitializeThreads({pid}); - return process_sp; + arch, mainloop, {pid})); } -llvm::Expected NativeProcessLinux::Factory::Attach( +llvm::Expected> +NativeProcessLinux::Factory::Attach( lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate, MainLoop &mainloop) const { Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); @@ -282,10 +281,8 @@ llvm::Expected NativeProcessLinux::Factory::Attach( if (!tids_or) return tids_or.takeError(); - std::shared_ptr process_sp( - new NativeProcessLinux(pid, -1, native_delegate, arch, mainloop)); - process_sp->InitializeThreads(*tids_or); - return process_sp; + return std::unique_ptr(new NativeProcessLinux( + pid, -1, native_delegate, arch, mainloop, *tids_or)); } // ----------------------------------------------------------------------------- @@ -294,7 +291,8 @@ llvm::Expected NativeProcessLinux::Factory::Attach( NativeProcessLinux::NativeProcessLinux(::pid_t pid, int terminal_fd, NativeDelegate &delegate, - const ArchSpec &arch, MainLoop &mainloop) + const ArchSpec &arch, MainLoop &mainloop, + llvm::ArrayRef<::pid_t> tids) : NativeProcessProtocol(pid, terminal_fd, delegate), m_arch(arch) { if (m_terminal_fd != -1) { Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK); @@ -305,9 +303,7 @@ NativeProcessLinux::NativeProcessLinux(::pid_t pid, int terminal_fd, m_sigchld_handle = mainloop.RegisterSignal( SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, status); assert(m_sigchld_handle && status.Success()); -} -void NativeProcessLinux::InitializeThreads(llvm::ArrayRef<::pid_t> tids) { for (const auto &tid : tids) { NativeThreadLinuxSP thread_sp = AddThread(tid); assert(thread_sp && "AddThread() returned a nullptr thread"); @@ -2009,7 +2005,7 @@ NativeThreadLinuxSP NativeProcessLinux::AddThread(lldb::tid_t thread_id) { if (m_threads.empty()) SetCurrentThreadID(thread_id); - auto thread_sp = std::make_shared(this, thread_id); + auto thread_sp = std::make_shared(*this, thread_id); m_threads.push_back(thread_sp); if (m_pt_proces_trace_id != LLDB_INVALID_UID) { diff --git a/source/Plugins/Process/Linux/NativeProcessLinux.h b/source/Plugins/Process/Linux/NativeProcessLinux.h index 9584713d3654..c9ec002760f8 100644 --- a/source/Plugins/Process/Linux/NativeProcessLinux.h +++ b/source/Plugins/Process/Linux/NativeProcessLinux.h @@ -10,7 +10,7 @@ #ifndef liblldb_NativeProcessLinux_H_ #define liblldb_NativeProcessLinux_H_ -// C++ Includes +#include #include // Other libraries and framework includes @@ -42,11 +42,11 @@ class NativeProcessLinux : public NativeProcessProtocol { public: class Factory : public NativeProcessProtocol::Factory { public: - llvm::Expected + llvm::Expected> Launch(ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate, MainLoop &mainloop) const override; - llvm::Expected + llvm::Expected> Attach(lldb::pid_t pid, NativeDelegate &native_delegate, MainLoop &mainloop) const override; }; @@ -160,15 +160,14 @@ class NativeProcessLinux : public NativeProcessProtocol { // Private Instance Methods // --------------------------------------------------------------------- NativeProcessLinux(::pid_t pid, int terminal_fd, NativeDelegate &delegate, - const ArchSpec &arch, MainLoop &mainloop); + const ArchSpec &arch, MainLoop &mainloop, + llvm::ArrayRef<::pid_t> tids); // Returns a list of process threads that we have attached to. static llvm::Expected> Attach(::pid_t pid); static Status SetDefaultPtraceOpts(const lldb::pid_t); - void InitializeThreads(llvm::ArrayRef<::pid_t> tids); - void MonitorCallback(lldb::pid_t pid, bool exited, WaitStatus status); void WaitForNewThread(::pid_t tid); diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp index 43253f388019..30f09f0c3a3f 100644 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp @@ -30,11 +30,7 @@ lldb::ByteOrder NativeRegisterContextLinux::GetByteOrder() const { // read. lldb::ByteOrder byte_order = lldb::eByteOrderInvalid; - NativeProcessProtocolSP process_sp(m_thread.GetProcess()); - if (!process_sp) - return byte_order; - - if (!process_sp->GetByteOrder(byte_order)) { + if (!m_thread.GetProcess().GetByteOrder(byte_order)) { // FIXME log here } diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp index 1a5b304ac697..7aad062e3f93 100644 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp @@ -873,7 +873,7 @@ Status NativeRegisterContextLinux_arm64::DoReadRegisterValue( PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, sizeof regs); if (error.Success()) { ArchSpec arch; - if (m_thread.GetProcess()->GetArchitecture(arch)) + if (m_thread.GetProcess().GetArchitecture(arch)) value.SetBytes((void *)(((unsigned char *)(®s)) + offset), 16, arch.GetByteOrder()); else @@ -890,7 +890,7 @@ Status NativeRegisterContextLinux_arm64::DoReadRegisterValue( PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, sizeof regs); if (error.Success()) { ArchSpec arch; - if (m_thread.GetProcess()->GetArchitecture(arch)) + if (m_thread.GetProcess().GetArchitecture(arch)) value.SetBytes((void *)(((unsigned char *)(regs)) + offset), 8, arch.GetByteOrder()); else diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp index dee2c064a346..f35ff2be0d94 100644 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp @@ -953,7 +953,7 @@ NativeRegisterContextLinux_mips64::GetWatchpointHitAddress(uint32_t wp_index) { return LLDB_INVALID_ADDRESS; EmulatorBaton baton( - static_cast(m_thread.GetProcess().get()), this); + static_cast(&m_thread.GetProcess()), this); emulator_ap->SetBaton(&baton); emulator_ap->SetReadMemCallback(&ReadMemoryCallback); emulator_ap->SetReadRegCallback(&ReadRegisterCallback); @@ -1034,7 +1034,7 @@ Status NativeRegisterContextLinux_mips64::Read_SR_Config(uint32_t offset, PTRACE_GETREGS, m_thread.GetID(), NULL, ®s, sizeof regs); if (error.Success()) { lldb_private::ArchSpec arch; - if (m_thread.GetProcess()->GetArchitecture(arch)) { + if (m_thread.GetProcess().GetArchitecture(arch)) { void *target_address = ((uint8_t *)®s) + offset + 4 * (arch.GetMachine() == llvm::Triple::mips); value.SetUInt(*(uint32_t *)target_address, size); diff --git a/source/Plugins/Process/Linux/NativeThreadLinux.cpp b/source/Plugins/Process/Linux/NativeThreadLinux.cpp index b1d13668f327..5cd40941dcf8 100644 --- a/source/Plugins/Process/Linux/NativeThreadLinux.cpp +++ b/source/Plugins/Process/Linux/NativeThreadLinux.cpp @@ -85,7 +85,7 @@ void LogThreadStopInfo(Log &log, const ThreadStopInfo &stop_info, } } -NativeThreadLinux::NativeThreadLinux(NativeProcessLinux *process, +NativeThreadLinux::NativeThreadLinux(NativeProcessLinux &process, lldb::tid_t tid) : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid), m_stop_info(), m_reg_context_sp(), m_stop_description() {} @@ -144,12 +144,8 @@ NativeRegisterContextSP NativeThreadLinux::GetRegisterContext() { if (m_reg_context_sp) return m_reg_context_sp; - NativeProcessProtocolSP m_process_sp = m_process_wp.lock(); - if (!m_process_sp) - return NativeRegisterContextSP(); - ArchSpec target_arch; - if (!m_process_sp->GetArchitecture(target_arch)) + if (!m_process.GetArchitecture(target_arch)) return NativeRegisterContextSP(); const uint32_t concrete_frame_idx = 0; @@ -460,20 +456,10 @@ void NativeThreadLinux::MaybeLogStateChange(lldb::StateType new_state) { if (new_state == old_state) return; - NativeProcessProtocolSP m_process_sp = m_process_wp.lock(); - lldb::pid_t pid = - m_process_sp ? m_process_sp->GetID() : LLDB_INVALID_PROCESS_ID; - - // Log it. - log->Printf("NativeThreadLinux: thread (pid=%" PRIu64 ", tid=%" PRIu64 - ") changing from state %s to %s", - pid, GetID(), StateAsCString(old_state), - StateAsCString(new_state)); + LLDB_LOG(log, "pid={0}, tid={1}: changing from state {2} to {3}", + m_process.GetID(), GetID(), old_state, new_state); } NativeProcessLinux &NativeThreadLinux::GetProcess() { - auto process_sp = std::static_pointer_cast( - NativeThreadProtocol::GetProcess()); - assert(process_sp); - return *process_sp; + return static_cast(m_process); } diff --git a/source/Plugins/Process/Linux/NativeThreadLinux.h b/source/Plugins/Process/Linux/NativeThreadLinux.h index b9126b3752a0..6ae87feffcda 100644 --- a/source/Plugins/Process/Linux/NativeThreadLinux.h +++ b/source/Plugins/Process/Linux/NativeThreadLinux.h @@ -14,6 +14,7 @@ #include "lldb/Host/common/NativeThreadProtocol.h" #include "lldb/lldb-private-forward.h" +#include #include #include #include @@ -27,7 +28,7 @@ class NativeThreadLinux : public NativeThreadProtocol { friend class NativeProcessLinux; public: - NativeThreadLinux(NativeProcessLinux *process, lldb::tid_t tid); + NativeThreadLinux(NativeProcessLinux &process, lldb::tid_t tid); // --------------------------------------------------------------------- // NativeThreadProtocol Interface diff --git a/source/Plugins/Process/Linux/ProcessorTrace.h b/source/Plugins/Process/Linux/ProcessorTrace.h index ddcaf0f842b5..6603c7d60478 100644 --- a/source/Plugins/Process/Linux/ProcessorTrace.h +++ b/source/Plugins/Process/Linux/ProcessorTrace.h @@ -18,6 +18,7 @@ #include #include +#include namespace lldb_private { diff --git a/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp b/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp index b9ef02efa65d..388989a21f76 100644 --- a/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp +++ b/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp @@ -64,7 +64,7 @@ static Status EnsureFDFlags(int fd, int flags) { // Public Static Methods // ----------------------------------------------------------------------------- -llvm::Expected +llvm::Expected> NativeProcessNetBSD::Factory::Launch(ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate, MainLoop &mainloop) const { @@ -101,24 +101,25 @@ NativeProcessNetBSD::Factory::Launch(ProcessLaunchInfo &launch_info, LLDB_LOG(log, "pid = {0:x}, detected architecture {1}", pid, arch.GetArchitectureName()); - std::shared_ptr process_sp(new NativeProcessNetBSD( + std::unique_ptr process_up(new NativeProcessNetBSD( pid, launch_info.GetPTY().ReleaseMasterFileDescriptor(), native_delegate, arch, mainloop)); - status = process_sp->ReinitializeThreads(); + status = process_up->ReinitializeThreads(); if (status.Fail()) return status.ToError(); - for (const auto &thread_sp : process_sp->m_threads) { + for (const auto &thread_sp : process_up->m_threads) { static_pointer_cast(thread_sp)->SetStoppedBySignal( SIGSTOP); } - process_sp->SetState(StateType::eStateStopped); + process_up->SetState(StateType::eStateStopped); - return process_sp; + return std::move(process_up); } -llvm::Expected NativeProcessNetBSD::Factory::Attach( +llvm::Expected> +NativeProcessNetBSD::Factory::Attach( lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate, MainLoop &mainloop) const { Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); @@ -130,14 +131,14 @@ llvm::Expected NativeProcessNetBSD::Factory::Attach( if (!status.Success()) return status.ToError(); - std::shared_ptr process_sp( + std::unique_ptr process_up( new NativeProcessNetBSD(pid, -1, native_delegate, arch, mainloop)); - status = process_sp->Attach(); + status = process_up->Attach(); if (!status.Success()) return status.ToError(); - return process_sp; + return std::move(process_up); } // ----------------------------------------------------------------------------- @@ -787,7 +788,7 @@ NativeThreadNetBSDSP NativeProcessNetBSD::AddThread(lldb::tid_t thread_id) { if (m_threads.empty()) SetCurrentThreadID(thread_id); - auto thread_sp = std::make_shared(this, thread_id); + auto thread_sp = std::make_shared(*this, thread_id); m_threads.push_back(thread_sp); return thread_sp; } diff --git a/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h b/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h index 34b892f1fc88..2cbd5e30ab23 100644 --- a/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h +++ b/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h @@ -34,11 +34,11 @@ class NativeProcessNetBSD : public NativeProcessProtocol { public: class Factory : public NativeProcessProtocol::Factory { public: - llvm::Expected + llvm::Expected> Launch(ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate, MainLoop &mainloop) const override; - llvm::Expected + llvm::Expected> Attach(lldb::pid_t pid, NativeDelegate &native_delegate, MainLoop &mainloop) const override; }; diff --git a/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp b/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp index b442fc3462cc..dde86880c41a 100644 --- a/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp +++ b/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp @@ -104,15 +104,9 @@ Status NativeRegisterContextNetBSD::DoWriteDBR(void *buf) { } NativeProcessNetBSD &NativeRegisterContextNetBSD::GetProcess() { - auto process_sp = - std::static_pointer_cast(m_thread.GetProcess()); - assert(process_sp); - return *process_sp; + return static_cast(m_thread.GetProcess()); } ::pid_t NativeRegisterContextNetBSD::GetProcessPid() { - NativeProcessNetBSD &process = GetProcess(); - lldb::pid_t pid = process.GetID(); - - return pid; + return GetProcess().GetID(); } diff --git a/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp b/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp index 8a16431b016d..1fd7400bf800 100644 --- a/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp +++ b/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp @@ -24,7 +24,7 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::process_netbsd; -NativeThreadNetBSD::NativeThreadNetBSD(NativeProcessNetBSD *process, +NativeThreadNetBSD::NativeThreadNetBSD(NativeProcessNetBSD &process, lldb::tid_t tid) : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid), m_stop_info(), m_reg_context_sp(), m_stop_description() {} @@ -144,12 +144,8 @@ NativeRegisterContextSP NativeThreadNetBSD::GetRegisterContext() { if (m_reg_context_sp) return m_reg_context_sp; - NativeProcessProtocolSP m_process_sp = m_process_wp.lock(); - if (!m_process_sp) - return NativeRegisterContextSP(); - ArchSpec target_arch; - if (!m_process_sp->GetArchitecture(target_arch)) + if (!m_process.GetArchitecture(target_arch)) return NativeRegisterContextSP(); const uint32_t concrete_frame_idx = 0; diff --git a/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h b/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h index dcd360cdd310..1e3f587be5f5 100644 --- a/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h +++ b/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h @@ -12,6 +12,7 @@ #include "lldb/Host/common/NativeThreadProtocol.h" +#include #include #include @@ -24,7 +25,7 @@ class NativeThreadNetBSD : public NativeThreadProtocol { friend class NativeProcessNetBSD; public: - NativeThreadNetBSD(NativeProcessNetBSD *process, lldb::tid_t tid); + NativeThreadNetBSD(NativeProcessNetBSD &process, lldb::tid_t tid); // --------------------------------------------------------------------- // NativeThreadProtocol Interface diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index a7fe4ee3b147..9294359dbef1 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -29,6 +29,7 @@ #include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" +#include "lldb/Host/PosixApi.h" #include "lldb/Host/common/NativeProcessProtocol.h" #include "lldb/Host/common/NativeRegisterContext.h" #include "lldb/Host/common/NativeThreadProtocol.h" @@ -239,7 +240,7 @@ Status GDBRemoteCommunicationServerLLGS::LaunchProcess() { { std::lock_guard guard(m_debugged_process_mutex); - assert(!m_debugged_process_sp && "lldb-server creating debugged " + assert(!m_debugged_process_up && "lldb-server creating debugged " "process but one already exists"); auto process_or = m_process_factory.Launch(m_process_launch_info, *this, m_mainloop); @@ -250,7 +251,7 @@ Status GDBRemoteCommunicationServerLLGS::LaunchProcess() { m_process_launch_info.GetArguments().GetArgumentAtIndex(0), status); return status; } - m_debugged_process_sp = *process_or; + m_debugged_process_up = std::move(*process_or); } // Handle mirroring of inferior stdout/stderr over the gdb-remote protocol @@ -263,14 +264,13 @@ Status GDBRemoteCommunicationServerLLGS::LaunchProcess() { // nullptr means it's not redirected to file or pty (in case of LLGS local) // at least one of stdio will be transferred pty<->gdb-remote // we need to give the pty master handle to this object to read and/or write - if (log) - log->Printf( - "GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 - " setting up stdout/stderr redirection via $O gdb-remote commands", - __FUNCTION__, m_debugged_process_sp->GetID()); + LLDB_LOG(log, + "pid = {0}: setting up stdout/stderr redirection via $O " + "gdb-remote commands", + m_debugged_process_up->GetID()); // Setup stdout/stderr mapping from inferior to $O - auto terminal_fd = m_debugged_process_sp->GetTerminalFileDescriptor(); + auto terminal_fd = m_debugged_process_up->GetTerminalFileDescriptor(); if (terminal_fd >= 0) { if (log) log->Printf("ProcessGDBRemoteCommunicationServerLLGS::%s setting " @@ -286,16 +286,15 @@ Status GDBRemoteCommunicationServerLLGS::LaunchProcess() { __FUNCTION__, terminal_fd); } } else { - if (log) - log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 - " skipping stdout/stderr redirection via $O: inferior will " - "communicate over client-provided file descriptors", - __FUNCTION__, m_debugged_process_sp->GetID()); + LLDB_LOG(log, + "pid = {0} skipping stdout/stderr redirection via $O: inferior " + "will communicate over client-provided file descriptors", + m_debugged_process_up->GetID()); } printf("Launched '%s' as process %" PRIu64 "...\n", m_process_launch_info.GetArguments().GetArgumentAtIndex(0), - m_debugged_process_sp->GetID()); + m_debugged_process_up->GetID()); return Status(); } @@ -308,12 +307,12 @@ Status GDBRemoteCommunicationServerLLGS::AttachToProcess(lldb::pid_t pid) { // Before we try to attach, make sure we aren't already monitoring something // else. - if (m_debugged_process_sp && - m_debugged_process_sp->GetID() != LLDB_INVALID_PROCESS_ID) + if (m_debugged_process_up && + m_debugged_process_up->GetID() != LLDB_INVALID_PROCESS_ID) return Status("cannot attach to a process %" PRIu64 " when another process with pid %" PRIu64 " is being debugged.", - pid, m_debugged_process_sp->GetID()); + pid, m_debugged_process_up->GetID()); // Try to attach. auto process_or = m_process_factory.Attach(pid, *this, m_mainloop); @@ -323,10 +322,10 @@ Status GDBRemoteCommunicationServerLLGS::AttachToProcess(lldb::pid_t pid) { status); return status; } - m_debugged_process_sp = *process_or; + m_debugged_process_up = std::move(*process_or); // Setup stdout/stderr mapping from inferior. - auto terminal_fd = m_debugged_process_sp->GetTerminalFileDescriptor(); + auto terminal_fd = m_debugged_process_up->GetTerminalFileDescriptor(); if (terminal_fd >= 0) { if (log) log->Printf("ProcessGDBRemoteCommunicationServerLLGS::%s setting " @@ -597,18 +596,15 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); // Ensure we have a debugged process. - if (!m_debugged_process_sp || - (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) + if (!m_debugged_process_up || + (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) return SendErrorResponse(50); - if (log) - log->Printf( - "GDBRemoteCommunicationServerLLGS::%s preparing packet for pid %" PRIu64 - " tid %" PRIu64, - __FUNCTION__, m_debugged_process_sp->GetID(), tid); + LLDB_LOG(log, "preparing packet for pid {0} tid {1}", + m_debugged_process_up->GetID(), tid); // Ensure we can get info on the given thread. - NativeThreadProtocolSP thread_sp(m_debugged_process_sp->GetThreadByID(tid)); + NativeThreadProtocolSP thread_sp(m_debugged_process_up->GetThreadByID(tid)); if (!thread_sp) return SendErrorResponse(51); @@ -629,13 +625,11 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( // Output the T packet with the thread response.PutChar('T'); int signum = tid_stop_info.details.signal.signo; - if (log) { - log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 - " tid %" PRIu64 - " got signal signo = %d, reason = %d, exc_type = %" PRIu64, - __FUNCTION__, m_debugged_process_sp->GetID(), tid, signum, - tid_stop_info.reason, tid_stop_info.details.exception.type); - } + LLDB_LOG( + log, + "pid {0}, tid {1}, got signal signo = {2}, reason = {3}, exc_type = {4}", + m_debugged_process_up->GetID(), tid, signum, int(tid_stop_info.reason), + tid_stop_info.details.exception.type); // Print the signal number. response.PutHex8(signum & 0xff); @@ -673,9 +667,9 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( uint32_t thread_index = 0; NativeThreadProtocolSP listed_thread_sp; for (listed_thread_sp = - m_debugged_process_sp->GetThreadAtIndex(thread_index); + m_debugged_process_up->GetThreadAtIndex(thread_index); listed_thread_sp; ++thread_index, - listed_thread_sp = m_debugged_process_sp->GetThreadAtIndex( + listed_thread_sp = m_debugged_process_up->GetThreadAtIndex( thread_index)) { if (thread_index > 0) response.PutChar(','); @@ -692,24 +686,23 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( if (thread_index > 0) { const bool threads_with_valid_stop_info_only = true; JSONArray::SP threads_info_sp = GetJSONThreadsInfo( - *m_debugged_process_sp, threads_with_valid_stop_info_only); + *m_debugged_process_up, threads_with_valid_stop_info_only); if (threads_info_sp) { response.PutCString("jstopinfo:"); StreamString unescaped_response; threads_info_sp->Write(unescaped_response); response.PutCStringAsRawHex8(unescaped_response.GetData()); response.PutChar(';'); - } else if (log) - log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to prepare a " - "jstopinfo field for pid %" PRIu64, - __FUNCTION__, m_debugged_process_sp->GetID()); + } else + LLDB_LOG(log, "failed to prepare a jstopinfo field for pid {0}", + m_debugged_process_up->GetID()); } uint32_t i = 0; response.PutCString("thread-pcs"); char delimiter = ':'; for (NativeThreadProtocolSP thread_sp; - (thread_sp = m_debugged_process_sp->GetThreadAtIndex(i)) != nullptr; + (thread_sp = m_debugged_process_up->GetThreadAtIndex(i)) != nullptr; ++i) { NativeRegisterContextSP reg_ctx_sp = thread_sp->GetRegisterContext(); if (!reg_ctx_sp) @@ -1069,8 +1062,8 @@ GDBRemoteCommunicationServerLLGS::Handle_jTraceStart( StringExtractorGDBRemote &packet) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); // Fail if we don't have a current process. - if (!m_debugged_process_sp || - (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) + if (!m_debugged_process_up || + (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) return SendErrorResponse(68); if (!packet.ConsumeFront("jTraceStart:")) @@ -1120,7 +1113,7 @@ GDBRemoteCommunicationServerLLGS::Handle_jTraceStart( Status error; lldb::user_id_t uid = LLDB_INVALID_UID; - uid = m_debugged_process_sp->StartTrace(options, error); + uid = m_debugged_process_up->StartTrace(options, error); LLDB_LOG(log, "uid is {0} , error is {1}", uid, error.GetError()); if (error.Fail()) return SendErrorResponse(error); @@ -1134,8 +1127,8 @@ GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_jTraceStop( StringExtractorGDBRemote &packet) { // Fail if we don't have a current process. - if (!m_debugged_process_sp || - (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) + if (!m_debugged_process_up || + (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) return SendErrorResponse(68); if (!packet.ConsumeFront("jTraceStop:")) @@ -1157,7 +1150,7 @@ GDBRemoteCommunicationServerLLGS::Handle_jTraceStop( json_dict->GetValueForKeyAsInteger("threadid", tid); - Status error = m_debugged_process_sp->StopTrace(uid, tid); + Status error = m_debugged_process_up->StopTrace(uid, tid); if (error.Fail()) return SendErrorResponse(error); @@ -1170,8 +1163,8 @@ GDBRemoteCommunicationServerLLGS::Handle_jTraceConfigRead( StringExtractorGDBRemote &packet) { // Fail if we don't have a current process. - if (!m_debugged_process_sp || - (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) + if (!m_debugged_process_up || + (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) return SendErrorResponse(68); if (!packet.ConsumeFront("jTraceConfigRead:")) @@ -1200,7 +1193,7 @@ GDBRemoteCommunicationServerLLGS::Handle_jTraceConfigRead( StreamGDBRemote response; options.setThreadID(threadid); - Status error = m_debugged_process_sp->GetTraceConfig(uid, options); + Status error = m_debugged_process_up->GetTraceConfig(uid, options); if (error.Fail()) return SendErrorResponse(error); @@ -1228,8 +1221,8 @@ GDBRemoteCommunicationServerLLGS::Handle_jTraceRead( StringExtractorGDBRemote &packet) { // Fail if we don't have a current process. - if (!m_debugged_process_sp || - (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) + if (!m_debugged_process_up || + (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) return SendErrorResponse(68); enum PacketType { MetaData, BufferData }; @@ -1274,9 +1267,9 @@ GDBRemoteCommunicationServerLLGS::Handle_jTraceRead( llvm::MutableArrayRef buf(buffer.get(), byte_count); if (tracetype == BufferData) - error = m_debugged_process_sp->GetData(uid, tid, buf, offset); + error = m_debugged_process_up->GetData(uid, tid, buf, offset); else if (tracetype == MetaData) - error = m_debugged_process_sp->GetMetaData(uid, tid, buf, offset); + error = m_debugged_process_up->GetMetaData(uid, tid, buf, offset); if (error.Fail()) return SendErrorResponse(error); @@ -1293,11 +1286,11 @@ GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_qProcessInfo( StringExtractorGDBRemote &packet) { // Fail if we don't have a current process. - if (!m_debugged_process_sp || - (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) + if (!m_debugged_process_up || + (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) return SendErrorResponse(68); - lldb::pid_t pid = m_debugged_process_sp->GetID(); + lldb::pid_t pid = m_debugged_process_up->GetID(); if (pid == LLDB_INVALID_PROCESS_ID) return SendErrorResponse(1); @@ -1314,16 +1307,16 @@ GDBRemoteCommunicationServerLLGS::Handle_qProcessInfo( GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_qC(StringExtractorGDBRemote &packet) { // Fail if we don't have a current process. - if (!m_debugged_process_sp || - (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) + if (!m_debugged_process_up || + (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) return SendErrorResponse(68); // Make sure we set the current thread so g and p packets return // the data the gdb will expect. - lldb::tid_t tid = m_debugged_process_sp->GetCurrentThreadID(); + lldb::tid_t tid = m_debugged_process_up->GetCurrentThreadID(); SetCurrentThreadID(tid); - NativeThreadProtocolSP thread_sp = m_debugged_process_sp->GetCurrentThread(); + NativeThreadProtocolSP thread_sp = m_debugged_process_up->GetCurrentThread(); if (!thread_sp) return SendErrorResponse(69); @@ -1339,20 +1332,15 @@ GDBRemoteCommunicationServerLLGS::Handle_k(StringExtractorGDBRemote &packet) { StopSTDIOForwarding(); - if (!m_debugged_process_sp) { - if (log) - log->Printf( - "GDBRemoteCommunicationServerLLGS::%s No debugged process found.", - __FUNCTION__); + if (!m_debugged_process_up) { + LLDB_LOG(log, "No debugged process found."); return PacketResult::Success; } - Status error = m_debugged_process_sp->Kill(); - if (error.Fail() && log) - log->Printf("GDBRemoteCommunicationServerLLGS::%s Failed to kill debugged " - "process %" PRIu64 ": %s", - __FUNCTION__, m_debugged_process_sp->GetID(), - error.AsCString()); + Status error = m_debugged_process_up->Kill(); + if (error.Fail()) + LLDB_LOG(log, "Failed to kill debugged process {0}: {1}", + m_debugged_process_up->GetID(), error); // No OK response for kill packet. // return SendOKResponse (); @@ -1400,7 +1388,7 @@ GDBRemoteCommunicationServerLLGS::Handle_C(StringExtractorGDBRemote &packet) { log->Printf("GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__); // Ensure we have a native process. - if (!m_debugged_process_sp) { + if (!m_debugged_process_up) { if (log) log->Printf("GDBRemoteCommunicationServerLLGS::%s no debugged process " "shared pointer", @@ -1453,26 +1441,20 @@ GDBRemoteCommunicationServerLLGS::Handle_C(StringExtractorGDBRemote &packet) { } else { // Send the signal to the process since we weren't targeting a specific // continue thread with the signal. - error = m_debugged_process_sp->Signal(signo); + error = m_debugged_process_up->Signal(signo); if (error.Fail()) { - if (log) - log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to send " - "signal for process %" PRIu64 ": %s", - __FUNCTION__, m_debugged_process_sp->GetID(), - error.AsCString()); + LLDB_LOG(log, "failed to send signal for process {0}: {1}", + m_debugged_process_up->GetID(), error); return SendErrorResponse(0x52); } } // Resume the threads. - error = m_debugged_process_sp->Resume(resume_actions); + error = m_debugged_process_up->Resume(resume_actions); if (error.Fail()) { - if (log) - log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to resume " - "threads for process %" PRIu64 ": %s", - __FUNCTION__, m_debugged_process_sp->GetID(), - error.AsCString()); + LLDB_LOG(log, "failed to resume threads for process {0}: {1}", + m_debugged_process_up->GetID(), error); return SendErrorResponse(0x38); } @@ -1492,15 +1474,13 @@ GDBRemoteCommunicationServerLLGS::Handle_c(StringExtractorGDBRemote &packet) { // For now just support all continue. const bool has_continue_address = (packet.GetBytesLeft() > 0); if (has_continue_address) { - if (log) - log->Printf("GDBRemoteCommunicationServerLLGS::%s not implemented for " - "c{address} variant [%s remains]", - __FUNCTION__, packet.Peek()); + LLDB_LOG(log, "not implemented for c[address] variant [{0} remains]", + packet.Peek()); return SendUnimplementedResponse(packet.GetStringRef().c_str()); } // Ensure we have a native process. - if (!m_debugged_process_sp) { + if (!m_debugged_process_up) { if (log) log->Printf("GDBRemoteCommunicationServerLLGS::%s no debugged process " "shared pointer", @@ -1511,22 +1491,14 @@ GDBRemoteCommunicationServerLLGS::Handle_c(StringExtractorGDBRemote &packet) { // Build the ResumeActionList ResumeActionList actions(StateType::eStateRunning, 0); - Status error = m_debugged_process_sp->Resume(actions); + Status error = m_debugged_process_up->Resume(actions); if (error.Fail()) { - if (log) { - log->Printf( - "GDBRemoteCommunicationServerLLGS::%s c failed for process %" PRIu64 - ": %s", - __FUNCTION__, m_debugged_process_sp->GetID(), error.AsCString()); - } + LLDB_LOG(log, "c failed for process {0}: {1}", + m_debugged_process_up->GetID(), error); return SendErrorResponse(GDBRemoteServerError::eErrorResume); } - if (log) - log->Printf( - "GDBRemoteCommunicationServerLLGS::%s continued process %" PRIu64, - __FUNCTION__, m_debugged_process_sp->GetID()); - + LLDB_LOG(log, "continued process {0}", m_debugged_process_up->GetID()); // No response required from continue. return PacketResult::Success; } @@ -1570,11 +1542,8 @@ GDBRemoteCommunicationServerLLGS::Handle_vCont( } // Ensure we have a native process. - if (!m_debugged_process_sp) { - if (log) - log->Printf("GDBRemoteCommunicationServerLLGS::%s no debugged process " - "shared pointer", - __FUNCTION__); + if (!m_debugged_process_up) { + LLDB_LOG(log, "no debugged process"); return SendErrorResponse(0x36); } @@ -1635,44 +1604,30 @@ GDBRemoteCommunicationServerLLGS::Handle_vCont( thread_actions.Append(thread_action); } - Status error = m_debugged_process_sp->Resume(thread_actions); + Status error = m_debugged_process_up->Resume(thread_actions); if (error.Fail()) { - if (log) { - log->Printf("GDBRemoteCommunicationServerLLGS::%s vCont failed for " - "process %" PRIu64 ": %s", - __FUNCTION__, m_debugged_process_sp->GetID(), - error.AsCString()); - } + LLDB_LOG(log, "vCont failed for process {0}: {1}", + m_debugged_process_up->GetID(), error); return SendErrorResponse(GDBRemoteServerError::eErrorResume); } - if (log) - log->Printf( - "GDBRemoteCommunicationServerLLGS::%s continued process %" PRIu64, - __FUNCTION__, m_debugged_process_sp->GetID()); - + LLDB_LOG(log, "continued process {0}", m_debugged_process_up->GetID()); // No response required from vCont. return PacketResult::Success; } void GDBRemoteCommunicationServerLLGS::SetCurrentThreadID(lldb::tid_t tid) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); - if (log) - log->Printf("GDBRemoteCommunicationServerLLGS::%s setting current thread " - "id to %" PRIu64, - __FUNCTION__, tid); + LLDB_LOG(log, "setting current thread id to {0}", tid); m_current_tid = tid; - if (m_debugged_process_sp) - m_debugged_process_sp->SetCurrentThreadID(m_current_tid); + if (m_debugged_process_up) + m_debugged_process_up->SetCurrentThreadID(m_current_tid); } void GDBRemoteCommunicationServerLLGS::SetContinueThreadID(lldb::tid_t tid) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); - if (log) - log->Printf("GDBRemoteCommunicationServerLLGS::%s setting continue thread " - "id to %" PRIu64, - __FUNCTION__, tid); + LLDB_LOG(log, "setting continue thread id to {0}", tid); m_continue_tid = tid; } @@ -1683,10 +1638,10 @@ GDBRemoteCommunicationServerLLGS::Handle_stop_reason( // Handle the $? gdbremote command. // If no process, indicate error - if (!m_debugged_process_sp) + if (!m_debugged_process_up) return SendErrorResponse(02); - return SendStopReasonForState(m_debugged_process_sp->GetState()); + return SendStopReasonForState(m_debugged_process_up->GetState()); } GDBRemoteCommunication::PacketResult @@ -1707,7 +1662,7 @@ GDBRemoteCommunicationServerLLGS::SendStopReasonForState( case eStateSuspended: case eStateStopped: case eStateCrashed: { - lldb::tid_t tid = m_debugged_process_sp->GetCurrentThreadID(); + lldb::tid_t tid = m_debugged_process_up->GetCurrentThreadID(); // Make sure we set the current thread so g and p packets return // the data the gdb will expect. SetCurrentThreadID(tid); @@ -1717,15 +1672,11 @@ GDBRemoteCommunicationServerLLGS::SendStopReasonForState( case eStateInvalid: case eStateUnloaded: case eStateExited: - return SendWResponse(m_debugged_process_sp.get()); + return SendWResponse(m_debugged_process_up.get()); default: - if (log) { - log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 - ", current state reporting not handled: %s", - __FUNCTION__, m_debugged_process_sp->GetID(), - StateAsCString(process_state)); - } + LLDB_LOG(log, "pid {0}, current state reporting not handled: {1}", + m_debugged_process_up->GetID(), process_state); break; } @@ -1736,12 +1687,12 @@ GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_qRegisterInfo( StringExtractorGDBRemote &packet) { // Fail if we don't have a current process. - if (!m_debugged_process_sp || - (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) + if (!m_debugged_process_up || + (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) return SendErrorResponse(68); // Ensure we have a thread. - NativeThreadProtocolSP thread_sp(m_debugged_process_sp->GetThreadAtIndex(0)); + NativeThreadProtocolSP thread_sp(m_debugged_process_up->GetThreadAtIndex(0)); if (!thread_sp) return SendErrorResponse(69); @@ -1945,47 +1896,33 @@ GDBRemoteCommunicationServerLLGS::Handle_qfThreadInfo( Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); // Fail if we don't have a current process. - if (!m_debugged_process_sp || - (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { - if (log) - log->Printf("GDBRemoteCommunicationServerLLGS::%s() no process (%s), " - "returning OK", - __FUNCTION__, - m_debugged_process_sp ? "invalid process id" - : "null m_debugged_process_sp"); + if (!m_debugged_process_up || + (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { + LLDB_LOG(log, "no process ({0}), returning OK", + m_debugged_process_up ? "invalid process id" + : "null m_debugged_process_up"); return SendOKResponse(); } StreamGDBRemote response; response.PutChar('m'); - if (log) - log->Printf( - "GDBRemoteCommunicationServerLLGS::%s() starting thread iteration", - __FUNCTION__); - + LLDB_LOG(log, "starting thread iteration"); NativeThreadProtocolSP thread_sp; uint32_t thread_index; for (thread_index = 0, - thread_sp = m_debugged_process_sp->GetThreadAtIndex(thread_index); + thread_sp = m_debugged_process_up->GetThreadAtIndex(thread_index); thread_sp; ++thread_index, - thread_sp = m_debugged_process_sp->GetThreadAtIndex(thread_index)) { - if (log) - log->Printf( - "GDBRemoteCommunicationServerLLGS::%s() iterated thread %" PRIu32 - "(%s, tid=0x%" PRIx64 ")", - __FUNCTION__, thread_index, thread_sp ? "is not null" : "null", - thread_sp ? thread_sp->GetID() : LLDB_INVALID_THREAD_ID); + thread_sp = m_debugged_process_up->GetThreadAtIndex(thread_index)) { + LLDB_LOG(log, "iterated thread {0}({1}, tid={2})", thread_index, + thread_sp ? "is not null" : "null", + thread_sp ? thread_sp->GetID() : LLDB_INVALID_THREAD_ID); if (thread_index > 0) response.PutChar(','); response.Printf("%" PRIx64, thread_sp->GetID()); } - if (log) - log->Printf( - "GDBRemoteCommunicationServerLLGS::%s() finished thread iteration", - __FUNCTION__); - + LLDB_LOG(log, "finished thread iteration"); return SendPacketNoLock(response.GetString()); } @@ -2026,11 +1963,10 @@ GDBRemoteCommunicationServerLLGS::Handle_p(StringExtractorGDBRemote &packet) { // Get the thread's register context. NativeRegisterContextSP reg_context_sp(thread_sp->GetRegisterContext()); if (!reg_context_sp) { - if (log) - log->Printf( - "GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 - " failed, no register context available for the thread", - __FUNCTION__, m_debugged_process_sp->GetID(), thread_sp->GetID()); + LLDB_LOG( + log, + "pid {0} tid {1} failed, no register context available for the thread", + m_debugged_process_up->GetID(), thread_sp->GetID()); return SendErrorResponse(0x15); } @@ -2113,8 +2049,8 @@ GDBRemoteCommunicationServerLLGS::Handle_P(StringExtractorGDBRemote &packet) { // Get process architecture. ArchSpec process_arch; - if (!m_debugged_process_sp || - !m_debugged_process_sp->GetArchitecture(process_arch)) { + if (!m_debugged_process_up || + !m_debugged_process_up->GetArchitecture(process_arch)) { if (log) log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to retrieve " "inferior architecture", @@ -2143,7 +2079,7 @@ GDBRemoteCommunicationServerLLGS::Handle_P(StringExtractorGDBRemote &packet) { log->Printf( "GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", - __FUNCTION__, m_debugged_process_sp->GetID(), thread_sp->GetID()); + __FUNCTION__, m_debugged_process_up->GetID(), thread_sp->GetID()); return SendErrorResponse(0x15); } @@ -2197,8 +2133,8 @@ GDBRemoteCommunicationServerLLGS::Handle_H(StringExtractorGDBRemote &packet) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); // Fail if we don't have a current process. - if (!m_debugged_process_sp || - (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (!m_debugged_process_up || + (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { if (log) log->Printf( "GDBRemoteCommunicationServerLLGS::%s failed, no process available", @@ -2241,7 +2177,7 @@ GDBRemoteCommunicationServerLLGS::Handle_H(StringExtractorGDBRemote &packet) { // Ensure we have the given thread when not specifying -1 (all threads) or 0 // (any thread). if (tid != LLDB_INVALID_THREAD_ID && tid != 0) { - NativeThreadProtocolSP thread_sp(m_debugged_process_sp->GetThreadByID(tid)); + NativeThreadProtocolSP thread_sp(m_debugged_process_up->GetThreadByID(tid)); if (!thread_sp) { if (log) log->Printf("GDBRemoteCommunicationServerLLGS::%s failed, tid %" PRIu64 @@ -2275,8 +2211,8 @@ GDBRemoteCommunicationServerLLGS::Handle_I(StringExtractorGDBRemote &packet) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); // Fail if we don't have a current process. - if (!m_debugged_process_sp || - (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (!m_debugged_process_up || + (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { if (log) log->Printf( "GDBRemoteCommunicationServerLLGS::%s failed, no process available", @@ -2311,30 +2247,21 @@ GDBRemoteCommunicationServerLLGS::Handle_interrupt( Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); // Fail if we don't have a current process. - if (!m_debugged_process_sp || - (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { - if (log) - log->Printf( - "GDBRemoteCommunicationServerLLGS::%s failed, no process available", - __FUNCTION__); + if (!m_debugged_process_up || + (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { + LLDB_LOG(log, "failed, no process available"); return SendErrorResponse(0x15); } // Interrupt the process. - Status error = m_debugged_process_sp->Interrupt(); + Status error = m_debugged_process_up->Interrupt(); if (error.Fail()) { - if (log) { - log->Printf( - "GDBRemoteCommunicationServerLLGS::%s failed for process %" PRIu64 - ": %s", - __FUNCTION__, m_debugged_process_sp->GetID(), error.AsCString()); - } + LLDB_LOG(log, "failed for process {0}: {1}", m_debugged_process_up->GetID(), + error); return SendErrorResponse(GDBRemoteServerError::eErrorResume); } - if (log) - log->Printf("GDBRemoteCommunicationServerLLGS::%s stopped process %" PRIu64, - __FUNCTION__, m_debugged_process_sp->GetID()); + LLDB_LOG(log, "stopped process {0}", m_debugged_process_up->GetID()); // No response required from stop all. return PacketResult::Success; @@ -2345,8 +2272,8 @@ GDBRemoteCommunicationServerLLGS::Handle_memory_read( StringExtractorGDBRemote &packet) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (!m_debugged_process_sp || - (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (!m_debugged_process_up || + (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { if (log) log->Printf( "GDBRemoteCommunicationServerLLGS::%s failed, no process available", @@ -2388,13 +2315,13 @@ GDBRemoteCommunicationServerLLGS::Handle_memory_read( // Retrieve the process memory. size_t bytes_read = 0; - Status error = m_debugged_process_sp->ReadMemoryWithoutTrap( + Status error = m_debugged_process_up->ReadMemoryWithoutTrap( read_addr, &buf[0], byte_count, bytes_read); if (error.Fail()) { if (log) log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " mem 0x%" PRIx64 ": failed to read. Error: %s", - __FUNCTION__, m_debugged_process_sp->GetID(), read_addr, + __FUNCTION__, m_debugged_process_up->GetID(), read_addr, error.AsCString()); return SendErrorResponse(0x08); } @@ -2403,7 +2330,7 @@ GDBRemoteCommunicationServerLLGS::Handle_memory_read( if (log) log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " mem 0x%" PRIx64 ": read 0 of %" PRIu64 " requested bytes", - __FUNCTION__, m_debugged_process_sp->GetID(), read_addr, + __FUNCTION__, m_debugged_process_up->GetID(), read_addr, byte_count); return SendErrorResponse(0x08); } @@ -2426,8 +2353,8 @@ GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_M(StringExtractorGDBRemote &packet) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (!m_debugged_process_sp || - (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (!m_debugged_process_up || + (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { if (log) log->Printf( "GDBRemoteCommunicationServerLLGS::%s failed, no process available", @@ -2455,10 +2382,7 @@ GDBRemoteCommunicationServerLLGS::Handle_M(StringExtractorGDBRemote &packet) { const uint64_t byte_count = packet.GetHexMaxU64(false, 0); if (byte_count == 0) { - if (log) - log->Printf("GDBRemoteCommunicationServerLLGS::%s nothing to write: " - "zero-length packet", - __FUNCTION__); + LLDB_LOG(log, "nothing to write: zero-length packet"); return PacketResult::Success; } @@ -2476,12 +2400,11 @@ GDBRemoteCommunicationServerLLGS::Handle_M(StringExtractorGDBRemote &packet) { StreamGDBRemote response; const uint64_t convert_count = packet.GetHexBytes(buf, 0); if (convert_count != byte_count) { - if (log) - log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 - " mem 0x%" PRIx64 ": asked to write %" PRIu64 - " bytes, but only found %" PRIu64 " to convert.", - __FUNCTION__, m_debugged_process_sp->GetID(), write_addr, - byte_count, convert_count); + LLDB_LOG(log, + "pid {0} mem {1:x}: asked to write {2} bytes, but only found {3} " + "to convert.", + m_debugged_process_up->GetID(), write_addr, byte_count, + convert_count); return SendIllFormedResponse(packet, "M content byte length specified did " "not match hex-encoded content " "length"); @@ -2489,23 +2412,17 @@ GDBRemoteCommunicationServerLLGS::Handle_M(StringExtractorGDBRemote &packet) { // Write the process memory. size_t bytes_written = 0; - Status error = m_debugged_process_sp->WriteMemory(write_addr, &buf[0], + Status error = m_debugged_process_up->WriteMemory(write_addr, &buf[0], byte_count, bytes_written); if (error.Fail()) { - if (log) - log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 - " mem 0x%" PRIx64 ": failed to write. Error: %s", - __FUNCTION__, m_debugged_process_sp->GetID(), write_addr, - error.AsCString()); + LLDB_LOG(log, "pid {0} mem {1:x}: failed to write. Error: {2}", + m_debugged_process_up->GetID(), write_addr, error); return SendErrorResponse(0x09); } if (bytes_written == 0) { - if (log) - log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 - " mem 0x%" PRIx64 ": wrote 0 of %" PRIu64 " requested bytes", - __FUNCTION__, m_debugged_process_sp->GetID(), write_addr, - byte_count); + LLDB_LOG(log, "pid {0} mem {1:x}: wrote 0 of {2} requested bytes", + m_debugged_process_up->GetID(), write_addr, byte_count); return SendErrorResponse(0x09); } @@ -2525,8 +2442,8 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfoSupported( // Ensure we have a process running; otherwise, we can't figure this out // since we won't have a NativeProcessProtocol. - if (!m_debugged_process_sp || - (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (!m_debugged_process_up || + (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { if (log) log->Printf( "GDBRemoteCommunicationServerLLGS::%s failed, no process available", @@ -2537,7 +2454,7 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfoSupported( // Test if we can get any region back when asking for the region around NULL. MemoryRegionInfo region_info; const Status error = - m_debugged_process_sp->GetMemoryRegionInfo(0, region_info); + m_debugged_process_up->GetMemoryRegionInfo(0, region_info); if (error.Fail()) { // We don't support memory region info collection for this // NativeProcessProtocol. @@ -2553,8 +2470,8 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo( Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); // Ensure we have a process. - if (!m_debugged_process_sp || - (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (!m_debugged_process_up || + (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { if (log) log->Printf( "GDBRemoteCommunicationServerLLGS::%s failed, no process available", @@ -2575,7 +2492,7 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo( // Get the memory region info for the target address. MemoryRegionInfo region_info; const Status error = - m_debugged_process_sp->GetMemoryRegionInfo(read_addr, region_info); + m_debugged_process_up->GetMemoryRegionInfo(read_addr, region_info); if (error.Fail()) { // Return the error message. @@ -2619,13 +2536,10 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo( GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_Z(StringExtractorGDBRemote &packet) { // Ensure we have a process. - if (!m_debugged_process_sp || - (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (!m_debugged_process_up || + (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf( - "GDBRemoteCommunicationServerLLGS::%s failed, no process available", - __FUNCTION__); + LLDB_LOG(log, "failed, no process available"); return SendErrorResponse(0x15); } @@ -2693,28 +2607,22 @@ GDBRemoteCommunicationServerLLGS::Handle_Z(StringExtractorGDBRemote &packet) { if (want_breakpoint) { // Try to set the breakpoint. const Status error = - m_debugged_process_sp->SetBreakpoint(addr, size, want_hardware); + m_debugged_process_up->SetBreakpoint(addr, size, want_hardware); if (error.Success()) return SendOKResponse(); Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); - if (log) - log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 - " failed to set breakpoint: %s", - __FUNCTION__, m_debugged_process_sp->GetID(), - error.AsCString()); + LLDB_LOG(log, "pid {0} failed to set breakpoint: {1}", + m_debugged_process_up->GetID(), error); return SendErrorResponse(0x09); } else { // Try to set the watchpoint. - const Status error = m_debugged_process_sp->SetWatchpoint( + const Status error = m_debugged_process_up->SetWatchpoint( addr, size, watch_flags, want_hardware); if (error.Success()) return SendOKResponse(); Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); - if (log) - log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 - " failed to set watchpoint: %s", - __FUNCTION__, m_debugged_process_sp->GetID(), - error.AsCString()); + LLDB_LOG(log, "pid {0} failed to set watchpoint: {1}", + m_debugged_process_up->GetID(), error); return SendErrorResponse(0x09); } } @@ -2722,13 +2630,10 @@ GDBRemoteCommunicationServerLLGS::Handle_Z(StringExtractorGDBRemote &packet) { GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_z(StringExtractorGDBRemote &packet) { // Ensure we have a process. - if (!m_debugged_process_sp || - (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (!m_debugged_process_up || + (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf( - "GDBRemoteCommunicationServerLLGS::%s failed, no process available", - __FUNCTION__); + LLDB_LOG(log, "failed, no process available"); return SendErrorResponse(0x15); } @@ -2790,27 +2695,21 @@ GDBRemoteCommunicationServerLLGS::Handle_z(StringExtractorGDBRemote &packet) { if (want_breakpoint) { // Try to clear the breakpoint. const Status error = - m_debugged_process_sp->RemoveBreakpoint(addr, want_hardware); + m_debugged_process_up->RemoveBreakpoint(addr, want_hardware); if (error.Success()) return SendOKResponse(); Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); - if (log) - log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 - " failed to remove breakpoint: %s", - __FUNCTION__, m_debugged_process_sp->GetID(), - error.AsCString()); + LLDB_LOG(log, "pid {0} failed to remove breakpoint: {1}", + m_debugged_process_up->GetID(), error); return SendErrorResponse(0x09); } else { // Try to clear the watchpoint. - const Status error = m_debugged_process_sp->RemoveWatchpoint(addr); + const Status error = m_debugged_process_up->RemoveWatchpoint(addr); if (error.Success()) return SendOKResponse(); Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); - if (log) - log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 - " failed to remove watchpoint: %s", - __FUNCTION__, m_debugged_process_sp->GetID(), - error.AsCString()); + LLDB_LOG(log, "pid {0} failed to remove watchpoint: {1}", + m_debugged_process_up->GetID(), error); return SendErrorResponse(0x09); } } @@ -2820,8 +2719,8 @@ GDBRemoteCommunicationServerLLGS::Handle_s(StringExtractorGDBRemote &packet) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); // Ensure we have a process. - if (!m_debugged_process_sp || - (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (!m_debugged_process_up || + (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { if (log) log->Printf( "GDBRemoteCommunicationServerLLGS::%s failed, no process available", @@ -2840,7 +2739,7 @@ GDBRemoteCommunicationServerLLGS::Handle_s(StringExtractorGDBRemote &packet) { // Double check that we have such a thread. // TODO investigate: on MacOSX we might need to do an UpdateThreads () here. - NativeThreadProtocolSP thread_sp = m_debugged_process_sp->GetThreadByID(tid); + NativeThreadProtocolSP thread_sp = m_debugged_process_up->GetThreadByID(tid); if (!thread_sp || thread_sp->GetID() != tid) return SendErrorResponse(0x33); @@ -2853,12 +2752,12 @@ GDBRemoteCommunicationServerLLGS::Handle_s(StringExtractorGDBRemote &packet) { // All other threads stop while we're single stepping a thread. actions.SetDefaultThreadActionIfNeeded(eStateStopped, 0); - Status error = m_debugged_process_sp->Resume(actions); + Status error = m_debugged_process_up->Resume(actions); if (error.Fail()) { if (log) log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 " Resume() failed with error: %s", - __FUNCTION__, m_debugged_process_sp->GetID(), tid, + __FUNCTION__, m_debugged_process_up->GetID(), tid, error.AsCString()); return SendErrorResponse(0x49); } @@ -2901,8 +2800,8 @@ GDBRemoteCommunicationServerLLGS::Handle_qXfer_auxv_read( // Grab the auxv data if we need it. if (!m_active_auxv_buffer_up) { // Make sure we have a valid process. - if (!m_debugged_process_sp || - (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (!m_debugged_process_up || + (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { if (log) log->Printf( "GDBRemoteCommunicationServerLLGS::%s failed, no process available", @@ -2911,7 +2810,7 @@ GDBRemoteCommunicationServerLLGS::Handle_qXfer_auxv_read( } // Grab the auxv data. - auto buffer_or_error = m_debugged_process_sp->GetAuxvData(); + auto buffer_or_error = m_debugged_process_up->GetAuxvData(); if (!buffer_or_error) { std::error_code ec = buffer_or_error.getError(); LLDB_LOG(log, "no auxv data retrieved: {0}", ec.message()); @@ -2979,11 +2878,10 @@ GDBRemoteCommunicationServerLLGS::Handle_QSaveRegisterState( // Grab the register context for the thread. NativeRegisterContextSP reg_context_sp(thread_sp->GetRegisterContext()); if (!reg_context_sp) { - if (log) - log->Printf( - "GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 - " failed, no register context available for the thread", - __FUNCTION__, m_debugged_process_sp->GetID(), thread_sp->GetID()); + LLDB_LOG( + log, + "pid {0} tid {1} failed, no register context available for the thread", + m_debugged_process_up->GetID(), thread_sp->GetID()); return SendErrorResponse(0x15); } @@ -2991,11 +2889,8 @@ GDBRemoteCommunicationServerLLGS::Handle_QSaveRegisterState( DataBufferSP register_data_sp; Status error = reg_context_sp->ReadAllRegisterValues(register_data_sp); if (error.Fail()) { - if (log) - log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 - " failed to save all register values: %s", - __FUNCTION__, m_debugged_process_sp->GetID(), - error.AsCString()); + LLDB_LOG(log, "pid {0} failed to save all register values: {1}", + m_debugged_process_up->GetID(), error); return SendErrorResponse(0x75); } @@ -3029,10 +2924,8 @@ GDBRemoteCommunicationServerLLGS::Handle_QRestoreRegisterState( const uint32_t save_id = packet.GetU32(0); if (save_id == 0) { - if (log) - log->Printf("GDBRemoteCommunicationServerLLGS::%s QRestoreRegisterState " - "packet has malformed save id, expecting decimal uint32_t", - __FUNCTION__); + LLDB_LOG(log, "QRestoreRegisterState packet has malformed save id, " + "expecting decimal uint32_t"); return SendErrorResponse(0x76); } @@ -3050,11 +2943,10 @@ GDBRemoteCommunicationServerLLGS::Handle_QRestoreRegisterState( // Grab the register context for the thread. NativeRegisterContextSP reg_context_sp(thread_sp->GetRegisterContext()); if (!reg_context_sp) { - if (log) - log->Printf( - "GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 - " failed, no register context available for the thread", - __FUNCTION__, m_debugged_process_sp->GetID(), thread_sp->GetID()); + LLDB_LOG( + log, + "pid {0} tid {1} failed, no register context available for the thread", + m_debugged_process_up->GetID(), thread_sp->GetID()); return SendErrorResponse(0x15); } @@ -3066,10 +2958,9 @@ GDBRemoteCommunicationServerLLGS::Handle_QRestoreRegisterState( // Find the register set buffer for the given save id. auto it = m_saved_registers_map.find(save_id); if (it == m_saved_registers_map.end()) { - if (log) - log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 - " does not have a register set save buffer for id %" PRIu32, - __FUNCTION__, m_debugged_process_sp->GetID(), save_id); + LLDB_LOG(log, + "pid {0} does not have a register set save buffer for id {1}", + m_debugged_process_up->GetID(), save_id); return SendErrorResponse(0x77); } register_data_sp = it->second; @@ -3080,11 +2971,8 @@ GDBRemoteCommunicationServerLLGS::Handle_QRestoreRegisterState( Status error = reg_context_sp->WriteAllRegisterValues(register_data_sp); if (error.Fail()) { - if (log) - log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 - " failed to restore all register values: %s", - __FUNCTION__, m_debugged_process_sp->GetID(), - error.AsCString()); + LLDB_LOG(log, "pid {0} failed to restore all register values: {1}", + m_debugged_process_up->GetID(), error); return SendErrorResponse(0x77); } @@ -3124,7 +3012,7 @@ GDBRemoteCommunicationServerLLGS::Handle_vAttach( } // Notify we attached by sending a stop packet. - return SendStopReasonForState(m_debugged_process_sp->GetState()); + return SendStopReasonForState(m_debugged_process_up->GetState()); } GDBRemoteCommunication::PacketResult @@ -3134,8 +3022,8 @@ GDBRemoteCommunicationServerLLGS::Handle_D(StringExtractorGDBRemote &packet) { StopSTDIOForwarding(); // Fail if we don't have a current process. - if (!m_debugged_process_sp || - (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (!m_debugged_process_up || + (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { if (log) log->Printf( "GDBRemoteCommunicationServerLLGS::%s failed, no process available", @@ -3157,16 +3045,16 @@ GDBRemoteCommunicationServerLLGS::Handle_D(StringExtractorGDBRemote &packet) { return SendIllFormedResponse(packet, "D failed to parse the process id"); } - if (pid != LLDB_INVALID_PROCESS_ID && m_debugged_process_sp->GetID() != pid) { + if (pid != LLDB_INVALID_PROCESS_ID && m_debugged_process_up->GetID() != pid) { return SendIllFormedResponse(packet, "Invalid pid"); } - const Status error = m_debugged_process_sp->Detach(); + const Status error = m_debugged_process_up->Detach(); if (error.Fail()) { if (log) log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to detach from " "pid %" PRIu64 ": %s\n", - __FUNCTION__, m_debugged_process_sp->GetID(), + __FUNCTION__, m_debugged_process_up->GetID(), error.AsCString()); return SendErrorResponse(0x01); } @@ -3197,24 +3085,18 @@ GDBRemoteCommunicationServerLLGS::Handle_jThreadsInfo( Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); // Ensure we have a debugged process. - if (!m_debugged_process_sp || - (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) + if (!m_debugged_process_up || + (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) return SendErrorResponse(50); - - if (log) - log->Printf("GDBRemoteCommunicationServerLLGS::%s preparing packet for pid " - "%" PRIu64, - __FUNCTION__, m_debugged_process_sp->GetID()); + LLDB_LOG(log, "preparing packet for pid {0}", m_debugged_process_up->GetID()); StreamString response; const bool threads_with_valid_stop_info_only = false; JSONArray::SP threads_array_sp = GetJSONThreadsInfo( - *m_debugged_process_sp, threads_with_valid_stop_info_only); + *m_debugged_process_up, threads_with_valid_stop_info_only); if (!threads_array_sp) { - if (log) - log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to prepare a " - "packet for pid %" PRIu64, - __FUNCTION__, m_debugged_process_sp->GetID()); + LLDB_LOG(log, "failed to prepare a packet for pid {0}", + m_debugged_process_up->GetID()); return SendErrorResponse(52); } @@ -3228,8 +3110,8 @@ GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_qWatchpointSupportInfo( StringExtractorGDBRemote &packet) { // Fail if we don't have a current process. - if (!m_debugged_process_sp || - m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID) + if (!m_debugged_process_up || + m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID) return SendErrorResponse(68); packet.SetFilePos(strlen("qWatchpointSupportInfo")); @@ -3238,7 +3120,7 @@ GDBRemoteCommunicationServerLLGS::Handle_qWatchpointSupportInfo( if (packet.GetChar() != ':') return SendErrorResponse(67); - auto hw_debug_cap = m_debugged_process_sp->GetHardwareDebugSupportInfo(); + auto hw_debug_cap = m_debugged_process_up->GetHardwareDebugSupportInfo(); StreamGDBRemote response; if (hw_debug_cap == llvm::None) @@ -3253,8 +3135,8 @@ GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_qFileLoadAddress( StringExtractorGDBRemote &packet) { // Fail if we don't have a current process. - if (!m_debugged_process_sp || - m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID) + if (!m_debugged_process_up || + m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID) return SendErrorResponse(67); packet.SetFilePos(strlen("qFileLoadAddress:")); @@ -3266,7 +3148,7 @@ GDBRemoteCommunicationServerLLGS::Handle_qFileLoadAddress( lldb::addr_t file_load_address = LLDB_INVALID_ADDRESS; Status error = - m_debugged_process_sp->GetFileLoadAddress(file_name, file_load_address); + m_debugged_process_up->GetFileLoadAddress(file_name, file_load_address); if (error.Fail()) return SendErrorResponse(69); @@ -3302,10 +3184,10 @@ GDBRemoteCommunicationServerLLGS::Handle_QPassSignals( } // Fail if we don't have a current process. - if (!m_debugged_process_sp) + if (!m_debugged_process_up) return SendErrorResponse(68); - Status error = m_debugged_process_sp->IgnoreSignals(signals); + Status error = m_debugged_process_up->IgnoreSignals(signals); if (error.Fail()) return SendErrorResponse(69); @@ -3342,8 +3224,8 @@ NativeThreadProtocolSP GDBRemoteCommunicationServerLLGS::GetThreadFromSuffix( NativeThreadProtocolSP thread_sp; // We have no thread if we don't have a process. - if (!m_debugged_process_sp || - m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID) + if (!m_debugged_process_up || + m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID) return thread_sp; // If the client hasn't asked for thread suffix support, there will not be a @@ -3355,9 +3237,9 @@ NativeThreadProtocolSP GDBRemoteCommunicationServerLLGS::GetThreadFromSuffix( return thread_sp; else if (current_tid == 0) { // Pick a thread. - return m_debugged_process_sp->GetThreadAtIndex(0); + return m_debugged_process_up->GetThreadAtIndex(0); } else - return m_debugged_process_sp->GetThreadByID(current_tid); + return m_debugged_process_up->GetThreadByID(current_tid); } Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); @@ -3387,7 +3269,7 @@ NativeThreadProtocolSP GDBRemoteCommunicationServerLLGS::GetThreadFromSuffix( packet.SetFilePos(packet.GetFilePos() + strlen("thread:")); const lldb::tid_t tid = packet.GetHexMaxU64(false, 0); if (tid != 0) - return m_debugged_process_sp->GetThreadByID(tid); + return m_debugged_process_up->GetThreadByID(tid); return thread_sp; } @@ -3397,9 +3279,9 @@ lldb::tid_t GDBRemoteCommunicationServerLLGS::GetCurrentThreadID() const { // Use whatever the debug process says is the current thread id // since the protocol either didn't specify or specified we want // any/all threads marked as the current thread. - if (!m_debugged_process_sp) + if (!m_debugged_process_up) return LLDB_INVALID_THREAD_ID; - return m_debugged_process_sp->GetCurrentThreadID(); + return m_debugged_process_up->GetCurrentThreadID(); } // Use the specific current thread id set by the gdb remote protocol. return m_current_tid; @@ -3420,9 +3302,9 @@ void GDBRemoteCommunicationServerLLGS::ClearProcessSpecificData() { FileSpec GDBRemoteCommunicationServerLLGS::FindModuleFile(const std::string &module_path, const ArchSpec &arch) { - if (m_debugged_process_sp) { + if (m_debugged_process_up) { FileSpec file_spec; - if (m_debugged_process_sp + if (m_debugged_process_up ->GetLoadedModuleFileSpec(module_path.c_str(), file_spec) .Success()) { if (file_spec.Exists()) diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h index b065642d4aed..71199473bb8e 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h @@ -114,7 +114,7 @@ class GDBRemoteCommunicationServerLLGS lldb::tid_t m_current_tid = LLDB_INVALID_THREAD_ID; lldb::tid_t m_continue_tid = LLDB_INVALID_THREAD_ID; std::recursive_mutex m_debugged_process_mutex; - NativeProcessProtocolSP m_debugged_process_sp; + std::unique_ptr m_debugged_process_up; Communication m_stdio_communication; MainLoop::ReadHandleUP m_stdio_handle_up; diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 8a66f3865ebc..be11dd9bc7ec 100644 --- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -16,6 +16,7 @@ #include #include // for mmap #include +#include #endif #include #include @@ -40,6 +41,7 @@ #include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/HostThread.h" +#include "lldb/Host/PosixApi.h" #include "lldb/Host/PseudoTerminal.h" #include "lldb/Host/StringConvert.h" #include "lldb/Host/Symbols.h" diff --git a/source/Target/Target.cpp b/source/Target/Target.cpp index 4632ada26ed3..d97f651ca08b 100644 --- a/source/Target/Target.cpp +++ b/source/Target/Target.cpp @@ -34,6 +34,7 @@ #include "lldb/Expression/REPL.h" #include "lldb/Expression/UserExpression.h" #include "lldb/Host/Host.h" +#include "lldb/Host/PosixApi.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/OptionGroupWatchpoint.h" diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0cb744760a58..824dff51865d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -49,8 +49,8 @@ endif() # Users can override LLDB_TEST_USER_ARGS to specify arbitrary arguments to pass to the script set(LLDB_TEST_USER_ARGS - "${LLDB_TEST_USER_ARGS_New}" - CACHE STRING "Specify additional arguments to pass to test runner. For example: '-C gcc -C clang -A i386 -A x86_64'" FORCE) + "" + CACHE STRING "Specify additional arguments to pass to test runner. For example: '-C gcc -C clang -A i386 -A x86_64'") set(LLDB_TEST_COMMON_ARGS --arch=${LLDB_TEST_ARCH} @@ -101,19 +101,19 @@ if(CMAKE_HOST_APPLE) list(APPEND LLDB_TEST_COMMON_ARGS --server $) endif() +set(LLDB_DOTEST_ARGS ${LLDB_TEST_COMMON_ARGS};${LLDB_TEST_USER_ARGS}) + add_python_test_target(check-lldb-single ${LLDB_SOURCE_DIR}/test/dotest.py - "--no-multiprocess;${LLDB_TEST_COMMON_ARGS};${LLDB_TEST_USER_ARGS}" - "Testing LLDB with args: ${LLDB_TEST_COMMON_ARGS};${LLDB_TEST_USER_ARGS}" + "--no-multiprocess;${LLDB_DOTEST_ARGS}" + "Testing LLDB with args: ${LLDB_DOTEST_ARGS}" ) -set(LLDB_DOTEST_ARGS -q;${LLDB_TEST_COMMON_ARGS};${LLDB_TEST_USER_ARGS}) - # If tests crash cause LLDB to crash, or things are otherwise unstable, or if machine-parsable # output is desired (i.e. in continuous integration contexts) check-lldb-single is a better target. add_python_test_target(check-lldb ${LLDB_SOURCE_DIR}/test/dotest.py - "${LLDB_DOTEST_ARGS}" + "-q;${LLDB_DOTEST_ARGS}" "Testing LLDB (parallel execution, with a separate subprocess per test)" ) diff --git a/tools/debugserver/CMakeLists.txt b/tools/debugserver/CMakeLists.txt index d8414e5a2fe0..ae436b8f07c3 100644 --- a/tools/debugserver/CMakeLists.txt +++ b/tools/debugserver/CMakeLists.txt @@ -1,2 +1,19 @@ -project(C CXX ASM-ATT) +cmake_minimum_required(VERSION 3.4.3) + +project(Debugserver LANGUAGES C CXX ASM-ATT) + +if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) + set(CMAKE_MODULE_PATH + ${CMAKE_MODULE_PATH} + "${CMAKE_SOURCE_DIR}/../../cmake" + "${CMAKE_SOURCE_DIR}/../../cmake/modules" + ) + + include(LLDBStandalone) + include(AddLLDB) + + set(LLDB_SOURCE_DIR "${CMAKE_SOURCE_DIR}/../../") + include_directories(${LLDB_SOURCE_DIR}/include) +endif() + add_subdirectory(source) diff --git a/tools/debugserver/source/CMakeLists.txt b/tools/debugserver/source/CMakeLists.txt index 775a1a127b6f..bdca1602f4a8 100644 --- a/tools/debugserver/source/CMakeLists.txt +++ b/tools/debugserver/source/CMakeLists.txt @@ -1,3 +1,4 @@ +include(CheckCXXCompilerFlag) include_directories(${CMAKE_CURRENT_BINARY_DIR}/..) include_directories(${LLDB_SOURCE_DIR}/source) include_directories(MacOSX/DarwinLog) @@ -25,7 +26,6 @@ if (CXX_SUPPORTS_NO_EXTENDED_OFFSETOF) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-extended-offsetof") endif () -find_library(COCOA_LIBRARY Cocoa) add_subdirectory(MacOSX) set(generated_mach_interfaces @@ -91,11 +91,23 @@ set(lldbDebugserverCommonSources add_library(lldbDebugserverCommon ${lldbDebugserverCommonSources}) + +if (APPLE) + if(IOS) + find_library(COCOA_LIBRARY UIKit) + target_link_libraries(lldbDebugserverCommon INTERFACE ${COCOA_LIBRARY} ${CORE_FOUNDATION_LIBRARY} ${FOUNDATION_LIBRARY}) + else() + find_library(COCOA_LIBRARY Cocoa) + target_link_libraries(lldbDebugserverCommon INTERFACE ${COCOA_LIBRARY}) + endif() +endif() + target_link_libraries(lldbDebugserverCommon INTERFACE ${COCOA_LIBRARY} - lldbDebugserverMacOSX_I386 - lldbDebugserverMacOSX_X86_64 - lldbDebugserverMacOSX_DarwinLog) + ${CORE_FOUNDATION_LIBRARY} + ${FOUNDATION_LIBRARY} + lldbDebugserverArchSupport + lldbDebugserverDarwin_DarwinLog) set(LLVM_OPTIONAL_SOURCES ${lldbDebugserverCommonSources}) add_lldb_tool(debugserver INCLUDE_IN_FRAMEWORK diff --git a/tools/debugserver/source/MacOSX/CMakeLists.txt b/tools/debugserver/source/MacOSX/CMakeLists.txt index 59b39a1bff63..28877d122d94 100644 --- a/tools/debugserver/source/MacOSX/CMakeLists.txt +++ b/tools/debugserver/source/MacOSX/CMakeLists.txt @@ -1,8 +1,23 @@ -#add_subdirectory(arm64) -#add_subdirectory(arm) -add_subdirectory(i386) -#add_subdirectory(ppc) -add_subdirectory(x86_64) +if("${CMAKE_OSX_ARCHITECTURES}" MATCHES ".*arm.*") + list(APPEND SOURCES arm/DNBArchImpl.cpp arm64/DNBArchImplARM64.cpp) + include_directories(${CURRENT_SOURCE_DIR}/arm ${CURRENT_SOURCE_DIR}/arm64) +endif() + +if(NOT CMAKE_OSX_ARCHITECTURES OR "${CMAKE_OSX_ARCHITECTURES}" MATCHES ".*86.*") + list(APPEND SOURCES i386/DNBArchImplI386.cpp x86_64/DNBArchImplX86_64.cpp) + include_directories(${CURRENT_SOURCE_DIR}/i386 ${CURRENT_SOURCE_DIR}/x86_64) +endif() + +if("${CMAKE_OSX_ARCHITECTURES}" MATCHES ".*ppc.*") + list(APPEND SOURCES ppc/DNBArchImpl.cpp) + include_directories(${CURRENT_SOURCE_DIR}/ppc) +endif() + add_subdirectory(DarwinLog) include_directories(..) + +include_directories(${LLDB_SOURCE_DIR}/tools/debugserver/source) +add_library(lldbDebugserverArchSupport + ${SOURCES} + ) diff --git a/tools/debugserver/source/MacOSX/DarwinLog/CMakeLists.txt b/tools/debugserver/source/MacOSX/DarwinLog/CMakeLists.txt index 47e7362f0d5e..dffa357f1e68 100644 --- a/tools/debugserver/source/MacOSX/DarwinLog/CMakeLists.txt +++ b/tools/debugserver/source/MacOSX/DarwinLog/CMakeLists.txt @@ -3,7 +3,7 @@ # we must include the grandparent directory... include_directories(${LLDB_SOURCE_DIR}/tools/debugserver/source) -add_library(lldbDebugserverMacOSX_DarwinLog +add_library(lldbDebugserverDarwin_DarwinLog ActivityStore.cpp DarwinLogCollector.cpp LogFilter.cpp diff --git a/tools/debugserver/source/MacOSX/i386/CMakeLists.txt b/tools/debugserver/source/MacOSX/i386/CMakeLists.txt deleted file mode 100644 index dee2c1ea96b0..000000000000 --- a/tools/debugserver/source/MacOSX/i386/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -include_directories(${LLDB_SOURCE_DIR}/tools/debugserver/source) -add_library(lldbDebugserverMacOSX_I386 - DNBArchImplI386.cpp - ) diff --git a/tools/debugserver/source/MacOSX/x86_64/CMakeLists.txt b/tools/debugserver/source/MacOSX/x86_64/CMakeLists.txt deleted file mode 100644 index bb41b04d9d9e..000000000000 --- a/tools/debugserver/source/MacOSX/x86_64/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -# Due to sources including headers like: -# #include "MacOSX/i386/DNBArchImplI386.h" -# we must include the grandparent directory... -include_directories(${LLDB_SOURCE_DIR}/tools/debugserver/source) - -add_library(lldbDebugserverMacOSX_X86_64 - DNBArchImplX86_64.cpp - ) diff --git a/tools/debugserver/source/RNBSocket.cpp b/tools/debugserver/source/RNBSocket.cpp index 62a3e4f9adf5..f1db5e419ff2 100644 --- a/tools/debugserver/source/RNBSocket.cpp +++ b/tools/debugserver/source/RNBSocket.cpp @@ -79,9 +79,17 @@ rnb_err_t RNBSocket::Listen(const char *listen_host, uint16_t port, return rnb_err; } + bool any_addr = (strcmp(listen_host, "*") == 0); + + // If the user wants to allow connections from any address we should create + // sockets on all families that can resolve localhost. This will allow us to + // listen for IPv6 and IPv4 connections from all addresses if those interfaces + // are available. + const char *local_addr = any_addr ? "localhost" : listen_host; + std::map sockets; auto addresses = lldb_private::SocketAddress::GetAddressInfo( - listen_host, NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); + local_addr, NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); for (auto address : addresses) { int sock_fd = ::socket(address.GetFamily(), SOCK_STREAM, IPPROTO_TCP); @@ -90,9 +98,15 @@ rnb_err_t RNBSocket::Listen(const char *listen_host, uint16_t port, SetSocketOption(sock_fd, SOL_SOCKET, SO_REUSEADDR, 1); - address.SetPort(port); + lldb_private::SocketAddress bind_address = address; - int error = ::bind(sock_fd, &address.sockaddr(), address.GetLength()); + if(any_addr || !bind_address.IsLocalhost()) + bind_address.SetToAnyAddress(bind_address.GetFamily(), port); + else + bind_address.SetPort(port); + + int error = + ::bind(sock_fd, &bind_address.sockaddr(), bind_address.GetLength()); if (error == -1) { ClosePort(sock_fd, false); continue; @@ -179,6 +193,7 @@ rnb_err_t RNBSocket::Listen(const char *listen_host, uint16_t port, DNBLogThreaded("error: rejecting connection from %s (expecting %s)\n", accept_addr.GetIPAddress().c_str(), addr_in.GetIPAddress().c_str()); + err.Clear(); } } } diff --git a/tools/driver/Driver.cpp b/tools/driver/Driver.cpp index 8e226a97af35..102ba775da91 100644 --- a/tools/driver/Driver.cpp +++ b/tools/driver/Driver.cpp @@ -9,6 +9,7 @@ #include "Driver.h" +#include #include #include #include diff --git a/tools/lldb-mi/MICmnLLDBDebugger.cpp b/tools/lldb-mi/MICmnLLDBDebugger.cpp index a676ecc92602..b102cab9f93a 100644 --- a/tools/lldb-mi/MICmnLLDBDebugger.cpp +++ b/tools/lldb-mi/MICmnLLDBDebugger.cpp @@ -17,6 +17,7 @@ #include "lldb/API/SBTypeCategory.h" #include "lldb/API/SBTypeNameSpecifier.h" #include "lldb/API/SBTypeSummary.h" +#include // In-house headers: #include "MICmnLLDBDebugSessionInfo.h" diff --git a/tools/lldb-mi/MIDriver.cpp b/tools/lldb-mi/MIDriver.cpp index 49e8588bf732..7bd6b7b2e166 100644 --- a/tools/lldb-mi/MIDriver.cpp +++ b/tools/lldb-mi/MIDriver.cpp @@ -9,6 +9,8 @@ // Third party headers: #include "lldb/API/SBError.h" +#include +#include #include // In-house headers: diff --git a/tools/lldb-mi/MIDriverMain.cpp b/tools/lldb-mi/MIDriverMain.cpp index fdced8dd4ea2..be01f1d97790 100644 --- a/tools/lldb-mi/MIDriverMain.cpp +++ b/tools/lldb-mi/MIDriverMain.cpp @@ -33,6 +33,7 @@ // Third party headers: #include "lldb/API/SBHostOS.h" +#include #include // In house headers: diff --git a/tools/lldb-server/lldb-gdbserver.cpp b/tools/lldb-server/lldb-gdbserver.cpp index 337f244c2c2d..f1a9b113c8ee 100644 --- a/tools/lldb-server/lldb-gdbserver.cpp +++ b/tools/lldb-server/lldb-gdbserver.cpp @@ -67,13 +67,13 @@ typedef process_netbsd::NativeProcessNetBSD::Factory NativeProcessFactory; // Dummy implementation to make sure the code compiles class NativeProcessFactory : public NativeProcessProtocol::Factory { public: - llvm::Expected + llvm::Expected> Launch(ProcessLaunchInfo &launch_info, NativeProcessProtocol::NativeDelegate &delegate, MainLoop &mainloop) const override { llvm_unreachable("Not implemented"); } - llvm::Expected + llvm::Expected> Attach(lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &delegate, MainLoop &mainloop) const override { llvm_unreachable("Not implemented"); diff --git a/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp b/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp index 8c7fade83759..1e7dd77c4dee 100644 --- a/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp +++ b/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp @@ -62,6 +62,11 @@ TEST(CPlusPlusLanguage, MethodNameParsing) { "XX::(anonymous namespace)::anon_class", "anon_func", "()", "const", "XX::(anonymous namespace)::anon_class::anon_func"}, + // Lambda + {"main::{lambda()#1}::operator()() const::{lambda()#1}::operator()() const", + "main::{lambda()#1}::operator()() const::{lambda()#1}", "operator()", "()", "const", + "main::{lambda()#1}::operator()() const::{lambda()#1}::operator()"}, + // Function pointers {"string (*f(vector&&))(float)", "", "f", "(vector&&)", "", "f"}, diff --git a/unittests/debugserver/RNBSocketTest.cpp b/unittests/debugserver/RNBSocketTest.cpp index 163e12bfcac8..37169a53de5a 100644 --- a/unittests/debugserver/RNBSocketTest.cpp +++ b/unittests/debugserver/RNBSocketTest.cpp @@ -85,6 +85,8 @@ TEST(RNBSocket, LoopBackListenIPv4) { TestSocketListen("127.0.0.1"); } TEST(RNBSocket, LoopBackListenIPv6) { TestSocketListen("::1"); } +TEST(RNBSocket, AnyListen) { TestSocketListen("*"); } + void TestSocketConnect(const char *addr) { // Skip IPv6 tests if there isn't a valid interafce auto addresses = lldb_private::SocketAddress::GetAddressInfo( From 3ad6a4b447326bc16c17df65637ca02330b8d090 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Sat, 29 Jul 2017 21:25:18 +0000 Subject: [PATCH 06/10] Vendor import of llvm release_50 branch r309439: https://llvm.org/svn/llvm-project/llvm/branches/release_50@309439 --- CMakeLists.txt | 2 +- docs/ReleaseNotes.rst | 28 +- examples/ParallelJIT/ParallelJIT.cpp | 1 + .../CodeGen/GlobalISel/InstructionSelector.h | 6 +- include/llvm/Support/CommandLine.h | 7 +- include/llvm/Support/TargetRegistry.h | 2 +- include/llvm/Transforms/Utils/LoopUtils.h | 4 +- lib/CodeGen/CodeGenPrepare.cpp | 17 +- lib/CodeGen/InlineSpiller.cpp | 7 +- lib/CodeGen/RegAllocBase.cpp | 9 +- .../SelectionDAG/LegalizeVectorTypes.cpp | 21 +- lib/Option/OptTable.cpp | 4 +- lib/Support/CommandLine.cpp | 18 +- lib/Support/ErrorHandling.cpp | 3 +- lib/Support/TargetRegistry.cpp | 3 +- lib/Target/AArch64/AArch64ISelLowering.cpp | 7 +- .../AMDGPU/InstPrinter/AMDGPUInstPrinter.cpp | 5 + lib/Target/AMDGPU/SIRegisterInfo.td | 3 +- .../Sparc/MCTargetDesc/SparcAsmBackend.cpp | 15 +- lib/Target/SystemZ/SystemZScheduleZ14.td | 22 +- lib/Target/X86/X86ISelDAGToDAG.cpp | 5 +- lib/Target/X86/X86ISelLowering.cpp | 9 +- lib/Transforms/Scalar/JumpThreading.cpp | 28 +- lib/Transforms/Utils/LoopUtils.cpp | 27 +- lib/Transforms/Utils/SimplifyCFG.cpp | 16 +- .../lvi-after-jumpthreading.ll | 5 +- test/CodeGen/AArch64/aarch64-loop-gep-opt.ll | 6 +- .../CodeGen/AArch64/aarch64_win64cc_vararg.ll | 10 +- test/CodeGen/AArch64/win64_vararg.ll | 66 +- .../AMDGPU/spill-empty-live-interval.mir | 74 ++ test/CodeGen/X86/memcmp-minsize.ll | 87 ++ test/CodeGen/X86/memcmp-optsize.ll | 76 ++ test/CodeGen/X86/memcmp.ll | 410 +++---- test/CodeGen/X86/pr33844.ll | 38 + test/CodeGen/X86/pr33960.ll | 39 + test/CodeGen/X86/vector-shift-ashr-256.ll | 5 +- test/MC/Sparc/sparc-tls-relocations.s | 83 ++ test/Transforms/CodeGenPrepare/X86/memcmp.ll | 1074 +---------------- test/Transforms/JumpThreading/pr33605.ll | 64 + test/Transforms/JumpThreading/pr33917.ll | 57 + .../JumpThreading/static-profile.ll | 4 +- test/Transforms/LoopUnroll/peel-loop.ll | 12 +- .../LoopUnswitch/2015-06-17-Metadata.ll | 4 +- test/Transforms/LoopUnswitch/infinite-loop.ll | 4 +- .../LoopVectorize/X86/float-induction-x86.ll | 2 +- .../LoopVectorize/float-induction.ll | 2 +- .../SimplifyCFG/X86/switch_to_lookup_table.ll | 4 +- test/Transforms/SimplifyCFG/multiple-phis.ll | 2 +- test/Transforms/SimplifyCFG/pr33605.ll | 64 + .../preserve-llvm-loop-metadata.ll | 2 +- utils/release/test-release.sh | 2 +- 51 files changed, 1082 insertions(+), 1383 deletions(-) create mode 100644 test/CodeGen/AMDGPU/spill-empty-live-interval.mir create mode 100644 test/CodeGen/X86/pr33844.ll create mode 100644 test/CodeGen/X86/pr33960.ll create mode 100644 test/MC/Sparc/sparc-tls-relocations.s create mode 100644 test/Transforms/JumpThreading/pr33605.ll create mode 100644 test/Transforms/JumpThreading/pr33917.ll create mode 100644 test/Transforms/SimplifyCFG/pr33605.ll diff --git a/CMakeLists.txt b/CMakeLists.txt index 61ecfdf970d0..6af2cba10093 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,7 +29,7 @@ if(NOT DEFINED LLVM_VERSION_PATCH) set(LLVM_VERSION_PATCH 0) endif() if(NOT DEFINED LLVM_VERSION_SUFFIX) - set(LLVM_VERSION_SUFFIX svn) + set(LLVM_VERSION_SUFFIX "") endif() if (POLICY CMP0048) diff --git a/docs/ReleaseNotes.rst b/docs/ReleaseNotes.rst index ddb31acfd029..800a8ec115b3 100644 --- a/docs/ReleaseNotes.rst +++ b/docs/ReleaseNotes.rst @@ -71,6 +71,12 @@ Non-comprehensive list of changes in this release Changes to the LLVM IR ---------------------- +* The datalayout string may now indicate an address space to use for + the pointer type of alloca rather than the default of 0. + +* Added speculatable attribute indicating a function which does has no + side-effects which could inhibit hoisting of calls. + Changes to the ARM Backend -------------------------- @@ -91,12 +97,30 @@ Changes to the PowerPC Target Changes to the X86 Target ------------------------- - During this release ... +* Added initial AMD Ryzen (znver1) scheduler support. + +* Added support for Intel Goldmont CPUs. + +* Add support for avx512vpopcntdq instructions. + +* Added heuristics to convert CMOV into branches when it may be profitable. + +* More aggressive inlining of memcmp calls. + +* Improve vXi64 shuffles on 32-bit targets. + +* Improved use of PMOVMSKB for any_of/all_of comparision reductions. + +* Improved Silvermont, Sandybridge, and Jaguar (btver2) schedulers. + +* Improved support for AVX512 vector rotations. + +* Added support for AMD Lightweight Profiling (LWP) instructions. Changes to the AMDGPU Target ----------------------------- - During this release ... +* Initial gfx9 support Changes to the AVR Target ----------------------------- diff --git a/examples/ParallelJIT/ParallelJIT.cpp b/examples/ParallelJIT/ParallelJIT.cpp index f1932d2471cb..ff44375e3921 100644 --- a/examples/ParallelJIT/ParallelJIT.cpp +++ b/examples/ParallelJIT/ParallelJIT.cpp @@ -145,6 +145,7 @@ class WaitForThreads waitFor = 0; int result = pthread_cond_init( &condition, nullptr ); + (void)result; assert( result == 0 ); result = pthread_mutex_init( &mutex, nullptr ); diff --git a/include/llvm/CodeGen/GlobalISel/InstructionSelector.h b/include/llvm/CodeGen/GlobalISel/InstructionSelector.h index 59a4073646eb..1060d8fd667e 100644 --- a/include/llvm/CodeGen/GlobalISel/InstructionSelector.h +++ b/include/llvm/CodeGen/GlobalISel/InstructionSelector.h @@ -40,7 +40,8 @@ class TargetRegisterInfo; /// This is convenient because std::bitset does not have a constructor /// with an initializer list of set bits. /// -/// Each InstructionSelector subclass should define a PredicateBitset class with: +/// Each InstructionSelector subclass should define a PredicateBitset class +/// with: /// const unsigned MAX_SUBTARGET_PREDICATES = 192; /// using PredicateBitset = PredicateBitsetImpl; /// and updating the constant to suit the target. Tablegen provides a suitable @@ -102,7 +103,8 @@ enum { /// - OpIdx - Operand index /// - Expected integer GIM_CheckConstantInt, - /// Check the operand is a specific literal integer (i.e. MO.isImm() or MO.isCImm() is true). + /// Check the operand is a specific literal integer (i.e. MO.isImm() or + /// MO.isCImm() is true). /// - InsnID - Instruction ID /// - OpIdx - Operand index /// - Expected integer diff --git a/include/llvm/Support/CommandLine.h b/include/llvm/Support/CommandLine.h index 771b0a8c26a9..71d2f0293083 100644 --- a/include/llvm/Support/CommandLine.h +++ b/include/llvm/Support/CommandLine.h @@ -66,15 +66,12 @@ bool ParseCommandLineOptions(int argc, const char *const *argv, void ParseEnvironmentOptions(const char *progName, const char *envvar, const char *Overview = ""); -// Function pointer type for printing version information. -using VersionPrinterTy = std::function; - ///===---------------------------------------------------------------------===// /// SetVersionPrinter - Override the default (LLVM specific) version printer /// used to print out the version when --version is given /// on the command line. This allows other systems using the /// CommandLine utilities to print their own version string. -void SetVersionPrinter(VersionPrinterTy func); +void SetVersionPrinter(void (*func)()); ///===---------------------------------------------------------------------===// /// AddExtraVersionPrinter - Add an extra printer to use in addition to the @@ -83,7 +80,7 @@ void SetVersionPrinter(VersionPrinterTy func); /// which will be called after the basic LLVM version /// printing is complete. Each can then add additional /// information specific to the tool. -void AddExtraVersionPrinter(VersionPrinterTy func); +void AddExtraVersionPrinter(void (*func)()); // PrintOptionValues - Print option values. // With -print-options print the difference between option values and defaults. diff --git a/include/llvm/Support/TargetRegistry.h b/include/llvm/Support/TargetRegistry.h index 90d6c084ee95..8454b27b6f04 100644 --- a/include/llvm/Support/TargetRegistry.h +++ b/include/llvm/Support/TargetRegistry.h @@ -599,7 +599,7 @@ struct TargetRegistry { /// printRegisteredTargetsForVersion - Print the registered targets /// appropriately for inclusion in a tool's version output. - static void printRegisteredTargetsForVersion(raw_ostream &OS); + static void printRegisteredTargetsForVersion(); /// @name Registry Access /// @{ diff --git a/include/llvm/Transforms/Utils/LoopUtils.h b/include/llvm/Transforms/Utils/LoopUtils.h index 1344285917ba..94e20b83754e 100644 --- a/include/llvm/Transforms/Utils/LoopUtils.h +++ b/include/llvm/Transforms/Utils/LoopUtils.h @@ -531,8 +531,10 @@ Value *createTargetReduction(IRBuilder<> &B, const TargetTransformInfo *TTI, /// Get the intersection (logical and) of all of the potential IR flags /// of each scalar operation (VL) that will be converted into a vector (I). +/// If OpValue is non-null, we only consider operations similar to OpValue +/// when intersecting. /// Flag set: NSW, NUW, exact, and all of fast-math. -void propagateIRFlags(Value *I, ArrayRef VL); +void propagateIRFlags(Value *I, ArrayRef VL, Value *OpValue = nullptr); } // end namespace llvm diff --git a/lib/CodeGen/CodeGenPrepare.cpp b/lib/CodeGen/CodeGenPrepare.cpp index 45dc13d58de7..dc02a00e0fcc 100644 --- a/lib/CodeGen/CodeGenPrepare.cpp +++ b/lib/CodeGen/CodeGenPrepare.cpp @@ -4016,14 +4016,18 @@ static bool IsOperandAMemoryOperand(CallInst *CI, InlineAsm *IA, Value *OpVal, return true; } +// Max number of memory uses to look at before aborting the search to conserve +// compile time. +static constexpr int MaxMemoryUsesToScan = 20; + /// Recursively walk all the uses of I until we find a memory use. /// If we find an obviously non-foldable instruction, return true. /// Add the ultimately found memory instructions to MemoryUses. static bool FindAllMemoryUses( Instruction *I, SmallVectorImpl> &MemoryUses, - SmallPtrSetImpl &ConsideredInsts, - const TargetLowering &TLI, const TargetRegisterInfo &TRI) { + SmallPtrSetImpl &ConsideredInsts, const TargetLowering &TLI, + const TargetRegisterInfo &TRI, int SeenInsts = 0) { // If we already considered this instruction, we're done. if (!ConsideredInsts.insert(I).second) return false; @@ -4036,8 +4040,12 @@ static bool FindAllMemoryUses( // Loop over all the uses, recursively processing them. for (Use &U : I->uses()) { - Instruction *UserI = cast(U.getUser()); + // Conservatively return true if we're seeing a large number or a deep chain + // of users. This avoids excessive compilation times in pathological cases. + if (SeenInsts++ >= MaxMemoryUsesToScan) + return true; + Instruction *UserI = cast(U.getUser()); if (LoadInst *LI = dyn_cast(UserI)) { MemoryUses.push_back(std::make_pair(LI, U.getOperandNo())); continue; @@ -4082,7 +4090,8 @@ static bool FindAllMemoryUses( continue; } - if (FindAllMemoryUses(UserI, MemoryUses, ConsideredInsts, TLI, TRI)) + if (FindAllMemoryUses(UserI, MemoryUses, ConsideredInsts, TLI, TRI, + SeenInsts)) return true; } diff --git a/lib/CodeGen/InlineSpiller.cpp b/lib/CodeGen/InlineSpiller.cpp index 4e6a3ec21866..eda4f74c7874 100644 --- a/lib/CodeGen/InlineSpiller.cpp +++ b/lib/CodeGen/InlineSpiller.cpp @@ -643,8 +643,11 @@ void InlineSpiller::reMaterializeAll() { Edit->eraseVirtReg(Reg); continue; } - assert((LIS.hasInterval(Reg) && !LIS.getInterval(Reg).empty()) && - "Reg with empty interval has reference"); + + assert(LIS.hasInterval(Reg) && + (!LIS.getInterval(Reg).empty() || !MRI.reg_nodbg_empty(Reg)) && + "Empty and not used live-range?!"); + RegsToSpill[ResultPos++] = Reg; } RegsToSpill.erase(RegsToSpill.begin() + ResultPos, RegsToSpill.end()); diff --git a/lib/CodeGen/RegAllocBase.cpp b/lib/CodeGen/RegAllocBase.cpp index a7b7a9f8ab15..7b4fbace2c1c 100644 --- a/lib/CodeGen/RegAllocBase.cpp +++ b/lib/CodeGen/RegAllocBase.cpp @@ -133,18 +133,19 @@ void RegAllocBase::allocatePhysRegs() { if (AvailablePhysReg) Matrix->assign(*VirtReg, AvailablePhysReg); - for (VirtRegVec::iterator I = SplitVRegs.begin(), E = SplitVRegs.end(); - I != E; ++I) { - LiveInterval *SplitVirtReg = &LIS->getInterval(*I); + for (unsigned Reg : SplitVRegs) { + assert(LIS->hasInterval(Reg)); + + LiveInterval *SplitVirtReg = &LIS->getInterval(Reg); assert(!VRM->hasPhys(SplitVirtReg->reg) && "Register already assigned"); if (MRI->reg_nodbg_empty(SplitVirtReg->reg)) { + assert(SplitVirtReg->empty() && "Non-empty but used interval"); DEBUG(dbgs() << "not queueing unused " << *SplitVirtReg << '\n'); aboutToRemoveInterval(*SplitVirtReg); LIS->removeInterval(SplitVirtReg->reg); continue; } DEBUG(dbgs() << "queuing new interval: " << *SplitVirtReg << "\n"); - assert(!SplitVirtReg->empty() && "expecting non-empty interval"); assert(TargetRegisterInfo::isVirtualRegister(SplitVirtReg->reg) && "expect split value in virtual register"); enqueue(SplitVirtReg); diff --git a/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp b/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp index d41054b15bbc..0cad20db0964 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp @@ -2965,7 +2965,12 @@ static inline bool isSETCCorConvertedSETCC(SDValue N) { else if (N.getOpcode() == ISD::SIGN_EXTEND) N = N.getOperand(0); - return (N.getOpcode() == ISD::SETCC); + if (isLogicalMaskOp(N.getOpcode())) + return isSETCCorConvertedSETCC(N.getOperand(0)) && + isSETCCorConvertedSETCC(N.getOperand(1)); + + return (N.getOpcode() == ISD::SETCC || + ISD::isBuildVectorOfConstantSDNodes(N.getNode())); } #endif @@ -2973,28 +2978,20 @@ static inline bool isSETCCorConvertedSETCC(SDValue N) { // to ToMaskVT if needed with vector extension or truncation. SDValue DAGTypeLegalizer::convertMask(SDValue InMask, EVT MaskVT, EVT ToMaskVT) { - LLVMContext &Ctx = *DAG.getContext(); - // Currently a SETCC or a AND/OR/XOR with two SETCCs are handled. - unsigned InMaskOpc = InMask->getOpcode(); - // FIXME: This code seems to be too restrictive, we might consider // generalizing it or dropping it. - assert((InMaskOpc == ISD::SETCC || - ISD::isBuildVectorOfConstantSDNodes(InMask.getNode()) || - (isLogicalMaskOp(InMaskOpc) && - isSETCCorConvertedSETCC(InMask->getOperand(0)) && - isSETCCorConvertedSETCC(InMask->getOperand(1)))) && - "Unexpected mask argument."); + assert(isSETCCorConvertedSETCC(InMask) && "Unexpected mask argument."); // Make a new Mask node, with a legal result VT. SmallVector Ops; for (unsigned i = 0; i < InMask->getNumOperands(); ++i) Ops.push_back(InMask->getOperand(i)); - SDValue Mask = DAG.getNode(InMaskOpc, SDLoc(InMask), MaskVT, Ops); + SDValue Mask = DAG.getNode(InMask->getOpcode(), SDLoc(InMask), MaskVT, Ops); // If MaskVT has smaller or bigger elements than ToMaskVT, a vector sign // extend or truncate is needed. + LLVMContext &Ctx = *DAG.getContext(); unsigned MaskScalarBits = MaskVT.getScalarSizeInBits(); unsigned ToMaskScalBits = ToMaskVT.getScalarSizeInBits(); if (MaskScalarBits < ToMaskScalBits) { diff --git a/lib/Option/OptTable.cpp b/lib/Option/OptTable.cpp index f3b438e829d6..51c62d33f8e1 100644 --- a/lib/Option/OptTable.cpp +++ b/lib/Option/OptTable.cpp @@ -235,7 +235,9 @@ OptTable::findByPrefix(StringRef Cur, unsigned short DisableFlags) const { continue; for (int I = 0; In.Prefixes[I]; I++) { - std::string S = std::string(In.Prefixes[I]) + std::string(In.Name); + std::string S = std::string(In.Prefixes[I]) + std::string(In.Name) + "\t"; + if (In.HelpText) + S += In.HelpText; if (StringRef(S).startswith(Cur)) Ret.push_back(S); } diff --git a/lib/Support/CommandLine.cpp b/lib/Support/CommandLine.cpp index 50173f5256bf..8eeb685a18a9 100644 --- a/lib/Support/CommandLine.cpp +++ b/lib/Support/CommandLine.cpp @@ -2039,9 +2039,9 @@ void CommandLineParser::printOptionValues() { Opts[i].second->printOptionValue(MaxArgLen, PrintAllOptions); } -static VersionPrinterTy OverrideVersionPrinter = nullptr; +static void (*OverrideVersionPrinter)() = nullptr; -static std::vector *ExtraVersionPrinters = nullptr; +static std::vector *ExtraVersionPrinters = nullptr; namespace { class VersionPrinter { @@ -2081,7 +2081,7 @@ class VersionPrinter { return; if (OverrideVersionPrinter != nullptr) { - OverrideVersionPrinter(outs()); + (*OverrideVersionPrinter)(); exit(0); } print(); @@ -2090,8 +2090,10 @@ class VersionPrinter { // information. if (ExtraVersionPrinters != nullptr) { outs() << '\n'; - for (auto I : *ExtraVersionPrinters) - I(outs()); + for (std::vector::iterator I = ExtraVersionPrinters->begin(), + E = ExtraVersionPrinters->end(); + I != E; ++I) + (*I)(); } exit(0); @@ -2129,11 +2131,11 @@ void cl::PrintHelpMessage(bool Hidden, bool Categorized) { /// Utility function for printing version number. void cl::PrintVersionMessage() { VersionPrinterInstance.print(); } -void cl::SetVersionPrinter(VersionPrinterTy func) { OverrideVersionPrinter = func; } +void cl::SetVersionPrinter(void (*func)()) { OverrideVersionPrinter = func; } -void cl::AddExtraVersionPrinter(VersionPrinterTy func) { +void cl::AddExtraVersionPrinter(void (*func)()) { if (!ExtraVersionPrinters) - ExtraVersionPrinters = new std::vector; + ExtraVersionPrinters = new std::vector; ExtraVersionPrinters->push_back(func); } diff --git a/lib/Support/ErrorHandling.cpp b/lib/Support/ErrorHandling.cpp index 2fd4f3ea0d45..fb8ae4c1cd5e 100644 --- a/lib/Support/ErrorHandling.cpp +++ b/lib/Support/ErrorHandling.cpp @@ -169,7 +169,8 @@ void llvm::report_bad_alloc_error(const char *Reason, bool GenCrashDiag) { // Don't call the normal error handler. It may allocate memory. Directly write // an OOM to stderr and abort. char OOMMessage[] = "LLVM ERROR: out of memory\n"; - (void)::write(2, OOMMessage, strlen(OOMMessage)); + ssize_t written = ::write(2, OOMMessage, strlen(OOMMessage)); + (void)written; abort(); #endif } diff --git a/lib/Support/TargetRegistry.cpp b/lib/Support/TargetRegistry.cpp index b5c283253117..bed9ed64f802 100644 --- a/lib/Support/TargetRegistry.cpp +++ b/lib/Support/TargetRegistry.cpp @@ -114,7 +114,7 @@ static int TargetArraySortFn(const std::pair *LHS, return LHS->first.compare(RHS->first); } -void TargetRegistry::printRegisteredTargetsForVersion(raw_ostream &OS) { +void TargetRegistry::printRegisteredTargetsForVersion() { std::vector > Targets; size_t Width = 0; for (const auto &T : TargetRegistry::targets()) { @@ -123,6 +123,7 @@ void TargetRegistry::printRegisteredTargetsForVersion(raw_ostream &OS) { } array_pod_sort(Targets.begin(), Targets.end(), TargetArraySortFn); + raw_ostream &OS = outs(); OS << " Registered Targets:\n"; for (unsigned i = 0, e = Targets.size(); i != e; ++i) { OS << " " << Targets[i].first; diff --git a/lib/Target/AArch64/AArch64ISelLowering.cpp b/lib/Target/AArch64/AArch64ISelLowering.cpp index c6150f9e5d1d..8c30c4410c09 100644 --- a/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -2889,9 +2889,12 @@ void AArch64TargetLowering::saveVarArgRegisters(CCState &CCInfo, unsigned GPRSaveSize = 8 * (NumGPRArgRegs - FirstVariadicGPR); int GPRIdx = 0; if (GPRSaveSize != 0) { - if (IsWin64) + if (IsWin64) { GPRIdx = MFI.CreateFixedObject(GPRSaveSize, -(int)GPRSaveSize, false); - else + if (GPRSaveSize & 15) + // The extra size here, if triggered, will always be 8. + MFI.CreateFixedObject(16 - (GPRSaveSize & 15), -(int)alignTo(GPRSaveSize, 16), false); + } else GPRIdx = MFI.CreateStackObject(GPRSaveSize, 8, false); SDValue FIN = DAG.getFrameIndex(GPRIdx, PtrVT); diff --git a/lib/Target/AMDGPU/InstPrinter/AMDGPUInstPrinter.cpp b/lib/Target/AMDGPU/InstPrinter/AMDGPUInstPrinter.cpp index 7c31c8e397ba..a844081db5b2 100644 --- a/lib/Target/AMDGPU/InstPrinter/AMDGPUInstPrinter.cpp +++ b/lib/Target/AMDGPU/InstPrinter/AMDGPUInstPrinter.cpp @@ -297,6 +297,11 @@ void AMDGPUInstPrinter::printRegOperand(unsigned RegNo, raw_ostream &O, case AMDGPU::FLAT_SCR_HI: O << "flat_scratch_hi"; return; + case AMDGPU::FP_REG: + case AMDGPU::SP_REG: + case AMDGPU::SCRATCH_WAVE_OFFSET_REG: + case AMDGPU::PRIVATE_RSRC_REG: + llvm_unreachable("pseudo-register should not ever be emitted"); default: break; } diff --git a/lib/Target/AMDGPU/SIRegisterInfo.td b/lib/Target/AMDGPU/SIRegisterInfo.td index 54ea7805e18d..d097b78890e3 100644 --- a/lib/Target/AMDGPU/SIRegisterInfo.td +++ b/lib/Target/AMDGPU/SIRegisterInfo.td @@ -274,8 +274,7 @@ def VGPR_512 : RegisterTuples<[sub0, sub1, sub2, sub3, sub4, sub5, sub6, sub7, def SReg_32_XM0_XEXEC : RegisterClass<"AMDGPU", [i32, f32, i16, f16, v2i16, v2f16], 32, (add SGPR_32, VCC_LO, VCC_HI, FLAT_SCR_LO, FLAT_SCR_HI, TTMP_32, TMA_LO, TMA_HI, TBA_LO, TBA_HI, SRC_SHARED_BASE, SRC_SHARED_LIMIT, - SRC_PRIVATE_BASE, SRC_PRIVATE_LIMIT, - FP_REG, SP_REG, SCRATCH_WAVE_OFFSET_REG)> { + SRC_PRIVATE_BASE, SRC_PRIVATE_LIMIT)> { let AllocationPriority = 7; } diff --git a/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp b/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp index 0d021d67033e..0a72a4438218 100644 --- a/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp +++ b/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp @@ -61,14 +61,6 @@ static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) { case Sparc::fixup_sparc_lo10: return Value & 0x3ff; - case Sparc::fixup_sparc_tls_ldo_hix22: - case Sparc::fixup_sparc_tls_le_hix22: - return (~Value >> 10) & 0x3fffff; - - case Sparc::fixup_sparc_tls_ldo_lox10: - case Sparc::fixup_sparc_tls_le_lox10: - return (~(~Value & 0x3ff)) & 0x1fff; - case Sparc::fixup_sparc_h44: return (Value >> 22) & 0x3fffff; @@ -84,6 +76,13 @@ static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) { case Sparc::fixup_sparc_hm: return (Value >> 32) & 0x3ff; + case Sparc::fixup_sparc_tls_ldo_hix22: + case Sparc::fixup_sparc_tls_le_hix22: + case Sparc::fixup_sparc_tls_ldo_lox10: + case Sparc::fixup_sparc_tls_le_lox10: + assert(Value == 0 && "Sparc TLS relocs expect zero Value"); + return 0; + case Sparc::fixup_sparc_tls_gd_add: case Sparc::fixup_sparc_tls_gd_call: case Sparc::fixup_sparc_tls_ldm_add: diff --git a/lib/Target/SystemZ/SystemZScheduleZ14.td b/lib/Target/SystemZ/SystemZScheduleZ14.td index f11177af91a5..698eb5627d19 100644 --- a/lib/Target/SystemZ/SystemZScheduleZ14.td +++ b/lib/Target/SystemZ/SystemZScheduleZ14.td @@ -455,10 +455,10 @@ def : InstRW<[FXa, LSU, Lat8], (instregex "MH(Y)?$")>; def : InstRW<[FXa2, Lat6, GroupAlone], (instregex "M(L)?R$")>; def : InstRW<[FXa2, LSU, Lat10, GroupAlone], (instregex "M(FY|L)?$")>; def : InstRW<[FXa, LSU, Lat8], (instregex "MGH$")>; -def : InstRW<[FXa, LSU, Lat12, GroupAlone], (instregex "MG$")>; -def : InstRW<[FXa, Lat8, GroupAlone], (instregex "MGRK$")>; -def : InstRW<[FXa, LSU, Lat9, GroupAlone], (instregex "MSC$")>; -def : InstRW<[FXa, LSU, Lat11, GroupAlone], (instregex "MSGC$")>; +def : InstRW<[FXa, FXa, LSU, Lat12, GroupAlone], (instregex "MG$")>; +def : InstRW<[FXa, FXa, Lat8, GroupAlone], (instregex "MGRK$")>; +def : InstRW<[FXa, LSU, Lat9], (instregex "MSC$")>; +def : InstRW<[FXa, LSU, Lat11], (instregex "MSGC$")>; def : InstRW<[FXa, Lat5], (instregex "MSRKC$")>; def : InstRW<[FXa, Lat7], (instregex "MSGRKC$")>; @@ -620,7 +620,7 @@ def : InstRW<[FXa, Lat30], (instregex "(PCC|PPNO|PRNO)$")>; def : InstRW<[LSU], (instregex "LGG$")>; def : InstRW<[LSU, Lat5], (instregex "LLGFSG$")>; -def : InstRW<[LSU, Lat30, GroupAlone], (instregex "(L|ST)GSC$")>; +def : InstRW<[LSU, Lat30], (instregex "(L|ST)GSC$")>; //===----------------------------------------------------------------------===// // Decimal arithmetic @@ -708,7 +708,7 @@ def : InstRW<[FXb, LSU, Lat5], (instregex "NTSTG$")>; // Processor assist //===----------------------------------------------------------------------===// -def : InstRW<[FXb], (instregex "PPA$")>; +def : InstRW<[FXb, GroupAlone], (instregex "PPA$")>; //===----------------------------------------------------------------------===// // Miscellaneous Instructions. @@ -1276,9 +1276,9 @@ def : InstRW<[VecXsPm], (instregex "VESRL(B|F|G|H)?$")>; def : InstRW<[VecXsPm], (instregex "VESRLV(B|F|G|H)?$")>; def : InstRW<[VecXsPm], (instregex "VSL(DB)?$")>; -def : InstRW<[VecXsPm, VecXsPm, Lat8], (instregex "VSLB$")>; +def : InstRW<[VecXsPm], (instregex "VSLB$")>; def : InstRW<[VecXsPm], (instregex "VSR(A|L)$")>; -def : InstRW<[VecXsPm, VecXsPm, Lat8], (instregex "VSR(A|L)B$")>; +def : InstRW<[VecXsPm], (instregex "VSR(A|L)B$")>; def : InstRW<[VecXsPm], (instregex "VSB(I|IQ|CBI|CBIQ)?$")>; def : InstRW<[VecXsPm], (instregex "VSCBI(B|F|G|H|Q)?$")>; @@ -1435,9 +1435,9 @@ def : InstRW<[VecStr, Lat5], (instregex "VSTRCZ(B|F|H)S$")>; // Vector: Packed-decimal instructions //===----------------------------------------------------------------------===// -def : InstRW<[VecDF, VecDF, Lat10, GroupAlone], (instregex "VLIP$")>; -def : InstRW<[VecDFX, LSU, Lat12, GroupAlone], (instregex "VPKZ$")>; -def : InstRW<[VecDFX, FXb, LSU, Lat12, GroupAlone], (instregex "VUPKZ$")>; +def : InstRW<[VecDF, VecDF, Lat10], (instregex "VLIP$")>; +def : InstRW<[VecDFX, LSU, GroupAlone], (instregex "VPKZ$")>; +def : InstRW<[VecDFX, FXb, LSU, Lat12, BeginGroup], (instregex "VUPKZ$")>; def : InstRW<[VecDF, VecDF, FXb, Lat20, GroupAlone], (instregex "VCVB(G)?$")>; def : InstRW<[VecDF, VecDF, FXb, Lat20, GroupAlone], (instregex "VCVD(G)?$")>; def : InstRW<[VecDFX], (instregex "V(A|S)P$")>; diff --git a/lib/Target/X86/X86ISelDAGToDAG.cpp b/lib/Target/X86/X86ISelDAGToDAG.cpp index 3c4589ab18f6..8f24f98be681 100644 --- a/lib/Target/X86/X86ISelDAGToDAG.cpp +++ b/lib/Target/X86/X86ISelDAGToDAG.cpp @@ -1055,7 +1055,10 @@ static bool foldMaskAndShiftToScale(SelectionDAG &DAG, SDValue N, // Scale the leading zero count down based on the actual size of the value. // Also scale it down based on the size of the shift. - MaskLZ -= (64 - X.getSimpleValueType().getSizeInBits()) + ShiftAmt; + unsigned ScaleDown = (64 - X.getSimpleValueType().getSizeInBits()) + ShiftAmt; + if (MaskLZ < ScaleDown) + return true; + MaskLZ -= ScaleDown; // The final check is to ensure that any masked out high bits of X are // already known to be zero. Otherwise, the mask has a semantic impact diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index 44eecd664714..ba8eb8656585 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -1672,8 +1672,8 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM, // TODO: These control memcmp expansion in CGP and could be raised higher, but // that needs to benchmarked and balanced with the potential use of vector - // load/store types (PR33329). - MaxLoadsPerMemcmp = 4; + // load/store types (PR33329, PR33914). + MaxLoadsPerMemcmp = 2; MaxLoadsPerMemcmpOptSize = 2; // Set loop alignment to 2^ExperimentalPrefLoopAlignment bytes (default: 2^4). @@ -22022,8 +22022,9 @@ static SDValue LowerScalarImmediateShift(SDValue Op, SelectionDAG &DAG, return getTargetVShiftByConstNode(X86Opc, dl, VT, R, ShiftAmt, DAG); // i64 SRA needs to be performed as partial shifts. - if ((VT == MVT::v2i64 || (Subtarget.hasInt256() && VT == MVT::v4i64)) && - Op.getOpcode() == ISD::SRA && !Subtarget.hasXOP()) + if (((!Subtarget.hasXOP() && VT == MVT::v2i64) || + (Subtarget.hasInt256() && VT == MVT::v4i64)) && + Op.getOpcode() == ISD::SRA) return ArithmeticShiftRight64(ShiftAmt); if (VT == MVT::v16i8 || diff --git a/lib/Transforms/Scalar/JumpThreading.cpp b/lib/Transforms/Scalar/JumpThreading.cpp index 4056cc5cb346..dc9143bebc45 100644 --- a/lib/Transforms/Scalar/JumpThreading.cpp +++ b/lib/Transforms/Scalar/JumpThreading.cpp @@ -64,6 +64,11 @@ ImplicationSearchThreshold( "condition to use to thread over a weaker condition"), cl::init(3), cl::Hidden); +static cl::opt PrintLVIAfterJumpThreading( + "print-lvi-after-jump-threading", + cl::desc("Print the LazyValueInfo cache after JumpThreading"), cl::init(false), + cl::Hidden); + namespace { /// This pass performs 'jump threading', which looks at blocks that have /// multiple predecessors and multiple successors. If one or more of the @@ -93,9 +98,10 @@ namespace { bool runOnFunction(Function &F) override; void getAnalysisUsage(AnalysisUsage &AU) const override { + if (PrintLVIAfterJumpThreading) + AU.addRequired(); AU.addRequired(); AU.addRequired(); - AU.addPreserved(); AU.addPreserved(); AU.addRequired(); } @@ -137,8 +143,14 @@ bool JumpThreading::runOnFunction(Function &F) { BFI.reset(new BlockFrequencyInfo(F, *BPI, LI)); } - return Impl.runImpl(F, TLI, LVI, AA, HasProfileData, std::move(BFI), - std::move(BPI)); + bool Changed = Impl.runImpl(F, TLI, LVI, AA, HasProfileData, std::move(BFI), + std::move(BPI)); + if (PrintLVIAfterJumpThreading) { + dbgs() << "LVI for function '" << F.getName() << "':\n"; + LVI->printLVI(F, getAnalysis().getDomTree(), + dbgs()); + } + return Changed; } PreservedAnalyses JumpThreadingPass::run(Function &F, @@ -231,13 +243,15 @@ bool JumpThreadingPass::runImpl(Function &F, TargetLibraryInfo *TLI_, // Can't thread an unconditional jump, but if the block is "almost // empty", we can replace uses of it with uses of the successor and make // this dead. - // We should not eliminate the loop header either, because eliminating - // a loop header might later prevent LoopSimplify from transforming nested - // loops into simplified form. + // We should not eliminate the loop header or latch either, because + // eliminating a loop header or latch might later prevent LoopSimplify + // from transforming nested loops into simplified form. We will rely on + // later passes in backend to clean up empty blocks. if (BI && BI->isUnconditional() && BB != &BB->getParent()->getEntryBlock() && // If the terminator is the only non-phi instruction, try to nuke it. - BB->getFirstNonPHIOrDbg()->isTerminator() && !LoopHeaders.count(BB)) { + BB->getFirstNonPHIOrDbg()->isTerminator() && !LoopHeaders.count(BB) && + !LoopHeaders.count(BI->getSuccessor(0))) { // FIXME: It is always conservatively correct to drop the info // for a block even if it doesn't get erased. This isn't totally // awesome, but it allows us to use AssertingVH to prevent nasty diff --git a/lib/Transforms/Utils/LoopUtils.cpp b/lib/Transforms/Utils/LoopUtils.cpp index 58b70be95d99..3c522786641a 100644 --- a/lib/Transforms/Utils/LoopUtils.cpp +++ b/lib/Transforms/Utils/LoopUtils.cpp @@ -1376,16 +1376,21 @@ Value *llvm::createTargetReduction(IRBuilder<> &Builder, } } -void llvm::propagateIRFlags(Value *I, ArrayRef VL) { - if (auto *VecOp = dyn_cast(I)) { - if (auto *I0 = dyn_cast(VL[0])) { - // VecOVp is initialized to the 0th scalar, so start counting from index - // '1'. - VecOp->copyIRFlags(I0); - for (int i = 1, e = VL.size(); i < e; ++i) { - if (auto *Scalar = dyn_cast(VL[i])) - VecOp->andIRFlags(Scalar); - } - } +void llvm::propagateIRFlags(Value *I, ArrayRef VL, Value *OpValue) { + auto *VecOp = dyn_cast(I); + if (!VecOp) + return; + auto *Intersection = (OpValue == nullptr) ? dyn_cast(VL[0]) + : dyn_cast(OpValue); + if (!Intersection) + return; + const unsigned Opcode = Intersection->getOpcode(); + VecOp->copyIRFlags(Intersection); + for (auto *V : VL) { + auto *Instr = dyn_cast(V); + if (!Instr) + continue; + if (OpValue == nullptr || Opcode == Instr->getOpcode()) + VecOp->andIRFlags(V); } } diff --git a/lib/Transforms/Utils/SimplifyCFG.cpp b/lib/Transforms/Utils/SimplifyCFG.cpp index dee658f98393..8784b9702141 100644 --- a/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/lib/Transforms/Utils/SimplifyCFG.cpp @@ -5656,20 +5656,22 @@ static bool TryToMergeLandingPad(LandingPadInst *LPad, BranchInst *BI, bool SimplifyCFGOpt::SimplifyUncondBranch(BranchInst *BI, IRBuilder<> &Builder) { BasicBlock *BB = BI->getParent(); + BasicBlock *Succ = BI->getSuccessor(0); if (SinkCommon && SinkThenElseCodeToEnd(BI)) return true; // If the Terminator is the only non-phi instruction, simplify the block. - // if LoopHeader is provided, check if the block is a loop header - // (This is for early invocations before loop simplify and vectorization - // to keep canonical loop forms for nested loops. - // These blocks can be eliminated when the pass is invoked later - // in the back-end.) + // if LoopHeader is provided, check if the block or its successor is a loop + // header (This is for early invocations before loop simplify and + // vectorization to keep canonical loop forms for nested loops. These blocks + // can be eliminated when the pass is invoked later in the back-end.) + bool NeedCanonicalLoop = + !LateSimplifyCFG && + (LoopHeaders && (LoopHeaders->count(BB) || LoopHeaders->count(Succ))); BasicBlock::iterator I = BB->getFirstNonPHIOrDbg()->getIterator(); if (I->isTerminator() && BB != &BB->getParent()->getEntryBlock() && - (!LoopHeaders || !LoopHeaders->count(BB)) && - TryToSimplifyUncondBranchFromEmptyBlock(BB)) + !NeedCanonicalLoop && TryToSimplifyUncondBranchFromEmptyBlock(BB)) return true; // If the only instruction in the block is a seteq/setne comparison diff --git a/test/Analysis/LazyValueAnalysis/lvi-after-jumpthreading.ll b/test/Analysis/LazyValueAnalysis/lvi-after-jumpthreading.ll index e797b377556e..41bb8c9c8201 100644 --- a/test/Analysis/LazyValueAnalysis/lvi-after-jumpthreading.ll +++ b/test/Analysis/LazyValueAnalysis/lvi-after-jumpthreading.ll @@ -1,4 +1,4 @@ -; RUN: opt < %s -jump-threading -print-lazy-value-info -disable-output 2>&1 | FileCheck %s +; RUN: opt < %s -jump-threading -print-lvi-after-jump-threading -disable-output 2>&1 | FileCheck %s ; Testing LVI cache after jump-threading @@ -19,13 +19,10 @@ entry: ; CHECK-NEXT: ; LatticeVal for: 'i32 %a' is: overdefined ; CHECK-NEXT: ; LatticeVal for: 'i32 %length' is: overdefined ; CHECK-NEXT: ; LatticeVal for: ' %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]' in BB: '%backedge' is: constantrange<0, 400> -; CHECK-NEXT: ; LatticeVal for: ' %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]' in BB: '%exit' is: constantrange<399, 400> ; CHECK-NEXT: %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ] ; CHECK-NEXT: ; LatticeVal for: ' %iv.next = add nsw i32 %iv, 1' in BB: '%backedge' is: constantrange<1, 401> -; CHECK-NEXT: ; LatticeVal for: ' %iv.next = add nsw i32 %iv, 1' in BB: '%exit' is: constantrange<400, 401> ; CHECK-NEXT: %iv.next = add nsw i32 %iv, 1 ; CHECK-NEXT: ; LatticeVal for: ' %cont = icmp slt i32 %iv.next, 400' in BB: '%backedge' is: overdefined -; CHECK-NEXT: ; LatticeVal for: ' %cont = icmp slt i32 %iv.next, 400' in BB: '%exit' is: constantrange<0, -1> ; CHECK-NEXT: %cont = icmp slt i32 %iv.next, 400 ; CHECK-NOT: loop loop: diff --git a/test/CodeGen/AArch64/aarch64-loop-gep-opt.ll b/test/CodeGen/AArch64/aarch64-loop-gep-opt.ll index 1b2ed4b89521..2b4e438a13aa 100644 --- a/test/CodeGen/AArch64/aarch64-loop-gep-opt.ll +++ b/test/CodeGen/AArch64/aarch64-loop-gep-opt.ll @@ -19,9 +19,9 @@ entry: do.body.i: ; CHECK-LABEL: do.body.i: -; CHECK: %uglygep2 = getelementptr i8, i8* %uglygep, i64 %3 -; CHECK-NEXT: %4 = bitcast i8* %uglygep2 to i32* -; CHECK-NOT: %uglygep2 = getelementptr i8, i8* %uglygep, i64 1032 +; CHECK: %uglygep1 = getelementptr i8, i8* %uglygep, i64 %3 +; CHECK-NEXT: %4 = bitcast i8* %uglygep1 to i32* +; CHECK-NOT: %uglygep1 = getelementptr i8, i8* %uglygep, i64 1032 %0 = phi i32 [ 256, %entry ], [ %.be, %do.body.i.backedge ] diff --git a/test/CodeGen/AArch64/aarch64_win64cc_vararg.ll b/test/CodeGen/AArch64/aarch64_win64cc_vararg.ll index 2546e7c90ce5..89efe335e329 100644 --- a/test/CodeGen/AArch64/aarch64_win64cc_vararg.ll +++ b/test/CodeGen/AArch64/aarch64_win64cc_vararg.ll @@ -59,10 +59,12 @@ entry: } ; CHECK-LABEL: f7: -; CHECK: sub sp, sp, #16 -; CHECK: add x8, sp, #8 -; CHECK: add x0, sp, #8 -; CHECK: stp x8, x7, [sp], #16 +; CHECK: sub sp, sp, #32 +; CHECK: add x8, sp, #24 +; CHECK: str x7, [sp, #24] +; CHECK: add x0, sp, #24 +; CHECK: str x8, [sp, #8] +; CHECK: add sp, sp, #32 ; CHECK: ret define win64cc i8* @f7(i64 %a0, i64 %a1, i64 %a2, i64 %a3, i64 %a4, i64 %a5, i64 %a6, ...) nounwind { entry: diff --git a/test/CodeGen/AArch64/win64_vararg.ll b/test/CodeGen/AArch64/win64_vararg.ll index b760e4acd16a..3acc7e520c96 100644 --- a/test/CodeGen/AArch64/win64_vararg.ll +++ b/test/CodeGen/AArch64/win64_vararg.ll @@ -59,10 +59,12 @@ entry: } ; CHECK-LABEL: f7: -; CHECK: sub sp, sp, #16 -; CHECK: add x8, sp, #8 -; CHECK: add x0, sp, #8 -; CHECK: stp x8, x7, [sp], #16 +; CHECK: sub sp, sp, #32 +; CHECK: add x8, sp, #24 +; CHECK: str x7, [sp, #24] +; CHECK: add x0, sp, #24 +; CHECK: str x8, [sp, #8] +; CHECK: add sp, sp, #32 ; CHECK: ret define i8* @f7(i64 %a0, i64 %a1, i64 %a2, i64 %a3, i64 %a4, i64 %a5, i64 %a6, ...) nounwind { entry: @@ -79,9 +81,8 @@ entry: ; CHECK: stp x6, x7, [sp, #64] ; CHECK: stp x4, x5, [sp, #48] ; CHECK: stp x2, x3, [sp, #32] -; CHECK: stp x8, x1, [sp, #16] -; CHECK: str x8, [sp, #8] -; CHECK: add sp, sp, #80 +; CHECK: str x1, [sp, #24] +; CHECK: stp x8, x8, [sp], #80 ; CHECK: ret define void @copy1(i64 %a0, ...) nounwind { entry: @@ -93,3 +94,54 @@ entry: call void @llvm.va_copy(i8* %cp1, i8* %ap1) ret void } + +declare void @llvm.va_end(i8*) +declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #1 +declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #1 + +declare i32 @__stdio_common_vsprintf(i64, i8*, i64, i8*, i8*, i8*) local_unnamed_addr #3 +declare i64* @__local_stdio_printf_options() local_unnamed_addr #4 + +; CHECK-LABEL: snprintf +; CHECK: sub sp, sp, #96 +; CHECK: stp x21, x20, [sp, #16] +; CHECK: stp x19, x30, [sp, #32] +; CHECK: add x8, sp, #56 +; CHECK: mov x19, x2 +; CHECK: mov x20, x1 +; CHECK: mov x21, x0 +; CHECK: stp x6, x7, [sp, #80] +; CHECK: stp x4, x5, [sp, #64] +; CHECK: str x3, [sp, #56] +; CHECK: str x8, [sp, #8] +; CHECK: bl __local_stdio_printf_options +; CHECK: ldr x8, [x0] +; CHECK: add x5, sp, #56 +; CHECK: mov x1, x21 +; CHECK: mov x2, x20 +; CHECK: orr x0, x8, #0x2 +; CHECK: mov x3, x19 +; CHECK: mov x4, xzr +; CHECK: bl __stdio_common_vsprintf +; CHECK: ldp x19, x30, [sp, #32] +; CHECK: ldp x21, x20, [sp, #16] +; CHECK: cmp w0, #0 +; CHECK: csinv w0, w0, wzr, ge +; CHECK: add sp, sp, #96 +; CHECK: ret +define i32 @snprintf(i8*, i64, i8*, ...) local_unnamed_addr #5 { + %4 = alloca i8*, align 8 + %5 = bitcast i8** %4 to i8* + call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %5) #2 + call void @llvm.va_start(i8* nonnull %5) + %6 = load i8*, i8** %4, align 8 + %7 = call i64* @__local_stdio_printf_options() #2 + %8 = load i64, i64* %7, align 8 + %9 = or i64 %8, 2 + %10 = call i32 @__stdio_common_vsprintf(i64 %9, i8* %0, i64 %1, i8* %2, i8* null, i8* %6) #2 + %11 = icmp sgt i32 %10, -1 + %12 = select i1 %11, i32 %10, i32 -1 + call void @llvm.va_end(i8* nonnull %5) + call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %5) #2 + ret i32 %12 +} diff --git a/test/CodeGen/AMDGPU/spill-empty-live-interval.mir b/test/CodeGen/AMDGPU/spill-empty-live-interval.mir new file mode 100644 index 000000000000..bb58da7a59f6 --- /dev/null +++ b/test/CodeGen/AMDGPU/spill-empty-live-interval.mir @@ -0,0 +1,74 @@ +# RUN: llc -mtriple=amdgcn-amd-amdhsa-opencl -verify-machineinstrs -stress-regalloc=1 -start-before=simple-register-coalescing -stop-after=greedy -o - %s | FileCheck %s +# https://bugs.llvm.org/show_bug.cgi?id=33620 + +--- +# This would assert due to the empty live interval created for %vreg9 +# on the last S_NOP with an undef subreg use. + +# CHECK-LABEL: name: expecting_non_empty_interval + +# CHECK: undef %7.sub1 = V_MAC_F32_e32 0, undef %1, undef %7.sub1, implicit %exec +# CHECK-NEXT: SI_SPILL_V64_SAVE %7, %stack.0, %sgpr0_sgpr1_sgpr2_sgpr3, %sgpr5, 0, implicit %exec :: (store 8 into %stack.0, align 4) +# CHECK-NEXT: undef %5.sub1 = V_MOV_B32_e32 1786773504, implicit %exec +# CHECK-NEXT: dead %2 = V_MUL_F32_e32 0, %5.sub1, implicit %exec + +# CHECK: S_NOP 0, implicit %6.sub1 +# CHECK-NEXT: %8 = SI_SPILL_V64_RESTORE %stack.0, %sgpr0_sgpr1_sgpr2_sgpr3, %sgpr5, 0, implicit %exec :: (load 8 from %stack.0, align 4) +# CHECK-NEXT: S_NOP 0, implicit %8.sub1 +# CHECK-NEXT: S_NOP 0, implicit undef %9.sub0 + +name: expecting_non_empty_interval +tracksRegLiveness: true +registers: + - { id: 0, class: vreg_64, preferred-register: '' } + - { id: 1, class: vgpr_32, preferred-register: '' } + - { id: 2, class: vgpr_32, preferred-register: '' } + - { id: 3, class: vreg_64, preferred-register: '' } +body: | + bb.0: + successors: %bb.1 + undef %0.sub1 = V_MAC_F32_e32 0, undef %1, undef %0.sub1, implicit %exec + undef %3.sub1 = V_MOV_B32_e32 1786773504, implicit %exec + dead %2 = V_MUL_F32_e32 0, %3.sub1, implicit %exec + + bb.1: + S_NOP 0, implicit %3.sub1 + S_NOP 0, implicit %0.sub1 + S_NOP 0, implicit undef %0.sub0 + S_ENDPGM + +... + +# Similar assert which happens when trying to rematerialize. +# https://bugs.llvm.org/show_bug.cgi?id=33884 +--- +# CHECK-LABEL: name: rematerialize_empty_interval_has_reference + +# CHECK-NOT: MOV +# CHECK: undef %3.sub2 = V_MOV_B32_e32 1786773504, implicit %exec + +# CHECK: bb.1: +# CHECK-NEXT: S_NOP 0, implicit %3.sub2 +# CHECK-NEXT: S_NOP 0, implicit undef %6.sub0 +# CHECK-NEXT: undef %4.sub2 = V_MOV_B32_e32 0, implicit %exec +# CHECK-NEXT: S_NOP 0, implicit %4.sub2 +name: rematerialize_empty_interval_has_reference +tracksRegLiveness: true +registers: + - { id: 0, class: vreg_128, preferred-register: '' } + - { id: 1, class: vgpr_32, preferred-register: '' } + - { id: 2, class: vgpr_32, preferred-register: '' } + - { id: 3, class: vreg_128, preferred-register: '' } +body: | + bb.0: + successors: %bb.1 + + undef %0.sub2 = V_MOV_B32_e32 0, implicit %exec + undef %3.sub2 = V_MOV_B32_e32 1786773504, implicit %exec + + bb.1: + S_NOP 0, implicit %3.sub2 + S_NOP 0, implicit undef %0.sub0 + S_NOP 0, implicit %0.sub2 + +... diff --git a/test/CodeGen/X86/memcmp-minsize.ll b/test/CodeGen/X86/memcmp-minsize.ll index a7f42644ca2d..a55c40f5bda8 100644 --- a/test/CodeGen/X86/memcmp-minsize.ll +++ b/test/CodeGen/X86/memcmp-minsize.ll @@ -527,6 +527,93 @@ define i1 @length16_eq_const(i8* %X) nounwind minsize { ret i1 %c } +; PR33914 - https://bugs.llvm.org/show_bug.cgi?id=33914 + +define i32 @length24(i8* %X, i8* %Y) nounwind minsize { +; X86-LABEL: length24: +; X86: # BB#0: +; X86-NEXT: subl $16, %esp +; X86-NEXT: movl {{[0-9]+}}(%esp), %eax +; X86-NEXT: movl {{[0-9]+}}(%esp), %ecx +; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp) +; X86-NEXT: movl %eax, (%esp) +; X86-NEXT: andl $0, {{[0-9]+}}(%esp) +; X86-NEXT: movl $24, {{[0-9]+}}(%esp) +; X86-NEXT: calll memcmp +; X86-NEXT: addl $16, %esp +; X86-NEXT: retl +; +; X64-LABEL: length24: +; X64: # BB#0: +; X64-NEXT: pushq $24 +; X64-NEXT: popq %rdx +; X64-NEXT: jmp memcmp # TAILCALL + %m = tail call i32 @memcmp(i8* %X, i8* %Y, i64 24) nounwind + ret i32 %m +} + +define i1 @length24_eq(i8* %x, i8* %y) nounwind minsize { +; X86-LABEL: length24_eq: +; X86: # BB#0: +; X86-NEXT: subl $16, %esp +; X86-NEXT: movl {{[0-9]+}}(%esp), %eax +; X86-NEXT: movl {{[0-9]+}}(%esp), %ecx +; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp) +; X86-NEXT: movl %eax, (%esp) +; X86-NEXT: andl $0, {{[0-9]+}}(%esp) +; X86-NEXT: movl $24, {{[0-9]+}}(%esp) +; X86-NEXT: calll memcmp +; X86-NEXT: testl %eax, %eax +; X86-NEXT: sete %al +; X86-NEXT: addl $16, %esp +; X86-NEXT: retl +; +; X64-LABEL: length24_eq: +; X64: # BB#0: +; X64-NEXT: pushq %rax +; X64-NEXT: pushq $24 +; X64-NEXT: popq %rdx +; X64-NEXT: callq memcmp +; X64-NEXT: testl %eax, %eax +; X64-NEXT: sete %al +; X64-NEXT: popq %rcx +; X64-NEXT: retq + %call = tail call i32 @memcmp(i8* %x, i8* %y, i64 24) nounwind + %cmp = icmp eq i32 %call, 0 + ret i1 %cmp +} + +define i1 @length24_eq_const(i8* %X) nounwind minsize { +; X86-LABEL: length24_eq_const: +; X86: # BB#0: +; X86-NEXT: subl $16, %esp +; X86-NEXT: movl {{[0-9]+}}(%esp), %eax +; X86-NEXT: movl %eax, (%esp) +; X86-NEXT: andl $0, {{[0-9]+}}(%esp) +; X86-NEXT: movl $24, {{[0-9]+}}(%esp) +; X86-NEXT: movl $.L.str, {{[0-9]+}}(%esp) +; X86-NEXT: calll memcmp +; X86-NEXT: testl %eax, %eax +; X86-NEXT: setne %al +; X86-NEXT: addl $16, %esp +; X86-NEXT: retl +; +; X64-LABEL: length24_eq_const: +; X64: # BB#0: +; X64-NEXT: pushq %rax +; X64-NEXT: pushq $24 +; X64-NEXT: popq %rdx +; X64-NEXT: movl $.L.str, %esi +; X64-NEXT: callq memcmp +; X64-NEXT: testl %eax, %eax +; X64-NEXT: setne %al +; X64-NEXT: popq %rcx +; X64-NEXT: retq + %m = tail call i32 @memcmp(i8* %X, i8* getelementptr inbounds ([65 x i8], [65 x i8]* @.str, i32 0, i32 0), i64 24) nounwind + %c = icmp ne i32 %m, 0 + ret i1 %c +} + define i32 @length32(i8* %X, i8* %Y) nounwind minsize { ; X86-LABEL: length32: ; X86: # BB#0: diff --git a/test/CodeGen/X86/memcmp-optsize.ll b/test/CodeGen/X86/memcmp-optsize.ll index 450205a966d2..4a5f30890513 100644 --- a/test/CodeGen/X86/memcmp-optsize.ll +++ b/test/CodeGen/X86/memcmp-optsize.ll @@ -699,6 +699,82 @@ define i1 @length16_eq_const(i8* %X) nounwind optsize { ret i1 %c } +; PR33914 - https://bugs.llvm.org/show_bug.cgi?id=33914 + +define i32 @length24(i8* %X, i8* %Y) nounwind optsize { +; X86-LABEL: length24: +; X86: # BB#0: +; X86-NEXT: pushl $0 +; X86-NEXT: pushl $24 +; X86-NEXT: pushl {{[0-9]+}}(%esp) +; X86-NEXT: pushl {{[0-9]+}}(%esp) +; X86-NEXT: calll memcmp +; X86-NEXT: addl $16, %esp +; X86-NEXT: retl +; +; X64-LABEL: length24: +; X64: # BB#0: +; X64-NEXT: movl $24, %edx +; X64-NEXT: jmp memcmp # TAILCALL + %m = tail call i32 @memcmp(i8* %X, i8* %Y, i64 24) nounwind + ret i32 %m +} + +define i1 @length24_eq(i8* %x, i8* %y) nounwind optsize { +; X86-LABEL: length24_eq: +; X86: # BB#0: +; X86-NEXT: pushl $0 +; X86-NEXT: pushl $24 +; X86-NEXT: pushl {{[0-9]+}}(%esp) +; X86-NEXT: pushl {{[0-9]+}}(%esp) +; X86-NEXT: calll memcmp +; X86-NEXT: addl $16, %esp +; X86-NEXT: testl %eax, %eax +; X86-NEXT: sete %al +; X86-NEXT: retl +; +; X64-LABEL: length24_eq: +; X64: # BB#0: +; X64-NEXT: pushq %rax +; X64-NEXT: movl $24, %edx +; X64-NEXT: callq memcmp +; X64-NEXT: testl %eax, %eax +; X64-NEXT: sete %al +; X64-NEXT: popq %rcx +; X64-NEXT: retq + %call = tail call i32 @memcmp(i8* %x, i8* %y, i64 24) nounwind + %cmp = icmp eq i32 %call, 0 + ret i1 %cmp +} + +define i1 @length24_eq_const(i8* %X) nounwind optsize { +; X86-LABEL: length24_eq_const: +; X86: # BB#0: +; X86-NEXT: pushl $0 +; X86-NEXT: pushl $24 +; X86-NEXT: pushl $.L.str +; X86-NEXT: pushl {{[0-9]+}}(%esp) +; X86-NEXT: calll memcmp +; X86-NEXT: addl $16, %esp +; X86-NEXT: testl %eax, %eax +; X86-NEXT: setne %al +; X86-NEXT: retl +; +; X64-LABEL: length24_eq_const: +; X64: # BB#0: +; X64-NEXT: pushq %rax +; X64-NEXT: movl $.L.str, %esi +; X64-NEXT: movl $24, %edx +; X64-NEXT: callq memcmp +; X64-NEXT: testl %eax, %eax +; X64-NEXT: setne %al +; X64-NEXT: popq %rcx +; X64-NEXT: retq + %m = tail call i32 @memcmp(i8* %X, i8* getelementptr inbounds ([65 x i8], [65 x i8]* @.str, i32 0, i32 0), i64 24) nounwind + %c = icmp ne i32 %m, 0 + ret i1 %c +} + define i32 @length32(i8* %X, i8* %Y) nounwind optsize { ; X86-LABEL: length32: ; X86: # BB#0: diff --git a/test/CodeGen/X86/memcmp.ll b/test/CodeGen/X86/memcmp.ll index 2e6782765462..889f6a74bf7f 100644 --- a/test/CodeGen/X86/memcmp.ll +++ b/test/CodeGen/X86/memcmp.ll @@ -475,25 +475,14 @@ define i1 @length8_eq_const(i8* %X) nounwind { define i1 @length12_eq(i8* %X, i8* %Y) nounwind { ; X86-LABEL: length12_eq: -; X86: # BB#0: # %loadbb -; X86-NEXT: movl {{[0-9]+}}(%esp), %eax -; X86-NEXT: movl {{[0-9]+}}(%esp), %ecx -; X86-NEXT: movl (%ecx), %edx -; X86-NEXT: cmpl (%eax), %edx -; X86-NEXT: jne .LBB14_1 -; X86-NEXT: # BB#2: # %loadbb1 -; X86-NEXT: movl 4(%ecx), %edx -; X86-NEXT: cmpl 4(%eax), %edx -; X86-NEXT: jne .LBB14_1 -; X86-NEXT: # BB#3: # %loadbb2 -; X86-NEXT: movl 8(%ecx), %edx -; X86-NEXT: xorl %ecx, %ecx -; X86-NEXT: cmpl 8(%eax), %edx -; X86-NEXT: je .LBB14_4 -; X86-NEXT: .LBB14_1: # %res_block -; X86-NEXT: movl $1, %ecx -; X86-NEXT: .LBB14_4: # %endblock -; X86-NEXT: testl %ecx, %ecx +; X86: # BB#0: +; X86-NEXT: pushl $0 +; X86-NEXT: pushl $12 +; X86-NEXT: pushl {{[0-9]+}}(%esp) +; X86-NEXT: pushl {{[0-9]+}}(%esp) +; X86-NEXT: calll memcmp +; X86-NEXT: addl $16, %esp +; X86-NEXT: testl %eax, %eax ; X86-NEXT: setne %al ; X86-NEXT: retl ; @@ -520,40 +509,13 @@ define i1 @length12_eq(i8* %X, i8* %Y) nounwind { define i32 @length12(i8* %X, i8* %Y) nounwind { ; X86-LABEL: length12: -; X86: # BB#0: # %loadbb -; X86-NEXT: pushl %esi -; X86-NEXT: movl {{[0-9]+}}(%esp), %eax -; X86-NEXT: movl {{[0-9]+}}(%esp), %esi -; X86-NEXT: movl (%esi), %ecx -; X86-NEXT: movl (%eax), %edx -; X86-NEXT: bswapl %ecx -; X86-NEXT: bswapl %edx -; X86-NEXT: cmpl %edx, %ecx -; X86-NEXT: jne .LBB15_1 -; X86-NEXT: # BB#2: # %loadbb1 -; X86-NEXT: movl 4(%esi), %ecx -; X86-NEXT: movl 4(%eax), %edx -; X86-NEXT: bswapl %ecx -; X86-NEXT: bswapl %edx -; X86-NEXT: cmpl %edx, %ecx -; X86-NEXT: jne .LBB15_1 -; X86-NEXT: # BB#3: # %loadbb2 -; X86-NEXT: movl 8(%esi), %ecx -; X86-NEXT: movl 8(%eax), %edx -; X86-NEXT: bswapl %ecx -; X86-NEXT: bswapl %edx -; X86-NEXT: xorl %eax, %eax -; X86-NEXT: cmpl %edx, %ecx -; X86-NEXT: jne .LBB15_1 -; X86-NEXT: # BB#4: # %endblock -; X86-NEXT: popl %esi -; X86-NEXT: retl -; X86-NEXT: .LBB15_1: # %res_block -; X86-NEXT: cmpl %edx, %ecx -; X86-NEXT: movl $-1, %ecx -; X86-NEXT: movl $1, %eax -; X86-NEXT: cmovbl %ecx, %eax -; X86-NEXT: popl %esi +; X86: # BB#0: +; X86-NEXT: pushl $0 +; X86-NEXT: pushl $12 +; X86-NEXT: pushl {{[0-9]+}}(%esp) +; X86-NEXT: pushl {{[0-9]+}}(%esp) +; X86-NEXT: calll memcmp +; X86-NEXT: addl $16, %esp ; X86-NEXT: retl ; ; X64-LABEL: length12: @@ -588,47 +550,13 @@ define i32 @length12(i8* %X, i8* %Y) nounwind { define i32 @length16(i8* %X, i8* %Y) nounwind { ; X86-LABEL: length16: -; X86: # BB#0: # %loadbb -; X86-NEXT: pushl %esi -; X86-NEXT: movl {{[0-9]+}}(%esp), %eax -; X86-NEXT: movl {{[0-9]+}}(%esp), %esi -; X86-NEXT: movl (%esi), %ecx -; X86-NEXT: movl (%eax), %edx -; X86-NEXT: bswapl %ecx -; X86-NEXT: bswapl %edx -; X86-NEXT: cmpl %edx, %ecx -; X86-NEXT: jne .LBB16_1 -; X86-NEXT: # BB#2: # %loadbb1 -; X86-NEXT: movl 4(%esi), %ecx -; X86-NEXT: movl 4(%eax), %edx -; X86-NEXT: bswapl %ecx -; X86-NEXT: bswapl %edx -; X86-NEXT: cmpl %edx, %ecx -; X86-NEXT: jne .LBB16_1 -; X86-NEXT: # BB#3: # %loadbb2 -; X86-NEXT: movl 8(%esi), %ecx -; X86-NEXT: movl 8(%eax), %edx -; X86-NEXT: bswapl %ecx -; X86-NEXT: bswapl %edx -; X86-NEXT: cmpl %edx, %ecx -; X86-NEXT: jne .LBB16_1 -; X86-NEXT: # BB#4: # %loadbb3 -; X86-NEXT: movl 12(%esi), %ecx -; X86-NEXT: movl 12(%eax), %edx -; X86-NEXT: bswapl %ecx -; X86-NEXT: bswapl %edx -; X86-NEXT: xorl %eax, %eax -; X86-NEXT: cmpl %edx, %ecx -; X86-NEXT: jne .LBB16_1 -; X86-NEXT: # BB#5: # %endblock -; X86-NEXT: popl %esi -; X86-NEXT: retl -; X86-NEXT: .LBB16_1: # %res_block -; X86-NEXT: cmpl %edx, %ecx -; X86-NEXT: movl $-1, %ecx -; X86-NEXT: movl $1, %eax -; X86-NEXT: cmovbl %ecx, %eax -; X86-NEXT: popl %esi +; X86: # BB#0: +; X86-NEXT: pushl $0 +; X86-NEXT: pushl $16 +; X86-NEXT: pushl {{[0-9]+}}(%esp) +; X86-NEXT: pushl {{[0-9]+}}(%esp) +; X86-NEXT: calll memcmp +; X86-NEXT: addl $16, %esp ; X86-NEXT: retl ; ; X64-LABEL: length16: @@ -660,32 +588,29 @@ define i32 @length16(i8* %X, i8* %Y) nounwind { } define i1 @length16_eq(i8* %x, i8* %y) nounwind { -; X86-LABEL: length16_eq: -; X86: # BB#0: # %loadbb -; X86-NEXT: movl {{[0-9]+}}(%esp), %eax -; X86-NEXT: movl {{[0-9]+}}(%esp), %ecx -; X86-NEXT: movl (%ecx), %edx -; X86-NEXT: cmpl (%eax), %edx -; X86-NEXT: jne .LBB17_1 -; X86-NEXT: # BB#2: # %loadbb1 -; X86-NEXT: movl 4(%ecx), %edx -; X86-NEXT: cmpl 4(%eax), %edx -; X86-NEXT: jne .LBB17_1 -; X86-NEXT: # BB#3: # %loadbb2 -; X86-NEXT: movl 8(%ecx), %edx -; X86-NEXT: cmpl 8(%eax), %edx -; X86-NEXT: jne .LBB17_1 -; X86-NEXT: # BB#4: # %loadbb3 -; X86-NEXT: movl 12(%ecx), %edx -; X86-NEXT: xorl %ecx, %ecx -; X86-NEXT: cmpl 12(%eax), %edx -; X86-NEXT: je .LBB17_5 -; X86-NEXT: .LBB17_1: # %res_block -; X86-NEXT: movl $1, %ecx -; X86-NEXT: .LBB17_5: # %endblock -; X86-NEXT: testl %ecx, %ecx -; X86-NEXT: setne %al -; X86-NEXT: retl +; X86-NOSSE-LABEL: length16_eq: +; X86-NOSSE: # BB#0: +; X86-NOSSE-NEXT: pushl $0 +; X86-NOSSE-NEXT: pushl $16 +; X86-NOSSE-NEXT: pushl {{[0-9]+}}(%esp) +; X86-NOSSE-NEXT: pushl {{[0-9]+}}(%esp) +; X86-NOSSE-NEXT: calll memcmp +; X86-NOSSE-NEXT: addl $16, %esp +; X86-NOSSE-NEXT: testl %eax, %eax +; X86-NOSSE-NEXT: setne %al +; X86-NOSSE-NEXT: retl +; +; X86-SSE2-LABEL: length16_eq: +; X86-SSE2: # BB#0: +; X86-SSE2-NEXT: movl {{[0-9]+}}(%esp), %eax +; X86-SSE2-NEXT: movl {{[0-9]+}}(%esp), %ecx +; X86-SSE2-NEXT: movdqu (%ecx), %xmm0 +; X86-SSE2-NEXT: movdqu (%eax), %xmm1 +; X86-SSE2-NEXT: pcmpeqb %xmm0, %xmm1 +; X86-SSE2-NEXT: pmovmskb %xmm1, %eax +; X86-SSE2-NEXT: cmpl $65535, %eax # imm = 0xFFFF +; X86-SSE2-NEXT: setne %al +; X86-SSE2-NEXT: retl ; ; X64-LABEL: length16_eq: ; X64: # BB#0: # %loadbb @@ -709,27 +634,27 @@ define i1 @length16_eq(i8* %x, i8* %y) nounwind { } define i1 @length16_eq_const(i8* %X) nounwind { -; X86-LABEL: length16_eq_const: -; X86: # BB#0: # %loadbb -; X86-NEXT: movl {{[0-9]+}}(%esp), %eax -; X86-NEXT: cmpl $858927408, (%eax) # imm = 0x33323130 -; X86-NEXT: jne .LBB18_1 -; X86-NEXT: # BB#2: # %loadbb1 -; X86-NEXT: cmpl $926299444, 4(%eax) # imm = 0x37363534 -; X86-NEXT: jne .LBB18_1 -; X86-NEXT: # BB#3: # %loadbb2 -; X86-NEXT: cmpl $825243960, 8(%eax) # imm = 0x31303938 -; X86-NEXT: jne .LBB18_1 -; X86-NEXT: # BB#4: # %loadbb3 -; X86-NEXT: xorl %ecx, %ecx -; X86-NEXT: cmpl $892613426, 12(%eax) # imm = 0x35343332 -; X86-NEXT: je .LBB18_5 -; X86-NEXT: .LBB18_1: # %res_block -; X86-NEXT: movl $1, %ecx -; X86-NEXT: .LBB18_5: # %endblock -; X86-NEXT: testl %ecx, %ecx -; X86-NEXT: sete %al -; X86-NEXT: retl +; X86-NOSSE-LABEL: length16_eq_const: +; X86-NOSSE: # BB#0: +; X86-NOSSE-NEXT: pushl $0 +; X86-NOSSE-NEXT: pushl $16 +; X86-NOSSE-NEXT: pushl $.L.str +; X86-NOSSE-NEXT: pushl {{[0-9]+}}(%esp) +; X86-NOSSE-NEXT: calll memcmp +; X86-NOSSE-NEXT: addl $16, %esp +; X86-NOSSE-NEXT: testl %eax, %eax +; X86-NOSSE-NEXT: sete %al +; X86-NOSSE-NEXT: retl +; +; X86-SSE2-LABEL: length16_eq_const: +; X86-SSE2: # BB#0: +; X86-SSE2-NEXT: movl {{[0-9]+}}(%esp), %eax +; X86-SSE2-NEXT: movdqu (%eax), %xmm0 +; X86-SSE2-NEXT: pcmpeqb {{\.LCPI.*}}, %xmm0 +; X86-SSE2-NEXT: pmovmskb %xmm0, %eax +; X86-SSE2-NEXT: cmpl $65535, %eax # imm = 0xFFFF +; X86-SSE2-NEXT: sete %al +; X86-SSE2-NEXT: retl ; ; X64-LABEL: length16_eq_const: ; X64: # BB#0: # %loadbb @@ -752,6 +677,82 @@ define i1 @length16_eq_const(i8* %X) nounwind { ret i1 %c } +; PR33914 - https://bugs.llvm.org/show_bug.cgi?id=33914 + +define i32 @length24(i8* %X, i8* %Y) nounwind { +; X86-LABEL: length24: +; X86: # BB#0: +; X86-NEXT: pushl $0 +; X86-NEXT: pushl $24 +; X86-NEXT: pushl {{[0-9]+}}(%esp) +; X86-NEXT: pushl {{[0-9]+}}(%esp) +; X86-NEXT: calll memcmp +; X86-NEXT: addl $16, %esp +; X86-NEXT: retl +; +; X64-LABEL: length24: +; X64: # BB#0: +; X64-NEXT: movl $24, %edx +; X64-NEXT: jmp memcmp # TAILCALL + %m = tail call i32 @memcmp(i8* %X, i8* %Y, i64 24) nounwind + ret i32 %m +} + +define i1 @length24_eq(i8* %x, i8* %y) nounwind { +; X86-LABEL: length24_eq: +; X86: # BB#0: +; X86-NEXT: pushl $0 +; X86-NEXT: pushl $24 +; X86-NEXT: pushl {{[0-9]+}}(%esp) +; X86-NEXT: pushl {{[0-9]+}}(%esp) +; X86-NEXT: calll memcmp +; X86-NEXT: addl $16, %esp +; X86-NEXT: testl %eax, %eax +; X86-NEXT: sete %al +; X86-NEXT: retl +; +; X64-LABEL: length24_eq: +; X64: # BB#0: +; X64-NEXT: pushq %rax +; X64-NEXT: movl $24, %edx +; X64-NEXT: callq memcmp +; X64-NEXT: testl %eax, %eax +; X64-NEXT: sete %al +; X64-NEXT: popq %rcx +; X64-NEXT: retq + %call = tail call i32 @memcmp(i8* %x, i8* %y, i64 24) nounwind + %cmp = icmp eq i32 %call, 0 + ret i1 %cmp +} + +define i1 @length24_eq_const(i8* %X) nounwind { +; X86-LABEL: length24_eq_const: +; X86: # BB#0: +; X86-NEXT: pushl $0 +; X86-NEXT: pushl $24 +; X86-NEXT: pushl $.L.str +; X86-NEXT: pushl {{[0-9]+}}(%esp) +; X86-NEXT: calll memcmp +; X86-NEXT: addl $16, %esp +; X86-NEXT: testl %eax, %eax +; X86-NEXT: setne %al +; X86-NEXT: retl +; +; X64-LABEL: length24_eq_const: +; X64: # BB#0: +; X64-NEXT: pushq %rax +; X64-NEXT: movl $.L.str, %esi +; X64-NEXT: movl $24, %edx +; X64-NEXT: callq memcmp +; X64-NEXT: testl %eax, %eax +; X64-NEXT: setne %al +; X64-NEXT: popq %rcx +; X64-NEXT: retq + %m = tail call i32 @memcmp(i8* %X, i8* getelementptr inbounds ([65 x i8], [65 x i8]* @.str, i32 0, i32 0), i64 24) nounwind + %c = icmp ne i32 %m, 0 + ret i1 %c +} + define i32 @length32(i8* %X, i8* %Y) nounwind { ; X86-LABEL: length32: ; X86: # BB#0: @@ -764,43 +765,9 @@ define i32 @length32(i8* %X, i8* %Y) nounwind { ; X86-NEXT: retl ; ; X64-LABEL: length32: -; X64: # BB#0: # %loadbb -; X64-NEXT: movq (%rdi), %rcx -; X64-NEXT: movq (%rsi), %rdx -; X64-NEXT: bswapq %rcx -; X64-NEXT: bswapq %rdx -; X64-NEXT: cmpq %rdx, %rcx -; X64-NEXT: jne .LBB19_1 -; X64-NEXT: # BB#2: # %loadbb1 -; X64-NEXT: movq 8(%rdi), %rcx -; X64-NEXT: movq 8(%rsi), %rdx -; X64-NEXT: bswapq %rcx -; X64-NEXT: bswapq %rdx -; X64-NEXT: cmpq %rdx, %rcx -; X64-NEXT: jne .LBB19_1 -; X64-NEXT: # BB#3: # %loadbb2 -; X64-NEXT: movq 16(%rdi), %rcx -; X64-NEXT: movq 16(%rsi), %rdx -; X64-NEXT: bswapq %rcx -; X64-NEXT: bswapq %rdx -; X64-NEXT: cmpq %rdx, %rcx -; X64-NEXT: jne .LBB19_1 -; X64-NEXT: # BB#4: # %loadbb3 -; X64-NEXT: movq 24(%rdi), %rcx -; X64-NEXT: movq 24(%rsi), %rdx -; X64-NEXT: bswapq %rcx -; X64-NEXT: bswapq %rdx -; X64-NEXT: xorl %eax, %eax -; X64-NEXT: cmpq %rdx, %rcx -; X64-NEXT: jne .LBB19_1 -; X64-NEXT: # BB#5: # %endblock -; X64-NEXT: retq -; X64-NEXT: .LBB19_1: # %res_block -; X64-NEXT: cmpq %rdx, %rcx -; X64-NEXT: movl $-1, %ecx -; X64-NEXT: movl $1, %eax -; X64-NEXT: cmovbl %ecx, %eax -; X64-NEXT: retq +; X64: # BB#0: +; X64-NEXT: movl $32, %edx +; X64-NEXT: jmp memcmp # TAILCALL %m = tail call i32 @memcmp(i8* %X, i8* %Y, i64 32) nounwind ret i32 %m } @@ -820,30 +787,25 @@ define i1 @length32_eq(i8* %x, i8* %y) nounwind { ; X86-NEXT: sete %al ; X86-NEXT: retl ; -; X64-LABEL: length32_eq: -; X64: # BB#0: # %loadbb -; X64-NEXT: movq (%rdi), %rax -; X64-NEXT: cmpq (%rsi), %rax -; X64-NEXT: jne .LBB20_1 -; X64-NEXT: # BB#2: # %loadbb1 -; X64-NEXT: movq 8(%rdi), %rax -; X64-NEXT: cmpq 8(%rsi), %rax -; X64-NEXT: jne .LBB20_1 -; X64-NEXT: # BB#3: # %loadbb2 -; X64-NEXT: movq 16(%rdi), %rax -; X64-NEXT: cmpq 16(%rsi), %rax -; X64-NEXT: jne .LBB20_1 -; X64-NEXT: # BB#4: # %loadbb3 -; X64-NEXT: movq 24(%rdi), %rcx -; X64-NEXT: xorl %eax, %eax -; X64-NEXT: cmpq 24(%rsi), %rcx -; X64-NEXT: je .LBB20_5 -; X64-NEXT: .LBB20_1: # %res_block -; X64-NEXT: movl $1, %eax -; X64-NEXT: .LBB20_5: # %endblock -; X64-NEXT: testl %eax, %eax -; X64-NEXT: sete %al -; X64-NEXT: retq +; X64-SSE2-LABEL: length32_eq: +; X64-SSE2: # BB#0: +; X64-SSE2-NEXT: pushq %rax +; X64-SSE2-NEXT: movl $32, %edx +; X64-SSE2-NEXT: callq memcmp +; X64-SSE2-NEXT: testl %eax, %eax +; X64-SSE2-NEXT: sete %al +; X64-SSE2-NEXT: popq %rcx +; X64-SSE2-NEXT: retq +; +; X64-AVX2-LABEL: length32_eq: +; X64-AVX2: # BB#0: +; X64-AVX2-NEXT: vmovdqu (%rdi), %ymm0 +; X64-AVX2-NEXT: vpcmpeqb (%rsi), %ymm0, %ymm0 +; X64-AVX2-NEXT: vpmovmskb %ymm0, %eax +; X64-AVX2-NEXT: cmpl $-1, %eax +; X64-AVX2-NEXT: sete %al +; X64-AVX2-NEXT: vzeroupper +; X64-AVX2-NEXT: retq %call = tail call i32 @memcmp(i8* %x, i8* %y, i64 32) nounwind %cmp = icmp eq i32 %call, 0 ret i1 %cmp @@ -862,30 +824,26 @@ define i1 @length32_eq_const(i8* %X) nounwind { ; X86-NEXT: setne %al ; X86-NEXT: retl ; -; X64-LABEL: length32_eq_const: -; X64: # BB#0: # %loadbb -; X64-NEXT: movabsq $3978425819141910832, %rax # imm = 0x3736353433323130 -; X64-NEXT: cmpq %rax, (%rdi) -; X64-NEXT: jne .LBB21_1 -; X64-NEXT: # BB#2: # %loadbb1 -; X64-NEXT: movabsq $3833745473465760056, %rax # imm = 0x3534333231303938 -; X64-NEXT: cmpq %rax, 8(%rdi) -; X64-NEXT: jne .LBB21_1 -; X64-NEXT: # BB#3: # %loadbb2 -; X64-NEXT: movabsq $3689065127958034230, %rax # imm = 0x3332313039383736 -; X64-NEXT: cmpq %rax, 16(%rdi) -; X64-NEXT: jne .LBB21_1 -; X64-NEXT: # BB#4: # %loadbb3 -; X64-NEXT: xorl %eax, %eax -; X64-NEXT: movabsq $3544395820347831604, %rcx # imm = 0x3130393837363534 -; X64-NEXT: cmpq %rcx, 24(%rdi) -; X64-NEXT: je .LBB21_5 -; X64-NEXT: .LBB21_1: # %res_block -; X64-NEXT: movl $1, %eax -; X64-NEXT: .LBB21_5: # %endblock -; X64-NEXT: testl %eax, %eax -; X64-NEXT: setne %al -; X64-NEXT: retq +; X64-SSE2-LABEL: length32_eq_const: +; X64-SSE2: # BB#0: +; X64-SSE2-NEXT: pushq %rax +; X64-SSE2-NEXT: movl $.L.str, %esi +; X64-SSE2-NEXT: movl $32, %edx +; X64-SSE2-NEXT: callq memcmp +; X64-SSE2-NEXT: testl %eax, %eax +; X64-SSE2-NEXT: setne %al +; X64-SSE2-NEXT: popq %rcx +; X64-SSE2-NEXT: retq +; +; X64-AVX2-LABEL: length32_eq_const: +; X64-AVX2: # BB#0: +; X64-AVX2-NEXT: vmovdqu (%rdi), %ymm0 +; X64-AVX2-NEXT: vpcmpeqb {{.*}}(%rip), %ymm0, %ymm0 +; X64-AVX2-NEXT: vpmovmskb %ymm0, %eax +; X64-AVX2-NEXT: cmpl $-1, %eax +; X64-AVX2-NEXT: setne %al +; X64-AVX2-NEXT: vzeroupper +; X64-AVX2-NEXT: retq %m = tail call i32 @memcmp(i8* %X, i8* getelementptr inbounds ([65 x i8], [65 x i8]* @.str, i32 0, i32 0), i64 32) nounwind %c = icmp ne i32 %m, 0 ret i1 %c diff --git a/test/CodeGen/X86/pr33844.ll b/test/CodeGen/X86/pr33844.ll new file mode 100644 index 000000000000..2585945aa109 --- /dev/null +++ b/test/CodeGen/X86/pr33844.ll @@ -0,0 +1,38 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -o - %s | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@global = external global i32 +@global.1 = external global i64 + +define void @patatino() { +; CHECK-LABEL: patatino: +; CHECK: # BB#0: # %bb +; CHECK-NEXT: movl {{.*}}(%rip), %eax +; CHECK-NEXT: movl %eax, %ecx +; CHECK-NEXT: shrl $31, %ecx +; CHECK-NEXT: addl $2147483647, %ecx # imm = 0x7FFFFFFF +; CHECK-NEXT: shrl $31, %ecx +; CHECK-NEXT: andl $62, %ecx +; CHECK-NEXT: andl $-536870912, %eax # imm = 0xE0000000 +; CHECK-NEXT: orl %ecx, %eax +; CHECK-NEXT: movl %eax, {{.*}}(%rip) +; CHECK-NEXT: retq +bb: + %tmp = load i32, i32* @global + %tmp1 = lshr i32 %tmp, 31 + %tmp2 = add nuw nsw i32 %tmp1, 2147483647 + %tmp3 = load i64, i64* @global.1 + %tmp4 = shl i64 %tmp3, 23 + %tmp5 = add nsw i64 %tmp4, 8388639 + %tmp6 = trunc i64 %tmp5 to i32 + %tmp7 = lshr i32 %tmp2, %tmp6 + %tmp8 = load i32, i32* @global + %tmp9 = and i32 %tmp7, 62 + %tmp10 = and i32 %tmp8, -536870912 + %tmp11 = or i32 %tmp9, %tmp10 + store i32 %tmp11, i32* @global + ret void +} diff --git a/test/CodeGen/X86/pr33960.ll b/test/CodeGen/X86/pr33960.ll new file mode 100644 index 000000000000..fb9236d3ffa2 --- /dev/null +++ b/test/CodeGen/X86/pr33960.ll @@ -0,0 +1,39 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=i686-unknown -mattr=+avx | FileCheck %s --check-prefix=X86 +; RUN: llc < %s -mtriple=x86_64-unknown -mattr=+avx | FileCheck %s --check-prefix=X64 + +@b = external local_unnamed_addr global i32, align 4 + +define void @PR33960() { +; X86-LABEL: PR33960: +; X86: # BB#0: # %entry +; X86-NEXT: movl $0, b +; X86-NEXT: retl +; +; X64-LABEL: PR33960: +; X64: # BB#0: # %entry +; X64-NEXT: movl $0, {{.*}}(%rip) +; X64-NEXT: retq +entry: + %tmp = insertelement <4 x i32> , i32 -2, i32 3 + %predphi26 = insertelement <4 x i32> %tmp, i32 -7, i32 0 + %tmp1 = trunc <4 x i32> %predphi26 to <4 x i16> + %tmp2 = icmp eq <4 x i16> %tmp1, zeroinitializer + %tmp3 = icmp eq <4 x i32> undef, zeroinitializer + %tmp4 = and <4 x i1> %tmp2, %tmp3 + %predphi17 = select <4 x i1> %tmp4, <4 x i32> undef, <4 x i32> zeroinitializer + %tmp5 = shl <4 x i32> %predphi17, + %tmp6 = ashr exact <4 x i32> %tmp5, + %tmp7 = or <4 x i32> %tmp6, undef + %tmp8 = or <4 x i32> undef, %tmp7 + %tmp9 = or <4 x i32> undef, %tmp8 + %tmp10 = or <4 x i32> undef, %tmp9 + %tmp11 = or <4 x i32> undef, %tmp10 + %tmp12 = or <4 x i32> undef, %tmp11 + %bin.rdx = or <4 x i32> %tmp12, undef + %bin.rdx19 = or <4 x i32> %bin.rdx, undef + %tmp13 = extractelement <4 x i32> %bin.rdx19, i32 0 + %or = or i32 0, %tmp13 + store i32 %or, i32* @b, align 4 + ret void +} diff --git a/test/CodeGen/X86/vector-shift-ashr-256.ll b/test/CodeGen/X86/vector-shift-ashr-256.ll index 5f2b18fc9c03..6bb57d8f5f71 100644 --- a/test/CodeGen/X86/vector-shift-ashr-256.ll +++ b/test/CodeGen/X86/vector-shift-ashr-256.ll @@ -1699,10 +1699,9 @@ define <4 x i64> @splatconstant_shift_v4i64(<4 x i64> %a) nounwind { ; ; XOPAVX2-LABEL: splatconstant_shift_v4i64: ; XOPAVX2: # BB#0: +; XOPAVX2-NEXT: vpsrad $7, %ymm0, %ymm1 ; XOPAVX2-NEXT: vpsrlq $7, %ymm0, %ymm0 -; XOPAVX2-NEXT: vpbroadcastq {{.*#+}} ymm1 = [72057594037927936,72057594037927936,72057594037927936,72057594037927936] -; XOPAVX2-NEXT: vpxor %ymm1, %ymm0, %ymm0 -; XOPAVX2-NEXT: vpsubq %ymm1, %ymm0, %ymm0 +; XOPAVX2-NEXT: vpblendd {{.*#+}} ymm0 = ymm0[0],ymm1[1],ymm0[2],ymm1[3],ymm0[4],ymm1[5],ymm0[6],ymm1[7] ; XOPAVX2-NEXT: retq ; ; AVX512-LABEL: splatconstant_shift_v4i64: diff --git a/test/MC/Sparc/sparc-tls-relocations.s b/test/MC/Sparc/sparc-tls-relocations.s new file mode 100644 index 000000000000..3d1b80b5f191 --- /dev/null +++ b/test/MC/Sparc/sparc-tls-relocations.s @@ -0,0 +1,83 @@ +! Testing Sparc TLS relocations emission +! (for now a couple local ones). +! +! RUN: llvm-mc %s -arch=sparc -show-encoding | FileCheck %s --check-prefix=ASM +! RUN: llvm-mc %s -arch=sparcv9 -show-encoding | FileCheck %s --check-prefix=ASM +! RUN: llvm-mc %s -arch=sparc -filetype=obj | llvm-readobj -r | FileCheck %s --check-prefix=REL +! RUN: llvm-mc %s -arch=sparcv9 -filetype=obj | llvm-readobj -r | FileCheck %s --check-prefix=REL +! RUN: llvm-mc %s -arch=sparc -filetype=obj | llvm-objdump -r -d - | FileCheck %s --check-prefix=OBJDUMP +! RUN: llvm-mc %s -arch=sparcv9 -filetype=obj | llvm-objdump -r -d - | FileCheck %s --check-prefix=OBJDUMP + +! REL: Arch: sparc +! REL: Relocations [ +! REL: 0x{{[0-9,A-F]+}} R_SPARC_TLS_LE_HIX22 Head 0x0 +! REL: 0x{{[0-9,A-F]+}} R_SPARC_TLS_LE_LOX10 Head 0x0 +! REL: 0x{{[0-9,A-F]+}} R_SPARC_TLS_LDO_HIX22 Head 0x0 +! REL: 0x{{[0-9,A-F]+}} R_SPARC_TLS_LDM_HI22 Head 0x0 +! REL: 0x{{[0-9,A-F]+}} R_SPARC_TLS_LDM_LO10 Head 0x0 +! REL: 0x{{[0-9,A-F]+}} R_SPARC_TLS_LDO_LOX10 Head 0x0 +! REL: ] + + +! OBJDUMP: foo: +foo: +! Here we use two different sequences to get the address of a static TLS variable 'Head' +! (note - there is no intent to have valid assembler function here, +! we just check how TLS relocations are emitted) +! +! First sequence uses LE_HIX22/LE_LOX10 + +! OBJDUMP: {{[0-9,a-f]+}}: 31 00 00 00 sethi 0, %i0 +! OBJDUMP: {{[0-9,a-f]+}}: R_SPARC_TLS_LE_HIX22 Unknown +! ASM: sethi %tle_hix22(Head), %i0 ! encoding: [0x31,0x00,0x00,0x00] +! ASM: ! fixup A - offset: 0, value: %tle_hix22(Head), kind: fixup_sparc_tls_le_hix22 + sethi %tle_hix22(Head), %i0 + +! OBJDUMP: {{[0-9,a-f]+}}: b0 1e 20 00 xor %i0, 0, %i0 +! OBJDUMP: {{[0-9,a-f]+}}: R_SPARC_TLS_LE_LOX10 Unknown +! ASM: xor %i0, %tle_lox10(Head), %i0 ! encoding: [0xb0,0x1e,0x20,0x00] +! ASM: ! fixup A - offset: 0, value: %tle_lox10(Head), kind: fixup_sparc_tls_le_lox10 + xor %i0, %tle_lox10(Head), %i0 + + +! Second sequence is for PIC, so it is more complicated. +! It uses LDO_HIX22/LDO_LOX10/LDO_ADD/LDM_HI22/LDM_LO10/LDM_ADD/LDM_CALL + +! OBJDUMP: {{[0-9,a-f]+}}: 33 00 00 00 sethi 0, %i1 +! OBJDUMP: {{[0-9,a-f]+}}: R_SPARC_TLS_LDO_HIX22 Unknown +! ASM: sethi %tldo_hix22(Head), %i1 ! encoding: [0x33,0b00AAAAAA,A,A] +! ASM: ! fixup A - offset: 0, value: %tldo_hix22(Head), kind: fixup_sparc_tls_ldo_hix22 + sethi %tldo_hix22(Head), %i1 + +! OBJDUMP: {{[0-9,a-f]+}}: 35 00 00 00 sethi 0, %i2 +! OBJDUMP: {{[0-9,a-f]+}}: R_SPARC_TLS_LDM_HI22 Unknown +! ASM: sethi %tldm_hi22(Head), %i2 ! encoding: [0x35,0b00AAAAAA,A,A] +! ASM: ! fixup A - offset: 0, value: %tldm_hi22(Head), kind: fixup_sparc_tls_ldm_hi22 + sethi %tldm_hi22(Head), %i2 + +! OBJDUMP: {{[0-9,a-f]+}}: b4 06 a0 00 add %i2, 0, %i2 +! OBJDUMP: {{[0-9,a-f]+}}: R_SPARC_TLS_LDM_LO10 Unknown +! ASM: add %i2, %tldm_lo10(Head), %i2 ! encoding: [0xb4,0x06,0b101000AA,A] +! ASM: ! fixup A - offset: 0, value: %tldm_lo10(Head), kind: fixup_sparc_tls_ldm_lo10 + add %i2, %tldm_lo10(Head), %i2 + + ! ???error from llvm-mc on the next asm line??? + ! add %i0, %i2, %o0, %tldm_add(Head) + +! OBJDUMP: {{[0-9,a-f]+}}: b0 1e 60 00 xor %i1, 0, %i0 +! OBJDUMP: {{[0-9,a-f]+}}: R_SPARC_TLS_LDO_LOX10 Unknown +! ASM: xor %i1, %tldo_lox10(Head), %i0 ! encoding: [0xb0,0x1e,0b011000AA,A] +! ASM: ! fixup A - offset: 0, value: %tldo_lox10(Head), kind: fixup_sparc_tls_ldo_lox10 + xor %i1, %tldo_lox10(Head), %i0 + + ! ???error from llvm-mc on the next asm line??? + ! call __tls_get_addr, %tldm_call(Head) + ! nop + ! ???error from llvm-mc on the next asm line??? + ! add %o0, %i0, %i0, %tldo_add(Head) + + .type Head,@object + .section .tbss,#alloc,#write,#tls +Head: + .word 0 + .size Head, 4 diff --git a/test/Transforms/CodeGenPrepare/X86/memcmp.ll b/test/Transforms/CodeGenPrepare/X86/memcmp.ll index 1dfc08761965..c5281a9e5733 100644 --- a/test/Transforms/CodeGenPrepare/X86/memcmp.ll +++ b/test/Transforms/CodeGenPrepare/X86/memcmp.ll @@ -238,91 +238,9 @@ define i32 @cmp6(i8* nocapture readonly %x, i8* nocapture readonly %y) { } define i32 @cmp7(i8* nocapture readonly %x, i8* nocapture readonly %y) { -; X32-LABEL: @cmp7( -; X32-NEXT: loadbb: -; X32-NEXT: [[TMP0:%.*]] = bitcast i8* [[X:%.*]] to i32* -; X32-NEXT: [[TMP1:%.*]] = bitcast i8* [[Y:%.*]] to i32* -; X32-NEXT: [[TMP2:%.*]] = load i32, i32* [[TMP0]] -; X32-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP1]] -; X32-NEXT: [[TMP4:%.*]] = call i32 @llvm.bswap.i32(i32 [[TMP2]]) -; X32-NEXT: [[TMP5:%.*]] = call i32 @llvm.bswap.i32(i32 [[TMP3]]) -; X32-NEXT: [[TMP6:%.*]] = icmp eq i32 [[TMP4]], [[TMP5]] -; X32-NEXT: br i1 [[TMP6]], label [[LOADBB1:%.*]], label [[RES_BLOCK:%.*]] -; X32: res_block: -; X32-NEXT: [[PHI_SRC1:%.*]] = phi i32 [ [[TMP4]], [[LOADBB:%.*]] ], [ [[TMP17:%.*]], [[LOADBB1]] ] -; X32-NEXT: [[PHI_SRC2:%.*]] = phi i32 [ [[TMP5]], [[LOADBB]] ], [ [[TMP18:%.*]], [[LOADBB1]] ] -; X32-NEXT: [[TMP7:%.*]] = icmp ult i32 [[PHI_SRC1]], [[PHI_SRC2]] -; X32-NEXT: [[TMP8:%.*]] = select i1 [[TMP7]], i32 -1, i32 1 -; X32-NEXT: br label [[ENDBLOCK:%.*]] -; X32: loadbb1: -; X32-NEXT: [[TMP9:%.*]] = bitcast i8* [[X]] to i16* -; X32-NEXT: [[TMP10:%.*]] = bitcast i8* [[Y]] to i16* -; X32-NEXT: [[TMP11:%.*]] = getelementptr i16, i16* [[TMP9]], i16 2 -; X32-NEXT: [[TMP12:%.*]] = getelementptr i16, i16* [[TMP10]], i16 2 -; X32-NEXT: [[TMP13:%.*]] = load i16, i16* [[TMP11]] -; X32-NEXT: [[TMP14:%.*]] = load i16, i16* [[TMP12]] -; X32-NEXT: [[TMP15:%.*]] = call i16 @llvm.bswap.i16(i16 [[TMP13]]) -; X32-NEXT: [[TMP16:%.*]] = call i16 @llvm.bswap.i16(i16 [[TMP14]]) -; X32-NEXT: [[TMP17]] = zext i16 [[TMP15]] to i32 -; X32-NEXT: [[TMP18]] = zext i16 [[TMP16]] to i32 -; X32-NEXT: [[TMP19:%.*]] = icmp eq i32 [[TMP17]], [[TMP18]] -; X32-NEXT: br i1 [[TMP19]], label [[LOADBB2:%.*]], label [[RES_BLOCK]] -; X32: loadbb2: -; X32-NEXT: [[TMP20:%.*]] = getelementptr i8, i8* [[X]], i8 6 -; X32-NEXT: [[TMP21:%.*]] = getelementptr i8, i8* [[Y]], i8 6 -; X32-NEXT: [[TMP22:%.*]] = load i8, i8* [[TMP20]] -; X32-NEXT: [[TMP23:%.*]] = load i8, i8* [[TMP21]] -; X32-NEXT: [[TMP24:%.*]] = zext i8 [[TMP22]] to i32 -; X32-NEXT: [[TMP25:%.*]] = zext i8 [[TMP23]] to i32 -; X32-NEXT: [[TMP26:%.*]] = sub i32 [[TMP24]], [[TMP25]] -; X32-NEXT: br label [[ENDBLOCK]] -; X32: endblock: -; X32-NEXT: [[PHI_RES:%.*]] = phi i32 [ [[TMP26]], [[LOADBB2]] ], [ [[TMP8]], [[RES_BLOCK]] ] -; X32-NEXT: ret i32 [[PHI_RES]] -; -; X64-LABEL: @cmp7( -; X64-NEXT: loadbb: -; X64-NEXT: [[TMP0:%.*]] = bitcast i8* [[X:%.*]] to i32* -; X64-NEXT: [[TMP1:%.*]] = bitcast i8* [[Y:%.*]] to i32* -; X64-NEXT: [[TMP2:%.*]] = load i32, i32* [[TMP0]] -; X64-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP1]] -; X64-NEXT: [[TMP4:%.*]] = call i32 @llvm.bswap.i32(i32 [[TMP2]]) -; X64-NEXT: [[TMP5:%.*]] = call i32 @llvm.bswap.i32(i32 [[TMP3]]) -; X64-NEXT: [[TMP6:%.*]] = zext i32 [[TMP4]] to i64 -; X64-NEXT: [[TMP7:%.*]] = zext i32 [[TMP5]] to i64 -; X64-NEXT: [[TMP8:%.*]] = icmp eq i64 [[TMP6]], [[TMP7]] -; X64-NEXT: br i1 [[TMP8]], label [[LOADBB1:%.*]], label [[RES_BLOCK:%.*]] -; X64: res_block: -; X64-NEXT: [[PHI_SRC1:%.*]] = phi i64 [ [[TMP6]], [[LOADBB:%.*]] ], [ [[TMP19:%.*]], [[LOADBB1]] ] -; X64-NEXT: [[PHI_SRC2:%.*]] = phi i64 [ [[TMP7]], [[LOADBB]] ], [ [[TMP20:%.*]], [[LOADBB1]] ] -; X64-NEXT: [[TMP9:%.*]] = icmp ult i64 [[PHI_SRC1]], [[PHI_SRC2]] -; X64-NEXT: [[TMP10:%.*]] = select i1 [[TMP9]], i32 -1, i32 1 -; X64-NEXT: br label [[ENDBLOCK:%.*]] -; X64: loadbb1: -; X64-NEXT: [[TMP11:%.*]] = bitcast i8* [[X]] to i16* -; X64-NEXT: [[TMP12:%.*]] = bitcast i8* [[Y]] to i16* -; X64-NEXT: [[TMP13:%.*]] = getelementptr i16, i16* [[TMP11]], i16 2 -; X64-NEXT: [[TMP14:%.*]] = getelementptr i16, i16* [[TMP12]], i16 2 -; X64-NEXT: [[TMP15:%.*]] = load i16, i16* [[TMP13]] -; X64-NEXT: [[TMP16:%.*]] = load i16, i16* [[TMP14]] -; X64-NEXT: [[TMP17:%.*]] = call i16 @llvm.bswap.i16(i16 [[TMP15]]) -; X64-NEXT: [[TMP18:%.*]] = call i16 @llvm.bswap.i16(i16 [[TMP16]]) -; X64-NEXT: [[TMP19]] = zext i16 [[TMP17]] to i64 -; X64-NEXT: [[TMP20]] = zext i16 [[TMP18]] to i64 -; X64-NEXT: [[TMP21:%.*]] = icmp eq i64 [[TMP19]], [[TMP20]] -; X64-NEXT: br i1 [[TMP21]], label [[LOADBB2:%.*]], label [[RES_BLOCK]] -; X64: loadbb2: -; X64-NEXT: [[TMP22:%.*]] = getelementptr i8, i8* [[X]], i8 6 -; X64-NEXT: [[TMP23:%.*]] = getelementptr i8, i8* [[Y]], i8 6 -; X64-NEXT: [[TMP24:%.*]] = load i8, i8* [[TMP22]] -; X64-NEXT: [[TMP25:%.*]] = load i8, i8* [[TMP23]] -; X64-NEXT: [[TMP26:%.*]] = zext i8 [[TMP24]] to i32 -; X64-NEXT: [[TMP27:%.*]] = zext i8 [[TMP25]] to i32 -; X64-NEXT: [[TMP28:%.*]] = sub i32 [[TMP26]], [[TMP27]] -; X64-NEXT: br label [[ENDBLOCK]] -; X64: endblock: -; X64-NEXT: [[PHI_RES:%.*]] = phi i32 [ [[TMP28]], [[LOADBB2]] ], [ [[TMP10]], [[RES_BLOCK]] ] -; X64-NEXT: ret i32 [[PHI_RES]] +; ALL-LABEL: @cmp7( +; ALL-NEXT: [[CALL:%.*]] = tail call i32 @memcmp(i8* [[X:%.*]], i8* [[Y:%.*]], i64 7) +; ALL-NEXT: ret i32 [[CALL]] ; %call = tail call i32 @memcmp(i8* %x, i8* %y, i64 7) ret i32 %call @@ -379,44 +297,8 @@ define i32 @cmp8(i8* nocapture readonly %x, i8* nocapture readonly %y) { define i32 @cmp9(i8* nocapture readonly %x, i8* nocapture readonly %y) { ; X32-LABEL: @cmp9( -; X32-NEXT: loadbb: -; X32-NEXT: [[TMP0:%.*]] = bitcast i8* [[X:%.*]] to i32* -; X32-NEXT: [[TMP1:%.*]] = bitcast i8* [[Y:%.*]] to i32* -; X32-NEXT: [[TMP2:%.*]] = load i32, i32* [[TMP0]] -; X32-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP1]] -; X32-NEXT: [[TMP4:%.*]] = call i32 @llvm.bswap.i32(i32 [[TMP2]]) -; X32-NEXT: [[TMP5:%.*]] = call i32 @llvm.bswap.i32(i32 [[TMP3]]) -; X32-NEXT: [[TMP6:%.*]] = icmp eq i32 [[TMP4]], [[TMP5]] -; X32-NEXT: br i1 [[TMP6]], label [[LOADBB1:%.*]], label [[RES_BLOCK:%.*]] -; X32: res_block: -; X32-NEXT: [[PHI_SRC1:%.*]] = phi i32 [ [[TMP4]], [[LOADBB:%.*]] ], [ [[TMP15:%.*]], [[LOADBB1]] ] -; X32-NEXT: [[PHI_SRC2:%.*]] = phi i32 [ [[TMP5]], [[LOADBB]] ], [ [[TMP16:%.*]], [[LOADBB1]] ] -; X32-NEXT: [[TMP7:%.*]] = icmp ult i32 [[PHI_SRC1]], [[PHI_SRC2]] -; X32-NEXT: [[TMP8:%.*]] = select i1 [[TMP7]], i32 -1, i32 1 -; X32-NEXT: br label [[ENDBLOCK:%.*]] -; X32: loadbb1: -; X32-NEXT: [[TMP9:%.*]] = bitcast i8* [[X]] to i32* -; X32-NEXT: [[TMP10:%.*]] = bitcast i8* [[Y]] to i32* -; X32-NEXT: [[TMP11:%.*]] = getelementptr i32, i32* [[TMP9]], i32 1 -; X32-NEXT: [[TMP12:%.*]] = getelementptr i32, i32* [[TMP10]], i32 1 -; X32-NEXT: [[TMP13:%.*]] = load i32, i32* [[TMP11]] -; X32-NEXT: [[TMP14:%.*]] = load i32, i32* [[TMP12]] -; X32-NEXT: [[TMP15]] = call i32 @llvm.bswap.i32(i32 [[TMP13]]) -; X32-NEXT: [[TMP16]] = call i32 @llvm.bswap.i32(i32 [[TMP14]]) -; X32-NEXT: [[TMP17:%.*]] = icmp eq i32 [[TMP15]], [[TMP16]] -; X32-NEXT: br i1 [[TMP17]], label [[LOADBB2:%.*]], label [[RES_BLOCK]] -; X32: loadbb2: -; X32-NEXT: [[TMP18:%.*]] = getelementptr i8, i8* [[X]], i8 8 -; X32-NEXT: [[TMP19:%.*]] = getelementptr i8, i8* [[Y]], i8 8 -; X32-NEXT: [[TMP20:%.*]] = load i8, i8* [[TMP18]] -; X32-NEXT: [[TMP21:%.*]] = load i8, i8* [[TMP19]] -; X32-NEXT: [[TMP22:%.*]] = zext i8 [[TMP20]] to i32 -; X32-NEXT: [[TMP23:%.*]] = zext i8 [[TMP21]] to i32 -; X32-NEXT: [[TMP24:%.*]] = sub i32 [[TMP22]], [[TMP23]] -; X32-NEXT: br label [[ENDBLOCK]] -; X32: endblock: -; X32-NEXT: [[PHI_RES:%.*]] = phi i32 [ [[TMP24]], [[LOADBB2]] ], [ [[TMP8]], [[RES_BLOCK]] ] -; X32-NEXT: ret i32 [[PHI_RES]] +; X32-NEXT: [[CALL:%.*]] = tail call i32 @memcmp(i8* [[X:%.*]], i8* [[Y:%.*]], i64 9) +; X32-NEXT: ret i32 [[CALL]] ; ; X64-LABEL: @cmp9( ; X64-NEXT: loadbb: @@ -451,48 +333,8 @@ define i32 @cmp9(i8* nocapture readonly %x, i8* nocapture readonly %y) { define i32 @cmp10(i8* nocapture readonly %x, i8* nocapture readonly %y) { ; X32-LABEL: @cmp10( -; X32-NEXT: loadbb: -; X32-NEXT: [[TMP0:%.*]] = bitcast i8* [[X:%.*]] to i32* -; X32-NEXT: [[TMP1:%.*]] = bitcast i8* [[Y:%.*]] to i32* -; X32-NEXT: [[TMP2:%.*]] = load i32, i32* [[TMP0]] -; X32-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP1]] -; X32-NEXT: [[TMP4:%.*]] = call i32 @llvm.bswap.i32(i32 [[TMP2]]) -; X32-NEXT: [[TMP5:%.*]] = call i32 @llvm.bswap.i32(i32 [[TMP3]]) -; X32-NEXT: [[TMP6:%.*]] = icmp eq i32 [[TMP4]], [[TMP5]] -; X32-NEXT: br i1 [[TMP6]], label [[LOADBB1:%.*]], label [[RES_BLOCK:%.*]] -; X32: res_block: -; X32-NEXT: [[PHI_SRC1:%.*]] = phi i32 [ [[TMP4]], [[LOADBB:%.*]] ], [ [[TMP15:%.*]], [[LOADBB1]] ], [ [[TMP26:%.*]], [[LOADBB2:%.*]] ] -; X32-NEXT: [[PHI_SRC2:%.*]] = phi i32 [ [[TMP5]], [[LOADBB]] ], [ [[TMP16:%.*]], [[LOADBB1]] ], [ [[TMP27:%.*]], [[LOADBB2]] ] -; X32-NEXT: [[TMP7:%.*]] = icmp ult i32 [[PHI_SRC1]], [[PHI_SRC2]] -; X32-NEXT: [[TMP8:%.*]] = select i1 [[TMP7]], i32 -1, i32 1 -; X32-NEXT: br label [[ENDBLOCK:%.*]] -; X32: loadbb1: -; X32-NEXT: [[TMP9:%.*]] = bitcast i8* [[X]] to i32* -; X32-NEXT: [[TMP10:%.*]] = bitcast i8* [[Y]] to i32* -; X32-NEXT: [[TMP11:%.*]] = getelementptr i32, i32* [[TMP9]], i32 1 -; X32-NEXT: [[TMP12:%.*]] = getelementptr i32, i32* [[TMP10]], i32 1 -; X32-NEXT: [[TMP13:%.*]] = load i32, i32* [[TMP11]] -; X32-NEXT: [[TMP14:%.*]] = load i32, i32* [[TMP12]] -; X32-NEXT: [[TMP15]] = call i32 @llvm.bswap.i32(i32 [[TMP13]]) -; X32-NEXT: [[TMP16]] = call i32 @llvm.bswap.i32(i32 [[TMP14]]) -; X32-NEXT: [[TMP17:%.*]] = icmp eq i32 [[TMP15]], [[TMP16]] -; X32-NEXT: br i1 [[TMP17]], label [[LOADBB2]], label [[RES_BLOCK]] -; X32: loadbb2: -; X32-NEXT: [[TMP18:%.*]] = bitcast i8* [[X]] to i16* -; X32-NEXT: [[TMP19:%.*]] = bitcast i8* [[Y]] to i16* -; X32-NEXT: [[TMP20:%.*]] = getelementptr i16, i16* [[TMP18]], i16 4 -; X32-NEXT: [[TMP21:%.*]] = getelementptr i16, i16* [[TMP19]], i16 4 -; X32-NEXT: [[TMP22:%.*]] = load i16, i16* [[TMP20]] -; X32-NEXT: [[TMP23:%.*]] = load i16, i16* [[TMP21]] -; X32-NEXT: [[TMP24:%.*]] = call i16 @llvm.bswap.i16(i16 [[TMP22]]) -; X32-NEXT: [[TMP25:%.*]] = call i16 @llvm.bswap.i16(i16 [[TMP23]]) -; X32-NEXT: [[TMP26]] = zext i16 [[TMP24]] to i32 -; X32-NEXT: [[TMP27]] = zext i16 [[TMP25]] to i32 -; X32-NEXT: [[TMP28:%.*]] = icmp eq i32 [[TMP26]], [[TMP27]] -; X32-NEXT: br i1 [[TMP28]], label [[ENDBLOCK]], label [[RES_BLOCK]] -; X32: endblock: -; X32-NEXT: [[PHI_RES:%.*]] = phi i32 [ 0, [[LOADBB2]] ], [ [[TMP8]], [[RES_BLOCK]] ] -; X32-NEXT: ret i32 [[PHI_RES]] +; X32-NEXT: [[CALL:%.*]] = tail call i32 @memcmp(i8* [[X:%.*]], i8* [[Y:%.*]], i64 10) +; X32-NEXT: ret i32 [[CALL]] ; ; X64-LABEL: @cmp10( ; X64-NEXT: loadbb: @@ -532,100 +374,9 @@ define i32 @cmp10(i8* nocapture readonly %x, i8* nocapture readonly %y) { } define i32 @cmp11(i8* nocapture readonly %x, i8* nocapture readonly %y) { -; X32-LABEL: @cmp11( -; X32-NEXT: loadbb: -; X32-NEXT: [[TMP0:%.*]] = bitcast i8* [[X:%.*]] to i32* -; X32-NEXT: [[TMP1:%.*]] = bitcast i8* [[Y:%.*]] to i32* -; X32-NEXT: [[TMP2:%.*]] = load i32, i32* [[TMP0]] -; X32-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP1]] -; X32-NEXT: [[TMP4:%.*]] = call i32 @llvm.bswap.i32(i32 [[TMP2]]) -; X32-NEXT: [[TMP5:%.*]] = call i32 @llvm.bswap.i32(i32 [[TMP3]]) -; X32-NEXT: [[TMP6:%.*]] = icmp eq i32 [[TMP4]], [[TMP5]] -; X32-NEXT: br i1 [[TMP6]], label [[LOADBB1:%.*]], label [[RES_BLOCK:%.*]] -; X32: res_block: -; X32-NEXT: [[PHI_SRC1:%.*]] = phi i32 [ [[TMP4]], [[LOADBB:%.*]] ], [ [[TMP15:%.*]], [[LOADBB1]] ], [ [[TMP26:%.*]], [[LOADBB2:%.*]] ] -; X32-NEXT: [[PHI_SRC2:%.*]] = phi i32 [ [[TMP5]], [[LOADBB]] ], [ [[TMP16:%.*]], [[LOADBB1]] ], [ [[TMP27:%.*]], [[LOADBB2]] ] -; X32-NEXT: [[TMP7:%.*]] = icmp ult i32 [[PHI_SRC1]], [[PHI_SRC2]] -; X32-NEXT: [[TMP8:%.*]] = select i1 [[TMP7]], i32 -1, i32 1 -; X32-NEXT: br label [[ENDBLOCK:%.*]] -; X32: loadbb1: -; X32-NEXT: [[TMP9:%.*]] = bitcast i8* [[X]] to i32* -; X32-NEXT: [[TMP10:%.*]] = bitcast i8* [[Y]] to i32* -; X32-NEXT: [[TMP11:%.*]] = getelementptr i32, i32* [[TMP9]], i32 1 -; X32-NEXT: [[TMP12:%.*]] = getelementptr i32, i32* [[TMP10]], i32 1 -; X32-NEXT: [[TMP13:%.*]] = load i32, i32* [[TMP11]] -; X32-NEXT: [[TMP14:%.*]] = load i32, i32* [[TMP12]] -; X32-NEXT: [[TMP15]] = call i32 @llvm.bswap.i32(i32 [[TMP13]]) -; X32-NEXT: [[TMP16]] = call i32 @llvm.bswap.i32(i32 [[TMP14]]) -; X32-NEXT: [[TMP17:%.*]] = icmp eq i32 [[TMP15]], [[TMP16]] -; X32-NEXT: br i1 [[TMP17]], label [[LOADBB2]], label [[RES_BLOCK]] -; X32: loadbb2: -; X32-NEXT: [[TMP18:%.*]] = bitcast i8* [[X]] to i16* -; X32-NEXT: [[TMP19:%.*]] = bitcast i8* [[Y]] to i16* -; X32-NEXT: [[TMP20:%.*]] = getelementptr i16, i16* [[TMP18]], i16 4 -; X32-NEXT: [[TMP21:%.*]] = getelementptr i16, i16* [[TMP19]], i16 4 -; X32-NEXT: [[TMP22:%.*]] = load i16, i16* [[TMP20]] -; X32-NEXT: [[TMP23:%.*]] = load i16, i16* [[TMP21]] -; X32-NEXT: [[TMP24:%.*]] = call i16 @llvm.bswap.i16(i16 [[TMP22]]) -; X32-NEXT: [[TMP25:%.*]] = call i16 @llvm.bswap.i16(i16 [[TMP23]]) -; X32-NEXT: [[TMP26]] = zext i16 [[TMP24]] to i32 -; X32-NEXT: [[TMP27]] = zext i16 [[TMP25]] to i32 -; X32-NEXT: [[TMP28:%.*]] = icmp eq i32 [[TMP26]], [[TMP27]] -; X32-NEXT: br i1 [[TMP28]], label [[LOADBB3:%.*]], label [[RES_BLOCK]] -; X32: loadbb3: -; X32-NEXT: [[TMP29:%.*]] = getelementptr i8, i8* [[X]], i8 10 -; X32-NEXT: [[TMP30:%.*]] = getelementptr i8, i8* [[Y]], i8 10 -; X32-NEXT: [[TMP31:%.*]] = load i8, i8* [[TMP29]] -; X32-NEXT: [[TMP32:%.*]] = load i8, i8* [[TMP30]] -; X32-NEXT: [[TMP33:%.*]] = zext i8 [[TMP31]] to i32 -; X32-NEXT: [[TMP34:%.*]] = zext i8 [[TMP32]] to i32 -; X32-NEXT: [[TMP35:%.*]] = sub i32 [[TMP33]], [[TMP34]] -; X32-NEXT: br label [[ENDBLOCK]] -; X32: endblock: -; X32-NEXT: [[PHI_RES:%.*]] = phi i32 [ [[TMP35]], [[LOADBB3]] ], [ [[TMP8]], [[RES_BLOCK]] ] -; X32-NEXT: ret i32 [[PHI_RES]] -; -; X64-LABEL: @cmp11( -; X64-NEXT: loadbb: -; X64-NEXT: [[TMP0:%.*]] = bitcast i8* [[X:%.*]] to i64* -; X64-NEXT: [[TMP1:%.*]] = bitcast i8* [[Y:%.*]] to i64* -; X64-NEXT: [[TMP2:%.*]] = load i64, i64* [[TMP0]] -; X64-NEXT: [[TMP3:%.*]] = load i64, i64* [[TMP1]] -; X64-NEXT: [[TMP4:%.*]] = call i64 @llvm.bswap.i64(i64 [[TMP2]]) -; X64-NEXT: [[TMP5:%.*]] = call i64 @llvm.bswap.i64(i64 [[TMP3]]) -; X64-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP4]], [[TMP5]] -; X64-NEXT: br i1 [[TMP6]], label [[LOADBB1:%.*]], label [[RES_BLOCK:%.*]] -; X64: res_block: -; X64-NEXT: [[PHI_SRC1:%.*]] = phi i64 [ [[TMP4]], [[LOADBB:%.*]] ], [ [[TMP17:%.*]], [[LOADBB1]] ] -; X64-NEXT: [[PHI_SRC2:%.*]] = phi i64 [ [[TMP5]], [[LOADBB]] ], [ [[TMP18:%.*]], [[LOADBB1]] ] -; X64-NEXT: [[TMP7:%.*]] = icmp ult i64 [[PHI_SRC1]], [[PHI_SRC2]] -; X64-NEXT: [[TMP8:%.*]] = select i1 [[TMP7]], i32 -1, i32 1 -; X64-NEXT: br label [[ENDBLOCK:%.*]] -; X64: loadbb1: -; X64-NEXT: [[TMP9:%.*]] = bitcast i8* [[X]] to i16* -; X64-NEXT: [[TMP10:%.*]] = bitcast i8* [[Y]] to i16* -; X64-NEXT: [[TMP11:%.*]] = getelementptr i16, i16* [[TMP9]], i16 4 -; X64-NEXT: [[TMP12:%.*]] = getelementptr i16, i16* [[TMP10]], i16 4 -; X64-NEXT: [[TMP13:%.*]] = load i16, i16* [[TMP11]] -; X64-NEXT: [[TMP14:%.*]] = load i16, i16* [[TMP12]] -; X64-NEXT: [[TMP15:%.*]] = call i16 @llvm.bswap.i16(i16 [[TMP13]]) -; X64-NEXT: [[TMP16:%.*]] = call i16 @llvm.bswap.i16(i16 [[TMP14]]) -; X64-NEXT: [[TMP17]] = zext i16 [[TMP15]] to i64 -; X64-NEXT: [[TMP18]] = zext i16 [[TMP16]] to i64 -; X64-NEXT: [[TMP19:%.*]] = icmp eq i64 [[TMP17]], [[TMP18]] -; X64-NEXT: br i1 [[TMP19]], label [[LOADBB2:%.*]], label [[RES_BLOCK]] -; X64: loadbb2: -; X64-NEXT: [[TMP20:%.*]] = getelementptr i8, i8* [[X]], i8 10 -; X64-NEXT: [[TMP21:%.*]] = getelementptr i8, i8* [[Y]], i8 10 -; X64-NEXT: [[TMP22:%.*]] = load i8, i8* [[TMP20]] -; X64-NEXT: [[TMP23:%.*]] = load i8, i8* [[TMP21]] -; X64-NEXT: [[TMP24:%.*]] = zext i8 [[TMP22]] to i32 -; X64-NEXT: [[TMP25:%.*]] = zext i8 [[TMP23]] to i32 -; X64-NEXT: [[TMP26:%.*]] = sub i32 [[TMP24]], [[TMP25]] -; X64-NEXT: br label [[ENDBLOCK]] -; X64: endblock: -; X64-NEXT: [[PHI_RES:%.*]] = phi i32 [ [[TMP26]], [[LOADBB2]] ], [ [[TMP8]], [[RES_BLOCK]] ] -; X64-NEXT: ret i32 [[PHI_RES]] +; ALL-LABEL: @cmp11( +; ALL-NEXT: [[CALL:%.*]] = tail call i32 @memcmp(i8* [[X:%.*]], i8* [[Y:%.*]], i64 11) +; ALL-NEXT: ret i32 [[CALL]] ; %call = tail call i32 @memcmp(i8* %x, i8* %y, i64 11) ret i32 %call @@ -633,46 +384,8 @@ define i32 @cmp11(i8* nocapture readonly %x, i8* nocapture readonly %y) { define i32 @cmp12(i8* nocapture readonly %x, i8* nocapture readonly %y) { ; X32-LABEL: @cmp12( -; X32-NEXT: loadbb: -; X32-NEXT: [[TMP0:%.*]] = bitcast i8* [[X:%.*]] to i32* -; X32-NEXT: [[TMP1:%.*]] = bitcast i8* [[Y:%.*]] to i32* -; X32-NEXT: [[TMP2:%.*]] = load i32, i32* [[TMP0]] -; X32-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP1]] -; X32-NEXT: [[TMP4:%.*]] = call i32 @llvm.bswap.i32(i32 [[TMP2]]) -; X32-NEXT: [[TMP5:%.*]] = call i32 @llvm.bswap.i32(i32 [[TMP3]]) -; X32-NEXT: [[TMP6:%.*]] = icmp eq i32 [[TMP4]], [[TMP5]] -; X32-NEXT: br i1 [[TMP6]], label [[LOADBB1:%.*]], label [[RES_BLOCK:%.*]] -; X32: res_block: -; X32-NEXT: [[PHI_SRC1:%.*]] = phi i32 [ [[TMP4]], [[LOADBB:%.*]] ], [ [[TMP15:%.*]], [[LOADBB1]] ], [ [[TMP24:%.*]], [[LOADBB2:%.*]] ] -; X32-NEXT: [[PHI_SRC2:%.*]] = phi i32 [ [[TMP5]], [[LOADBB]] ], [ [[TMP16:%.*]], [[LOADBB1]] ], [ [[TMP25:%.*]], [[LOADBB2]] ] -; X32-NEXT: [[TMP7:%.*]] = icmp ult i32 [[PHI_SRC1]], [[PHI_SRC2]] -; X32-NEXT: [[TMP8:%.*]] = select i1 [[TMP7]], i32 -1, i32 1 -; X32-NEXT: br label [[ENDBLOCK:%.*]] -; X32: loadbb1: -; X32-NEXT: [[TMP9:%.*]] = bitcast i8* [[X]] to i32* -; X32-NEXT: [[TMP10:%.*]] = bitcast i8* [[Y]] to i32* -; X32-NEXT: [[TMP11:%.*]] = getelementptr i32, i32* [[TMP9]], i32 1 -; X32-NEXT: [[TMP12:%.*]] = getelementptr i32, i32* [[TMP10]], i32 1 -; X32-NEXT: [[TMP13:%.*]] = load i32, i32* [[TMP11]] -; X32-NEXT: [[TMP14:%.*]] = load i32, i32* [[TMP12]] -; X32-NEXT: [[TMP15]] = call i32 @llvm.bswap.i32(i32 [[TMP13]]) -; X32-NEXT: [[TMP16]] = call i32 @llvm.bswap.i32(i32 [[TMP14]]) -; X32-NEXT: [[TMP17:%.*]] = icmp eq i32 [[TMP15]], [[TMP16]] -; X32-NEXT: br i1 [[TMP17]], label [[LOADBB2]], label [[RES_BLOCK]] -; X32: loadbb2: -; X32-NEXT: [[TMP18:%.*]] = bitcast i8* [[X]] to i32* -; X32-NEXT: [[TMP19:%.*]] = bitcast i8* [[Y]] to i32* -; X32-NEXT: [[TMP20:%.*]] = getelementptr i32, i32* [[TMP18]], i32 2 -; X32-NEXT: [[TMP21:%.*]] = getelementptr i32, i32* [[TMP19]], i32 2 -; X32-NEXT: [[TMP22:%.*]] = load i32, i32* [[TMP20]] -; X32-NEXT: [[TMP23:%.*]] = load i32, i32* [[TMP21]] -; X32-NEXT: [[TMP24]] = call i32 @llvm.bswap.i32(i32 [[TMP22]]) -; X32-NEXT: [[TMP25]] = call i32 @llvm.bswap.i32(i32 [[TMP23]]) -; X32-NEXT: [[TMP26:%.*]] = icmp eq i32 [[TMP24]], [[TMP25]] -; X32-NEXT: br i1 [[TMP26]], label [[ENDBLOCK]], label [[RES_BLOCK]] -; X32: endblock: -; X32-NEXT: [[PHI_RES:%.*]] = phi i32 [ 0, [[LOADBB2]] ], [ [[TMP8]], [[RES_BLOCK]] ] -; X32-NEXT: ret i32 [[PHI_RES]] +; X32-NEXT: [[CALL:%.*]] = tail call i32 @memcmp(i8* [[X:%.*]], i8* [[Y:%.*]], i64 12) +; X32-NEXT: ret i32 [[CALL]] ; ; X64-LABEL: @cmp12( ; X64-NEXT: loadbb: @@ -712,268 +425,27 @@ define i32 @cmp12(i8* nocapture readonly %x, i8* nocapture readonly %y) { } define i32 @cmp13(i8* nocapture readonly %x, i8* nocapture readonly %y) { -; X32-LABEL: @cmp13( -; X32-NEXT: loadbb: -; X32-NEXT: [[TMP0:%.*]] = bitcast i8* [[X:%.*]] to i32* -; X32-NEXT: [[TMP1:%.*]] = bitcast i8* [[Y:%.*]] to i32* -; X32-NEXT: [[TMP2:%.*]] = load i32, i32* [[TMP0]] -; X32-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP1]] -; X32-NEXT: [[TMP4:%.*]] = call i32 @llvm.bswap.i32(i32 [[TMP2]]) -; X32-NEXT: [[TMP5:%.*]] = call i32 @llvm.bswap.i32(i32 [[TMP3]]) -; X32-NEXT: [[TMP6:%.*]] = icmp eq i32 [[TMP4]], [[TMP5]] -; X32-NEXT: br i1 [[TMP6]], label [[LOADBB1:%.*]], label [[RES_BLOCK:%.*]] -; X32: res_block: -; X32-NEXT: [[PHI_SRC1:%.*]] = phi i32 [ [[TMP4]], [[LOADBB:%.*]] ], [ [[TMP15:%.*]], [[LOADBB1]] ], [ [[TMP24:%.*]], [[LOADBB2:%.*]] ] -; X32-NEXT: [[PHI_SRC2:%.*]] = phi i32 [ [[TMP5]], [[LOADBB]] ], [ [[TMP16:%.*]], [[LOADBB1]] ], [ [[TMP25:%.*]], [[LOADBB2]] ] -; X32-NEXT: [[TMP7:%.*]] = icmp ult i32 [[PHI_SRC1]], [[PHI_SRC2]] -; X32-NEXT: [[TMP8:%.*]] = select i1 [[TMP7]], i32 -1, i32 1 -; X32-NEXT: br label [[ENDBLOCK:%.*]] -; X32: loadbb1: -; X32-NEXT: [[TMP9:%.*]] = bitcast i8* [[X]] to i32* -; X32-NEXT: [[TMP10:%.*]] = bitcast i8* [[Y]] to i32* -; X32-NEXT: [[TMP11:%.*]] = getelementptr i32, i32* [[TMP9]], i32 1 -; X32-NEXT: [[TMP12:%.*]] = getelementptr i32, i32* [[TMP10]], i32 1 -; X32-NEXT: [[TMP13:%.*]] = load i32, i32* [[TMP11]] -; X32-NEXT: [[TMP14:%.*]] = load i32, i32* [[TMP12]] -; X32-NEXT: [[TMP15]] = call i32 @llvm.bswap.i32(i32 [[TMP13]]) -; X32-NEXT: [[TMP16]] = call i32 @llvm.bswap.i32(i32 [[TMP14]]) -; X32-NEXT: [[TMP17:%.*]] = icmp eq i32 [[TMP15]], [[TMP16]] -; X32-NEXT: br i1 [[TMP17]], label [[LOADBB2]], label [[RES_BLOCK]] -; X32: loadbb2: -; X32-NEXT: [[TMP18:%.*]] = bitcast i8* [[X]] to i32* -; X32-NEXT: [[TMP19:%.*]] = bitcast i8* [[Y]] to i32* -; X32-NEXT: [[TMP20:%.*]] = getelementptr i32, i32* [[TMP18]], i32 2 -; X32-NEXT: [[TMP21:%.*]] = getelementptr i32, i32* [[TMP19]], i32 2 -; X32-NEXT: [[TMP22:%.*]] = load i32, i32* [[TMP20]] -; X32-NEXT: [[TMP23:%.*]] = load i32, i32* [[TMP21]] -; X32-NEXT: [[TMP24]] = call i32 @llvm.bswap.i32(i32 [[TMP22]]) -; X32-NEXT: [[TMP25]] = call i32 @llvm.bswap.i32(i32 [[TMP23]]) -; X32-NEXT: [[TMP26:%.*]] = icmp eq i32 [[TMP24]], [[TMP25]] -; X32-NEXT: br i1 [[TMP26]], label [[LOADBB3:%.*]], label [[RES_BLOCK]] -; X32: loadbb3: -; X32-NEXT: [[TMP27:%.*]] = getelementptr i8, i8* [[X]], i8 12 -; X32-NEXT: [[TMP28:%.*]] = getelementptr i8, i8* [[Y]], i8 12 -; X32-NEXT: [[TMP29:%.*]] = load i8, i8* [[TMP27]] -; X32-NEXT: [[TMP30:%.*]] = load i8, i8* [[TMP28]] -; X32-NEXT: [[TMP31:%.*]] = zext i8 [[TMP29]] to i32 -; X32-NEXT: [[TMP32:%.*]] = zext i8 [[TMP30]] to i32 -; X32-NEXT: [[TMP33:%.*]] = sub i32 [[TMP31]], [[TMP32]] -; X32-NEXT: br label [[ENDBLOCK]] -; X32: endblock: -; X32-NEXT: [[PHI_RES:%.*]] = phi i32 [ [[TMP33]], [[LOADBB3]] ], [ [[TMP8]], [[RES_BLOCK]] ] -; X32-NEXT: ret i32 [[PHI_RES]] -; -; X64-LABEL: @cmp13( -; X64-NEXT: loadbb: -; X64-NEXT: [[TMP0:%.*]] = bitcast i8* [[X:%.*]] to i64* -; X64-NEXT: [[TMP1:%.*]] = bitcast i8* [[Y:%.*]] to i64* -; X64-NEXT: [[TMP2:%.*]] = load i64, i64* [[TMP0]] -; X64-NEXT: [[TMP3:%.*]] = load i64, i64* [[TMP1]] -; X64-NEXT: [[TMP4:%.*]] = call i64 @llvm.bswap.i64(i64 [[TMP2]]) -; X64-NEXT: [[TMP5:%.*]] = call i64 @llvm.bswap.i64(i64 [[TMP3]]) -; X64-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP4]], [[TMP5]] -; X64-NEXT: br i1 [[TMP6]], label [[LOADBB1:%.*]], label [[RES_BLOCK:%.*]] -; X64: res_block: -; X64-NEXT: [[PHI_SRC1:%.*]] = phi i64 [ [[TMP4]], [[LOADBB:%.*]] ], [ [[TMP17:%.*]], [[LOADBB1]] ] -; X64-NEXT: [[PHI_SRC2:%.*]] = phi i64 [ [[TMP5]], [[LOADBB]] ], [ [[TMP18:%.*]], [[LOADBB1]] ] -; X64-NEXT: [[TMP7:%.*]] = icmp ult i64 [[PHI_SRC1]], [[PHI_SRC2]] -; X64-NEXT: [[TMP8:%.*]] = select i1 [[TMP7]], i32 -1, i32 1 -; X64-NEXT: br label [[ENDBLOCK:%.*]] -; X64: loadbb1: -; X64-NEXT: [[TMP9:%.*]] = bitcast i8* [[X]] to i32* -; X64-NEXT: [[TMP10:%.*]] = bitcast i8* [[Y]] to i32* -; X64-NEXT: [[TMP11:%.*]] = getelementptr i32, i32* [[TMP9]], i32 2 -; X64-NEXT: [[TMP12:%.*]] = getelementptr i32, i32* [[TMP10]], i32 2 -; X64-NEXT: [[TMP13:%.*]] = load i32, i32* [[TMP11]] -; X64-NEXT: [[TMP14:%.*]] = load i32, i32* [[TMP12]] -; X64-NEXT: [[TMP15:%.*]] = call i32 @llvm.bswap.i32(i32 [[TMP13]]) -; X64-NEXT: [[TMP16:%.*]] = call i32 @llvm.bswap.i32(i32 [[TMP14]]) -; X64-NEXT: [[TMP17]] = zext i32 [[TMP15]] to i64 -; X64-NEXT: [[TMP18]] = zext i32 [[TMP16]] to i64 -; X64-NEXT: [[TMP19:%.*]] = icmp eq i64 [[TMP17]], [[TMP18]] -; X64-NEXT: br i1 [[TMP19]], label [[LOADBB2:%.*]], label [[RES_BLOCK]] -; X64: loadbb2: -; X64-NEXT: [[TMP20:%.*]] = getelementptr i8, i8* [[X]], i8 12 -; X64-NEXT: [[TMP21:%.*]] = getelementptr i8, i8* [[Y]], i8 12 -; X64-NEXT: [[TMP22:%.*]] = load i8, i8* [[TMP20]] -; X64-NEXT: [[TMP23:%.*]] = load i8, i8* [[TMP21]] -; X64-NEXT: [[TMP24:%.*]] = zext i8 [[TMP22]] to i32 -; X64-NEXT: [[TMP25:%.*]] = zext i8 [[TMP23]] to i32 -; X64-NEXT: [[TMP26:%.*]] = sub i32 [[TMP24]], [[TMP25]] -; X64-NEXT: br label [[ENDBLOCK]] -; X64: endblock: -; X64-NEXT: [[PHI_RES:%.*]] = phi i32 [ [[TMP26]], [[LOADBB2]] ], [ [[TMP8]], [[RES_BLOCK]] ] -; X64-NEXT: ret i32 [[PHI_RES]] +; ALL-LABEL: @cmp13( +; ALL-NEXT: [[CALL:%.*]] = tail call i32 @memcmp(i8* [[X:%.*]], i8* [[Y:%.*]], i64 13) +; ALL-NEXT: ret i32 [[CALL]] ; %call = tail call i32 @memcmp(i8* %x, i8* %y, i64 13) ret i32 %call } define i32 @cmp14(i8* nocapture readonly %x, i8* nocapture readonly %y) { -; X32-LABEL: @cmp14( -; X32-NEXT: loadbb: -; X32-NEXT: [[TMP0:%.*]] = bitcast i8* [[X:%.*]] to i32* -; X32-NEXT: [[TMP1:%.*]] = bitcast i8* [[Y:%.*]] to i32* -; X32-NEXT: [[TMP2:%.*]] = load i32, i32* [[TMP0]] -; X32-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP1]] -; X32-NEXT: [[TMP4:%.*]] = call i32 @llvm.bswap.i32(i32 [[TMP2]]) -; X32-NEXT: [[TMP5:%.*]] = call i32 @llvm.bswap.i32(i32 [[TMP3]]) -; X32-NEXT: [[TMP6:%.*]] = icmp eq i32 [[TMP4]], [[TMP5]] -; X32-NEXT: br i1 [[TMP6]], label [[LOADBB1:%.*]], label [[RES_BLOCK:%.*]] -; X32: res_block: -; X32-NEXT: [[PHI_SRC1:%.*]] = phi i32 [ [[TMP4]], [[LOADBB:%.*]] ], [ [[TMP15:%.*]], [[LOADBB1]] ], [ [[TMP24:%.*]], [[LOADBB2:%.*]] ], [ [[TMP35:%.*]], [[LOADBB3:%.*]] ] -; X32-NEXT: [[PHI_SRC2:%.*]] = phi i32 [ [[TMP5]], [[LOADBB]] ], [ [[TMP16:%.*]], [[LOADBB1]] ], [ [[TMP25:%.*]], [[LOADBB2]] ], [ [[TMP36:%.*]], [[LOADBB3]] ] -; X32-NEXT: [[TMP7:%.*]] = icmp ult i32 [[PHI_SRC1]], [[PHI_SRC2]] -; X32-NEXT: [[TMP8:%.*]] = select i1 [[TMP7]], i32 -1, i32 1 -; X32-NEXT: br label [[ENDBLOCK:%.*]] -; X32: loadbb1: -; X32-NEXT: [[TMP9:%.*]] = bitcast i8* [[X]] to i32* -; X32-NEXT: [[TMP10:%.*]] = bitcast i8* [[Y]] to i32* -; X32-NEXT: [[TMP11:%.*]] = getelementptr i32, i32* [[TMP9]], i32 1 -; X32-NEXT: [[TMP12:%.*]] = getelementptr i32, i32* [[TMP10]], i32 1 -; X32-NEXT: [[TMP13:%.*]] = load i32, i32* [[TMP11]] -; X32-NEXT: [[TMP14:%.*]] = load i32, i32* [[TMP12]] -; X32-NEXT: [[TMP15]] = call i32 @llvm.bswap.i32(i32 [[TMP13]]) -; X32-NEXT: [[TMP16]] = call i32 @llvm.bswap.i32(i32 [[TMP14]]) -; X32-NEXT: [[TMP17:%.*]] = icmp eq i32 [[TMP15]], [[TMP16]] -; X32-NEXT: br i1 [[TMP17]], label [[LOADBB2]], label [[RES_BLOCK]] -; X32: loadbb2: -; X32-NEXT: [[TMP18:%.*]] = bitcast i8* [[X]] to i32* -; X32-NEXT: [[TMP19:%.*]] = bitcast i8* [[Y]] to i32* -; X32-NEXT: [[TMP20:%.*]] = getelementptr i32, i32* [[TMP18]], i32 2 -; X32-NEXT: [[TMP21:%.*]] = getelementptr i32, i32* [[TMP19]], i32 2 -; X32-NEXT: [[TMP22:%.*]] = load i32, i32* [[TMP20]] -; X32-NEXT: [[TMP23:%.*]] = load i32, i32* [[TMP21]] -; X32-NEXT: [[TMP24]] = call i32 @llvm.bswap.i32(i32 [[TMP22]]) -; X32-NEXT: [[TMP25]] = call i32 @llvm.bswap.i32(i32 [[TMP23]]) -; X32-NEXT: [[TMP26:%.*]] = icmp eq i32 [[TMP24]], [[TMP25]] -; X32-NEXT: br i1 [[TMP26]], label [[LOADBB3]], label [[RES_BLOCK]] -; X32: loadbb3: -; X32-NEXT: [[TMP27:%.*]] = bitcast i8* [[X]] to i16* -; X32-NEXT: [[TMP28:%.*]] = bitcast i8* [[Y]] to i16* -; X32-NEXT: [[TMP29:%.*]] = getelementptr i16, i16* [[TMP27]], i16 6 -; X32-NEXT: [[TMP30:%.*]] = getelementptr i16, i16* [[TMP28]], i16 6 -; X32-NEXT: [[TMP31:%.*]] = load i16, i16* [[TMP29]] -; X32-NEXT: [[TMP32:%.*]] = load i16, i16* [[TMP30]] -; X32-NEXT: [[TMP33:%.*]] = call i16 @llvm.bswap.i16(i16 [[TMP31]]) -; X32-NEXT: [[TMP34:%.*]] = call i16 @llvm.bswap.i16(i16 [[TMP32]]) -; X32-NEXT: [[TMP35]] = zext i16 [[TMP33]] to i32 -; X32-NEXT: [[TMP36]] = zext i16 [[TMP34]] to i32 -; X32-NEXT: [[TMP37:%.*]] = icmp eq i32 [[TMP35]], [[TMP36]] -; X32-NEXT: br i1 [[TMP37]], label [[ENDBLOCK]], label [[RES_BLOCK]] -; X32: endblock: -; X32-NEXT: [[PHI_RES:%.*]] = phi i32 [ 0, [[LOADBB3]] ], [ [[TMP8]], [[RES_BLOCK]] ] -; X32-NEXT: ret i32 [[PHI_RES]] -; -; X64-LABEL: @cmp14( -; X64-NEXT: loadbb: -; X64-NEXT: [[TMP0:%.*]] = bitcast i8* [[X:%.*]] to i64* -; X64-NEXT: [[TMP1:%.*]] = bitcast i8* [[Y:%.*]] to i64* -; X64-NEXT: [[TMP2:%.*]] = load i64, i64* [[TMP0]] -; X64-NEXT: [[TMP3:%.*]] = load i64, i64* [[TMP1]] -; X64-NEXT: [[TMP4:%.*]] = call i64 @llvm.bswap.i64(i64 [[TMP2]]) -; X64-NEXT: [[TMP5:%.*]] = call i64 @llvm.bswap.i64(i64 [[TMP3]]) -; X64-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP4]], [[TMP5]] -; X64-NEXT: br i1 [[TMP6]], label [[LOADBB1:%.*]], label [[RES_BLOCK:%.*]] -; X64: res_block: -; X64-NEXT: [[PHI_SRC1:%.*]] = phi i64 [ [[TMP4]], [[LOADBB:%.*]] ], [ [[TMP17:%.*]], [[LOADBB1]] ], [ [[TMP28:%.*]], [[LOADBB2:%.*]] ] -; X64-NEXT: [[PHI_SRC2:%.*]] = phi i64 [ [[TMP5]], [[LOADBB]] ], [ [[TMP18:%.*]], [[LOADBB1]] ], [ [[TMP29:%.*]], [[LOADBB2]] ] -; X64-NEXT: [[TMP7:%.*]] = icmp ult i64 [[PHI_SRC1]], [[PHI_SRC2]] -; X64-NEXT: [[TMP8:%.*]] = select i1 [[TMP7]], i32 -1, i32 1 -; X64-NEXT: br label [[ENDBLOCK:%.*]] -; X64: loadbb1: -; X64-NEXT: [[TMP9:%.*]] = bitcast i8* [[X]] to i32* -; X64-NEXT: [[TMP10:%.*]] = bitcast i8* [[Y]] to i32* -; X64-NEXT: [[TMP11:%.*]] = getelementptr i32, i32* [[TMP9]], i32 2 -; X64-NEXT: [[TMP12:%.*]] = getelementptr i32, i32* [[TMP10]], i32 2 -; X64-NEXT: [[TMP13:%.*]] = load i32, i32* [[TMP11]] -; X64-NEXT: [[TMP14:%.*]] = load i32, i32* [[TMP12]] -; X64-NEXT: [[TMP15:%.*]] = call i32 @llvm.bswap.i32(i32 [[TMP13]]) -; X64-NEXT: [[TMP16:%.*]] = call i32 @llvm.bswap.i32(i32 [[TMP14]]) -; X64-NEXT: [[TMP17]] = zext i32 [[TMP15]] to i64 -; X64-NEXT: [[TMP18]] = zext i32 [[TMP16]] to i64 -; X64-NEXT: [[TMP19:%.*]] = icmp eq i64 [[TMP17]], [[TMP18]] -; X64-NEXT: br i1 [[TMP19]], label [[LOADBB2]], label [[RES_BLOCK]] -; X64: loadbb2: -; X64-NEXT: [[TMP20:%.*]] = bitcast i8* [[X]] to i16* -; X64-NEXT: [[TMP21:%.*]] = bitcast i8* [[Y]] to i16* -; X64-NEXT: [[TMP22:%.*]] = getelementptr i16, i16* [[TMP20]], i16 6 -; X64-NEXT: [[TMP23:%.*]] = getelementptr i16, i16* [[TMP21]], i16 6 -; X64-NEXT: [[TMP24:%.*]] = load i16, i16* [[TMP22]] -; X64-NEXT: [[TMP25:%.*]] = load i16, i16* [[TMP23]] -; X64-NEXT: [[TMP26:%.*]] = call i16 @llvm.bswap.i16(i16 [[TMP24]]) -; X64-NEXT: [[TMP27:%.*]] = call i16 @llvm.bswap.i16(i16 [[TMP25]]) -; X64-NEXT: [[TMP28]] = zext i16 [[TMP26]] to i64 -; X64-NEXT: [[TMP29]] = zext i16 [[TMP27]] to i64 -; X64-NEXT: [[TMP30:%.*]] = icmp eq i64 [[TMP28]], [[TMP29]] -; X64-NEXT: br i1 [[TMP30]], label [[ENDBLOCK]], label [[RES_BLOCK]] -; X64: endblock: -; X64-NEXT: [[PHI_RES:%.*]] = phi i32 [ 0, [[LOADBB2]] ], [ [[TMP8]], [[RES_BLOCK]] ] -; X64-NEXT: ret i32 [[PHI_RES]] +; ALL-LABEL: @cmp14( +; ALL-NEXT: [[CALL:%.*]] = tail call i32 @memcmp(i8* [[X:%.*]], i8* [[Y:%.*]], i64 14) +; ALL-NEXT: ret i32 [[CALL]] ; %call = tail call i32 @memcmp(i8* %x, i8* %y, i64 14) ret i32 %call } define i32 @cmp15(i8* nocapture readonly %x, i8* nocapture readonly %y) { -; X32-LABEL: @cmp15( -; X32-NEXT: [[CALL:%.*]] = tail call i32 @memcmp(i8* [[X:%.*]], i8* [[Y:%.*]], i64 15) -; X32-NEXT: ret i32 [[CALL]] -; -; X64-LABEL: @cmp15( -; X64-NEXT: loadbb: -; X64-NEXT: [[TMP0:%.*]] = bitcast i8* [[X:%.*]] to i64* -; X64-NEXT: [[TMP1:%.*]] = bitcast i8* [[Y:%.*]] to i64* -; X64-NEXT: [[TMP2:%.*]] = load i64, i64* [[TMP0]] -; X64-NEXT: [[TMP3:%.*]] = load i64, i64* [[TMP1]] -; X64-NEXT: [[TMP4:%.*]] = call i64 @llvm.bswap.i64(i64 [[TMP2]]) -; X64-NEXT: [[TMP5:%.*]] = call i64 @llvm.bswap.i64(i64 [[TMP3]]) -; X64-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP4]], [[TMP5]] -; X64-NEXT: br i1 [[TMP6]], label [[LOADBB1:%.*]], label [[RES_BLOCK:%.*]] -; X64: res_block: -; X64-NEXT: [[PHI_SRC1:%.*]] = phi i64 [ [[TMP4]], [[LOADBB:%.*]] ], [ [[TMP17:%.*]], [[LOADBB1]] ], [ [[TMP28:%.*]], [[LOADBB2:%.*]] ] -; X64-NEXT: [[PHI_SRC2:%.*]] = phi i64 [ [[TMP5]], [[LOADBB]] ], [ [[TMP18:%.*]], [[LOADBB1]] ], [ [[TMP29:%.*]], [[LOADBB2]] ] -; X64-NEXT: [[TMP7:%.*]] = icmp ult i64 [[PHI_SRC1]], [[PHI_SRC2]] -; X64-NEXT: [[TMP8:%.*]] = select i1 [[TMP7]], i32 -1, i32 1 -; X64-NEXT: br label [[ENDBLOCK:%.*]] -; X64: loadbb1: -; X64-NEXT: [[TMP9:%.*]] = bitcast i8* [[X]] to i32* -; X64-NEXT: [[TMP10:%.*]] = bitcast i8* [[Y]] to i32* -; X64-NEXT: [[TMP11:%.*]] = getelementptr i32, i32* [[TMP9]], i32 2 -; X64-NEXT: [[TMP12:%.*]] = getelementptr i32, i32* [[TMP10]], i32 2 -; X64-NEXT: [[TMP13:%.*]] = load i32, i32* [[TMP11]] -; X64-NEXT: [[TMP14:%.*]] = load i32, i32* [[TMP12]] -; X64-NEXT: [[TMP15:%.*]] = call i32 @llvm.bswap.i32(i32 [[TMP13]]) -; X64-NEXT: [[TMP16:%.*]] = call i32 @llvm.bswap.i32(i32 [[TMP14]]) -; X64-NEXT: [[TMP17]] = zext i32 [[TMP15]] to i64 -; X64-NEXT: [[TMP18]] = zext i32 [[TMP16]] to i64 -; X64-NEXT: [[TMP19:%.*]] = icmp eq i64 [[TMP17]], [[TMP18]] -; X64-NEXT: br i1 [[TMP19]], label [[LOADBB2]], label [[RES_BLOCK]] -; X64: loadbb2: -; X64-NEXT: [[TMP20:%.*]] = bitcast i8* [[X]] to i16* -; X64-NEXT: [[TMP21:%.*]] = bitcast i8* [[Y]] to i16* -; X64-NEXT: [[TMP22:%.*]] = getelementptr i16, i16* [[TMP20]], i16 6 -; X64-NEXT: [[TMP23:%.*]] = getelementptr i16, i16* [[TMP21]], i16 6 -; X64-NEXT: [[TMP24:%.*]] = load i16, i16* [[TMP22]] -; X64-NEXT: [[TMP25:%.*]] = load i16, i16* [[TMP23]] -; X64-NEXT: [[TMP26:%.*]] = call i16 @llvm.bswap.i16(i16 [[TMP24]]) -; X64-NEXT: [[TMP27:%.*]] = call i16 @llvm.bswap.i16(i16 [[TMP25]]) -; X64-NEXT: [[TMP28]] = zext i16 [[TMP26]] to i64 -; X64-NEXT: [[TMP29]] = zext i16 [[TMP27]] to i64 -; X64-NEXT: [[TMP30:%.*]] = icmp eq i64 [[TMP28]], [[TMP29]] -; X64-NEXT: br i1 [[TMP30]], label [[LOADBB3:%.*]], label [[RES_BLOCK]] -; X64: loadbb3: -; X64-NEXT: [[TMP31:%.*]] = getelementptr i8, i8* [[X]], i8 14 -; X64-NEXT: [[TMP32:%.*]] = getelementptr i8, i8* [[Y]], i8 14 -; X64-NEXT: [[TMP33:%.*]] = load i8, i8* [[TMP31]] -; X64-NEXT: [[TMP34:%.*]] = load i8, i8* [[TMP32]] -; X64-NEXT: [[TMP35:%.*]] = zext i8 [[TMP33]] to i32 -; X64-NEXT: [[TMP36:%.*]] = zext i8 [[TMP34]] to i32 -; X64-NEXT: [[TMP37:%.*]] = sub i32 [[TMP35]], [[TMP36]] -; X64-NEXT: br label [[ENDBLOCK]] -; X64: endblock: -; X64-NEXT: [[PHI_RES:%.*]] = phi i32 [ [[TMP37]], [[LOADBB3]] ], [ [[TMP8]], [[RES_BLOCK]] ] -; X64-NEXT: ret i32 [[PHI_RES]] +; ALL-LABEL: @cmp15( +; ALL-NEXT: [[CALL:%.*]] = tail call i32 @memcmp(i8* [[X:%.*]], i8* [[Y:%.*]], i64 15) +; ALL-NEXT: ret i32 [[CALL]] ; %call = tail call i32 @memcmp(i8* %x, i8* %y, i64 15) ret i32 %call @@ -981,57 +453,8 @@ define i32 @cmp15(i8* nocapture readonly %x, i8* nocapture readonly %y) { define i32 @cmp16(i8* nocapture readonly %x, i8* nocapture readonly %y) { ; X32-LABEL: @cmp16( -; X32-NEXT: loadbb: -; X32-NEXT: [[TMP0:%.*]] = bitcast i8* [[X:%.*]] to i32* -; X32-NEXT: [[TMP1:%.*]] = bitcast i8* [[Y:%.*]] to i32* -; X32-NEXT: [[TMP2:%.*]] = load i32, i32* [[TMP0]] -; X32-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP1]] -; X32-NEXT: [[TMP4:%.*]] = call i32 @llvm.bswap.i32(i32 [[TMP2]]) -; X32-NEXT: [[TMP5:%.*]] = call i32 @llvm.bswap.i32(i32 [[TMP3]]) -; X32-NEXT: [[TMP6:%.*]] = icmp eq i32 [[TMP4]], [[TMP5]] -; X32-NEXT: br i1 [[TMP6]], label [[LOADBB1:%.*]], label [[RES_BLOCK:%.*]] -; X32: res_block: -; X32-NEXT: [[PHI_SRC1:%.*]] = phi i32 [ [[TMP4]], [[LOADBB:%.*]] ], [ [[TMP15:%.*]], [[LOADBB1]] ], [ [[TMP24:%.*]], [[LOADBB2:%.*]] ], [ [[TMP33:%.*]], [[LOADBB3:%.*]] ] -; X32-NEXT: [[PHI_SRC2:%.*]] = phi i32 [ [[TMP5]], [[LOADBB]] ], [ [[TMP16:%.*]], [[LOADBB1]] ], [ [[TMP25:%.*]], [[LOADBB2]] ], [ [[TMP34:%.*]], [[LOADBB3]] ] -; X32-NEXT: [[TMP7:%.*]] = icmp ult i32 [[PHI_SRC1]], [[PHI_SRC2]] -; X32-NEXT: [[TMP8:%.*]] = select i1 [[TMP7]], i32 -1, i32 1 -; X32-NEXT: br label [[ENDBLOCK:%.*]] -; X32: loadbb1: -; X32-NEXT: [[TMP9:%.*]] = bitcast i8* [[X]] to i32* -; X32-NEXT: [[TMP10:%.*]] = bitcast i8* [[Y]] to i32* -; X32-NEXT: [[TMP11:%.*]] = getelementptr i32, i32* [[TMP9]], i32 1 -; X32-NEXT: [[TMP12:%.*]] = getelementptr i32, i32* [[TMP10]], i32 1 -; X32-NEXT: [[TMP13:%.*]] = load i32, i32* [[TMP11]] -; X32-NEXT: [[TMP14:%.*]] = load i32, i32* [[TMP12]] -; X32-NEXT: [[TMP15]] = call i32 @llvm.bswap.i32(i32 [[TMP13]]) -; X32-NEXT: [[TMP16]] = call i32 @llvm.bswap.i32(i32 [[TMP14]]) -; X32-NEXT: [[TMP17:%.*]] = icmp eq i32 [[TMP15]], [[TMP16]] -; X32-NEXT: br i1 [[TMP17]], label [[LOADBB2]], label [[RES_BLOCK]] -; X32: loadbb2: -; X32-NEXT: [[TMP18:%.*]] = bitcast i8* [[X]] to i32* -; X32-NEXT: [[TMP19:%.*]] = bitcast i8* [[Y]] to i32* -; X32-NEXT: [[TMP20:%.*]] = getelementptr i32, i32* [[TMP18]], i32 2 -; X32-NEXT: [[TMP21:%.*]] = getelementptr i32, i32* [[TMP19]], i32 2 -; X32-NEXT: [[TMP22:%.*]] = load i32, i32* [[TMP20]] -; X32-NEXT: [[TMP23:%.*]] = load i32, i32* [[TMP21]] -; X32-NEXT: [[TMP24]] = call i32 @llvm.bswap.i32(i32 [[TMP22]]) -; X32-NEXT: [[TMP25]] = call i32 @llvm.bswap.i32(i32 [[TMP23]]) -; X32-NEXT: [[TMP26:%.*]] = icmp eq i32 [[TMP24]], [[TMP25]] -; X32-NEXT: br i1 [[TMP26]], label [[LOADBB3]], label [[RES_BLOCK]] -; X32: loadbb3: -; X32-NEXT: [[TMP27:%.*]] = bitcast i8* [[X]] to i32* -; X32-NEXT: [[TMP28:%.*]] = bitcast i8* [[Y]] to i32* -; X32-NEXT: [[TMP29:%.*]] = getelementptr i32, i32* [[TMP27]], i32 3 -; X32-NEXT: [[TMP30:%.*]] = getelementptr i32, i32* [[TMP28]], i32 3 -; X32-NEXT: [[TMP31:%.*]] = load i32, i32* [[TMP29]] -; X32-NEXT: [[TMP32:%.*]] = load i32, i32* [[TMP30]] -; X32-NEXT: [[TMP33]] = call i32 @llvm.bswap.i32(i32 [[TMP31]]) -; X32-NEXT: [[TMP34]] = call i32 @llvm.bswap.i32(i32 [[TMP32]]) -; X32-NEXT: [[TMP35:%.*]] = icmp eq i32 [[TMP33]], [[TMP34]] -; X32-NEXT: br i1 [[TMP35]], label [[ENDBLOCK]], label [[RES_BLOCK]] -; X32: endblock: -; X32-NEXT: [[PHI_RES:%.*]] = phi i32 [ 0, [[LOADBB3]] ], [ [[TMP8]], [[RES_BLOCK]] ] -; X32-NEXT: ret i32 [[PHI_RES]] +; X32-NEXT: [[CALL:%.*]] = tail call i32 @memcmp(i8* [[X:%.*]], i8* [[Y:%.*]], i64 16) +; X32-NEXT: ret i32 [[CALL]] ; ; X64-LABEL: @cmp16( ; X64-NEXT: loadbb: @@ -1198,34 +621,8 @@ define i32 @cmp_eq6(i8* nocapture readonly %x, i8* nocapture readonly %y) { define i32 @cmp_eq7(i8* nocapture readonly %x, i8* nocapture readonly %y) { ; ALL-LABEL: @cmp_eq7( -; ALL-NEXT: loadbb: -; ALL-NEXT: [[TMP0:%.*]] = bitcast i8* [[X:%.*]] to i32* -; ALL-NEXT: [[TMP1:%.*]] = bitcast i8* [[Y:%.*]] to i32* -; ALL-NEXT: [[TMP2:%.*]] = load i32, i32* [[TMP0]] -; ALL-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP1]] -; ALL-NEXT: [[TMP4:%.*]] = icmp ne i32 [[TMP2]], [[TMP3]] -; ALL-NEXT: br i1 [[TMP4]], label [[RES_BLOCK:%.*]], label [[LOADBB1:%.*]] -; ALL: res_block: -; ALL-NEXT: br label [[ENDBLOCK:%.*]] -; ALL: loadbb1: -; ALL-NEXT: [[TMP5:%.*]] = bitcast i8* [[X]] to i16* -; ALL-NEXT: [[TMP6:%.*]] = bitcast i8* [[Y]] to i16* -; ALL-NEXT: [[TMP7:%.*]] = getelementptr i16, i16* [[TMP5]], i16 2 -; ALL-NEXT: [[TMP8:%.*]] = getelementptr i16, i16* [[TMP6]], i16 2 -; ALL-NEXT: [[TMP9:%.*]] = load i16, i16* [[TMP7]] -; ALL-NEXT: [[TMP10:%.*]] = load i16, i16* [[TMP8]] -; ALL-NEXT: [[TMP11:%.*]] = icmp ne i16 [[TMP9]], [[TMP10]] -; ALL-NEXT: br i1 [[TMP11]], label [[RES_BLOCK]], label [[LOADBB2:%.*]] -; ALL: loadbb2: -; ALL-NEXT: [[TMP12:%.*]] = getelementptr i8, i8* [[X]], i8 6 -; ALL-NEXT: [[TMP13:%.*]] = getelementptr i8, i8* [[Y]], i8 6 -; ALL-NEXT: [[TMP14:%.*]] = load i8, i8* [[TMP12]] -; ALL-NEXT: [[TMP15:%.*]] = load i8, i8* [[TMP13]] -; ALL-NEXT: [[TMP16:%.*]] = icmp ne i8 [[TMP14]], [[TMP15]] -; ALL-NEXT: br i1 [[TMP16]], label [[RES_BLOCK]], label [[ENDBLOCK]] -; ALL: endblock: -; ALL-NEXT: [[PHI_RES:%.*]] = phi i32 [ 0, [[LOADBB2]] ], [ 1, [[RES_BLOCK]] ] -; ALL-NEXT: [[CMP:%.*]] = icmp eq i32 [[PHI_RES]], 0 +; ALL-NEXT: [[CALL:%.*]] = tail call i32 @memcmp(i8* [[X:%.*]], i8* [[Y:%.*]], i64 7) +; ALL-NEXT: [[CMP:%.*]] = icmp eq i32 [[CALL]], 0 ; ALL-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 ; ALL-NEXT: ret i32 [[CONV]] ; @@ -1280,34 +677,8 @@ define i32 @cmp_eq8(i8* nocapture readonly %x, i8* nocapture readonly %y) { define i32 @cmp_eq9(i8* nocapture readonly %x, i8* nocapture readonly %y) { ; X32-LABEL: @cmp_eq9( -; X32-NEXT: loadbb: -; X32-NEXT: [[TMP0:%.*]] = bitcast i8* [[X:%.*]] to i32* -; X32-NEXT: [[TMP1:%.*]] = bitcast i8* [[Y:%.*]] to i32* -; X32-NEXT: [[TMP2:%.*]] = load i32, i32* [[TMP0]] -; X32-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP1]] -; X32-NEXT: [[TMP4:%.*]] = icmp ne i32 [[TMP2]], [[TMP3]] -; X32-NEXT: br i1 [[TMP4]], label [[RES_BLOCK:%.*]], label [[LOADBB1:%.*]] -; X32: res_block: -; X32-NEXT: br label [[ENDBLOCK:%.*]] -; X32: loadbb1: -; X32-NEXT: [[TMP5:%.*]] = bitcast i8* [[X]] to i32* -; X32-NEXT: [[TMP6:%.*]] = bitcast i8* [[Y]] to i32* -; X32-NEXT: [[TMP7:%.*]] = getelementptr i32, i32* [[TMP5]], i32 1 -; X32-NEXT: [[TMP8:%.*]] = getelementptr i32, i32* [[TMP6]], i32 1 -; X32-NEXT: [[TMP9:%.*]] = load i32, i32* [[TMP7]] -; X32-NEXT: [[TMP10:%.*]] = load i32, i32* [[TMP8]] -; X32-NEXT: [[TMP11:%.*]] = icmp ne i32 [[TMP9]], [[TMP10]] -; X32-NEXT: br i1 [[TMP11]], label [[RES_BLOCK]], label [[LOADBB2:%.*]] -; X32: loadbb2: -; X32-NEXT: [[TMP12:%.*]] = getelementptr i8, i8* [[X]], i8 8 -; X32-NEXT: [[TMP13:%.*]] = getelementptr i8, i8* [[Y]], i8 8 -; X32-NEXT: [[TMP14:%.*]] = load i8, i8* [[TMP12]] -; X32-NEXT: [[TMP15:%.*]] = load i8, i8* [[TMP13]] -; X32-NEXT: [[TMP16:%.*]] = icmp ne i8 [[TMP14]], [[TMP15]] -; X32-NEXT: br i1 [[TMP16]], label [[RES_BLOCK]], label [[ENDBLOCK]] -; X32: endblock: -; X32-NEXT: [[PHI_RES:%.*]] = phi i32 [ 0, [[LOADBB2]] ], [ 1, [[RES_BLOCK]] ] -; X32-NEXT: [[CMP:%.*]] = icmp eq i32 [[PHI_RES]], 0 +; X32-NEXT: [[CALL:%.*]] = tail call i32 @memcmp(i8* [[X:%.*]], i8* [[Y:%.*]], i64 9) +; X32-NEXT: [[CMP:%.*]] = icmp eq i32 [[CALL]], 0 ; X32-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 ; X32-NEXT: ret i32 [[CONV]] ; @@ -1342,36 +713,8 @@ define i32 @cmp_eq9(i8* nocapture readonly %x, i8* nocapture readonly %y) { define i32 @cmp_eq10(i8* nocapture readonly %x, i8* nocapture readonly %y) { ; X32-LABEL: @cmp_eq10( -; X32-NEXT: loadbb: -; X32-NEXT: [[TMP0:%.*]] = bitcast i8* [[X:%.*]] to i32* -; X32-NEXT: [[TMP1:%.*]] = bitcast i8* [[Y:%.*]] to i32* -; X32-NEXT: [[TMP2:%.*]] = load i32, i32* [[TMP0]] -; X32-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP1]] -; X32-NEXT: [[TMP4:%.*]] = icmp ne i32 [[TMP2]], [[TMP3]] -; X32-NEXT: br i1 [[TMP4]], label [[RES_BLOCK:%.*]], label [[LOADBB1:%.*]] -; X32: res_block: -; X32-NEXT: br label [[ENDBLOCK:%.*]] -; X32: loadbb1: -; X32-NEXT: [[TMP5:%.*]] = bitcast i8* [[X]] to i32* -; X32-NEXT: [[TMP6:%.*]] = bitcast i8* [[Y]] to i32* -; X32-NEXT: [[TMP7:%.*]] = getelementptr i32, i32* [[TMP5]], i32 1 -; X32-NEXT: [[TMP8:%.*]] = getelementptr i32, i32* [[TMP6]], i32 1 -; X32-NEXT: [[TMP9:%.*]] = load i32, i32* [[TMP7]] -; X32-NEXT: [[TMP10:%.*]] = load i32, i32* [[TMP8]] -; X32-NEXT: [[TMP11:%.*]] = icmp ne i32 [[TMP9]], [[TMP10]] -; X32-NEXT: br i1 [[TMP11]], label [[RES_BLOCK]], label [[LOADBB2:%.*]] -; X32: loadbb2: -; X32-NEXT: [[TMP12:%.*]] = bitcast i8* [[X]] to i16* -; X32-NEXT: [[TMP13:%.*]] = bitcast i8* [[Y]] to i16* -; X32-NEXT: [[TMP14:%.*]] = getelementptr i16, i16* [[TMP12]], i16 4 -; X32-NEXT: [[TMP15:%.*]] = getelementptr i16, i16* [[TMP13]], i16 4 -; X32-NEXT: [[TMP16:%.*]] = load i16, i16* [[TMP14]] -; X32-NEXT: [[TMP17:%.*]] = load i16, i16* [[TMP15]] -; X32-NEXT: [[TMP18:%.*]] = icmp ne i16 [[TMP16]], [[TMP17]] -; X32-NEXT: br i1 [[TMP18]], label [[RES_BLOCK]], label [[ENDBLOCK]] -; X32: endblock: -; X32-NEXT: [[PHI_RES:%.*]] = phi i32 [ 0, [[LOADBB2]] ], [ 1, [[RES_BLOCK]] ] -; X32-NEXT: [[CMP:%.*]] = icmp eq i32 [[PHI_RES]], 0 +; X32-NEXT: [[CALL:%.*]] = tail call i32 @memcmp(i8* [[X:%.*]], i8* [[Y:%.*]], i64 10) +; X32-NEXT: [[CMP:%.*]] = icmp eq i32 [[CALL]], 0 ; X32-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 ; X32-NEXT: ret i32 [[CONV]] ; @@ -1407,78 +750,11 @@ define i32 @cmp_eq10(i8* nocapture readonly %x, i8* nocapture readonly %y) { } define i32 @cmp_eq11(i8* nocapture readonly %x, i8* nocapture readonly %y) { -; X32-LABEL: @cmp_eq11( -; X32-NEXT: loadbb: -; X32-NEXT: [[TMP0:%.*]] = bitcast i8* [[X:%.*]] to i32* -; X32-NEXT: [[TMP1:%.*]] = bitcast i8* [[Y:%.*]] to i32* -; X32-NEXT: [[TMP2:%.*]] = load i32, i32* [[TMP0]] -; X32-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP1]] -; X32-NEXT: [[TMP4:%.*]] = icmp ne i32 [[TMP2]], [[TMP3]] -; X32-NEXT: br i1 [[TMP4]], label [[RES_BLOCK:%.*]], label [[LOADBB1:%.*]] -; X32: res_block: -; X32-NEXT: br label [[ENDBLOCK:%.*]] -; X32: loadbb1: -; X32-NEXT: [[TMP5:%.*]] = bitcast i8* [[X]] to i32* -; X32-NEXT: [[TMP6:%.*]] = bitcast i8* [[Y]] to i32* -; X32-NEXT: [[TMP7:%.*]] = getelementptr i32, i32* [[TMP5]], i32 1 -; X32-NEXT: [[TMP8:%.*]] = getelementptr i32, i32* [[TMP6]], i32 1 -; X32-NEXT: [[TMP9:%.*]] = load i32, i32* [[TMP7]] -; X32-NEXT: [[TMP10:%.*]] = load i32, i32* [[TMP8]] -; X32-NEXT: [[TMP11:%.*]] = icmp ne i32 [[TMP9]], [[TMP10]] -; X32-NEXT: br i1 [[TMP11]], label [[RES_BLOCK]], label [[LOADBB2:%.*]] -; X32: loadbb2: -; X32-NEXT: [[TMP12:%.*]] = bitcast i8* [[X]] to i16* -; X32-NEXT: [[TMP13:%.*]] = bitcast i8* [[Y]] to i16* -; X32-NEXT: [[TMP14:%.*]] = getelementptr i16, i16* [[TMP12]], i16 4 -; X32-NEXT: [[TMP15:%.*]] = getelementptr i16, i16* [[TMP13]], i16 4 -; X32-NEXT: [[TMP16:%.*]] = load i16, i16* [[TMP14]] -; X32-NEXT: [[TMP17:%.*]] = load i16, i16* [[TMP15]] -; X32-NEXT: [[TMP18:%.*]] = icmp ne i16 [[TMP16]], [[TMP17]] -; X32-NEXT: br i1 [[TMP18]], label [[RES_BLOCK]], label [[LOADBB3:%.*]] -; X32: loadbb3: -; X32-NEXT: [[TMP19:%.*]] = getelementptr i8, i8* [[X]], i8 10 -; X32-NEXT: [[TMP20:%.*]] = getelementptr i8, i8* [[Y]], i8 10 -; X32-NEXT: [[TMP21:%.*]] = load i8, i8* [[TMP19]] -; X32-NEXT: [[TMP22:%.*]] = load i8, i8* [[TMP20]] -; X32-NEXT: [[TMP23:%.*]] = icmp ne i8 [[TMP21]], [[TMP22]] -; X32-NEXT: br i1 [[TMP23]], label [[RES_BLOCK]], label [[ENDBLOCK]] -; X32: endblock: -; X32-NEXT: [[PHI_RES:%.*]] = phi i32 [ 0, [[LOADBB3]] ], [ 1, [[RES_BLOCK]] ] -; X32-NEXT: [[CMP:%.*]] = icmp eq i32 [[PHI_RES]], 0 -; X32-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 -; X32-NEXT: ret i32 [[CONV]] -; -; X64-LABEL: @cmp_eq11( -; X64-NEXT: loadbb: -; X64-NEXT: [[TMP0:%.*]] = bitcast i8* [[X:%.*]] to i64* -; X64-NEXT: [[TMP1:%.*]] = bitcast i8* [[Y:%.*]] to i64* -; X64-NEXT: [[TMP2:%.*]] = load i64, i64* [[TMP0]] -; X64-NEXT: [[TMP3:%.*]] = load i64, i64* [[TMP1]] -; X64-NEXT: [[TMP4:%.*]] = icmp ne i64 [[TMP2]], [[TMP3]] -; X64-NEXT: br i1 [[TMP4]], label [[RES_BLOCK:%.*]], label [[LOADBB1:%.*]] -; X64: res_block: -; X64-NEXT: br label [[ENDBLOCK:%.*]] -; X64: loadbb1: -; X64-NEXT: [[TMP5:%.*]] = bitcast i8* [[X]] to i16* -; X64-NEXT: [[TMP6:%.*]] = bitcast i8* [[Y]] to i16* -; X64-NEXT: [[TMP7:%.*]] = getelementptr i16, i16* [[TMP5]], i16 4 -; X64-NEXT: [[TMP8:%.*]] = getelementptr i16, i16* [[TMP6]], i16 4 -; X64-NEXT: [[TMP9:%.*]] = load i16, i16* [[TMP7]] -; X64-NEXT: [[TMP10:%.*]] = load i16, i16* [[TMP8]] -; X64-NEXT: [[TMP11:%.*]] = icmp ne i16 [[TMP9]], [[TMP10]] -; X64-NEXT: br i1 [[TMP11]], label [[RES_BLOCK]], label [[LOADBB2:%.*]] -; X64: loadbb2: -; X64-NEXT: [[TMP12:%.*]] = getelementptr i8, i8* [[X]], i8 10 -; X64-NEXT: [[TMP13:%.*]] = getelementptr i8, i8* [[Y]], i8 10 -; X64-NEXT: [[TMP14:%.*]] = load i8, i8* [[TMP12]] -; X64-NEXT: [[TMP15:%.*]] = load i8, i8* [[TMP13]] -; X64-NEXT: [[TMP16:%.*]] = icmp ne i8 [[TMP14]], [[TMP15]] -; X64-NEXT: br i1 [[TMP16]], label [[RES_BLOCK]], label [[ENDBLOCK]] -; X64: endblock: -; X64-NEXT: [[PHI_RES:%.*]] = phi i32 [ 0, [[LOADBB2]] ], [ 1, [[RES_BLOCK]] ] -; X64-NEXT: [[CMP:%.*]] = icmp eq i32 [[PHI_RES]], 0 -; X64-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 -; X64-NEXT: ret i32 [[CONV]] +; ALL-LABEL: @cmp_eq11( +; ALL-NEXT: [[CALL:%.*]] = tail call i32 @memcmp(i8* [[X:%.*]], i8* [[Y:%.*]], i64 11) +; ALL-NEXT: [[CMP:%.*]] = icmp eq i32 [[CALL]], 0 +; ALL-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 +; ALL-NEXT: ret i32 [[CONV]] ; %call = tail call i32 @memcmp(i8* %x, i8* %y, i64 11) %cmp = icmp eq i32 %call, 0 @@ -1488,36 +764,8 @@ define i32 @cmp_eq11(i8* nocapture readonly %x, i8* nocapture readonly %y) { define i32 @cmp_eq12(i8* nocapture readonly %x, i8* nocapture readonly %y) { ; X32-LABEL: @cmp_eq12( -; X32-NEXT: loadbb: -; X32-NEXT: [[TMP0:%.*]] = bitcast i8* [[X:%.*]] to i32* -; X32-NEXT: [[TMP1:%.*]] = bitcast i8* [[Y:%.*]] to i32* -; X32-NEXT: [[TMP2:%.*]] = load i32, i32* [[TMP0]] -; X32-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP1]] -; X32-NEXT: [[TMP4:%.*]] = icmp ne i32 [[TMP2]], [[TMP3]] -; X32-NEXT: br i1 [[TMP4]], label [[RES_BLOCK:%.*]], label [[LOADBB1:%.*]] -; X32: res_block: -; X32-NEXT: br label [[ENDBLOCK:%.*]] -; X32: loadbb1: -; X32-NEXT: [[TMP5:%.*]] = bitcast i8* [[X]] to i32* -; X32-NEXT: [[TMP6:%.*]] = bitcast i8* [[Y]] to i32* -; X32-NEXT: [[TMP7:%.*]] = getelementptr i32, i32* [[TMP5]], i32 1 -; X32-NEXT: [[TMP8:%.*]] = getelementptr i32, i32* [[TMP6]], i32 1 -; X32-NEXT: [[TMP9:%.*]] = load i32, i32* [[TMP7]] -; X32-NEXT: [[TMP10:%.*]] = load i32, i32* [[TMP8]] -; X32-NEXT: [[TMP11:%.*]] = icmp ne i32 [[TMP9]], [[TMP10]] -; X32-NEXT: br i1 [[TMP11]], label [[RES_BLOCK]], label [[LOADBB2:%.*]] -; X32: loadbb2: -; X32-NEXT: [[TMP12:%.*]] = bitcast i8* [[X]] to i32* -; X32-NEXT: [[TMP13:%.*]] = bitcast i8* [[Y]] to i32* -; X32-NEXT: [[TMP14:%.*]] = getelementptr i32, i32* [[TMP12]], i32 2 -; X32-NEXT: [[TMP15:%.*]] = getelementptr i32, i32* [[TMP13]], i32 2 -; X32-NEXT: [[TMP16:%.*]] = load i32, i32* [[TMP14]] -; X32-NEXT: [[TMP17:%.*]] = load i32, i32* [[TMP15]] -; X32-NEXT: [[TMP18:%.*]] = icmp ne i32 [[TMP16]], [[TMP17]] -; X32-NEXT: br i1 [[TMP18]], label [[RES_BLOCK]], label [[ENDBLOCK]] -; X32: endblock: -; X32-NEXT: [[PHI_RES:%.*]] = phi i32 [ 0, [[LOADBB2]] ], [ 1, [[RES_BLOCK]] ] -; X32-NEXT: [[CMP:%.*]] = icmp eq i32 [[PHI_RES]], 0 +; X32-NEXT: [[CALL:%.*]] = tail call i32 @memcmp(i8* [[X:%.*]], i8* [[Y:%.*]], i64 12) +; X32-NEXT: [[CMP:%.*]] = icmp eq i32 [[CALL]], 0 ; X32-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 ; X32-NEXT: ret i32 [[CONV]] ; @@ -1553,78 +801,11 @@ define i32 @cmp_eq12(i8* nocapture readonly %x, i8* nocapture readonly %y) { } define i32 @cmp_eq13(i8* nocapture readonly %x, i8* nocapture readonly %y) { -; X32-LABEL: @cmp_eq13( -; X32-NEXT: loadbb: -; X32-NEXT: [[TMP0:%.*]] = bitcast i8* [[X:%.*]] to i32* -; X32-NEXT: [[TMP1:%.*]] = bitcast i8* [[Y:%.*]] to i32* -; X32-NEXT: [[TMP2:%.*]] = load i32, i32* [[TMP0]] -; X32-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP1]] -; X32-NEXT: [[TMP4:%.*]] = icmp ne i32 [[TMP2]], [[TMP3]] -; X32-NEXT: br i1 [[TMP4]], label [[RES_BLOCK:%.*]], label [[LOADBB1:%.*]] -; X32: res_block: -; X32-NEXT: br label [[ENDBLOCK:%.*]] -; X32: loadbb1: -; X32-NEXT: [[TMP5:%.*]] = bitcast i8* [[X]] to i32* -; X32-NEXT: [[TMP6:%.*]] = bitcast i8* [[Y]] to i32* -; X32-NEXT: [[TMP7:%.*]] = getelementptr i32, i32* [[TMP5]], i32 1 -; X32-NEXT: [[TMP8:%.*]] = getelementptr i32, i32* [[TMP6]], i32 1 -; X32-NEXT: [[TMP9:%.*]] = load i32, i32* [[TMP7]] -; X32-NEXT: [[TMP10:%.*]] = load i32, i32* [[TMP8]] -; X32-NEXT: [[TMP11:%.*]] = icmp ne i32 [[TMP9]], [[TMP10]] -; X32-NEXT: br i1 [[TMP11]], label [[RES_BLOCK]], label [[LOADBB2:%.*]] -; X32: loadbb2: -; X32-NEXT: [[TMP12:%.*]] = bitcast i8* [[X]] to i32* -; X32-NEXT: [[TMP13:%.*]] = bitcast i8* [[Y]] to i32* -; X32-NEXT: [[TMP14:%.*]] = getelementptr i32, i32* [[TMP12]], i32 2 -; X32-NEXT: [[TMP15:%.*]] = getelementptr i32, i32* [[TMP13]], i32 2 -; X32-NEXT: [[TMP16:%.*]] = load i32, i32* [[TMP14]] -; X32-NEXT: [[TMP17:%.*]] = load i32, i32* [[TMP15]] -; X32-NEXT: [[TMP18:%.*]] = icmp ne i32 [[TMP16]], [[TMP17]] -; X32-NEXT: br i1 [[TMP18]], label [[RES_BLOCK]], label [[LOADBB3:%.*]] -; X32: loadbb3: -; X32-NEXT: [[TMP19:%.*]] = getelementptr i8, i8* [[X]], i8 12 -; X32-NEXT: [[TMP20:%.*]] = getelementptr i8, i8* [[Y]], i8 12 -; X32-NEXT: [[TMP21:%.*]] = load i8, i8* [[TMP19]] -; X32-NEXT: [[TMP22:%.*]] = load i8, i8* [[TMP20]] -; X32-NEXT: [[TMP23:%.*]] = icmp ne i8 [[TMP21]], [[TMP22]] -; X32-NEXT: br i1 [[TMP23]], label [[RES_BLOCK]], label [[ENDBLOCK]] -; X32: endblock: -; X32-NEXT: [[PHI_RES:%.*]] = phi i32 [ 0, [[LOADBB3]] ], [ 1, [[RES_BLOCK]] ] -; X32-NEXT: [[CMP:%.*]] = icmp eq i32 [[PHI_RES]], 0 -; X32-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 -; X32-NEXT: ret i32 [[CONV]] -; -; X64-LABEL: @cmp_eq13( -; X64-NEXT: loadbb: -; X64-NEXT: [[TMP0:%.*]] = bitcast i8* [[X:%.*]] to i64* -; X64-NEXT: [[TMP1:%.*]] = bitcast i8* [[Y:%.*]] to i64* -; X64-NEXT: [[TMP2:%.*]] = load i64, i64* [[TMP0]] -; X64-NEXT: [[TMP3:%.*]] = load i64, i64* [[TMP1]] -; X64-NEXT: [[TMP4:%.*]] = icmp ne i64 [[TMP2]], [[TMP3]] -; X64-NEXT: br i1 [[TMP4]], label [[RES_BLOCK:%.*]], label [[LOADBB1:%.*]] -; X64: res_block: -; X64-NEXT: br label [[ENDBLOCK:%.*]] -; X64: loadbb1: -; X64-NEXT: [[TMP5:%.*]] = bitcast i8* [[X]] to i32* -; X64-NEXT: [[TMP6:%.*]] = bitcast i8* [[Y]] to i32* -; X64-NEXT: [[TMP7:%.*]] = getelementptr i32, i32* [[TMP5]], i32 2 -; X64-NEXT: [[TMP8:%.*]] = getelementptr i32, i32* [[TMP6]], i32 2 -; X64-NEXT: [[TMP9:%.*]] = load i32, i32* [[TMP7]] -; X64-NEXT: [[TMP10:%.*]] = load i32, i32* [[TMP8]] -; X64-NEXT: [[TMP11:%.*]] = icmp ne i32 [[TMP9]], [[TMP10]] -; X64-NEXT: br i1 [[TMP11]], label [[RES_BLOCK]], label [[LOADBB2:%.*]] -; X64: loadbb2: -; X64-NEXT: [[TMP12:%.*]] = getelementptr i8, i8* [[X]], i8 12 -; X64-NEXT: [[TMP13:%.*]] = getelementptr i8, i8* [[Y]], i8 12 -; X64-NEXT: [[TMP14:%.*]] = load i8, i8* [[TMP12]] -; X64-NEXT: [[TMP15:%.*]] = load i8, i8* [[TMP13]] -; X64-NEXT: [[TMP16:%.*]] = icmp ne i8 [[TMP14]], [[TMP15]] -; X64-NEXT: br i1 [[TMP16]], label [[RES_BLOCK]], label [[ENDBLOCK]] -; X64: endblock: -; X64-NEXT: [[PHI_RES:%.*]] = phi i32 [ 0, [[LOADBB2]] ], [ 1, [[RES_BLOCK]] ] -; X64-NEXT: [[CMP:%.*]] = icmp eq i32 [[PHI_RES]], 0 -; X64-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 -; X64-NEXT: ret i32 [[CONV]] +; ALL-LABEL: @cmp_eq13( +; ALL-NEXT: [[CALL:%.*]] = tail call i32 @memcmp(i8* [[X:%.*]], i8* [[Y:%.*]], i64 13) +; ALL-NEXT: [[CMP:%.*]] = icmp eq i32 [[CALL]], 0 +; ALL-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 +; ALL-NEXT: ret i32 [[CONV]] ; %call = tail call i32 @memcmp(i8* %x, i8* %y, i64 13) %cmp = icmp eq i32 %call, 0 @@ -1633,82 +814,11 @@ define i32 @cmp_eq13(i8* nocapture readonly %x, i8* nocapture readonly %y) { } define i32 @cmp_eq14(i8* nocapture readonly %x, i8* nocapture readonly %y) { -; X32-LABEL: @cmp_eq14( -; X32-NEXT: loadbb: -; X32-NEXT: [[TMP0:%.*]] = bitcast i8* [[X:%.*]] to i32* -; X32-NEXT: [[TMP1:%.*]] = bitcast i8* [[Y:%.*]] to i32* -; X32-NEXT: [[TMP2:%.*]] = load i32, i32* [[TMP0]] -; X32-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP1]] -; X32-NEXT: [[TMP4:%.*]] = icmp ne i32 [[TMP2]], [[TMP3]] -; X32-NEXT: br i1 [[TMP4]], label [[RES_BLOCK:%.*]], label [[LOADBB1:%.*]] -; X32: res_block: -; X32-NEXT: br label [[ENDBLOCK:%.*]] -; X32: loadbb1: -; X32-NEXT: [[TMP5:%.*]] = bitcast i8* [[X]] to i32* -; X32-NEXT: [[TMP6:%.*]] = bitcast i8* [[Y]] to i32* -; X32-NEXT: [[TMP7:%.*]] = getelementptr i32, i32* [[TMP5]], i32 1 -; X32-NEXT: [[TMP8:%.*]] = getelementptr i32, i32* [[TMP6]], i32 1 -; X32-NEXT: [[TMP9:%.*]] = load i32, i32* [[TMP7]] -; X32-NEXT: [[TMP10:%.*]] = load i32, i32* [[TMP8]] -; X32-NEXT: [[TMP11:%.*]] = icmp ne i32 [[TMP9]], [[TMP10]] -; X32-NEXT: br i1 [[TMP11]], label [[RES_BLOCK]], label [[LOADBB2:%.*]] -; X32: loadbb2: -; X32-NEXT: [[TMP12:%.*]] = bitcast i8* [[X]] to i32* -; X32-NEXT: [[TMP13:%.*]] = bitcast i8* [[Y]] to i32* -; X32-NEXT: [[TMP14:%.*]] = getelementptr i32, i32* [[TMP12]], i32 2 -; X32-NEXT: [[TMP15:%.*]] = getelementptr i32, i32* [[TMP13]], i32 2 -; X32-NEXT: [[TMP16:%.*]] = load i32, i32* [[TMP14]] -; X32-NEXT: [[TMP17:%.*]] = load i32, i32* [[TMP15]] -; X32-NEXT: [[TMP18:%.*]] = icmp ne i32 [[TMP16]], [[TMP17]] -; X32-NEXT: br i1 [[TMP18]], label [[RES_BLOCK]], label [[LOADBB3:%.*]] -; X32: loadbb3: -; X32-NEXT: [[TMP19:%.*]] = bitcast i8* [[X]] to i16* -; X32-NEXT: [[TMP20:%.*]] = bitcast i8* [[Y]] to i16* -; X32-NEXT: [[TMP21:%.*]] = getelementptr i16, i16* [[TMP19]], i16 6 -; X32-NEXT: [[TMP22:%.*]] = getelementptr i16, i16* [[TMP20]], i16 6 -; X32-NEXT: [[TMP23:%.*]] = load i16, i16* [[TMP21]] -; X32-NEXT: [[TMP24:%.*]] = load i16, i16* [[TMP22]] -; X32-NEXT: [[TMP25:%.*]] = icmp ne i16 [[TMP23]], [[TMP24]] -; X32-NEXT: br i1 [[TMP25]], label [[RES_BLOCK]], label [[ENDBLOCK]] -; X32: endblock: -; X32-NEXT: [[PHI_RES:%.*]] = phi i32 [ 0, [[LOADBB3]] ], [ 1, [[RES_BLOCK]] ] -; X32-NEXT: [[CMP:%.*]] = icmp eq i32 [[PHI_RES]], 0 -; X32-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 -; X32-NEXT: ret i32 [[CONV]] -; -; X64-LABEL: @cmp_eq14( -; X64-NEXT: loadbb: -; X64-NEXT: [[TMP0:%.*]] = bitcast i8* [[X:%.*]] to i64* -; X64-NEXT: [[TMP1:%.*]] = bitcast i8* [[Y:%.*]] to i64* -; X64-NEXT: [[TMP2:%.*]] = load i64, i64* [[TMP0]] -; X64-NEXT: [[TMP3:%.*]] = load i64, i64* [[TMP1]] -; X64-NEXT: [[TMP4:%.*]] = icmp ne i64 [[TMP2]], [[TMP3]] -; X64-NEXT: br i1 [[TMP4]], label [[RES_BLOCK:%.*]], label [[LOADBB1:%.*]] -; X64: res_block: -; X64-NEXT: br label [[ENDBLOCK:%.*]] -; X64: loadbb1: -; X64-NEXT: [[TMP5:%.*]] = bitcast i8* [[X]] to i32* -; X64-NEXT: [[TMP6:%.*]] = bitcast i8* [[Y]] to i32* -; X64-NEXT: [[TMP7:%.*]] = getelementptr i32, i32* [[TMP5]], i32 2 -; X64-NEXT: [[TMP8:%.*]] = getelementptr i32, i32* [[TMP6]], i32 2 -; X64-NEXT: [[TMP9:%.*]] = load i32, i32* [[TMP7]] -; X64-NEXT: [[TMP10:%.*]] = load i32, i32* [[TMP8]] -; X64-NEXT: [[TMP11:%.*]] = icmp ne i32 [[TMP9]], [[TMP10]] -; X64-NEXT: br i1 [[TMP11]], label [[RES_BLOCK]], label [[LOADBB2:%.*]] -; X64: loadbb2: -; X64-NEXT: [[TMP12:%.*]] = bitcast i8* [[X]] to i16* -; X64-NEXT: [[TMP13:%.*]] = bitcast i8* [[Y]] to i16* -; X64-NEXT: [[TMP14:%.*]] = getelementptr i16, i16* [[TMP12]], i16 6 -; X64-NEXT: [[TMP15:%.*]] = getelementptr i16, i16* [[TMP13]], i16 6 -; X64-NEXT: [[TMP16:%.*]] = load i16, i16* [[TMP14]] -; X64-NEXT: [[TMP17:%.*]] = load i16, i16* [[TMP15]] -; X64-NEXT: [[TMP18:%.*]] = icmp ne i16 [[TMP16]], [[TMP17]] -; X64-NEXT: br i1 [[TMP18]], label [[RES_BLOCK]], label [[ENDBLOCK]] -; X64: endblock: -; X64-NEXT: [[PHI_RES:%.*]] = phi i32 [ 0, [[LOADBB2]] ], [ 1, [[RES_BLOCK]] ] -; X64-NEXT: [[CMP:%.*]] = icmp eq i32 [[PHI_RES]], 0 -; X64-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 -; X64-NEXT: ret i32 [[CONV]] +; ALL-LABEL: @cmp_eq14( +; ALL-NEXT: [[CALL:%.*]] = tail call i32 @memcmp(i8* [[X:%.*]], i8* [[Y:%.*]], i64 14) +; ALL-NEXT: [[CMP:%.*]] = icmp eq i32 [[CALL]], 0 +; ALL-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 +; ALL-NEXT: ret i32 [[CONV]] ; %call = tail call i32 @memcmp(i8* %x, i8* %y, i64 14) %cmp = icmp eq i32 %call, 0 @@ -1717,52 +827,11 @@ define i32 @cmp_eq14(i8* nocapture readonly %x, i8* nocapture readonly %y) { } define i32 @cmp_eq15(i8* nocapture readonly %x, i8* nocapture readonly %y) { -; X32-LABEL: @cmp_eq15( -; X32-NEXT: [[CALL:%.*]] = tail call i32 @memcmp(i8* [[X:%.*]], i8* [[Y:%.*]], i64 15) -; X32-NEXT: [[CMP:%.*]] = icmp eq i32 [[CALL]], 0 -; X32-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 -; X32-NEXT: ret i32 [[CONV]] -; -; X64-LABEL: @cmp_eq15( -; X64-NEXT: loadbb: -; X64-NEXT: [[TMP0:%.*]] = bitcast i8* [[X:%.*]] to i64* -; X64-NEXT: [[TMP1:%.*]] = bitcast i8* [[Y:%.*]] to i64* -; X64-NEXT: [[TMP2:%.*]] = load i64, i64* [[TMP0]] -; X64-NEXT: [[TMP3:%.*]] = load i64, i64* [[TMP1]] -; X64-NEXT: [[TMP4:%.*]] = icmp ne i64 [[TMP2]], [[TMP3]] -; X64-NEXT: br i1 [[TMP4]], label [[RES_BLOCK:%.*]], label [[LOADBB1:%.*]] -; X64: res_block: -; X64-NEXT: br label [[ENDBLOCK:%.*]] -; X64: loadbb1: -; X64-NEXT: [[TMP5:%.*]] = bitcast i8* [[X]] to i32* -; X64-NEXT: [[TMP6:%.*]] = bitcast i8* [[Y]] to i32* -; X64-NEXT: [[TMP7:%.*]] = getelementptr i32, i32* [[TMP5]], i32 2 -; X64-NEXT: [[TMP8:%.*]] = getelementptr i32, i32* [[TMP6]], i32 2 -; X64-NEXT: [[TMP9:%.*]] = load i32, i32* [[TMP7]] -; X64-NEXT: [[TMP10:%.*]] = load i32, i32* [[TMP8]] -; X64-NEXT: [[TMP11:%.*]] = icmp ne i32 [[TMP9]], [[TMP10]] -; X64-NEXT: br i1 [[TMP11]], label [[RES_BLOCK]], label [[LOADBB2:%.*]] -; X64: loadbb2: -; X64-NEXT: [[TMP12:%.*]] = bitcast i8* [[X]] to i16* -; X64-NEXT: [[TMP13:%.*]] = bitcast i8* [[Y]] to i16* -; X64-NEXT: [[TMP14:%.*]] = getelementptr i16, i16* [[TMP12]], i16 6 -; X64-NEXT: [[TMP15:%.*]] = getelementptr i16, i16* [[TMP13]], i16 6 -; X64-NEXT: [[TMP16:%.*]] = load i16, i16* [[TMP14]] -; X64-NEXT: [[TMP17:%.*]] = load i16, i16* [[TMP15]] -; X64-NEXT: [[TMP18:%.*]] = icmp ne i16 [[TMP16]], [[TMP17]] -; X64-NEXT: br i1 [[TMP18]], label [[RES_BLOCK]], label [[LOADBB3:%.*]] -; X64: loadbb3: -; X64-NEXT: [[TMP19:%.*]] = getelementptr i8, i8* [[X]], i8 14 -; X64-NEXT: [[TMP20:%.*]] = getelementptr i8, i8* [[Y]], i8 14 -; X64-NEXT: [[TMP21:%.*]] = load i8, i8* [[TMP19]] -; X64-NEXT: [[TMP22:%.*]] = load i8, i8* [[TMP20]] -; X64-NEXT: [[TMP23:%.*]] = icmp ne i8 [[TMP21]], [[TMP22]] -; X64-NEXT: br i1 [[TMP23]], label [[RES_BLOCK]], label [[ENDBLOCK]] -; X64: endblock: -; X64-NEXT: [[PHI_RES:%.*]] = phi i32 [ 0, [[LOADBB3]] ], [ 1, [[RES_BLOCK]] ] -; X64-NEXT: [[CMP:%.*]] = icmp eq i32 [[PHI_RES]], 0 -; X64-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 -; X64-NEXT: ret i32 [[CONV]] +; ALL-LABEL: @cmp_eq15( +; ALL-NEXT: [[CALL:%.*]] = tail call i32 @memcmp(i8* [[X:%.*]], i8* [[Y:%.*]], i64 15) +; ALL-NEXT: [[CMP:%.*]] = icmp eq i32 [[CALL]], 0 +; ALL-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 +; ALL-NEXT: ret i32 [[CONV]] ; %call = tail call i32 @memcmp(i8* %x, i8* %y, i64 15) %cmp = icmp eq i32 %call, 0 @@ -1772,45 +841,8 @@ define i32 @cmp_eq15(i8* nocapture readonly %x, i8* nocapture readonly %y) { define i32 @cmp_eq16(i8* nocapture readonly %x, i8* nocapture readonly %y) { ; X32-LABEL: @cmp_eq16( -; X32-NEXT: loadbb: -; X32-NEXT: [[TMP0:%.*]] = bitcast i8* [[X:%.*]] to i32* -; X32-NEXT: [[TMP1:%.*]] = bitcast i8* [[Y:%.*]] to i32* -; X32-NEXT: [[TMP2:%.*]] = load i32, i32* [[TMP0]] -; X32-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP1]] -; X32-NEXT: [[TMP4:%.*]] = icmp ne i32 [[TMP2]], [[TMP3]] -; X32-NEXT: br i1 [[TMP4]], label [[RES_BLOCK:%.*]], label [[LOADBB1:%.*]] -; X32: res_block: -; X32-NEXT: br label [[ENDBLOCK:%.*]] -; X32: loadbb1: -; X32-NEXT: [[TMP5:%.*]] = bitcast i8* [[X]] to i32* -; X32-NEXT: [[TMP6:%.*]] = bitcast i8* [[Y]] to i32* -; X32-NEXT: [[TMP7:%.*]] = getelementptr i32, i32* [[TMP5]], i32 1 -; X32-NEXT: [[TMP8:%.*]] = getelementptr i32, i32* [[TMP6]], i32 1 -; X32-NEXT: [[TMP9:%.*]] = load i32, i32* [[TMP7]] -; X32-NEXT: [[TMP10:%.*]] = load i32, i32* [[TMP8]] -; X32-NEXT: [[TMP11:%.*]] = icmp ne i32 [[TMP9]], [[TMP10]] -; X32-NEXT: br i1 [[TMP11]], label [[RES_BLOCK]], label [[LOADBB2:%.*]] -; X32: loadbb2: -; X32-NEXT: [[TMP12:%.*]] = bitcast i8* [[X]] to i32* -; X32-NEXT: [[TMP13:%.*]] = bitcast i8* [[Y]] to i32* -; X32-NEXT: [[TMP14:%.*]] = getelementptr i32, i32* [[TMP12]], i32 2 -; X32-NEXT: [[TMP15:%.*]] = getelementptr i32, i32* [[TMP13]], i32 2 -; X32-NEXT: [[TMP16:%.*]] = load i32, i32* [[TMP14]] -; X32-NEXT: [[TMP17:%.*]] = load i32, i32* [[TMP15]] -; X32-NEXT: [[TMP18:%.*]] = icmp ne i32 [[TMP16]], [[TMP17]] -; X32-NEXT: br i1 [[TMP18]], label [[RES_BLOCK]], label [[LOADBB3:%.*]] -; X32: loadbb3: -; X32-NEXT: [[TMP19:%.*]] = bitcast i8* [[X]] to i32* -; X32-NEXT: [[TMP20:%.*]] = bitcast i8* [[Y]] to i32* -; X32-NEXT: [[TMP21:%.*]] = getelementptr i32, i32* [[TMP19]], i32 3 -; X32-NEXT: [[TMP22:%.*]] = getelementptr i32, i32* [[TMP20]], i32 3 -; X32-NEXT: [[TMP23:%.*]] = load i32, i32* [[TMP21]] -; X32-NEXT: [[TMP24:%.*]] = load i32, i32* [[TMP22]] -; X32-NEXT: [[TMP25:%.*]] = icmp ne i32 [[TMP23]], [[TMP24]] -; X32-NEXT: br i1 [[TMP25]], label [[RES_BLOCK]], label [[ENDBLOCK]] -; X32: endblock: -; X32-NEXT: [[PHI_RES:%.*]] = phi i32 [ 0, [[LOADBB3]] ], [ 1, [[RES_BLOCK]] ] -; X32-NEXT: [[CMP:%.*]] = icmp eq i32 [[PHI_RES]], 0 +; X32-NEXT: [[CALL:%.*]] = tail call i32 @memcmp(i8* [[X:%.*]], i8* [[Y:%.*]], i64 16) +; X32-NEXT: [[CMP:%.*]] = icmp eq i32 [[CALL]], 0 ; X32-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 ; X32-NEXT: ret i32 [[CONV]] ; diff --git a/test/Transforms/JumpThreading/pr33605.ll b/test/Transforms/JumpThreading/pr33605.ll new file mode 100644 index 000000000000..eb8cab90fa50 --- /dev/null +++ b/test/Transforms/JumpThreading/pr33605.ll @@ -0,0 +1,64 @@ +; RUN: opt < %s -jump-threading -S | FileCheck %s + +; Skip simplifying unconditional branches from empty blocks in simplifyCFG, +; when it can destroy canonical loop structure. + +; void foo(); +; bool test(int a, int b, int *c) { +; bool changed = false; +; for (unsigned int i = 2; i--;) { +; int r = a | b; +; if ( r != c[i]) { +; c[i] = r; +; foo(); +; changed = true; +; } +; } +; return changed; +; } + +; CHECK-LABEL: @test( +; CHECK: for.cond: +; CHECK-NEXT: %i.0 = phi i32 [ 2, %entry ], [ %dec, %if.end ] +; CHECK: for.body: +; CHECK: br i1 %cmp, label %if.end, label %if.then +; CHECK-NOT: br i1 %cmp, label %for.cond, label %if.then +; CHECK: if.then: +; CHECK: br label %if.end +; CHECK-NOT: br label %for.cond +; CHECK: if.end: +; CHECK br label %for.cond +define i1 @test(i32 %a, i32 %b, i32* %c) { +entry: + br label %for.cond + +for.cond: ; preds = %if.end, %entry + %i.0 = phi i32 [ 2, %entry ], [ %dec, %if.end ] + %changed.0.off0 = phi i1 [ false, %entry ], [ %changed.1.off0, %if.end ] + %dec = add nsw i32 %i.0, -1 + %tobool = icmp eq i32 %i.0, 0 + br i1 %tobool, label %for.cond.cleanup, label %for.body + +for.cond.cleanup: ; preds = %for.cond + %changed.0.off0.lcssa = phi i1 [ %changed.0.off0, %for.cond ] + ret i1 %changed.0.off0.lcssa + +for.body: ; preds = %for.cond + %or = or i32 %a, %b + %idxprom = sext i32 %dec to i64 + %arrayidx = getelementptr inbounds i32, i32* %c, i64 %idxprom + %0 = load i32, i32* %arrayidx, align 4 + %cmp = icmp eq i32 %or, %0 + br i1 %cmp, label %if.end, label %if.then + +if.then: ; preds = %for.body + store i32 %or, i32* %arrayidx, align 4 + call void @foo() + br label %if.end + +if.end: ; preds = %for.body, %if.then + %changed.1.off0 = phi i1 [ true, %if.then ], [ %changed.0.off0, %for.body ] + br label %for.cond +} + +declare void @foo() diff --git a/test/Transforms/JumpThreading/pr33917.ll b/test/Transforms/JumpThreading/pr33917.ll new file mode 100644 index 000000000000..30652279a0e1 --- /dev/null +++ b/test/Transforms/JumpThreading/pr33917.ll @@ -0,0 +1,57 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -jump-threading -correlated-propagation %s -S | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +declare i8* @foo() + +declare i32 @rust_eh_personality() unnamed_addr + +; Function Attrs: nounwind +declare void @llvm.assume(i1) #0 + +define void @patatino() personality i32 ()* @rust_eh_personality { +; CHECK-LABEL: @patatino( +; CHECK-NEXT: bb9: +; CHECK-NEXT: [[T9:%.*]] = invoke i8* @foo() +; CHECK-NEXT: to label [[GOOD:%.*]] unwind label [[BAD:%.*]] +; CHECK: bad: +; CHECK-NEXT: [[T10:%.*]] = landingpad { i8*, i32 } +; CHECK-NEXT: cleanup +; CHECK-NEXT: resume { i8*, i32 } [[T10]] +; CHECK: good: +; CHECK-NEXT: [[T11:%.*]] = icmp ne i8* [[T9]], null +; CHECK-NEXT: [[T12:%.*]] = zext i1 [[T11]] to i64 +; CHECK-NEXT: [[COND:%.*]] = icmp eq i64 [[T12]], 1 +; CHECK-NEXT: br i1 [[COND]], label [[IF_TRUE:%.*]], label [[DONE:%.*]] +; CHECK: if_true: +; CHECK-NEXT: call void @llvm.assume(i1 [[T11]]) +; CHECK-NEXT: br label [[DONE]] +; CHECK: done: +; CHECK-NEXT: ret void +; +bb9: + %t9 = invoke i8* @foo() + to label %good unwind label %bad + +bad: + %t10 = landingpad { i8*, i32 } + cleanup + resume { i8*, i32 } %t10 + +good: + %t11 = icmp ne i8* %t9, null + %t12 = zext i1 %t11 to i64 + %cond = icmp eq i64 %t12, 1 + br i1 %cond, label %if_true, label %done + +if_true: + call void @llvm.assume(i1 %t11) + br label %done + +done: + ret void +} + +attributes #0 = { nounwind } diff --git a/test/Transforms/JumpThreading/static-profile.ll b/test/Transforms/JumpThreading/static-profile.ll index d634a607eabf..505e849f4806 100644 --- a/test/Transforms/JumpThreading/static-profile.ll +++ b/test/Transforms/JumpThreading/static-profile.ll @@ -86,7 +86,7 @@ eq_1: ; Verify the new backedge: ; CHECK: check_2.thread: ; CHECK-NEXT: call void @bar() -; CHECK-NEXT: br label %check_1 +; CHECK-NEXT: br label %check_3.thread check_2: %cond2 = icmp eq i32 %v, 2 @@ -100,7 +100,7 @@ eq_2: ; Verify the new backedge: ; CHECK: eq_2: ; CHECK-NEXT: call void @bar() -; CHECK-NEXT: br label %check_1 +; CHECK-NEXT: br label %check_3.thread check_3: %condE = icmp eq i32 %v, 3 diff --git a/test/Transforms/LoopUnroll/peel-loop.ll b/test/Transforms/LoopUnroll/peel-loop.ll index bf0801fc760a..3f7c64d8154c 100644 --- a/test/Transforms/LoopUnroll/peel-loop.ll +++ b/test/Transforms/LoopUnroll/peel-loop.ll @@ -18,9 +18,11 @@ ; CHECK: %[[INC2:.*]] = getelementptr inbounds i32, i32* %p, i64 2 ; CHECK: store i32 2, i32* %[[INC2]], align 4 ; CHECK: %[[CMP3:.*]] = icmp eq i32 %k, 3 -; CHECK: br i1 %[[CMP3]], label %for.end, label %[[LOOP:.*]] +; CHECK: br i1 %[[CMP3]], label %for.end, label %[[LOOP_PH:.*]] +; CHECK: [[LOOP_PH]]: +; CHECK: br label %[[LOOP:.*]] ; CHECK: [[LOOP]]: -; CHECK: %[[IV:.*]] = phi i32 [ {{.*}}, %[[LOOP]] ], [ 3, %[[NEXT2]] ] +; CHECK: %[[IV:.*]] = phi i32 [ 3, %[[LOOP_PH]] ], [ {{.*}}, %[[LOOP]] ] define void @basic(i32* %p, i32 %k) #0 { entry: @@ -65,9 +67,11 @@ for.end: ; preds = %for.cond.for.end_cr ; CHECK: %[[INC2:.*]] = getelementptr inbounds i32, i32* %p, i64 2 ; CHECK: store i32 2, i32* %[[INC2]], align 4 ; CHECK: %[[CMP3:.*]] = icmp eq i32 %k, 3 -; CHECK: br i1 %[[CMP3]], label %for.end, label %[[LOOP:.*]] +; CHECK: br i1 %[[CMP3]], label %for.end, label %[[LOOP_PH:.*]] +; CHECK: [[LOOP_PH]]: +; CHECK: br label %[[LOOP:.*]] ; CHECK: [[LOOP]]: -; CHECK: %[[IV:.*]] = phi i32 [ %[[IV:.*]], %[[LOOP]] ], [ 3, %[[NEXT2]] ] +; CHECK: %[[IV:.*]] = phi i32 [ 3, %[[LOOP_PH]] ], [ %[[IV:.*]], %[[LOOP]] ] ; CHECK: %ret = phi i32 [ 0, %entry ], [ 1, %[[NEXT0]] ], [ 2, %[[NEXT1]] ], [ 3, %[[NEXT2]] ], [ %[[IV]], %[[LOOP]] ] ; CHECK: ret i32 %ret define i32 @output(i32* %p, i32 %k) #0 { diff --git a/test/Transforms/LoopUnswitch/2015-06-17-Metadata.ll b/test/Transforms/LoopUnswitch/2015-06-17-Metadata.ll index a215be9d4877..8652829bc511 100644 --- a/test/Transforms/LoopUnswitch/2015-06-17-Metadata.ll +++ b/test/Transforms/LoopUnswitch/2015-06-17-Metadata.ll @@ -16,7 +16,7 @@ for.body: ; preds = %for.inc, %for.body. %cmp1 = icmp eq i32 %a, 12345 br i1 %cmp1, label %if.then, label %if.else, !prof !0 ; CHECK: %cmp1 = icmp eq i32 %a, 12345 -; CHECK-NEXT: br i1 %cmp1, label %for.body.us, label %for.body, !prof !0 +; CHECK-NEXT: br i1 %cmp1, label %for.body.preheader.split.us, label %for.body.preheader.split, !prof !0 if.then: ; preds = %for.body ; CHECK: for.body.us: ; CHECK: add nsw i32 %{{.*}}, 123 @@ -53,7 +53,7 @@ entry: br label %for.body ;CHECK: entry: ;CHECK-NEXT: %cmp1 = icmp eq i32 1, 2 -;CHECK-NEXT: br i1 %cmp1, label %for.body, label %for.cond.cleanup.split, !prof !1 +;CHECK-NEXT: br i1 %cmp1, label %entry.split, label %for.cond.cleanup.split, !prof !1 ;CHECK: for.body: for.body: ; preds = %for.inc, %entry %inc.i = phi i32 [ 0, %entry ], [ %inc, %if.then ] diff --git a/test/Transforms/LoopUnswitch/infinite-loop.ll b/test/Transforms/LoopUnswitch/infinite-loop.ll index 0aef9092a1fe..af8725b02a14 100644 --- a/test/Transforms/LoopUnswitch/infinite-loop.ll +++ b/test/Transforms/LoopUnswitch/infinite-loop.ll @@ -6,7 +6,7 @@ ; Loop unswitching shouldn't trivially unswitch the true case of condition %a ; in the code here because it leads to an infinite loop. While this doesn't ; contain any instructions with side effects, it's still a kind of side effect. -; It can trivially unswitch on the false cas of condition %a though. +; It can trivially unswitch on the false case of condition %a though. ; STATS: 2 loop-unswitch - Number of branches unswitched ; STATS: 2 loop-unswitch - Number of unswitches that are trivial @@ -16,7 +16,7 @@ ; CHECK-NEXT: br i1 %a, label %entry.split, label %abort0.split ; CHECK: entry.split: -; CHECK-NEXT: br i1 %b, label %for.body, label %abort1.split +; CHECK-NEXT: br i1 %b, label %entry.split.split, label %abort1.split ; CHECK: for.body: ; CHECK-NEXT: br label %for.body diff --git a/test/Transforms/LoopVectorize/X86/float-induction-x86.ll b/test/Transforms/LoopVectorize/X86/float-induction-x86.ll index 31c564779fb2..bf455807c586 100644 --- a/test/Transforms/LoopVectorize/X86/float-induction-x86.ll +++ b/test/Transforms/LoopVectorize/X86/float-induction-x86.ll @@ -1,4 +1,4 @@ -; RUN: opt < %s -O3 -mcpu=core-avx2 -mtriple=x86_64-unknown-linux-gnu -S | FileCheck --check-prefix AUTO_VEC %s +; RUN: opt < %s -O3 -latesimplifycfg -mcpu=core-avx2 -mtriple=x86_64-unknown-linux-gnu -S | FileCheck --check-prefix AUTO_VEC %s ; This test checks auto-vectorization with FP induction variable. ; The FP operation is not "fast" and requires "fast-math" function attribute. diff --git a/test/Transforms/LoopVectorize/float-induction.ll b/test/Transforms/LoopVectorize/float-induction.ll index a7cc4530ceb3..cf6ec88478be 100644 --- a/test/Transforms/LoopVectorize/float-induction.ll +++ b/test/Transforms/LoopVectorize/float-induction.ll @@ -1,7 +1,7 @@ ; RUN: opt < %s -loop-vectorize -force-vector-interleave=1 -force-vector-width=4 -dce -instcombine -S | FileCheck --check-prefix VEC4_INTERL1 %s ; RUN: opt < %s -loop-vectorize -force-vector-interleave=2 -force-vector-width=4 -dce -instcombine -S | FileCheck --check-prefix VEC4_INTERL2 %s ; RUN: opt < %s -loop-vectorize -force-vector-interleave=2 -force-vector-width=1 -dce -instcombine -S | FileCheck --check-prefix VEC1_INTERL2 %s -; RUN: opt < %s -loop-vectorize -force-vector-interleave=1 -force-vector-width=2 -dce -simplifycfg -instcombine -S | FileCheck --check-prefix VEC2_INTERL1_PRED_STORE %s +; RUN: opt < %s -loop-vectorize -force-vector-interleave=1 -force-vector-width=2 -dce -simplifycfg -instcombine -latesimplifycfg -S | FileCheck --check-prefix VEC2_INTERL1_PRED_STORE %s @fp_inc = common global float 0.000000e+00, align 4 diff --git a/test/Transforms/SimplifyCFG/X86/switch_to_lookup_table.ll b/test/Transforms/SimplifyCFG/X86/switch_to_lookup_table.ll index 656a276969f3..536d1d85c3d8 100644 --- a/test/Transforms/SimplifyCFG/X86/switch_to_lookup_table.ll +++ b/test/Transforms/SimplifyCFG/X86/switch_to_lookup_table.ll @@ -1322,8 +1322,8 @@ l6: ; Speculation depth must be limited to avoid a zero-cost instruction cycle. ; CHECK-LABEL: @PR26308( -; CHECK: while.body: -; CHECK-NEXT: br label %while.body +; CHECK: cleanup4: +; CHECK-NEXT: br label %cleanup4 define i32 @PR26308(i1 %B, i64 %load) { entry: diff --git a/test/Transforms/SimplifyCFG/multiple-phis.ll b/test/Transforms/SimplifyCFG/multiple-phis.ll index a6eef09ae646..823e2500eac1 100644 --- a/test/Transforms/SimplifyCFG/multiple-phis.ll +++ b/test/Transforms/SimplifyCFG/multiple-phis.ll @@ -1,4 +1,4 @@ -; RUN: opt -simplifycfg -S < %s | FileCheck %s +; RUN: opt -latesimplifycfg -S < %s | FileCheck %s ; It's not worthwhile to if-convert one of the phi nodes and leave ; the other behind, because that still requires a branch. If diff --git a/test/Transforms/SimplifyCFG/pr33605.ll b/test/Transforms/SimplifyCFG/pr33605.ll new file mode 100644 index 000000000000..963b15991263 --- /dev/null +++ b/test/Transforms/SimplifyCFG/pr33605.ll @@ -0,0 +1,64 @@ +; RUN: opt < %s -simplifycfg -S | FileCheck %s + +; Skip simplifying unconditional branches from empty blocks in simplifyCFG, +; when it can destroy canonical loop structure. + +; void foo(); +; bool test(int a, int b, int *c) { +; bool changed = false; +; for (unsigned int i = 2; i--;) { +; int r = a | b; +; if ( r != c[i]) { +; c[i] = r; +; foo(); +; changed = true; +; } +; } +; return changed; +; } + +; CHECK-LABEL: @test( +; CHECK: for.cond: +; CHECK-NEXT: %i.0 = phi i32 [ 2, %entry ], [ %dec, %if.end ] +; CHECK: for.body: +; CHECK: br i1 %cmp, label %if.end, label %if.then +; CHECK-NOT: br i1 %cmp, label %for.cond, label %if.then +; CHECK: if.then: +; CHECK: br label %if.end +; CHECK-NOT: br label %for.cond +; CHECK: if.end: +; CHECK br label %for.cond +define i1 @test(i32 %a, i32 %b, i32* %c) { +entry: + br label %for.cond + +for.cond: ; preds = %if.end, %entry + %i.0 = phi i32 [ 2, %entry ], [ %dec, %if.end ] + %changed.0.off0 = phi i1 [ false, %entry ], [ %changed.1.off0, %if.end ] + %dec = add nsw i32 %i.0, -1 + %tobool = icmp eq i32 %i.0, 0 + br i1 %tobool, label %for.cond.cleanup, label %for.body + +for.cond.cleanup: ; preds = %for.cond + %changed.0.off0.lcssa = phi i1 [ %changed.0.off0, %for.cond ] + ret i1 %changed.0.off0.lcssa + +for.body: ; preds = %for.cond + %or = or i32 %a, %b + %idxprom = sext i32 %dec to i64 + %arrayidx = getelementptr inbounds i32, i32* %c, i64 %idxprom + %0 = load i32, i32* %arrayidx, align 4 + %cmp = icmp eq i32 %or, %0 + br i1 %cmp, label %if.end, label %if.then + +if.then: ; preds = %for.body + store i32 %or, i32* %arrayidx, align 4 + call void @foo() + br label %if.end + +if.end: ; preds = %for.body, %if.then + %changed.1.off0 = phi i1 [ true, %if.then ], [ %changed.0.off0, %for.body ] + br label %for.cond +} + +declare void @foo() diff --git a/test/Transforms/SimplifyCFG/preserve-llvm-loop-metadata.ll b/test/Transforms/SimplifyCFG/preserve-llvm-loop-metadata.ll index 12a908b20f9e..e357104f2a66 100644 --- a/test/Transforms/SimplifyCFG/preserve-llvm-loop-metadata.ll +++ b/test/Transforms/SimplifyCFG/preserve-llvm-loop-metadata.ll @@ -1,4 +1,4 @@ -; RUN: opt -simplifycfg -S < %s | FileCheck %s +; RUN: opt -latesimplifycfg -S < %s | FileCheck %s define void @test1(i32 %n) #0 { entry: diff --git a/utils/release/test-release.sh b/utils/release/test-release.sh index 8ec3abb17551..02d8e7925f6e 100755 --- a/utils/release/test-release.sh +++ b/utils/release/test-release.sh @@ -562,7 +562,7 @@ for Flavor in $Flavors ; do # case there are build paths in the debug info. On some systems, # sed adds a newline to the output, so pass $p3 through sed too. if ! cmp -s \ - <(env LC_CTYPE=C sed -e 's,Phase2,Phase3,g' $p2) \ + <(env LC_CTYPE=C sed -e 's,Phase2,Phase3,g' -e 's,Phase1,Phase2,g' $p2) \ <(env LC_CTYPE=C sed -e '' $p3) 16 16; then echo "file `basename $p2` differs between phase 2 and phase 3" fi From 104a02fb6c96111ce06b53e282adfb2b4a59eeb6 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Sat, 29 Jul 2017 21:28:13 +0000 Subject: [PATCH 07/10] Vendor import of clang release_50 branch r309439: https://llvm.org/svn/llvm-project/cfe/branches/release_50@309439 --- docs/AttributeReference.rst | 3470 ++++++++++++++++- docs/ClangCommandLineReference.rst | 50 +- docs/UsersManual.rst | 47 + include/clang/AST/Type.h | 1 + lib/AST/StmtProfile.cpp | 15 + lib/AST/Type.cpp | 9 + lib/Basic/DiagnosticIDs.cpp | 2 +- lib/Basic/Version.cpp | 2 +- lib/CodeGen/CodeGenTBAA.cpp | 6 + lib/Driver/Driver.cpp | 7 +- lib/Headers/unwind.h | 78 +- lib/Sema/SemaCodeComplete.cpp | 43 +- test/CodeCompletion/functions.cpp | 2 +- test/CodeGenCXX/std-byte.cpp | 41 + test/Driver/autocomplete.c | 81 +- test/Index/code-completion.cpp | 4 +- test/Index/complete-optional-params.cpp | 36 +- tools/clang-format/ClangFormat.cpp | 3 +- .../ClangOffloadBundler.cpp | 3 +- utils/bash-autocomplete.sh | 12 +- 20 files changed, 3832 insertions(+), 80 deletions(-) create mode 100644 test/CodeGenCXX/std-byte.cpp diff --git a/docs/AttributeReference.rst b/docs/AttributeReference.rst index a763ddeaeb10..58004a3c0a32 100644 --- a/docs/AttributeReference.rst +++ b/docs/AttributeReference.rst @@ -1,13 +1,3471 @@ .. ------------------------------------------------------------------- NOTE: This file is automatically generated by running clang-tblgen - -gen-attr-docs. Do not edit this file by hand!! The contents for - this file are automatically generated by a server-side process. - - Please do not commit this file. The file exists for local testing - purposes only. + -gen-attr-docs. Do not edit this file by hand!! ------------------------------------------------------------------- =================== Attributes in Clang -=================== \ No newline at end of file +=================== +.. contents:: + :local: + +Introduction +============ + +This page lists the attributes currently supported by Clang. + +Function Attributes +=================== + + +interrupt +--------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "" + +Clang supports the GNU style ``__attribute__((interrupt("TYPE")))`` attribute on +ARM targets. This attribute may be attached to a function definition and +instructs the backend to generate appropriate function entry/exit code so that +it can be used directly as an interrupt service routine. + +The parameter passed to the interrupt attribute is optional, but if +provided it must be a string literal with one of the following values: "IRQ", +"FIQ", "SWI", "ABORT", "UNDEF". + +The semantics are as follows: + +- If the function is AAPCS, Clang instructs the backend to realign the stack to + 8 bytes on entry. This is a general requirement of the AAPCS at public + interfaces, but may not hold when an exception is taken. Doing this allows + other AAPCS functions to be called. +- If the CPU is M-class this is all that needs to be done since the architecture + itself is designed in such a way that functions obeying the normal AAPCS ABI + constraints are valid exception handlers. +- If the CPU is not M-class, the prologue and epilogue are modified to save all + non-banked registers that are used, so that upon return the user-mode state + will not be corrupted. Note that to avoid unnecessary overhead, only + general-purpose (integer) registers are saved in this way. If VFP operations + are needed, that state must be saved manually. + + Specifically, interrupt kinds other than "FIQ" will save all core registers + except "lr" and "sp". "FIQ" interrupts will save r0-r7. +- If the CPU is not M-class, the return instruction is changed to one of the + canonical sequences permitted by the architecture for exception return. Where + possible the function itself will make the necessary "lr" adjustments so that + the "preferred return address" is selected. + + Unfortunately the compiler is unable to make this guarantee for an "UNDEF" + handler, where the offset from "lr" to the preferred return address depends on + the execution state of the code which generated the exception. In this case + a sequence equivalent to "movs pc, lr" will be used. + + +interrupt +--------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "X" + +Clang supports the GNU style ``__attribute__((interrupt))`` attribute on +AVR targets. This attribute may be attached to a function definition and instructs +the backend to generate appropriate function entry/exit code so that it can be used +directly as an interrupt service routine. + +On the AVR, the hardware globally disables interrupts when an interrupt is executed. +The first instruction of an interrupt handler declared with this attribute is a SEI +instruction to re-enable interrupts. See also the signal attribute that +does not insert a SEI instruction. + + +signal +------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "X" + +Clang supports the GNU style ``__attribute__((signal))`` attribute on +AVR targets. This attribute may be attached to a function definition and instructs +the backend to generate appropriate function entry/exit code so that it can be used +directly as an interrupt service routine. + +Interrupt handler functions defined with the signal attribute do not re-enable interrupts. + + +abi_tag (gnu::abi_tag) +---------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "X" + +The ``abi_tag`` attribute can be applied to a function, variable, class or +inline namespace declaration to modify the mangled name of the entity. It gives +the ability to distinguish between different versions of the same entity but +with different ABI versions supported. For example, a newer version of a class +could have a different set of data members and thus have a different size. Using +the ``abi_tag`` attribute, it is possible to have different mangled names for +a global variable of the class type. Therefor, the old code could keep using +the old manged name and the new code will use the new mangled name with tags. + + +acquire_capability (acquire_shared_capability, clang::acquire_capability, clang::acquire_shared_capability) +----------------------------------------------------------------------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "" + +Marks a function as acquiring a capability. + + +alloc_align (gnu::alloc_align) +------------------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "" + +Use ``__attribute__((alloc_align())`` on a function +declaration to specify that the return value of the function (which must be a +pointer type) is at least as aligned as the value of the indicated parameter. The +parameter is given by its index in the list of formal parameters; the first +parameter has index 1 unless the function is a C++ non-static member function, +in which case the first parameter has index 2 to account for the implicit ``this`` +parameter. + +.. code-block:: c++ + + // The returned pointer has the alignment specified by the first parameter. + void *a(size_t align) __attribute__((alloc_align(1))); + + // The returned pointer has the alignment specified by the second parameter. + void *b(void *v, size_t align) __attribute__((alloc_align(2))); + + // The returned pointer has the alignment specified by the second visible + // parameter, however it must be adjusted for the implicit 'this' parameter. + void *Foo::b(void *v, size_t align) __attribute__((alloc_align(3))); + +Note that this attribute merely informs the compiler that a function always +returns a sufficiently aligned pointer. It does not cause the compiler to +emit code to enforce that alignment. The behavior is undefined if the returned +poitner is not sufficiently aligned. + + +alloc_size (gnu::alloc_size) +---------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "X" + +The ``alloc_size`` attribute can be placed on functions that return pointers in +order to hint to the compiler how many bytes of memory will be available at the +returned poiner. ``alloc_size`` takes one or two arguments. + +- ``alloc_size(N)`` implies that argument number N equals the number of + available bytes at the returned pointer. +- ``alloc_size(N, M)`` implies that the product of argument number N and + argument number M equals the number of available bytes at the returned + pointer. + +Argument numbers are 1-based. + +An example of how to use ``alloc_size`` + +.. code-block:: c + + void *my_malloc(int a) __attribute__((alloc_size(1))); + void *my_calloc(int a, int b) __attribute__((alloc_size(1, 2))); + + int main() { + void *const p = my_malloc(100); + assert(__builtin_object_size(p, 0) == 100); + void *const a = my_calloc(20, 5); + assert(__builtin_object_size(a, 0) == 100); + } + +.. Note:: This attribute works differently in clang than it does in GCC. + Specifically, clang will only trace ``const`` pointers (as above); we give up + on pointers that are not marked as ``const``. In the vast majority of cases, + this is unimportant, because LLVM has support for the ``alloc_size`` + attribute. However, this may cause mildly unintuitive behavior when used with + other attributes, such as ``enable_if``. + + +interrupt +--------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "" + +Clang supports the GNU style ``__attribute__((interrupt))`` attribute on +x86/x86-64 targets.The compiler generates function entry and exit sequences +suitable for use in an interrupt handler when this attribute is present. +The 'IRET' instruction, instead of the 'RET' instruction, is used to return +from interrupt or exception handlers. All registers, except for the EFLAGS +register which is restored by the 'IRET' instruction, are preserved by the +compiler. + +Any interruptible-without-stack-switch code must be compiled with +-mno-red-zone since interrupt handlers can and will, because of the +hardware design, touch the red zone. + +1. interrupt handler must be declared with a mandatory pointer argument: + + .. code-block:: c + + struct interrupt_frame + { + uword_t ip; + uword_t cs; + uword_t flags; + uword_t sp; + uword_t ss; + }; + + __attribute__ ((interrupt)) + void f (struct interrupt_frame *frame) { + ... + } + +2. exception handler: + + The exception handler is very similar to the interrupt handler with + a different mandatory function signature: + + .. code-block:: c + + __attribute__ ((interrupt)) + void f (struct interrupt_frame *frame, uword_t error_code) { + ... + } + + and compiler pops 'ERROR_CODE' off stack before the 'IRET' instruction. + + The exception handler should only be used for exceptions which push an + error code and all other exceptions must use the interrupt handler. + The system will crash if the wrong handler is used. + + +no_caller_saved_registers (gnu::no_caller_saved_registers) +---------------------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "" + +Use this attribute to indicate that the specified function has no +caller-saved registers. That is, all registers are callee-saved except for +registers used for passing parameters to the function or returning parameters +from the function. +The compiler saves and restores any modified registers that were not used for +passing or returning arguments to the function. + +The user can call functions specified with the 'no_caller_saved_registers' +attribute from an interrupt handler without saving and restoring all +call-clobbered registers. + +Note that 'no_caller_saved_registers' attribute is not a calling convention. +In fact, it only overrides the decision of which registers should be saved by +the caller, but not how the parameters are passed from the caller to the callee. + +For example: + + .. code-block:: c + + __attribute__ ((no_caller_saved_registers, fastcall)) + void f (int arg1, int arg2) { + ... + } + + In this case parameters 'arg1' and 'arg2' will be passed in registers. + In this case, on 32-bit x86 targets, the function 'f' will use ECX and EDX as + register parameters. However, it will not assume any scratch registers and + should save and restore any modified registers except for ECX and EDX. + + +assert_capability (assert_shared_capability, clang::assert_capability, clang::assert_shared_capability) +------------------------------------------------------------------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "" + +Marks a function that dynamically tests whether a capability is held, and halts +the program if it is not held. + + +assume_aligned (gnu::assume_aligned) +------------------------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "X" + +Use ``__attribute__((assume_aligned([,]))`` on a function +declaration to specify that the return value of the function (which must be a +pointer type) has the specified offset, in bytes, from an address with the +specified alignment. The offset is taken to be zero if omitted. + +.. code-block:: c++ + + // The returned pointer value has 32-byte alignment. + void *a() __attribute__((assume_aligned (32))); + + // The returned pointer value is 4 bytes greater than an address having + // 32-byte alignment. + void *b() __attribute__((assume_aligned (32, 4))); + +Note that this attribute provides information to the compiler regarding a +condition that the code already ensures is true. It does not cause the compiler +to enforce the provided alignment assumption. + + +availability +------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "X" + +The ``availability`` attribute can be placed on declarations to describe the +lifecycle of that declaration relative to operating system versions. Consider +the function declaration for a hypothetical function ``f``: + +.. code-block:: c++ + + void f(void) __attribute__((availability(macos,introduced=10.4,deprecated=10.6,obsoleted=10.7))); + +The availability attribute states that ``f`` was introduced in macOS 10.4, +deprecated in macOS 10.6, and obsoleted in macOS 10.7. This information +is used by Clang to determine when it is safe to use ``f``: for example, if +Clang is instructed to compile code for macOS 10.5, a call to ``f()`` +succeeds. If Clang is instructed to compile code for macOS 10.6, the call +succeeds but Clang emits a warning specifying that the function is deprecated. +Finally, if Clang is instructed to compile code for macOS 10.7, the call +fails because ``f()`` is no longer available. + +The availability attribute is a comma-separated list starting with the +platform name and then including clauses specifying important milestones in the +declaration's lifetime (in any order) along with additional information. Those +clauses can be: + +introduced=\ *version* + The first version in which this declaration was introduced. + +deprecated=\ *version* + The first version in which this declaration was deprecated, meaning that + users should migrate away from this API. + +obsoleted=\ *version* + The first version in which this declaration was obsoleted, meaning that it + was removed completely and can no longer be used. + +unavailable + This declaration is never available on this platform. + +message=\ *string-literal* + Additional message text that Clang will provide when emitting a warning or + error about use of a deprecated or obsoleted declaration. Useful to direct + users to replacement APIs. + +replacement=\ *string-literal* + Additional message text that Clang will use to provide Fix-It when emitting + a warning about use of a deprecated declaration. The Fix-It will replace + the deprecated declaration with the new declaration specified. + +Multiple availability attributes can be placed on a declaration, which may +correspond to different platforms. Only the availability attribute with the +platform corresponding to the target platform will be used; any others will be +ignored. If no availability attribute specifies availability for the current +target platform, the availability attributes are ignored. Supported platforms +are: + +``ios`` + Apple's iOS operating system. The minimum deployment target is specified by + the ``-mios-version-min=*version*`` or ``-miphoneos-version-min=*version*`` + command-line arguments. + +``macos`` + Apple's macOS operating system. The minimum deployment target is + specified by the ``-mmacosx-version-min=*version*`` command-line argument. + ``macosx`` is supported for backward-compatibility reasons, but it is + deprecated. + +``tvos`` + Apple's tvOS operating system. The minimum deployment target is specified by + the ``-mtvos-version-min=*version*`` command-line argument. + +``watchos`` + Apple's watchOS operating system. The minimum deployment target is specified by + the ``-mwatchos-version-min=*version*`` command-line argument. + +A declaration can typically be used even when deploying back to a platform +version prior to when the declaration was introduced. When this happens, the +declaration is `weakly linked +`_, +as if the ``weak_import`` attribute were added to the declaration. A +weakly-linked declaration may or may not be present a run-time, and a program +can determine whether the declaration is present by checking whether the +address of that declaration is non-NULL. + +The flag ``strict`` disallows using API when deploying back to a +platform version prior to when the declaration was introduced. An +attempt to use such API before its introduction causes a hard error. +Weakly-linking is almost always a better API choice, since it allows +users to query availability at runtime. + +If there are multiple declarations of the same entity, the availability +attributes must either match on a per-platform basis or later +declarations must not have availability attributes for that +platform. For example: + +.. code-block:: c + + void g(void) __attribute__((availability(macos,introduced=10.4))); + void g(void) __attribute__((availability(macos,introduced=10.4))); // okay, matches + void g(void) __attribute__((availability(ios,introduced=4.0))); // okay, adds a new platform + void g(void); // okay, inherits both macos and ios availability from above. + void g(void) __attribute__((availability(macos,introduced=10.5))); // error: mismatch + +When one method overrides another, the overriding method can be more widely available than the overridden method, e.g.,: + +.. code-block:: objc + + @interface A + - (id)method __attribute__((availability(macos,introduced=10.4))); + - (id)method2 __attribute__((availability(macos,introduced=10.4))); + @end + + @interface B : A + - (id)method __attribute__((availability(macos,introduced=10.3))); // okay: method moved into base class later + - (id)method __attribute__((availability(macos,introduced=10.5))); // error: this method was available via the base class in 10.4 + @end + +Starting with the macOS 10.12 SDK, the ``API_AVAILABLE`` macro from +```` can simplify the spelling: + +.. code-block:: objc + + @interface A + - (id)method API_AVAILABLE(macos(10.11))); + - (id)otherMethod API_AVAILABLE(macos(10.11), ios(11.0)); + @end + +Also see the documentation for `@available +`_ + + +_Noreturn +--------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "","","","X", "", "" + +A function declared as ``_Noreturn`` shall not return to its caller. The +compiler will generate a diagnostic for a function declared as ``_Noreturn`` +that appears to be capable of returning to its caller. + + +noreturn +-------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "","X","","", "", "X" + +A function declared as ``[[noreturn]]`` shall not return to its caller. The +compiler will generate a diagnostic for a function declared as ``[[noreturn]]`` +that appears to be capable of returning to its caller. + + +carries_dependency +------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "X" + +The ``carries_dependency`` attribute specifies dependency propagation into and +out of functions. + +When specified on a function or Objective-C method, the ``carries_dependency`` +attribute means that the return value carries a dependency out of the function, +so that the implementation need not constrain ordering upon return from that +function. Implementations of the function and its caller may choose to preserve +dependencies instead of emitting memory ordering instructions such as fences. + +Note, this attribute does not change the meaning of the program, but may result +in generation of more efficient code. + + +convergent (clang::convergent) +------------------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "X" + +The ``convergent`` attribute can be placed on a function declaration. It is +translated into the LLVM ``convergent`` attribute, which indicates that the call +instructions of a function with this attribute cannot be made control-dependent +on any additional values. + +In languages designed for SPMD/SIMT programming model, e.g. OpenCL or CUDA, +the call instructions of a function with this attribute must be executed by +all work items or threads in a work group or sub group. + +This attribute is different from ``noduplicate`` because it allows duplicating +function calls if it can be proved that the duplicated function calls are +not made control-dependent on any additional values, e.g., unrolling a loop +executed by all work items. + +Sample usage: +.. code-block:: c + + void convfunc(void) __attribute__((convergent)); + // Setting it as a C++11 attribute is also valid in a C++ program. + // void convfunc(void) [[clang::convergent]]; + + +deprecated (gnu::deprecated) +---------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","X","", "", "" + +The ``deprecated`` attribute can be applied to a function, a variable, or a +type. This is useful when identifying functions, variables, or types that are +expected to be removed in a future version of a program. + +Consider the function declaration for a hypothetical function ``f``: + +.. code-block:: c++ + + void f(void) __attribute__((deprecated("message", "replacement"))); + +When spelled as `__attribute__((deprecated))`, the deprecated attribute can have +two optional string arguments. The first one is the message to display when +emitting the warning; the second one enables the compiler to provide a Fix-It +to replace the deprecated name with a new name. Otherwise, when spelled as +`[[gnu::deprecated]] or [[deprecated]]`, the attribute can have one optional +string argument which is the message to display when emitting the warning. + + +diagnose_if +----------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "" + +The ``diagnose_if`` attribute can be placed on function declarations to emit +warnings or errors at compile-time if calls to the attributed function meet +certain user-defined criteria. For example: + +.. code-block:: c + + void abs(int a) + __attribute__((diagnose_if(a >= 0, "Redundant abs call", "warning"))); + void must_abs(int a) + __attribute__((diagnose_if(a >= 0, "Redundant abs call", "error"))); + + int val = abs(1); // warning: Redundant abs call + int val2 = must_abs(1); // error: Redundant abs call + int val3 = abs(val); + int val4 = must_abs(val); // Because run-time checks are not emitted for + // diagnose_if attributes, this executes without + // issue. + + +``diagnose_if`` is closely related to ``enable_if``, with a few key differences: + +* Overload resolution is not aware of ``diagnose_if`` attributes: they're + considered only after we select the best candidate from a given candidate set. +* Function declarations that differ only in their ``diagnose_if`` attributes are + considered to be redeclarations of the same function (not overloads). +* If the condition provided to ``diagnose_if`` cannot be evaluated, no + diagnostic will be emitted. + +Otherwise, ``diagnose_if`` is essentially the logical negation of ``enable_if``. + +As a result of bullet number two, ``diagnose_if`` attributes will stack on the +same function. For example: + +.. code-block:: c + + int foo() __attribute__((diagnose_if(1, "diag1", "warning"))); + int foo() __attribute__((diagnose_if(1, "diag2", "warning"))); + + int bar = foo(); // warning: diag1 + // warning: diag2 + int (*fooptr)(void) = foo; // warning: diag1 + // warning: diag2 + + constexpr int supportsAPILevel(int N) { return N < 5; } + int baz(int a) + __attribute__((diagnose_if(!supportsAPILevel(10), + "Upgrade to API level 10 to use baz", "error"))); + int baz(int a) + __attribute__((diagnose_if(!a, "0 is not recommended.", "warning"))); + + int (*bazptr)(int) = baz; // error: Upgrade to API level 10 to use baz + int v = baz(0); // error: Upgrade to API level 10 to use baz + +Query for this feature with ``__has_attribute(diagnose_if)``. + + +disable_tail_calls (clang::disable_tail_calls) +---------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "X" + +The ``disable_tail_calls`` attribute instructs the backend to not perform tail call optimization inside the marked function. + +For example: + + .. code-block:: c + + int callee(int); + + int foo(int a) __attribute__((disable_tail_calls)) { + return callee(a); // This call is not tail-call optimized. + } + +Marking virtual functions as ``disable_tail_calls`` is legal. + + .. code-block:: c++ + + int callee(int); + + class Base { + public: + [[clang::disable_tail_calls]] virtual int foo1() { + return callee(); // This call is not tail-call optimized. + } + }; + + class Derived1 : public Base { + public: + int foo1() override { + return callee(); // This call is tail-call optimized. + } + }; + + +enable_if +--------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "X" + +.. Note:: Some features of this attribute are experimental. The meaning of + multiple enable_if attributes on a single declaration is subject to change in + a future version of clang. Also, the ABI is not standardized and the name + mangling may change in future versions. To avoid that, use asm labels. + +The ``enable_if`` attribute can be placed on function declarations to control +which overload is selected based on the values of the function's arguments. +When combined with the ``overloadable`` attribute, this feature is also +available in C. + +.. code-block:: c++ + + int isdigit(int c); + int isdigit(int c) __attribute__((enable_if(c <= -1 || c > 255, "chosen when 'c' is out of range"))) __attribute__((unavailable("'c' must have the value of an unsigned char or EOF"))); + + void foo(char c) { + isdigit(c); + isdigit(10); + isdigit(-10); // results in a compile-time error. + } + +The enable_if attribute takes two arguments, the first is an expression written +in terms of the function parameters, the second is a string explaining why this +overload candidate could not be selected to be displayed in diagnostics. The +expression is part of the function signature for the purposes of determining +whether it is a redeclaration (following the rules used when determining +whether a C++ template specialization is ODR-equivalent), but is not part of +the type. + +The enable_if expression is evaluated as if it were the body of a +bool-returning constexpr function declared with the arguments of the function +it is being applied to, then called with the parameters at the call site. If the +result is false or could not be determined through constant expression +evaluation, then this overload will not be chosen and the provided string may +be used in a diagnostic if the compile fails as a result. + +Because the enable_if expression is an unevaluated context, there are no global +state changes, nor the ability to pass information from the enable_if +expression to the function body. For example, suppose we want calls to +strnlen(strbuf, maxlen) to resolve to strnlen_chk(strbuf, maxlen, size of +strbuf) only if the size of strbuf can be determined: + +.. code-block:: c++ + + __attribute__((always_inline)) + static inline size_t strnlen(const char *s, size_t maxlen) + __attribute__((overloadable)) + __attribute__((enable_if(__builtin_object_size(s, 0) != -1))), + "chosen when the buffer size is known but 'maxlen' is not"))) + { + return strnlen_chk(s, maxlen, __builtin_object_size(s, 0)); + } + +Multiple enable_if attributes may be applied to a single declaration. In this +case, the enable_if expressions are evaluated from left to right in the +following manner. First, the candidates whose enable_if expressions evaluate to +false or cannot be evaluated are discarded. If the remaining candidates do not +share ODR-equivalent enable_if expressions, the overload resolution is +ambiguous. Otherwise, enable_if overload resolution continues with the next +enable_if attribute on the candidates that have not been discarded and have +remaining enable_if attributes. In this way, we pick the most specific +overload out of a number of viable overloads using enable_if. + +.. code-block:: c++ + + void f() __attribute__((enable_if(true, ""))); // #1 + void f() __attribute__((enable_if(true, ""))) __attribute__((enable_if(true, ""))); // #2 + + void g(int i, int j) __attribute__((enable_if(i, ""))); // #1 + void g(int i, int j) __attribute__((enable_if(j, ""))) __attribute__((enable_if(true))); // #2 + +In this example, a call to f() is always resolved to #2, as the first enable_if +expression is ODR-equivalent for both declarations, but #1 does not have another +enable_if expression to continue evaluating, so the next round of evaluation has +only a single candidate. In a call to g(1, 1), the call is ambiguous even though +#2 has more enable_if attributes, because the first enable_if expressions are +not ODR-equivalent. + +Query for this feature with ``__has_attribute(enable_if)``. + +Note that functions with one or more ``enable_if`` attributes may not have +their address taken, unless all of the conditions specified by said +``enable_if`` are constants that evaluate to ``true``. For example: + +.. code-block:: c + + const int TrueConstant = 1; + const int FalseConstant = 0; + int f(int a) __attribute__((enable_if(a > 0, ""))); + int g(int a) __attribute__((enable_if(a == 0 || a != 0, ""))); + int h(int a) __attribute__((enable_if(1, ""))); + int i(int a) __attribute__((enable_if(TrueConstant, ""))); + int j(int a) __attribute__((enable_if(FalseConstant, ""))); + + void fn() { + int (*ptr)(int); + ptr = &f; // error: 'a > 0' is not always true + ptr = &g; // error: 'a == 0 || a != 0' is not a truthy constant + ptr = &h; // OK: 1 is a truthy constant + ptr = &i; // OK: 'TrueConstant' is a truthy constant + ptr = &j; // error: 'FalseConstant' is a constant, but not truthy + } + +Because ``enable_if`` evaluation happens during overload resolution, +``enable_if`` may give unintuitive results when used with templates, depending +on when overloads are resolved. In the example below, clang will emit a +diagnostic about no viable overloads for ``foo`` in ``bar``, but not in ``baz``: + +.. code-block:: c++ + + double foo(int i) __attribute__((enable_if(i > 0, ""))); + void *foo(int i) __attribute__((enable_if(i <= 0, ""))); + template + auto bar() { return foo(I); } + + template + auto baz() { return foo(T::number); } + + struct WithNumber { constexpr static int number = 1; }; + void callThem() { + bar(); + baz(); + } + +This is because, in ``bar``, ``foo`` is resolved prior to template +instantiation, so the value for ``I`` isn't known (thus, both ``enable_if`` +conditions for ``foo`` fail). However, in ``baz``, ``foo`` is resolved during +template instantiation, so the value for ``T::number`` is known. + + +external_source_symbol (clang::external_source_symbol) +------------------------------------------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "X" + +The ``external_source_symbol`` attribute specifies that a declaration originates +from an external source and describes the nature of that source. + +The fact that Clang is capable of recognizing declarations that were defined +externally can be used to provide better tooling support for mixed-language +projects or projects that rely on auto-generated code. For instance, an IDE that +uses Clang and that supports mixed-language projects can use this attribute to +provide a correct 'jump-to-definition' feature. For a concrete example, +consider a protocol that's defined in a Swift file: + +.. code-block:: swift + + @objc public protocol SwiftProtocol { + func method() + } + +This protocol can be used from Objective-C code by including a header file that +was generated by the Swift compiler. The declarations in that header can use +the ``external_source_symbol`` attribute to make Clang aware of the fact +that ``SwiftProtocol`` actually originates from a Swift module: + +.. code-block:: objc + + __attribute__((external_source_symbol(language="Swift",defined_in="module"))) + @protocol SwiftProtocol + @required + - (void) method; + @end + +Consequently, when 'jump-to-definition' is performed at a location that +references ``SwiftProtocol``, the IDE can jump to the original definition in +the Swift source file rather than jumping to the Objective-C declaration in the +auto-generated header file. + +The ``external_source_symbol`` attribute is a comma-separated list that includes +clauses that describe the origin and the nature of the particular declaration. +Those clauses can be: + +language=\ *string-literal* + The name of the source language in which this declaration was defined. + +defined_in=\ *string-literal* + The name of the source container in which the declaration was defined. The + exact definition of source container is language-specific, e.g. Swift's + source containers are modules, so ``defined_in`` should specify the Swift + module name. + +generated_declaration + This declaration was automatically generated by some tool. + +The clauses can be specified in any order. The clauses that are listed above are +all optional, but the attribute has to have at least one clause. + + +flatten (gnu::flatten) +---------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "X" + +The ``flatten`` attribute causes calls within the attributed function to +be inlined unless it is impossible to do so, for example if the body of the +callee is unavailable or if the callee has the ``noinline`` attribute. + + +format (gnu::format) +-------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "" + +Clang supports the ``format`` attribute, which indicates that the function +accepts a ``printf`` or ``scanf``-like format string and corresponding +arguments or a ``va_list`` that contains these arguments. + +Please see `GCC documentation about format attribute +`_ to find details +about attribute syntax. + +Clang implements two kinds of checks with this attribute. + +#. Clang checks that the function with the ``format`` attribute is called with + a format string that uses format specifiers that are allowed, and that + arguments match the format string. This is the ``-Wformat`` warning, it is + on by default. + +#. Clang checks that the format string argument is a literal string. This is + the ``-Wformat-nonliteral`` warning, it is off by default. + + Clang implements this mostly the same way as GCC, but there is a difference + for functions that accept a ``va_list`` argument (for example, ``vprintf``). + GCC does not emit ``-Wformat-nonliteral`` warning for calls to such + functions. Clang does not warn if the format string comes from a function + parameter, where the function is annotated with a compatible attribute, + otherwise it warns. For example: + + .. code-block:: c + + __attribute__((__format__ (__scanf__, 1, 3))) + void foo(const char* s, char *buf, ...) { + va_list ap; + va_start(ap, buf); + + vprintf(s, ap); // warning: format string is not a string literal + } + + In this case we warn because ``s`` contains a format string for a + ``scanf``-like function, but it is passed to a ``printf``-like function. + + If the attribute is removed, clang still warns, because the format string is + not a string literal. + + Another example: + + .. code-block:: c + + __attribute__((__format__ (__printf__, 1, 3))) + void foo(const char* s, char *buf, ...) { + va_list ap; + va_start(ap, buf); + + vprintf(s, ap); // warning + } + + In this case Clang does not warn because the format string ``s`` and + the corresponding arguments are annotated. If the arguments are + incorrect, the caller of ``foo`` will receive a warning. + + +ifunc (gnu::ifunc) +------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "X" + +``__attribute__((ifunc("resolver")))`` is used to mark that the address of a declaration should be resolved at runtime by calling a resolver function. + +The symbol name of the resolver function is given in quotes. A function with this name (after mangling) must be defined in the current translation unit; it may be ``static``. The resolver function should take no arguments and return a pointer. + +The ``ifunc`` attribute may only be used on a function declaration. A function declaration with an ``ifunc`` attribute is considered to be a definition of the declared entity. The entity must not have weak linkage; for example, in C++, it cannot be applied to a declaration if a definition at that location would be considered inline. + +Not all targets support this attribute. ELF targets support this attribute when using binutils v2.20.1 or higher and glibc v2.11.1 or higher. Non-ELF targets currently do not support this attribute. + + +internal_linkage (clang::internal_linkage) +------------------------------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "X" + +The ``internal_linkage`` attribute changes the linkage type of the declaration to internal. +This is similar to C-style ``static``, but can be used on classes and class methods. When applied to a class definition, +this attribute affects all methods and static data members of that class. +This can be used to contain the ABI of a C++ library by excluding unwanted class methods from the export tables. + + +micromips (gnu::micromips) +-------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "X" + +Clang supports the GNU style ``__attribute__((micromips))`` and +``__attribute__((nomicromips))`` attributes on MIPS targets. These attributes +may be attached to a function definition and instructs the backend to generate +or not to generate microMIPS code for that function. + +These attributes override the `-mmicromips` and `-mno-micromips` options +on the command line. + + +interrupt +--------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "X" + +Clang supports the GNU style ``__attribute__((interrupt("ARGUMENT")))`` attribute on +MIPS targets. This attribute may be attached to a function definition and instructs +the backend to generate appropriate function entry/exit code so that it can be used +directly as an interrupt service routine. + +By default, the compiler will produce a function prologue and epilogue suitable for +an interrupt service routine that handles an External Interrupt Controller (eic) +generated interrupt. This behaviour can be explicitly requested with the "eic" +argument. + +Otherwise, for use with vectored interrupt mode, the argument passed should be +of the form "vector=LEVEL" where LEVEL is one of the following values: +"sw0", "sw1", "hw0", "hw1", "hw2", "hw3", "hw4", "hw5". The compiler will +then set the interrupt mask to the corresponding level which will mask all +interrupts up to and including the argument. + +The semantics are as follows: + +- The prologue is modified so that the Exception Program Counter (EPC) and + Status coprocessor registers are saved to the stack. The interrupt mask is + set so that the function can only be interrupted by a higher priority + interrupt. The epilogue will restore the previous values of EPC and Status. + +- The prologue and epilogue are modified to save and restore all non-kernel + registers as necessary. + +- The FPU is disabled in the prologue, as the floating pointer registers are not + spilled to the stack. + +- The function return sequence is changed to use an exception return instruction. + +- The parameter sets the interrupt mask for the function corresponding to the + interrupt level specified. If no mask is specified the interrupt mask + defaults to "eic". + + +noalias +------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "","","X","", "", "" + +The ``noalias`` attribute indicates that the only memory accesses inside +function are loads and stores from objects pointed to by its pointer-typed +arguments, with arbitrary offsets. + + +noduplicate (clang::noduplicate) +-------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "X" + +The ``noduplicate`` attribute can be placed on function declarations to control +whether function calls to this function can be duplicated or not as a result of +optimizations. This is required for the implementation of functions with +certain special requirements, like the OpenCL "barrier" function, that might +need to be run concurrently by all the threads that are executing in lockstep +on the hardware. For example this attribute applied on the function +"nodupfunc" in the code below avoids that: + +.. code-block:: c + + void nodupfunc() __attribute__((noduplicate)); + // Setting it as a C++11 attribute is also valid + // void nodupfunc() [[clang::noduplicate]]; + void foo(); + void bar(); + + nodupfunc(); + if (a > n) { + foo(); + } else { + bar(); + } + +gets possibly modified by some optimizations into code similar to this: + +.. code-block:: c + + if (a > n) { + nodupfunc(); + foo(); + } else { + nodupfunc(); + bar(); + } + +where the call to "nodupfunc" is duplicated and sunk into the two branches +of the condition. + + +nomicromips (gnu::nomicromips) +------------------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "X" + +Clang supports the GNU style ``__attribute__((micromips))`` and +``__attribute__((nomicromips))`` attributes on MIPS targets. These attributes +may be attached to a function definition and instructs the backend to generate +or not to generate microMIPS code for that function. + +These attributes override the `-mmicromips` and `-mno-micromips` options +on the command line. + + +no_sanitize (clang::no_sanitize) +-------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "X" + +Use the ``no_sanitize`` attribute on a function declaration to specify +that a particular instrumentation or set of instrumentations should not be +applied to that function. The attribute takes a list of string literals, +which have the same meaning as values accepted by the ``-fno-sanitize=`` +flag. For example, ``__attribute__((no_sanitize("address", "thread")))`` +specifies that AddressSanitizer and ThreadSanitizer should not be applied +to the function. + +See :ref:`Controlling Code Generation ` for a +full list of supported sanitizer flags. + + +no_sanitize_address (no_address_safety_analysis, gnu::no_address_safety_analysis, gnu::no_sanitize_address) +----------------------------------------------------------------------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "X" + +.. _langext-address_sanitizer: + +Use ``__attribute__((no_sanitize_address))`` on a function declaration to +specify that address safety instrumentation (e.g. AddressSanitizer) should +not be applied to that function. + + +no_sanitize_thread +------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "X" + +.. _langext-thread_sanitizer: + +Use ``__attribute__((no_sanitize_thread))`` on a function declaration to +specify that checks for data races on plain (non-atomic) memory accesses should +not be inserted by ThreadSanitizer. The function is still instrumented by the +tool to avoid false positives and provide meaningful stack traces. + + +no_sanitize_memory +------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "X" + +.. _langext-memory_sanitizer: + +Use ``__attribute__((no_sanitize_memory))`` on a function declaration to +specify that checks for uninitialized memory should not be inserted +(e.g. by MemorySanitizer). The function may still be instrumented by the tool +to avoid false positives in other places. + + +no_split_stack (gnu::no_split_stack) +------------------------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "X" + +The ``no_split_stack`` attribute disables the emission of the split stack +preamble for a particular function. It has no effect if ``-fsplit-stack`` +is not specified. + + +not_tail_called (clang::not_tail_called) +---------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "X" + +The ``not_tail_called`` attribute prevents tail-call optimization on statically bound calls. It has no effect on indirect calls. Virtual functions, objective-c methods, and functions marked as ``always_inline`` cannot be marked as ``not_tail_called``. + +For example, it prevents tail-call optimization in the following case: + + .. code-block:: c + + int __attribute__((not_tail_called)) foo1(int); + + int foo2(int a) { + return foo1(a); // No tail-call optimization on direct calls. + } + +However, it doesn't prevent tail-call optimization in this case: + + .. code-block:: c + + int __attribute__((not_tail_called)) foo1(int); + + int foo2(int a) { + int (*fn)(int) = &foo1; + + // not_tail_called has no effect on an indirect call even if the call can be + // resolved at compile time. + return (*fn)(a); + } + +Marking virtual functions as ``not_tail_called`` is an error: + + .. code-block:: c++ + + class Base { + public: + // not_tail_called on a virtual function is an error. + [[clang::not_tail_called]] virtual int foo1(); + + virtual int foo2(); + + // Non-virtual functions can be marked ``not_tail_called``. + [[clang::not_tail_called]] int foo3(); + }; + + class Derived1 : public Base { + public: + int foo1() override; + + // not_tail_called on a virtual function is an error. + [[clang::not_tail_called]] int foo2() override; + }; + + +#pragma omp declare simd +------------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "","","","", "X", "" + +The `declare simd` construct can be applied to a function to enable the creation +of one or more versions that can process multiple arguments using SIMD +instructions from a single invocation in a SIMD loop. The `declare simd` +directive is a declarative directive. There may be multiple `declare simd` +directives for a function. The use of a `declare simd` construct on a function +enables the creation of SIMD versions of the associated function that can be +used to process multiple arguments from a single invocation from a SIMD loop +concurrently. +The syntax of the `declare simd` construct is as follows: + + .. code-block:: c + + #pragma omp declare simd [clause[[,] clause] ...] new-line + [#pragma omp declare simd [clause[[,] clause] ...] new-line] + [...] + function definition or declaration + +where clause is one of the following: + + .. code-block:: c + + simdlen(length) + linear(argument-list[:constant-linear-step]) + aligned(argument-list[:alignment]) + uniform(argument-list) + inbranch + notinbranch + + +#pragma omp declare target +-------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "","","","", "X", "" + +The `declare target` directive specifies that variables and functions are mapped +to a device for OpenMP offload mechanism. + +The syntax of the declare target directive is as follows: + + .. code-block:: c + + #pragma omp declare target new-line + declarations-definition-seq + #pragma omp end declare target new-line + + +objc_boxable +------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "X" + +Structs and unions marked with the ``objc_boxable`` attribute can be used +with the Objective-C boxed expression syntax, ``@(...)``. + +**Usage**: ``__attribute__((objc_boxable))``. This attribute +can only be placed on a declaration of a trivially-copyable struct or union: + +.. code-block:: objc + + struct __attribute__((objc_boxable)) some_struct { + int i; + }; + union __attribute__((objc_boxable)) some_union { + int i; + float f; + }; + typedef struct __attribute__((objc_boxable)) _some_struct some_struct; + + // ... + + some_struct ss; + NSValue *boxed = @(ss); + + +objc_method_family +------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "X" + +Many methods in Objective-C have conventional meanings determined by their +selectors. It is sometimes useful to be able to mark a method as having a +particular conventional meaning despite not having the right selector, or as +not having the conventional meaning that its selector would suggest. For these +use cases, we provide an attribute to specifically describe the "method family" +that a method belongs to. + +**Usage**: ``__attribute__((objc_method_family(X)))``, where ``X`` is one of +``none``, ``alloc``, ``copy``, ``init``, ``mutableCopy``, or ``new``. This +attribute can only be placed at the end of a method declaration: + +.. code-block:: objc + + - (NSString *)initMyStringValue __attribute__((objc_method_family(none))); + +Users who do not wish to change the conventional meaning of a method, and who +merely want to document its non-standard retain and release semantics, should +use the retaining behavior attributes (``ns_returns_retained``, +``ns_returns_not_retained``, etc). + +Query for this feature with ``__has_attribute(objc_method_family)``. + + +objc_requires_super +------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "X" + +Some Objective-C classes allow a subclass to override a particular method in a +parent class but expect that the overriding method also calls the overridden +method in the parent class. For these cases, we provide an attribute to +designate that a method requires a "call to ``super``" in the overriding +method in the subclass. + +**Usage**: ``__attribute__((objc_requires_super))``. This attribute can only +be placed at the end of a method declaration: + +.. code-block:: objc + + - (void)foo __attribute__((objc_requires_super)); + +This attribute can only be applied the method declarations within a class, and +not a protocol. Currently this attribute does not enforce any placement of +where the call occurs in the overriding method (such as in the case of +``-dealloc`` where the call must appear at the end). It checks only that it +exists. + +Note that on both OS X and iOS that the Foundation framework provides a +convenience macro ``NS_REQUIRES_SUPER`` that provides syntactic sugar for this +attribute: + +.. code-block:: objc + + - (void)foo NS_REQUIRES_SUPER; + +This macro is conditionally defined depending on the compiler's support for +this attribute. If the compiler does not support the attribute the macro +expands to nothing. + +Operationally, when a method has this annotation the compiler will warn if the +implementation of an override in a subclass does not call super. For example: + +.. code-block:: objc + + warning: method possibly missing a [super AnnotMeth] call + - (void) AnnotMeth{}; + ^ + + +objc_runtime_name +----------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "X" + +By default, the Objective-C interface or protocol identifier is used +in the metadata name for that object. The `objc_runtime_name` +attribute allows annotated interfaces or protocols to use the +specified string argument in the object's metadata name instead of the +default name. + +**Usage**: ``__attribute__((objc_runtime_name("MyLocalName")))``. This attribute +can only be placed before an @protocol or @interface declaration: + +.. code-block:: objc + + __attribute__((objc_runtime_name("MyLocalName"))) + @interface Message + @end + + +objc_runtime_visible +-------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "X" + +This attribute specifies that the Objective-C class to which it applies is visible to the Objective-C runtime but not to the linker. Classes annotated with this attribute cannot be subclassed and cannot have categories defined for them. + + +optnone (clang::optnone) +------------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "X" + +The ``optnone`` attribute suppresses essentially all optimizations +on a function or method, regardless of the optimization level applied to +the compilation unit as a whole. This is particularly useful when you +need to debug a particular function, but it is infeasible to build the +entire application without optimization. Avoiding optimization on the +specified function can improve the quality of the debugging information +for that function. + +This attribute is incompatible with the ``always_inline`` and ``minsize`` +attributes. + + +overloadable +------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "X" + +Clang provides support for C++ function overloading in C. Function overloading +in C is introduced using the ``overloadable`` attribute. For example, one +might provide several overloaded versions of a ``tgsin`` function that invokes +the appropriate standard function computing the sine of a value with ``float``, +``double``, or ``long double`` precision: + +.. code-block:: c + + #include + float __attribute__((overloadable)) tgsin(float x) { return sinf(x); } + double __attribute__((overloadable)) tgsin(double x) { return sin(x); } + long double __attribute__((overloadable)) tgsin(long double x) { return sinl(x); } + +Given these declarations, one can call ``tgsin`` with a ``float`` value to +receive a ``float`` result, with a ``double`` to receive a ``double`` result, +etc. Function overloading in C follows the rules of C++ function overloading +to pick the best overload given the call arguments, with a few C-specific +semantics: + +* Conversion from ``float`` or ``double`` to ``long double`` is ranked as a + floating-point promotion (per C99) rather than as a floating-point conversion + (as in C++). + +* A conversion from a pointer of type ``T*`` to a pointer of type ``U*`` is + considered a pointer conversion (with conversion rank) if ``T`` and ``U`` are + compatible types. + +* A conversion from type ``T`` to a value of type ``U`` is permitted if ``T`` + and ``U`` are compatible types. This conversion is given "conversion" rank. + +* If no viable candidates are otherwise available, we allow a conversion from a + pointer of type ``T*`` to a pointer of type ``U*``, where ``T`` and ``U`` are + incompatible. This conversion is ranked below all other types of conversions. + Please note: ``U`` lacking qualifiers that are present on ``T`` is sufficient + for ``T`` and ``U`` to be incompatible. + +The declaration of ``overloadable`` functions is restricted to function +declarations and definitions. If a function is marked with the ``overloadable`` +attribute, then all declarations and definitions of functions with that name, +except for at most one (see the note below about unmarked overloads), must have +the ``overloadable`` attribute. In addition, redeclarations of a function with +the ``overloadable`` attribute must have the ``overloadable`` attribute, and +redeclarations of a function without the ``overloadable`` attribute must *not* +have the ``overloadable`` attribute. e.g., + +.. code-block:: c + + int f(int) __attribute__((overloadable)); + float f(float); // error: declaration of "f" must have the "overloadable" attribute + int f(int); // error: redeclaration of "f" must have the "overloadable" attribute + + int g(int) __attribute__((overloadable)); + int g(int) { } // error: redeclaration of "g" must also have the "overloadable" attribute + + int h(int); + int h(int) __attribute__((overloadable)); // error: declaration of "h" must not + // have the "overloadable" attribute + +Functions marked ``overloadable`` must have prototypes. Therefore, the +following code is ill-formed: + +.. code-block:: c + + int h() __attribute__((overloadable)); // error: h does not have a prototype + +However, ``overloadable`` functions are allowed to use a ellipsis even if there +are no named parameters (as is permitted in C++). This feature is particularly +useful when combined with the ``unavailable`` attribute: + +.. code-block:: c++ + + void honeypot(...) __attribute__((overloadable, unavailable)); // calling me is an error + +Functions declared with the ``overloadable`` attribute have their names mangled +according to the same rules as C++ function names. For example, the three +``tgsin`` functions in our motivating example get the mangled names +``_Z5tgsinf``, ``_Z5tgsind``, and ``_Z5tgsine``, respectively. There are two +caveats to this use of name mangling: + +* Future versions of Clang may change the name mangling of functions overloaded + in C, so you should not depend on an specific mangling. To be completely + safe, we strongly urge the use of ``static inline`` with ``overloadable`` + functions. + +* The ``overloadable`` attribute has almost no meaning when used in C++, + because names will already be mangled and functions are already overloadable. + However, when an ``overloadable`` function occurs within an ``extern "C"`` + linkage specification, it's name *will* be mangled in the same way as it + would in C. + +For the purpose of backwards compatibility, at most one function with the same +name as other ``overloadable`` functions may omit the ``overloadable`` +attribute. In this case, the function without the ``overloadable`` attribute +will not have its name mangled. + +For example: + +.. code-block:: c + + // Notes with mangled names assume Itanium mangling. + int f(int); + int f(double) __attribute__((overloadable)); + void foo() { + f(5); // Emits a call to f (not _Z1fi, as it would with an overload that + // was marked with overloadable). + f(1.0); // Emits a call to _Z1fd. + } + +Support for unmarked overloads is not present in some versions of clang. You may +query for it using ``__has_extension(overloadable_unmarked)``. + +Query for this attribute with ``__has_attribute(overloadable)``. + + +release_capability (release_shared_capability, clang::release_capability, clang::release_shared_capability) +----------------------------------------------------------------------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "" + +Marks a function as releasing a capability. + + +kernel +------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "X" + +``__attribute__((kernel))`` is used to mark a ``kernel`` function in +RenderScript. + +In RenderScript, ``kernel`` functions are used to express data-parallel +computations. The RenderScript runtime efficiently parallelizes ``kernel`` +functions to run on computational resources such as multi-core CPUs and GPUs. +See the RenderScript_ documentation for more information. + +.. _RenderScript: https://developer.android.com/guide/topics/renderscript/compute.html + + +target (gnu::target) +-------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "X" + +Clang supports the GNU style ``__attribute__((target("OPTIONS")))`` attribute. +This attribute may be attached to a function definition and instructs +the backend to use different code generation options than were passed on the +command line. + +The current set of options correspond to the existing "subtarget features" for +the target with or without a "-mno-" in front corresponding to the absence +of the feature, as well as ``arch="CPU"`` which will change the default "CPU" +for the function. + +Example "subtarget features" from the x86 backend include: "mmx", "sse", "sse4.2", +"avx", "xop" and largely correspond to the machine specific options handled by +the front end. + + +try_acquire_capability (try_acquire_shared_capability, clang::try_acquire_capability, clang::try_acquire_shared_capability) +--------------------------------------------------------------------------------------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "" + +Marks a function that attempts to acquire a capability. This function may fail to +actually acquire the capability; they accept a Boolean value determining +whether acquiring the capability means success (true), or failing to acquire +the capability means success (false). + + +nodiscard, warn_unused_result, clang::warn_unused_result, gnu::warn_unused_result +--------------------------------------------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "X" + +Clang supports the ability to diagnose when the results of a function call +expression are discarded under suspicious circumstances. A diagnostic is +generated when a function or its return type is marked with ``[[nodiscard]]`` +(or ``__attribute__((warn_unused_result))``) and the function call appears as a +potentially-evaluated discarded-value expression that is not explicitly cast to +`void`. + +.. code-block: c++ + struct [[nodiscard]] error_info { /*...*/ }; + error_info enable_missile_safety_mode(); + + void launch_missiles(); + void test_missiles() { + enable_missile_safety_mode(); // diagnoses + launch_missiles(); + } + error_info &foo(); + void f() { foo(); } // Does not diagnose, error_info is a reference. + + +xray_always_instrument (clang::xray_always_instrument), xray_never_instrument (clang::xray_never_instrument), xray_log_args (clang::xray_log_args) +-------------------------------------------------------------------------------------------------------------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "X" + +``__attribute__((xray_always_instrument))`` or ``[[clang::xray_always_instrument]]`` is used to mark member functions (in C++), methods (in Objective C), and free functions (in C, C++, and Objective C) to be instrumented with XRay. This will cause the function to always have space at the beginning and exit points to allow for runtime patching. + +Conversely, ``__attribute__((xray_never_instrument))`` or ``[[clang::xray_never_instrument]]`` will inhibit the insertion of these instrumentation points. + +If a function has neither of these attributes, they become subject to the XRay heuristics used to determine whether a function should be instrumented or otherwise. + +``__attribute__((xray_log_args(N)))`` or ``[[clang::xray_log_args(N)]]`` is used to preserve N function arguments for the logging function. Currently, only N==1 is supported. + + +xray_always_instrument (clang::xray_always_instrument), xray_never_instrument (clang::xray_never_instrument), xray_log_args (clang::xray_log_args) +-------------------------------------------------------------------------------------------------------------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "X" + +``__attribute__((xray_always_instrument))`` or ``[[clang::xray_always_instrument]]`` is used to mark member functions (in C++), methods (in Objective C), and free functions (in C, C++, and Objective C) to be instrumented with XRay. This will cause the function to always have space at the beginning and exit points to allow for runtime patching. + +Conversely, ``__attribute__((xray_never_instrument))`` or ``[[clang::xray_never_instrument]]`` will inhibit the insertion of these instrumentation points. + +If a function has neither of these attributes, they become subject to the XRay heuristics used to determine whether a function should be instrumented or otherwise. + +``__attribute__((xray_log_args(N)))`` or ``[[clang::xray_log_args(N)]]`` is used to preserve N function arguments for the logging function. Currently, only N==1 is supported. + + +Variable Attributes +=================== + + +dllexport (gnu::dllexport) +-------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","X","", "", "X" + +The ``__declspec(dllexport)`` attribute declares a variable, function, or +Objective-C interface to be exported from the module. It is available under the +``-fdeclspec`` flag for compatibility with various compilers. The primary use +is for COFF object files which explicitly specify what interfaces are available +for external use. See the dllexport_ documentation on MSDN for more +information. + +.. _dllexport: https://msdn.microsoft.com/en-us/library/3y1sfaz2.aspx + + +dllimport (gnu::dllimport) +-------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","X","", "", "X" + +The ``__declspec(dllimport)`` attribute declares a variable, function, or +Objective-C interface to be imported from an external module. It is available +under the ``-fdeclspec`` flag for compatibility with various compilers. The +primary use is for COFF object files which explicitly specify what interfaces +are imported from external modules. See the dllimport_ documentation on MSDN +for more information. + +.. _dllimport: https://msdn.microsoft.com/en-us/library/3y1sfaz2.aspx + + +init_seg +-------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "","","","", "X", "" + +The attribute applied by ``pragma init_seg()`` controls the section into +which global initialization function pointers are emitted. It is only +available with ``-fms-extensions``. Typically, this function pointer is +emitted into ``.CRT$XCU`` on Windows. The user can change the order of +initialization by using a different section name with the same +``.CRT$XC`` prefix and a suffix that sorts lexicographically before or +after the standard ``.CRT$XCU`` sections. See the init_seg_ +documentation on MSDN for more information. + +.. _init_seg: http://msdn.microsoft.com/en-us/library/7977wcck(v=vs.110).aspx + + +nodebug (gnu::nodebug) +---------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "X" + +The ``nodebug`` attribute allows you to suppress debugging information for a +function or method, or for a variable that is not a parameter or a non-static +data member. + + +nosvm +----- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "X" + +OpenCL 2.0 supports the optional ``__attribute__((nosvm))`` qualifier for +pointer variable. It informs the compiler that the pointer does not refer +to a shared virtual memory region. See OpenCL v2.0 s6.7.2 for details. + +Since it is not widely used and has been removed from OpenCL 2.1, it is ignored +by Clang. + + +pass_object_size +---------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "X" + +.. Note:: The mangling of functions with parameters that are annotated with + ``pass_object_size`` is subject to change. You can get around this by + using ``__asm__("foo")`` to explicitly name your functions, thus preserving + your ABI; also, non-overloadable C functions with ``pass_object_size`` are + not mangled. + +The ``pass_object_size(Type)`` attribute can be placed on function parameters to +instruct clang to call ``__builtin_object_size(param, Type)`` at each callsite +of said function, and implicitly pass the result of this call in as an invisible +argument of type ``size_t`` directly after the parameter annotated with +``pass_object_size``. Clang will also replace any calls to +``__builtin_object_size(param, Type)`` in the function by said implicit +parameter. + +Example usage: + +.. code-block:: c + + int bzero1(char *const p __attribute__((pass_object_size(0)))) + __attribute__((noinline)) { + int i = 0; + for (/**/; i < (int)__builtin_object_size(p, 0); ++i) { + p[i] = 0; + } + return i; + } + + int main() { + char chars[100]; + int n = bzero1(&chars[0]); + assert(n == sizeof(chars)); + return 0; + } + +If successfully evaluating ``__builtin_object_size(param, Type)`` at the +callsite is not possible, then the "failed" value is passed in. So, using the +definition of ``bzero1`` from above, the following code would exit cleanly: + +.. code-block:: c + + int main2(int argc, char *argv[]) { + int n = bzero1(argv); + assert(n == -1); + return 0; + } + +``pass_object_size`` plays a part in overload resolution. If two overload +candidates are otherwise equally good, then the overload with one or more +parameters with ``pass_object_size`` is preferred. This implies that the choice +between two identical overloads both with ``pass_object_size`` on one or more +parameters will always be ambiguous; for this reason, having two such overloads +is illegal. For example: + +.. code-block:: c++ + + #define PS(N) __attribute__((pass_object_size(N))) + // OK + void Foo(char *a, char *b); // Overload A + // OK -- overload A has no parameters with pass_object_size. + void Foo(char *a PS(0), char *b PS(0)); // Overload B + // Error -- Same signature (sans pass_object_size) as overload B, and both + // overloads have one or more parameters with the pass_object_size attribute. + void Foo(void *a PS(0), void *b); + + // OK + void Bar(void *a PS(0)); // Overload C + // OK + void Bar(char *c PS(1)); // Overload D + + void main() { + char known[10], *unknown; + Foo(unknown, unknown); // Calls overload B + Foo(known, unknown); // Calls overload B + Foo(unknown, known); // Calls overload B + Foo(known, known); // Calls overload B + + Bar(known); // Calls overload D + Bar(unknown); // Calls overload D + } + +Currently, ``pass_object_size`` is a bit restricted in terms of its usage: + +* Only one use of ``pass_object_size`` is allowed per parameter. + +* It is an error to take the address of a function with ``pass_object_size`` on + any of its parameters. If you wish to do this, you can create an overload + without ``pass_object_size`` on any parameters. + +* It is an error to apply the ``pass_object_size`` attribute to parameters that + are not pointers. Additionally, any parameter that ``pass_object_size`` is + applied to must be marked ``const`` at its function's definition. + + +require_constant_initialization (clang::require_constant_initialization) +------------------------------------------------------------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "X" + +This attribute specifies that the variable to which it is attached is intended +to have a `constant initializer `_ +according to the rules of [basic.start.static]. The variable is required to +have static or thread storage duration. If the initialization of the variable +is not a constant initializer an error will be produced. This attribute may +only be used in C++. + +Note that in C++03 strict constant expression checking is not done. Instead +the attribute reports if Clang can emit the variable as a constant, even if it's +not technically a 'constant initializer'. This behavior is non-portable. + +Static storage duration variables with constant initializers avoid hard-to-find +bugs caused by the indeterminate order of dynamic initialization. They can also +be safely used during dynamic initialization across translation units. + +This attribute acts as a compile time assertion that the requirements +for constant initialization have been met. Since these requirements change +between dialects and have subtle pitfalls it's important to fail fast instead +of silently falling back on dynamic initialization. + +.. code-block:: c++ + + // -std=c++14 + #define SAFE_STATIC [[clang::require_constant_initialization]] + struct T { + constexpr T(int) {} + ~T(); // non-trivial + }; + SAFE_STATIC T x = {42}; // Initialization OK. Doesn't check destructor. + SAFE_STATIC T y = 42; // error: variable does not have a constant initializer + // copy initialization is not a constant expression on a non-literal type. + + +section (gnu::section, __declspec(allocate)) +-------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","X","", "", "X" + +The ``section`` attribute allows you to specify a specific section a +global variable or function should be in after translation. + + +swiftcall (gnu::swiftcall) +-------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "" + +The ``swiftcall`` attribute indicates that a function should be called +using the Swift calling convention for a function or function pointer. + +The lowering for the Swift calling convention, as described by the Swift +ABI documentation, occurs in multiple phases. The first, "high-level" +phase breaks down the formal parameters and results into innately direct +and indirect components, adds implicit paraameters for the generic +signature, and assigns the context and error ABI treatments to parameters +where applicable. The second phase breaks down the direct parameters +and results from the first phase and assigns them to registers or the +stack. The ``swiftcall`` convention only handles this second phase of +lowering; the C function type must accurately reflect the results +of the first phase, as follows: + +- Results classified as indirect by high-level lowering should be + represented as parameters with the ``swift_indirect_result`` attribute. + +- Results classified as direct by high-level lowering should be represented + as follows: + + - First, remove any empty direct results. + + - If there are no direct results, the C result type should be ``void``. + + - If there is one direct result, the C result type should be a type with + the exact layout of that result type. + + - If there are a multiple direct results, the C result type should be + a struct type with the exact layout of a tuple of those results. + +- Parameters classified as indirect by high-level lowering should be + represented as parameters of pointer type. + +- Parameters classified as direct by high-level lowering should be + omitted if they are empty types; otherwise, they should be represented + as a parameter type with a layout exactly matching the layout of the + Swift parameter type. + +- The context parameter, if present, should be represented as a trailing + parameter with the ``swift_context`` attribute. + +- The error result parameter, if present, should be represented as a + trailing parameter (always following a context parameter) with the + ``swift_error_result`` attribute. + +``swiftcall`` does not support variadic arguments or unprototyped functions. + +The parameter ABI treatment attributes are aspects of the function type. +A function type which which applies an ABI treatment attribute to a +parameter is a different type from an otherwise-identical function type +that does not. A single parameter may not have multiple ABI treatment +attributes. + +Support for this feature is target-dependent, although it should be +supported on every target that Swift supports. Query for this support +with ``__has_attribute(swiftcall)``. This implies support for the +``swift_context``, ``swift_error_result``, and ``swift_indirect_result`` +attributes. + + +swift_context (gnu::swift_context) +---------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "X" + +The ``swift_context`` attribute marks a parameter of a ``swiftcall`` +function as having the special context-parameter ABI treatment. + +This treatment generally passes the context value in a special register +which is normally callee-preserved. + +A ``swift_context`` parameter must either be the last parameter or must be +followed by a ``swift_error_result`` parameter (which itself must always be +the last parameter). + +A context parameter must have pointer or reference type. + + +swift_error_result (gnu::swift_error_result) +-------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "X" + +The ``swift_error_result`` attribute marks a parameter of a ``swiftcall`` +function as having the special error-result ABI treatment. + +This treatment generally passes the underlying error value in and out of +the function through a special register which is normally callee-preserved. +This is modeled in C by pretending that the register is addressable memory: + +- The caller appears to pass the address of a variable of pointer type. + The current value of this variable is copied into the register before + the call; if the call returns normally, the value is copied back into the + variable. + +- The callee appears to receive the address of a variable. This address + is actually a hidden location in its own stack, initialized with the + value of the register upon entry. When the function returns normally, + the value in that hidden location is written back to the register. + +A ``swift_error_result`` parameter must be the last parameter, and it must be +preceded by a ``swift_context`` parameter. + +A ``swift_error_result`` parameter must have type ``T**`` or ``T*&`` for some +type T. Note that no qualifiers are permitted on the intermediate level. + +It is undefined behavior if the caller does not pass a pointer or +reference to a valid object. + +The standard convention is that the error value itself (that is, the +value stored in the apparent argument) will be null upon function entry, +but this is not enforced by the ABI. + + +swift_indirect_result (gnu::swift_indirect_result) +-------------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "X" + +The ``swift_indirect_result`` attribute marks a parameter of a ``swiftcall`` +function as having the special indirect-result ABI treatment. + +This treatment gives the parameter the target's normal indirect-result +ABI treatment, which may involve passing it differently from an ordinary +parameter. However, only the first indirect result will receive this +treatment. Furthermore, low-level lowering may decide that a direct result +must be returned indirectly; if so, this will take priority over the +``swift_indirect_result`` parameters. + +A ``swift_indirect_result`` parameter must either be the first parameter or +follow another ``swift_indirect_result`` parameter. + +A ``swift_indirect_result`` parameter must have type ``T*`` or ``T&`` for +some object type ``T``. If ``T`` is a complete type at the point of +definition of a function, it is undefined behavior if the argument +value does not point to storage of adequate size and alignment for a +value of type ``T``. + +Making indirect results explicit in the signature allows C functions to +directly construct objects into them without relying on language +optimizations like C++'s named return value optimization (NRVO). + + +tls_model (gnu::tls_model) +-------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "X" + +The ``tls_model`` attribute allows you to specify which thread-local storage +model to use. It accepts the following strings: + +* global-dynamic +* local-dynamic +* initial-exec +* local-exec + +TLS models are mutually exclusive. + + +thread +------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "","","X","", "", "" + +The ``__declspec(thread)`` attribute declares a variable with thread local +storage. It is available under the ``-fms-extensions`` flag for MSVC +compatibility. See the documentation for `__declspec(thread)`_ on MSDN. + +.. _`__declspec(thread)`: http://msdn.microsoft.com/en-us/library/9w1sdazb.aspx + +In Clang, ``__declspec(thread)`` is generally equivalent in functionality to the +GNU ``__thread`` keyword. The variable must not have a destructor and must have +a constant initializer, if any. The attribute only applies to variables +declared with static storage duration, such as globals, class static data +members, and static locals. + + +maybe_unused, unused, gnu::unused +--------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "" + +When passing the ``-Wunused`` flag to Clang, entities that are unused by the +program may be diagnosed. The ``[[maybe_unused]]`` (or +``__attribute__((unused))``) attribute can be used to silence such diagnostics +when the entity cannot be removed. For instance, a local variable may exist +solely for use in an ``assert()`` statement, which makes the local variable +unused when ``NDEBUG`` is defined. + +The attribute may be applied to the declaration of a class, a typedef, a +variable, a function or method, a function parameter, an enumeration, an +enumerator, a non-static data member, or a label. + +.. code-block: c++ + #include + + [[maybe_unused]] void f([[maybe_unused]] bool thing1, + [[maybe_unused]] bool thing2) { + [[maybe_unused]] bool b = thing1 && thing2; + assert(b); + } + + +Type Attributes +=============== + + +align_value +----------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "X" + +The align_value attribute can be added to the typedef of a pointer type or the +declaration of a variable of pointer or reference type. It specifies that the +pointer will point to, or the reference will bind to, only objects with at +least the provided alignment. This alignment value must be some positive power +of 2. + + .. code-block:: c + + typedef double * aligned_double_ptr __attribute__((align_value(64))); + void foo(double & x __attribute__((align_value(128)), + aligned_double_ptr y) { ... } + +If the pointer value does not have the specified alignment at runtime, the +behavior of the program is undefined. + + +empty_bases +----------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "","","X","", "", "" + +The empty_bases attribute permits the compiler to utilize the +empty-base-optimization more frequently. +This attribute only applies to struct, class, and union types. +It is only supported when using the Microsoft C++ ABI. + + +enum_extensibility (clang::enum_extensibility) +---------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "X" + +Attribute ``enum_extensibility`` is used to distinguish between enum definitions +that are extensible and those that are not. The attribute can take either +``closed`` or ``open`` as an argument. ``closed`` indicates a variable of the +enum type takes a value that corresponds to one of the enumerators listed in the +enum definition or, when the enum is annotated with ``flag_enum``, a value that +can be constructed using values corresponding to the enumerators. ``open`` +indicates a variable of the enum type can take any values allowed by the +standard and instructs clang to be more lenient when issuing warnings. + +.. code-block:: c + + enum __attribute__((enum_extensibility(closed))) ClosedEnum { + A0, A1 + }; + + enum __attribute__((enum_extensibility(open))) OpenEnum { + B0, B1 + }; + + enum __attribute__((enum_extensibility(closed),flag_enum)) ClosedFlagEnum { + C0 = 1 << 0, C1 = 1 << 1 + }; + + enum __attribute__((enum_extensibility(open),flag_enum)) OpenFlagEnum { + D0 = 1 << 0, D1 = 1 << 1 + }; + + void foo1() { + enum ClosedEnum ce; + enum OpenEnum oe; + enum ClosedFlagEnum cfe; + enum OpenFlagEnum ofe; + + ce = A1; // no warnings + ce = 100; // warning issued + oe = B1; // no warnings + oe = 100; // no warnings + cfe = C0 | C1; // no warnings + cfe = C0 | C1 | 4; // warning issued + ofe = D0 | D1; // no warnings + ofe = D0 | D1 | 4; // no warnings + } + + +flag_enum +--------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "X" + +This attribute can be added to an enumerator to signal to the compiler that it +is intended to be used as a flag type. This will cause the compiler to assume +that the range of the type includes all of the values that you can get by +manipulating bits of the enumerator when issuing warnings. + + +lto_visibility_public (clang::lto_visibility_public) +---------------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "","X","","", "", "X" + +See :doc:`LTOVisibility`. + + +layout_version +-------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "","","X","", "", "" + +The layout_version attribute requests that the compiler utilize the class +layout rules of a particular compiler version. +This attribute only applies to struct, class, and union types. +It is only supported when using the Microsoft C++ ABI. + + +__single_inhertiance, __multiple_inheritance, __virtual_inheritance +------------------------------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "","","","X", "", "" + +This collection of keywords is enabled under ``-fms-extensions`` and controls +the pointer-to-member representation used on ``*-*-win32`` targets. + +The ``*-*-win32`` targets utilize a pointer-to-member representation which +varies in size and alignment depending on the definition of the underlying +class. + +However, this is problematic when a forward declaration is only available and +no definition has been made yet. In such cases, Clang is forced to utilize the +most general representation that is available to it. + +These keywords make it possible to use a pointer-to-member representation other +than the most general one regardless of whether or not the definition will ever +be present in the current translation unit. + +This family of keywords belong between the ``class-key`` and ``class-name``: + +.. code-block:: c++ + + struct __single_inheritance S; + int S::*i; + struct S {}; + +This keyword can be applied to class templates but only has an effect when used +on full specializations: + +.. code-block:: c++ + + template struct __single_inheritance A; // warning: inheritance model ignored on primary template + template struct __multiple_inheritance A; // warning: inheritance model ignored on partial specialization + template <> struct __single_inheritance A; + +Note that choosing an inheritance model less general than strictly necessary is +an error: + +.. code-block:: c++ + + struct __multiple_inheritance S; // error: inheritance model does not match definition + int S::*i; + struct S {}; + + +novtable +-------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "","","X","", "", "" + +This attribute can be added to a class declaration or definition to signal to +the compiler that constructors and destructors will not reference the virtual +function table. It is only supported when using the Microsoft C++ ABI. + + +objc_subclassing_restricted +--------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "X" + +This attribute can be added to an Objective-C ``@interface`` declaration to +ensure that this class cannot be subclassed. + + +transparent_union (gnu::transparent_union) +------------------------------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "" + +This attribute can be applied to a union to change the behaviour of calls to +functions that have an argument with a transparent union type. The compiler +behaviour is changed in the following manner: + +- A value whose type is any member of the transparent union can be passed as an + argument without the need to cast that value. + +- The argument is passed to the function using the calling convention of the + first member of the transparent union. Consequently, all the members of the + transparent union should have the same calling convention as its first member. + +Transparent unions are not supported in C++. + + +Statement Attributes +==================== + + +fallthrough, clang::fallthrough +------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "","X","","", "", "" + +The ``fallthrough`` (or ``clang::fallthrough``) attribute is used +to annotate intentional fall-through +between switch labels. It can only be applied to a null statement placed at a +point of execution between any statement and the next switch label. It is +common to mark these places with a specific comment, but this attribute is +meant to replace comments with a more strict annotation, which can be checked +by the compiler. This attribute doesn't change semantics of the code and can +be used wherever an intended fall-through occurs. It is designed to mimic +control-flow statements like ``break;``, so it can be placed in most places +where ``break;`` can, but only if there are no statements on the execution path +between it and the next switch label. + +By default, Clang does not warn on unannotated fallthrough from one ``switch`` +case to another. Diagnostics on fallthrough without a corresponding annotation +can be enabled with the ``-Wimplicit-fallthrough`` argument. + +Here is an example: + +.. code-block:: c++ + + // compile with -Wimplicit-fallthrough + switch (n) { + case 22: + case 33: // no warning: no statements between case labels + f(); + case 44: // warning: unannotated fall-through + g(); + [[clang::fallthrough]]; + case 55: // no warning + if (x) { + h(); + break; + } + else { + i(); + [[clang::fallthrough]]; + } + case 66: // no warning + p(); + [[clang::fallthrough]]; // warning: fallthrough annotation does not + // directly precede case label + q(); + case 77: // warning: unannotated fall-through + r(); + } + + +#pragma clang loop +------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "","","","", "X", "" + +The ``#pragma clang loop`` directive allows loop optimization hints to be +specified for the subsequent loop. The directive allows vectorization, +interleaving, and unrolling to be enabled or disabled. Vector width as well +as interleave and unrolling count can be manually specified. See +`language extensions +`_ +for details. + + +#pragma unroll, #pragma nounroll +-------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "","","","", "X", "" + +Loop unrolling optimization hints can be specified with ``#pragma unroll`` and +``#pragma nounroll``. The pragma is placed immediately before a for, while, +do-while, or c++11 range-based for loop. + +Specifying ``#pragma unroll`` without a parameter directs the loop unroller to +attempt to fully unroll the loop if the trip count is known at compile time and +attempt to partially unroll the loop if the trip count is not known at compile +time: + +.. code-block:: c++ + + #pragma unroll + for (...) { + ... + } + +Specifying the optional parameter, ``#pragma unroll _value_``, directs the +unroller to unroll the loop ``_value_`` times. The parameter may optionally be +enclosed in parentheses: + +.. code-block:: c++ + + #pragma unroll 16 + for (...) { + ... + } + + #pragma unroll(16) + for (...) { + ... + } + +Specifying ``#pragma nounroll`` indicates that the loop should not be unrolled: + +.. code-block:: c++ + + #pragma nounroll + for (...) { + ... + } + +``#pragma unroll`` and ``#pragma unroll _value_`` have identical semantics to +``#pragma clang loop unroll(full)`` and +``#pragma clang loop unroll_count(_value_)`` respectively. ``#pragma nounroll`` +is equivalent to ``#pragma clang loop unroll(disable)``. See +`language extensions +`_ +for further details including limitations of the unroll hints. + + +__read_only, __write_only, __read_write (read_only, write_only, read_write) +--------------------------------------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "","","","X", "", "" + +The access qualifiers must be used with image object arguments or pipe arguments +to declare if they are being read or written by a kernel or function. + +The read_only/__read_only, write_only/__write_only and read_write/__read_write +names are reserved for use as access qualifiers and shall not be used otherwise. + +.. code-block:: c + + kernel void + foo (read_only image2d_t imageA, + write_only image2d_t imageB) { + ... + } + +In the above example imageA is a read-only 2D image object, and imageB is a +write-only 2D image object. + +The read_write (or __read_write) qualifier can not be used with pipe. + +More details can be found in the OpenCL C language Spec v2.0, Section 6.6. + + +__attribute__((intel_reqd_sub_group_size)) +------------------------------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "X" + +The optional attribute intel_reqd_sub_group_size can be used to indicate that +the kernel must be compiled and executed with the specified subgroup size. When +this attribute is present, get_max_sub_group_size() is guaranteed to return the +specified integer value. This is important for the correctness of many subgroup +algorithms, and in some cases may be used by the compiler to generate more optimal +code. See `cl_intel_required_subgroup_size +` +for details. + + +__attribute__((opencl_unroll_hint)) +----------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "" + +The opencl_unroll_hint attribute qualifier can be used to specify that a loop +(for, while and do loops) can be unrolled. This attribute qualifier can be +used to specify full unrolling or partial unrolling by a specified amount. +This is a compiler hint and the compiler may ignore this directive. See +`OpenCL v2.0 `_ +s6.11.5 for details. + + +suppress (gsl::suppress) +------------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "","X","","", "", "" + +The ``[[gsl::suppress]]`` attribute suppresses specific +clang-tidy diagnostics for rules of the `C++ Core Guidelines`_ in a portable +way. The attribute can be attached to declarations, statements, and at +namespace scope. + +.. code-block:: c++ + + [[gsl::suppress("Rh-public")]] + void f_() { + int *p; + [[gsl::suppress("type")]] { + p = reinterpret_cast(7); + } + } + namespace N { + [[clang::suppress("type", "bounds")]]; + ... + } + +.. _`C++ Core Guidelines`: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#inforce-enforcement + + +Consumed Annotation Checking +============================ +Clang supports additional attributes for checking basic resource management +properties, specifically for unique objects that have a single owning reference. +The following attributes are currently supported, although **the implementation +for these annotations is currently in development and are subject to change.** + +callable_when +------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "X" + +Use ``__attribute__((callable_when(...)))`` to indicate what states a method +may be called in. Valid states are unconsumed, consumed, or unknown. Each +argument to this attribute must be a quoted string. E.g.: + +``__attribute__((callable_when("unconsumed", "unknown")))`` + + +consumable +---------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "X" + +Each ``class`` that uses any of the typestate annotations must first be marked +using the ``consumable`` attribute. Failure to do so will result in a warning. + +This attribute accepts a single parameter that must be one of the following: +``unknown``, ``consumed``, or ``unconsumed``. + + +param_typestate +--------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "X" + +This attribute specifies expectations about function parameters. Calls to an +function with annotated parameters will issue a warning if the corresponding +argument isn't in the expected state. The attribute is also used to set the +initial state of the parameter when analyzing the function's body. + + +return_typestate +---------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "X" + +The ``return_typestate`` attribute can be applied to functions or parameters. +When applied to a function the attribute specifies the state of the returned +value. The function's body is checked to ensure that it always returns a value +in the specified state. On the caller side, values returned by the annotated +function are initialized to the given state. + +When applied to a function parameter it modifies the state of an argument after +a call to the function returns. The function's body is checked to ensure that +the parameter is in the expected state before returning. + + +set_typestate +------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "X" + +Annotate methods that transition an object into a new state with +``__attribute__((set_typestate(new_state)))``. The new state must be +unconsumed, consumed, or unknown. + + +test_typestate +-------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "X" + +Use ``__attribute__((test_typestate(tested_state)))`` to indicate that a method +returns true if the object is in the specified state.. + + +AMD GPU Attributes +================== + + +amdgpu_flat_work_group_size +--------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "X" + +The flat work-group size is the number of work-items in the work-group size +specified when the kernel is dispatched. It is the product of the sizes of the +x, y, and z dimension of the work-group. + +Clang supports the +``__attribute__((amdgpu_flat_work_group_size(, )))`` attribute for the +AMDGPU target. This attribute may be attached to a kernel function definition +and is an optimization hint. + +```` parameter specifies the minimum flat work-group size, and ```` +parameter specifies the maximum flat work-group size (must be greater than +````) to which all dispatches of the kernel will conform. Passing ``0, 0`` +as ``, `` implies the default behavior (``128, 256``). + +If specified, the AMDGPU target backend might be able to produce better machine +code for barriers and perform scratch promotion by estimating available group +segment size. + +An error will be given if: + - Specified values violate subtarget specifications; + - Specified values are not compatible with values provided through other + attributes. + + +amdgpu_num_sgpr +--------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "X" + +Clang supports the ``__attribute__((amdgpu_num_sgpr()))`` and +``__attribute__((amdgpu_num_vgpr()))`` attributes for the AMDGPU +target. These attributes may be attached to a kernel function definition and are +an optimization hint. + +If these attributes are specified, then the AMDGPU target backend will attempt +to limit the number of SGPRs and/or VGPRs used to the specified value(s). The +number of used SGPRs and/or VGPRs may further be rounded up to satisfy the +allocation requirements or constraints of the subtarget. Passing ``0`` as +``num_sgpr`` and/or ``num_vgpr`` implies the default behavior (no limits). + +These attributes can be used to test the AMDGPU target backend. It is +recommended that the ``amdgpu_waves_per_eu`` attribute be used to control +resources such as SGPRs and VGPRs since it is aware of the limits for different +subtargets. + +An error will be given if: + - Specified values violate subtarget specifications; + - Specified values are not compatible with values provided through other + attributes; + - The AMDGPU target backend is unable to create machine code that can meet the + request. + + +amdgpu_num_vgpr +--------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "X" + +Clang supports the ``__attribute__((amdgpu_num_sgpr()))`` and +``__attribute__((amdgpu_num_vgpr()))`` attributes for the AMDGPU +target. These attributes may be attached to a kernel function definition and are +an optimization hint. + +If these attributes are specified, then the AMDGPU target backend will attempt +to limit the number of SGPRs and/or VGPRs used to the specified value(s). The +number of used SGPRs and/or VGPRs may further be rounded up to satisfy the +allocation requirements or constraints of the subtarget. Passing ``0`` as +``num_sgpr`` and/or ``num_vgpr`` implies the default behavior (no limits). + +These attributes can be used to test the AMDGPU target backend. It is +recommended that the ``amdgpu_waves_per_eu`` attribute be used to control +resources such as SGPRs and VGPRs since it is aware of the limits for different +subtargets. + +An error will be given if: + - Specified values violate subtarget specifications; + - Specified values are not compatible with values provided through other + attributes; + - The AMDGPU target backend is unable to create machine code that can meet the + request. + + +amdgpu_waves_per_eu +------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "X" + +A compute unit (CU) is responsible for executing the wavefronts of a work-group. +It is composed of one or more execution units (EU), which are responsible for +executing the wavefronts. An EU can have enough resources to maintain the state +of more than one executing wavefront. This allows an EU to hide latency by +switching between wavefronts in a similar way to symmetric multithreading on a +CPU. In order to allow the state for multiple wavefronts to fit on an EU, the +resources used by a single wavefront have to be limited. For example, the number +of SGPRs and VGPRs. Limiting such resources can allow greater latency hiding, +but can result in having to spill some register state to memory. + +Clang supports the ``__attribute__((amdgpu_waves_per_eu([, ])))`` +attribute for the AMDGPU target. This attribute may be attached to a kernel +function definition and is an optimization hint. + +```` parameter specifies the requested minimum number of waves per EU, and +*optional* ```` parameter specifies the requested maximum number of waves +per EU (must be greater than ```` if specified). If ```` is omitted, +then there is no restriction on the maximum number of waves per EU other than +the one dictated by the hardware for which the kernel is compiled. Passing +``0, 0`` as ``, `` implies the default behavior (no limits). + +If specified, this attribute allows an advanced developer to tune the number of +wavefronts that are capable of fitting within the resources of an EU. The AMDGPU +target backend can use this information to limit resources, such as number of +SGPRs, number of VGPRs, size of available group and private memory segments, in +such a way that guarantees that at least ```` wavefronts and at most +```` wavefronts are able to fit within the resources of an EU. Requesting +more wavefronts can hide memory latency but limits available registers which +can result in spilling. Requesting fewer wavefronts can help reduce cache +thrashing, but can reduce memory latency hiding. + +This attribute controls the machine code generated by the AMDGPU target backend +to ensure it is capable of meeting the requested values. However, when the +kernel is executed, there may be other reasons that prevent meeting the request, +for example, there may be wavefronts from other kernels executing on the EU. + +An error will be given if: + - Specified values violate subtarget specifications; + - Specified values are not compatible with values provided through other + attributes; + - The AMDGPU target backend is unable to create machine code that can meet the + request. + + +Calling Conventions +=================== +Clang supports several different calling conventions, depending on the target +platform and architecture. The calling convention used for a function determines +how parameters are passed, how results are returned to the caller, and other +low-level details of calling a function. + +fastcall (gnu::fastcall, __fastcall, _fastcall) +----------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","X", "", "" + +On 32-bit x86 targets, this attribute changes the calling convention of a +function to use ECX and EDX as register parameters and clear parameters off of +the stack on return. This convention does not support variadic calls or +unprototyped functions in C, and has no effect on x86_64 targets. This calling +convention is supported primarily for compatibility with existing code. Users +seeking register parameters should use the ``regparm`` attribute, which does +not require callee-cleanup. See the documentation for `__fastcall`_ on MSDN. + +.. _`__fastcall`: http://msdn.microsoft.com/en-us/library/6xa169sk.aspx + + +ms_abi (gnu::ms_abi) +-------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "" + +On non-Windows x86_64 targets, this attribute changes the calling convention of +a function to match the default convention used on Windows x86_64. This +attribute has no effect on Windows targets or non-x86_64 targets. + + +pcs (gnu::pcs) +-------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "" + +On ARM targets, this attribute can be used to select calling conventions +similar to ``stdcall`` on x86. Valid parameter values are "aapcs" and +"aapcs-vfp". + + +preserve_all +------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "" + +On X86-64 and AArch64 targets, this attribute changes the calling convention of +a function. The ``preserve_all`` calling convention attempts to make the code +in the caller even less intrusive than the ``preserve_most`` calling convention. +This calling convention also behaves identical to the ``C`` calling convention +on how arguments and return values are passed, but it uses a different set of +caller/callee-saved registers. This removes the burden of saving and +recovering a large register set before and after the call in the caller. If +the arguments are passed in callee-saved registers, then they will be +preserved by the callee across the call. This doesn't apply for values +returned in callee-saved registers. + +- On X86-64 the callee preserves all general purpose registers, except for + R11. R11 can be used as a scratch register. Furthermore it also preserves + all floating-point registers (XMMs/YMMs). + +The idea behind this convention is to support calls to runtime functions +that don't need to call out to any other functions. + +This calling convention, like the ``preserve_most`` calling convention, will be +used by a future version of the Objective-C runtime and should be considered +experimental at this time. + + +preserve_most +------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "" + +On X86-64 and AArch64 targets, this attribute changes the calling convention of +a function. The ``preserve_most`` calling convention attempts to make the code +in the caller as unintrusive as possible. This convention behaves identically +to the ``C`` calling convention on how arguments and return values are passed, +but it uses a different set of caller/callee-saved registers. This alleviates +the burden of saving and recovering a large register set before and after the +call in the caller. If the arguments are passed in callee-saved registers, +then they will be preserved by the callee across the call. This doesn't +apply for values returned in callee-saved registers. + +- On X86-64 the callee preserves all general purpose registers, except for + R11. R11 can be used as a scratch register. Floating-point registers + (XMMs/YMMs) are not preserved and need to be saved by the caller. + +The idea behind this convention is to support calls to runtime functions +that have a hot path and a cold path. The hot path is usually a small piece +of code that doesn't use many registers. The cold path might need to call out to +another function and therefore only needs to preserve the caller-saved +registers, which haven't already been saved by the caller. The +`preserve_most` calling convention is very similar to the ``cold`` calling +convention in terms of caller/callee-saved registers, but they are used for +different types of function calls. ``coldcc`` is for function calls that are +rarely executed, whereas `preserve_most` function calls are intended to be +on the hot path and definitely executed a lot. Furthermore ``preserve_most`` +doesn't prevent the inliner from inlining the function call. + +This calling convention will be used by a future version of the Objective-C +runtime and should therefore still be considered experimental at this time. +Although this convention was created to optimize certain runtime calls to +the Objective-C runtime, it is not limited to this runtime and might be used +by other runtimes in the future too. The current implementation only +supports X86-64 and AArch64, but the intention is to support more architectures +in the future. + + +regcall (gnu::regcall, __regcall) +--------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","X", "", "" + +On x86 targets, this attribute changes the calling convention to +`__regcall`_ convention. This convention aims to pass as many arguments +as possible in registers. It also tries to utilize registers for the +return value whenever it is possible. + +.. _`__regcall`: https://software.intel.com/en-us/node/693069 + + +regparm (gnu::regparm) +---------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "" + +On 32-bit x86 targets, the regparm attribute causes the compiler to pass +the first three integer parameters in EAX, EDX, and ECX instead of on the +stack. This attribute has no effect on variadic functions, and all parameters +are passed via the stack as normal. + + +stdcall (gnu::stdcall, __stdcall, _stdcall) +------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","X", "", "" + +On 32-bit x86 targets, this attribute changes the calling convention of a +function to clear parameters off of the stack on return. This convention does +not support variadic calls or unprototyped functions in C, and has no effect on +x86_64 targets. This calling convention is used widely by the Windows API and +COM applications. See the documentation for `__stdcall`_ on MSDN. + +.. _`__stdcall`: http://msdn.microsoft.com/en-us/library/zxk0tw93.aspx + + +thiscall (gnu::thiscall, __thiscall, _thiscall) +----------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","X", "", "" + +On 32-bit x86 targets, this attribute changes the calling convention of a +function to use ECX for the first parameter (typically the implicit ``this`` +parameter of C++ methods) and clear parameters off of the stack on return. This +convention does not support variadic calls or unprototyped functions in C, and +has no effect on x86_64 targets. See the documentation for `__thiscall`_ on +MSDN. + +.. _`__thiscall`: http://msdn.microsoft.com/en-us/library/ek8tkfbw.aspx + + +vectorcall (__vectorcall, _vectorcall) +-------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","X", "", "" + +On 32-bit x86 *and* x86_64 targets, this attribute changes the calling +convention of a function to pass vector parameters in SSE registers. + +On 32-bit x86 targets, this calling convention is similar to ``__fastcall``. +The first two integer parameters are passed in ECX and EDX. Subsequent integer +parameters are passed in memory, and callee clears the stack. On x86_64 +targets, the callee does *not* clear the stack, and integer parameters are +passed in RCX, RDX, R8, and R9 as is done for the default Windows x64 calling +convention. + +On both 32-bit x86 and x86_64 targets, vector and floating point arguments are +passed in XMM0-XMM5. Homogeneous vector aggregates of up to four elements are +passed in sequential SSE registers if enough are available. If AVX is enabled, +256 bit vectors are passed in YMM0-YMM5. Any vector or aggregate type that +cannot be passed in registers for any reason is passed by reference, which +allows the caller to align the parameter memory. + +See the documentation for `__vectorcall`_ on MSDN for more details. + +.. _`__vectorcall`: http://msdn.microsoft.com/en-us/library/dn375768.aspx + + +Type Safety Checking +==================== +Clang supports additional attributes to enable checking type safety properties +that can't be enforced by the C type system. To see warnings produced by these +checks, ensure that -Wtype-safety is enabled. Use cases include: + +* MPI library implementations, where these attributes enable checking that + the buffer type matches the passed ``MPI_Datatype``; +* for HDF5 library there is a similar use case to MPI; +* checking types of variadic functions' arguments for functions like + ``fcntl()`` and ``ioctl()``. + +You can detect support for these attributes with ``__has_attribute()``. For +example: + +.. code-block:: c++ + + #if defined(__has_attribute) + # if __has_attribute(argument_with_type_tag) && \ + __has_attribute(pointer_with_type_tag) && \ + __has_attribute(type_tag_for_datatype) + # define ATTR_MPI_PWT(buffer_idx, type_idx) __attribute__((pointer_with_type_tag(mpi,buffer_idx,type_idx))) + /* ... other macros ... */ + # endif + #endif + + #if !defined(ATTR_MPI_PWT) + # define ATTR_MPI_PWT(buffer_idx, type_idx) + #endif + + int MPI_Send(void *buf, int count, MPI_Datatype datatype /*, other args omitted */) + ATTR_MPI_PWT(1,3); + +argument_with_type_tag +---------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "" + +Use ``__attribute__((argument_with_type_tag(arg_kind, arg_idx, +type_tag_idx)))`` on a function declaration to specify that the function +accepts a type tag that determines the type of some other argument. + +This attribute is primarily useful for checking arguments of variadic functions +(``pointer_with_type_tag`` can be used in most non-variadic cases). + +In the attribute prototype above: + * ``arg_kind`` is an identifier that should be used when annotating all + applicable type tags. + * ``arg_idx`` provides the position of a function argument. The expected type of + this function argument will be determined by the function argument specified + by ``type_tag_idx``. In the code example below, "3" means that the type of the + function's third argument will be determined by ``type_tag_idx``. + * ``type_tag_idx`` provides the position of a function argument. This function + argument will be a type tag. The type tag will determine the expected type of + the argument specified by ``arg_idx``. In the code example below, "2" means + that the type tag associated with the function's second argument should agree + with the type of the argument specified by ``arg_idx``. + +For example: + +.. code-block:: c++ + + int fcntl(int fd, int cmd, ...) + __attribute__(( argument_with_type_tag(fcntl,3,2) )); + // The function's second argument will be a type tag; this type tag will + // determine the expected type of the function's third argument. + + +pointer_with_type_tag +--------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "" + +Use ``__attribute__((pointer_with_type_tag(ptr_kind, ptr_idx, type_tag_idx)))`` +on a function declaration to specify that the function accepts a type tag that +determines the pointee type of some other pointer argument. + +In the attribute prototype above: + * ``ptr_kind`` is an identifier that should be used when annotating all + applicable type tags. + * ``ptr_idx`` provides the position of a function argument; this function + argument will have a pointer type. The expected pointee type of this pointer + type will be determined by the function argument specified by + ``type_tag_idx``. In the code example below, "1" means that the pointee type + of the function's first argument will be determined by ``type_tag_idx``. + * ``type_tag_idx`` provides the position of a function argument; this function + argument will be a type tag. The type tag will determine the expected pointee + type of the pointer argument specified by ``ptr_idx``. In the code example + below, "3" means that the type tag associated with the function's third + argument should agree with the pointee type of the pointer argument specified + by ``ptr_idx``. + +For example: + +.. code-block:: c++ + + typedef int MPI_Datatype; + int MPI_Send(void *buf, int count, MPI_Datatype datatype /*, other args omitted */) + __attribute__(( pointer_with_type_tag(mpi,1,3) )); + // The function's 3rd argument will be a type tag; this type tag will + // determine the expected pointee type of the function's 1st argument. + + +type_tag_for_datatype +--------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","","","", "", "" + +When declaring a variable, use +``__attribute__((type_tag_for_datatype(kind, type)))`` to create a type tag that +is tied to the ``type`` argument given to the attribute. + +In the attribute prototype above: + * ``kind`` is an identifier that should be used when annotating all applicable + type tags. + * ``type`` indicates the name of the type. + +Clang supports annotating type tags of two forms. + + * **Type tag that is a reference to a declared identifier.** + Use ``__attribute__((type_tag_for_datatype(kind, type)))`` when declaring that + identifier: + + .. code-block:: c++ + + typedef int MPI_Datatype; + extern struct mpi_datatype mpi_datatype_int + __attribute__(( type_tag_for_datatype(mpi,int) )); + #define MPI_INT ((MPI_Datatype) &mpi_datatype_int) + // &mpi_datatype_int is a type tag. It is tied to type "int". + + * **Type tag that is an integral literal.** + Declare a ``static const`` variable with an initializer value and attach + ``__attribute__((type_tag_for_datatype(kind, type)))`` on that declaration: + + .. code-block:: c++ + + typedef int MPI_Datatype; + static const MPI_Datatype mpi_datatype_int + __attribute__(( type_tag_for_datatype(mpi,int) )) = 42; + #define MPI_INT ((MPI_Datatype) 42) + // The number 42 is a type tag. It is tied to type "int". + + +The ``type_tag_for_datatype`` attribute also accepts an optional third argument +that determines how the type of the function argument specified by either +``arg_idx`` or ``ptr_idx`` is compared against the type associated with the type +tag. (Recall that for the ``argument_with_type_tag`` attribute, the type of the +function argument specified by ``arg_idx`` is compared against the type +associated with the type tag. Also recall that for the ``pointer_with_type_tag`` +attribute, the pointee type of the function argument specified by ``ptr_idx`` is +compared against the type associated with the type tag.) There are two supported +values for this optional third argument: + + * ``layout_compatible`` will cause types to be compared according to + layout-compatibility rules (In C++11 [class.mem] p 17, 18, see the + layout-compatibility rules for two standard-layout struct types and for two + standard-layout union types). This is useful when creating a type tag + associated with a struct or union type. For example: + + .. code-block:: c++ + + /* In mpi.h */ + typedef int MPI_Datatype; + struct internal_mpi_double_int { double d; int i; }; + extern struct mpi_datatype mpi_datatype_double_int + __attribute__(( type_tag_for_datatype(mpi, + struct internal_mpi_double_int, layout_compatible) )); + + #define MPI_DOUBLE_INT ((MPI_Datatype) &mpi_datatype_double_int) + + int MPI_Send(void *buf, int count, MPI_Datatype datatype, ...) + __attribute__(( pointer_with_type_tag(mpi,1,3) )); + + /* In user code */ + struct my_pair { double a; int b; }; + struct my_pair *buffer; + MPI_Send(buffer, 1, MPI_DOUBLE_INT /*, ... */); // no warning because the + // layout of my_pair is + // compatible with that of + // internal_mpi_double_int + + struct my_int_pair { int a; int b; } + struct my_int_pair *buffer2; + MPI_Send(buffer2, 1, MPI_DOUBLE_INT /*, ... */); // warning because the + // layout of my_int_pair + // does not match that of + // internal_mpi_double_int + + * ``must_be_null`` specifies that the function argument specified by either + ``arg_idx`` (for the ``argument_with_type_tag`` attribute) or ``ptr_idx`` (for + the ``pointer_with_type_tag`` attribute) should be a null pointer constant. + The second argument to the ``type_tag_for_datatype`` attribute is ignored. For + example: + + .. code-block:: c++ + + /* In mpi.h */ + typedef int MPI_Datatype; + extern struct mpi_datatype mpi_datatype_null + __attribute__(( type_tag_for_datatype(mpi, void, must_be_null) )); + + #define MPI_DATATYPE_NULL ((MPI_Datatype) &mpi_datatype_null) + int MPI_Send(void *buf, int count, MPI_Datatype datatype, ...) + __attribute__(( pointer_with_type_tag(mpi,1,3) )); + + /* In user code */ + struct my_pair { double a; int b; }; + struct my_pair *buffer; + MPI_Send(buffer, 1, MPI_DATATYPE_NULL /*, ... */); // warning: MPI_DATATYPE_NULL + // was specified but buffer + // is not a null pointer + + +OpenCL Address Spaces +===================== +The address space qualifier may be used to specify the region of memory that is +used to allocate the object. OpenCL supports the following address spaces: +__generic(generic), __global(global), __local(local), __private(private), +__constant(constant). + + .. code-block:: c + + __constant int c = ...; + + __generic int* foo(global int* g) { + __local int* l; + private int p; + ... + return l; + } + +More details can be found in the OpenCL C language Spec v2.0, Section 6.5. + +constant (__constant) +--------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "","","","X", "", "" + +The constant address space attribute signals that an object is located in +a constant (non-modifiable) memory region. It is available to all work items. +Any type can be annotated with the constant address space attribute. Objects +with the constant address space qualifier can be declared in any scope and must +have an initializer. + + +generic (__generic) +------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "","","","X", "", "" + +The generic address space attribute is only available with OpenCL v2.0 and later. +It can be used with pointer types. Variables in global and local scope and +function parameters in non-kernel functions can have the generic address space +type attribute. It is intended to be a placeholder for any other address space +except for '__constant' in OpenCL code which can be used with multiple address +spaces. + + +global (__global) +----------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "","","","X", "", "" + +The global address space attribute specifies that an object is allocated in +global memory, which is accessible by all work items. The content stored in this +memory area persists between kernel executions. Pointer types to the global +address space are allowed as function parameters or local variables. Starting +with OpenCL v2.0, the global address space can be used with global (program +scope) variables and static local variable as well. + + +local (__local) +--------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "","","","X", "", "" + +The local address space specifies that an object is allocated in the local (work +group) memory area, which is accessible to all work items in the same work +group. The content stored in this memory region is not accessible after +the kernel execution ends. In a kernel function scope, any variable can be in +the local address space. In other scopes, only pointer types to the local address +space are allowed. Local address space variables cannot have an initializer. + + +private (__private) +------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "","","","X", "", "" + +The private address space specifies that an object is allocated in the private +(work item) memory. Other work items cannot access the same memory area and its +content is destroyed after work item execution ends. Local variables can be +declared in the private address space. Function arguments are always in the +private address space. Kernel function arguments of a pointer or an array type +cannot point to the private address space. + + +Nullability Attributes +====================== +Whether a particular pointer may be "null" is an important concern when working with pointers in the C family of languages. The various nullability attributes indicate whether a particular pointer can be null or not, which makes APIs more expressive and can help static analysis tools identify bugs involving null pointers. Clang supports several kinds of nullability attributes: the ``nonnull`` and ``returns_nonnull`` attributes indicate which function or method parameters and result types can never be null, while nullability type qualifiers indicate which pointer types can be null (``_Nullable``) or cannot be null (``_Nonnull``). + +The nullability (type) qualifiers express whether a value of a given pointer type can be null (the ``_Nullable`` qualifier), doesn't have a defined meaning for null (the ``_Nonnull`` qualifier), or for which the purpose of null is unclear (the ``_Null_unspecified`` qualifier). Because nullability qualifiers are expressed within the type system, they are more general than the ``nonnull`` and ``returns_nonnull`` attributes, allowing one to express (for example) a nullable pointer to an array of nonnull pointers. Nullability qualifiers are written to the right of the pointer to which they apply. For example: + + .. code-block:: c + + // No meaningful result when 'ptr' is null (here, it happens to be undefined behavior). + int fetch(int * _Nonnull ptr) { return *ptr; } + + // 'ptr' may be null. + int fetch_or_zero(int * _Nullable ptr) { + return ptr ? *ptr : 0; + } + + // A nullable pointer to non-null pointers to const characters. + const char *join_strings(const char * _Nonnull * _Nullable strings, unsigned n); + +In Objective-C, there is an alternate spelling for the nullability qualifiers that can be used in Objective-C methods and properties using context-sensitive, non-underscored keywords. For example: + + .. code-block:: objective-c + + @interface NSView : NSResponder + - (nullable NSView *)ancestorSharedWithView:(nonnull NSView *)aView; + @property (assign, nullable) NSView *superview; + @property (readonly, nonnull) NSArray *subviews; + @end + +nonnull (gnu::nonnull) +---------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "" + +The ``nonnull`` attribute indicates that some function parameters must not be null, and can be used in several different ways. It's original usage (`from GCC `_) is as a function (or Objective-C method) attribute that specifies which parameters of the function are nonnull in a comma-separated list. For example: + + .. code-block:: c + + extern void * my_memcpy (void *dest, const void *src, size_t len) + __attribute__((nonnull (1, 2))); + +Here, the ``nonnull`` attribute indicates that parameters 1 and 2 +cannot have a null value. Omitting the parenthesized list of parameter indices means that all parameters of pointer type cannot be null: + + .. code-block:: c + + extern void * my_memcpy (void *dest, const void *src, size_t len) + __attribute__((nonnull)); + +Clang also allows the ``nonnull`` attribute to be placed directly on a function (or Objective-C method) parameter, eliminating the need to specify the parameter index ahead of type. For example: + + .. code-block:: c + + extern void * my_memcpy (void *dest __attribute__((nonnull)), + const void *src __attribute__((nonnull)), size_t len); + +Note that the ``nonnull`` attribute indicates that passing null to a non-null parameter is undefined behavior, which the optimizer may take advantage of to, e.g., remove null checks. The ``_Nonnull`` type qualifier indicates that a pointer cannot be null in a more general manner (because it is part of the type system) and does not imply undefined behavior, making it more widely applicable. + + +returns_nonnull (gnu::returns_nonnull) +-------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "X","X","","", "", "X" + +The ``returns_nonnull`` attribute indicates that a particular function (or Objective-C method) always returns a non-null pointer. For example, a particular system ``malloc`` might be defined to terminate a process when memory is not available rather than returning a null pointer: + + .. code-block:: c + + extern void * malloc (size_t size) __attribute__((returns_nonnull)); + +The ``returns_nonnull`` attribute implies that returning a null pointer is undefined behavior, which the optimizer may take advantage of. The ``_Nonnull`` type qualifier indicates that a pointer cannot be null in a more general manner (because it is part of the type system) and does not imply undefined behavior, making it more widely applicable + + +_Nonnull +-------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "","","","X", "", "" + +The ``_Nonnull`` nullability qualifier indicates that null is not a meaningful value for a value of the ``_Nonnull`` pointer type. For example, given a declaration such as: + + .. code-block:: c + + int fetch(int * _Nonnull ptr); + +a caller of ``fetch`` should not provide a null value, and the compiler will produce a warning if it sees a literal null value passed to ``fetch``. Note that, unlike the declaration attribute ``nonnull``, the presence of ``_Nonnull`` does not imply that passing null is undefined behavior: ``fetch`` is free to consider null undefined behavior or (perhaps for backward-compatibility reasons) defensively handle null. + + +_Null_unspecified +----------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "","","","X", "", "" + +The ``_Null_unspecified`` nullability qualifier indicates that neither the ``_Nonnull`` nor ``_Nullable`` qualifiers make sense for a particular pointer type. It is used primarily to indicate that the role of null with specific pointers in a nullability-annotated header is unclear, e.g., due to overly-complex implementations or historical factors with a long-lived API. + + +_Nullable +--------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma", "Pragma clang attribute" + + "","","","X", "", "" + +The ``_Nullable`` nullability qualifier indicates that a value of the ``_Nullable`` pointer type can be null. For example, given: + + .. code-block:: c + + int fetch_or_zero(int * _Nullable ptr); + +a caller of ``fetch_or_zero`` can provide null. + + diff --git a/docs/ClangCommandLineReference.rst b/docs/ClangCommandLineReference.rst index add168829e1b..a7b485a39438 100644 --- a/docs/ClangCommandLineReference.rst +++ b/docs/ClangCommandLineReference.rst @@ -96,6 +96,8 @@ Emit ARC errors even if the migrator can fix them Output path for the plist report +.. option:: --autocomplete= + .. option:: -bind\_at\_load .. option:: -bundle @@ -292,7 +294,7 @@ Disable builtin #include directories .. option:: -nomultidefs -.. option:: -nopie +.. option:: -nopie, -no-pie .. option:: -noprebind @@ -704,6 +706,10 @@ Don't use blacklist file for sanitizers Level of field padding for AddressSanitizer +.. option:: -fsanitize-address-globals-dead-stripping + +Enable linker dead stripping of globals in AddressSanitizer + .. option:: -fsanitize-address-use-after-scope, -fno-sanitize-address-use-after-scope Enable use-after-scope detection in AddressSanitizer @@ -1071,6 +1077,10 @@ Target-independent compilation options Enable C++17 aligned allocation functions +.. option:: -fallow-editor-placeholders, -fno-allow-editor-placeholders + +Treat editor placeholders as valid source code + .. option:: -fallow-unsupported .. option:: -faltivec, -fno-altivec @@ -1205,6 +1215,10 @@ Print absolute paths in diagnostics .. option:: -fdiagnostics-color= .. program:: clang +.. option:: -fdiagnostics-hotness-threshold= + +Prevent optimization remarks from being output if they do not have at least this profile count + .. option:: -fdiagnostics-show-hotness, -fno-diagnostics-show-hotness Enable profile hotness information in diagnostic line @@ -1585,6 +1599,8 @@ Turn on loop reroller .. option:: -fretain-comments-from-system-headers +.. option:: -frewrite-imports, -fno-rewrite-imports + .. option:: -frewrite-includes, -fno-rewrite-includes .. option:: -frewrite-map-file @@ -1639,10 +1655,6 @@ Use SjLj style exceptions Enable the superword-level parallelism vectorization passes -.. option:: -fslp-vectorize-aggressive, -fno-slp-vectorize-aggressive - -Enable the BB vectorization passes - .. option:: -fspell-checking, -fno-spell-checking .. option:: -fspell-checking-limit= @@ -1911,6 +1923,8 @@ Link stack frames through backchain on System Z .. option:: -mcpu=, -mv4 (equivalent to -mcpu=hexagonv4), -mv5 (equivalent to -mcpu=hexagonv5), -mv55 (equivalent to -mcpu=hexagonv55), -mv60 (equivalent to -mcpu=hexagonv60), -mv62 (equivalent to -mcpu=hexagonv62) +.. option:: -mdefault-build-attributes, -mno-default-build-attributes + .. option:: -mdll .. option:: -mdouble-float @@ -1975,10 +1989,16 @@ Use Intel MCU ABI Generate branches with extended addressability, usually via indirect jumps. -.. option:: -mmacosx-version-min= +.. option:: -mmacosx-version-min=, -mmacos-version-min= Set Mac OS X deployment target +.. option:: -mmadd4, -mno-madd4 + +Enable the generation of 4-operand madd.s, madd.d and related instructions. + +.. option:: -mmcu= + .. option:: -mmicromips, -mno-micromips .. option:: -mms-bitfields, -mno-ms-bitfields @@ -1989,6 +2009,10 @@ Set the default structure layout to be compatible with the Microsoft compiler st Enable MSA ASE (MIPS only) +.. option:: -mmt, -mno-mt + +Enable MT ASE (MIPS only) + .. option:: -mnan= .. option:: -mno-mips16 @@ -2203,6 +2227,8 @@ X86 .. option:: -mavx512vl, -mno-avx512vl +.. option:: -mavx512vpopcntdq, -mno-avx512vpopcntdq + .. option:: -mbmi, -mno-bmi .. option:: -mbmi2, -mno-bmi2 @@ -2225,6 +2251,8 @@ X86 .. option:: -mfxsr, -mno-fxsr +.. option:: -mlwp, -mno-lwp + .. option:: -mlzcnt, -mno-lzcnt .. option:: -mmmx, -mno-mmx @@ -2372,6 +2400,16 @@ Debug information flags .. option:: -gstrict-dwarf, -gno-strict-dwarf +.. option:: -gz + +DWARF debug sections compression type + +.. program:: clang1 +.. option:: -gz= +.. program:: clang + +DWARF debug sections compression type + Static analyzer flags ===================== diff --git a/docs/UsersManual.rst b/docs/UsersManual.rst index 387ec63e9c3d..e5f33fc29569 100644 --- a/docs/UsersManual.rst +++ b/docs/UsersManual.rst @@ -2622,6 +2622,10 @@ Execute ``clang-cl /?`` to see a list of supported options: /Brepro Emit an object file which can be reproduced over time /C Don't discard comments when preprocessing /c Compile only + /d1reportAllClassLayout Dump record layout information + /diagnostics:caret Enable caret and column diagnostics (on by default) + /diagnostics:classic Disable column and caret diagnostics + /diagnostics:column Disable caret diagnostics but keep column info /D Define macro /EH Exception handling model /EP Disable linemarker output and preprocess to stdout @@ -2716,6 +2720,8 @@ Execute ``clang-cl /?`` to see a list of supported options: /Zc:threadSafeInit Enable thread-safe initialization of static variables /Zc:trigraphs- Disable trigraphs (default) /Zc:trigraphs Enable trigraphs + /Zc:twoPhase- Disable two-phase name lookup in templates + /Zc:twoPhase Enable two-phase name lookup in templates /Zd Emit debug line number tables only /Zi Alias for /Z7. Does not produce PDBs. /Zl Don't mention any default libraries in the object file @@ -2728,12 +2734,14 @@ Execute ``clang-cl /?`` to see a list of supported options: --analyze Run the static analyzer -fansi-escape-codes Use ANSI escape codes for diagnostics -fcolor-diagnostics Use colors in diagnostics + -fdebug-macro Emit macro debug information -fdelayed-template-parsing Parse templated function definitions at the end of the translation unit -fdiagnostics-absolute-paths Print absolute paths in diagnostics -fdiagnostics-parseable-fixits Print fix-its in machine parseable form + -flto= Set LTO mode to either 'full' or 'thin' -flto Enable LTO in 'full' mode -fms-compatibility-version= Dot-separated value representing the Microsoft compiler version @@ -2742,12 +2750,27 @@ Execute ``clang-cl /?`` to see a list of supported options: -fms-extensions Accept some non-standard constructs supported by the Microsoft compiler -fmsc-version= Microsoft compiler version number to report in _MSC_VER (0 = don't define it (default)) + -fno-debug-macro Do not emit macro debug information -fno-delayed-template-parsing Disable delayed template parsing + -fno-sanitize-address-use-after-scope + Disable use-after-scope detection in AddressSanitizer + -fno-sanitize-blacklist Don't use blacklist file for sanitizers + -fno-sanitize-cfi-cross-dso + Disable control flow integrity (CFI) checks for cross-DSO calls. -fno-sanitize-coverage= Disable specified features of coverage instrumentation for Sanitizers + -fno-sanitize-memory-track-origins + Disable origins tracking in MemorySanitizer -fno-sanitize-recover= Disable recovery for specified sanitizers + -fno-sanitize-stats Disable sanitizer statistics gathering. + -fno-sanitize-thread-atomics + Disable atomic operations instrumentation in ThreadSanitizer + -fno-sanitize-thread-func-entry-exit + Disable function entry/exit instrumentation in ThreadSanitizer + -fno-sanitize-thread-memory-access + Disable memory access instrumentation in ThreadSanitizer -fno-sanitize-trap= Disable trapping for specified sanitizers -fno-standalone-debug Limit debug information produced to reduce size of debug binary @@ -2759,13 +2782,36 @@ Execute ``clang-cl /?`` to see a list of supported options: (overridden by '=' form of option or LLVM_PROFILE_FILE env var) -fprofile-instr-use= Use instrumentation data for profile-guided optimization + -fsanitize-address-field-padding= + Level of field padding for AddressSanitizer + -fsanitize-address-globals-dead-stripping + Enable linker dead stripping of globals in AddressSanitizer + -fsanitize-address-use-after-scope + Enable use-after-scope detection in AddressSanitizer -fsanitize-blacklist= Path to blacklist file for sanitizers + -fsanitize-cfi-cross-dso + Enable control flow integrity (CFI) checks for cross-DSO calls. -fsanitize-coverage= Specify the type of coverage instrumentation for Sanitizers + -fsanitize-memory-track-origins= + Enable origins tracking in MemorySanitizer + -fsanitize-memory-track-origins + Enable origins tracking in MemorySanitizer + -fsanitize-memory-use-after-dtor + Enable use-after-destroy detection in MemorySanitizer -fsanitize-recover= Enable recovery for specified sanitizers + -fsanitize-stats Enable sanitizer statistics gathering. + -fsanitize-thread-atomics + Enable atomic operations instrumentation in ThreadSanitizer (default) + -fsanitize-thread-func-entry-exit + Enable function entry/exit instrumentation in ThreadSanitizer (default) + -fsanitize-thread-memory-access + Enable memory access instrumentation in ThreadSanitizer (default) -fsanitize-trap= Enable trapping for specified sanitizers + -fsanitize-undefined-strip-path-components= + Strip (or keep only, if negative) a given number of path components when emitting check metadata. -fsanitize= Turn on runtime checks for various forms of undefined or suspicious behavior. See user manual for available checks -fstandalone-debug Emit full debug info for all types used by the program @@ -2773,6 +2819,7 @@ Execute ``clang-cl /?`` to see a list of supported options: -gline-tables-only Emit debug line number tables only -miamcu Use Intel MCU ABI -mllvm Additional arguments to forward to LLVM's option processing + -nobuiltininc Disable builtin #include directories -Qunused-arguments Don't emit warning for unused driver arguments -R Enable the specified remark --target= Generate code for the given target diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 64bd3c701985..984096ffa987 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -1752,6 +1752,7 @@ class Type : public ExtQualsTypeCommonBase { bool isTemplateTypeParmType() const; // C++ template type parameter bool isNullPtrType() const; // C++11 std::nullptr_t bool isAlignValT() const; // C++17 std::align_val_t + bool isStdByteType() const; // C++17 std::byte bool isAtomicType() const; // C11 _Atomic() #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index e06386018d68..7ec0d1d5e017 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -1388,6 +1388,15 @@ static Stmt::StmtClass DecodeOperatorCall(const CXXOperatorCallExpr *S, llvm_unreachable("Invalid overloaded operator expression"); } +#if defined(_MSC_VER) +#if _MSC_VER == 1911 +// Work around https://developercommunity.visualstudio.com/content/problem/84002/clang-cl-when-built-with-vc-2017-crashes-cause-vc.html +// MSVC 2017 update 3 miscompiles this function, and a clang built with it +// will crash in stage 2 of a bootstrap build. +#pragma optimize("", off) +#endif +#endif + void StmtProfiler::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) { if (S->isTypeDependent()) { // Type-dependent operator calls are profiled like their underlying @@ -1420,6 +1429,12 @@ void StmtProfiler::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) { ID.AddInteger(S->getOperator()); } +#if defined(_MSC_VER) +#if _MSC_VER == 1911 +#pragma optimize("", on) +#endif +#endif + void StmtProfiler::VisitCXXMemberCallExpr(const CXXMemberCallExpr *S) { VisitCallExpr(S); } diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index eac02c0102bc..d21781dc3899 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -2313,6 +2313,15 @@ bool Type::isAlignValT() const { return false; } +bool Type::isStdByteType() const { + if (auto *ET = getAs()) { + auto *II = ET->getDecl()->getIdentifier(); + if (II && II->isStr("byte") && ET->getDecl()->isInStdNamespace()) + return true; + } + return false; +} + bool Type::isPromotableIntegerType() const { if (const BuiltinType *BT = getAs()) switch (BT->getKind()) { diff --git a/lib/Basic/DiagnosticIDs.cpp b/lib/Basic/DiagnosticIDs.cpp index 932b3f1934cc..0cdaf8e03643 100644 --- a/lib/Basic/DiagnosticIDs.cpp +++ b/lib/Basic/DiagnosticIDs.cpp @@ -516,7 +516,7 @@ std::vector DiagnosticIDs::getDiagnosticFlags() { std::string Diag(DiagGroupNames + I + 1, DiagGroupNames[I]); I += DiagGroupNames[I] + 1; Res.push_back("-W" + Diag); - Res.push_back("-Wno" + Diag); + Res.push_back("-Wno-" + Diag); } return Res; diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp index a1a67c2bc144..3fd322483392 100644 --- a/lib/Basic/Version.cpp +++ b/lib/Basic/Version.cpp @@ -36,7 +36,7 @@ std::string getClangRepositoryPath() { // If the SVN_REPOSITORY is empty, try to use the SVN keyword. This helps us // pick up a tag in an SVN export, for example. - StringRef SVNRepository("$URL: https://llvm.org/svn/llvm-project/cfe/trunk/lib/Basic/Version.cpp $"); + StringRef SVNRepository("$URL: https://llvm.org/svn/llvm-project/cfe/branches/release_50/lib/Basic/Version.cpp $"); if (URL.empty()) { URL = SVNRepository.slice(SVNRepository.find(':'), SVNRepository.find("/lib/Basic")); diff --git a/lib/CodeGen/CodeGenTBAA.cpp b/lib/CodeGen/CodeGenTBAA.cpp index 04224e726797..8a75a552d9fa 100644 --- a/lib/CodeGen/CodeGenTBAA.cpp +++ b/lib/CodeGen/CodeGenTBAA.cpp @@ -139,6 +139,12 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) { } } + // C++1z [basic.lval]p10: "If a program attempts to access the stored value of + // an object through a glvalue of other than one of the following types the + // behavior is undefined: [...] a char, unsigned char, or std::byte type." + if (Ty->isStdByteType()) + return MetadataCache[Ty] = getChar(); + // Handle pointers. // TODO: Implement C++'s type "similarity" and consider dis-"similar" // pointers distinct. diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 1d35d6e78cca..ba4d0e836b44 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -69,7 +69,6 @@ #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Process.h" #include "llvm/Support/Program.h" -#include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" #include #include @@ -1193,10 +1192,6 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { if (C.getArgs().hasArg(options::OPT__version)) { // Follow gcc behavior and use stdout for --version and stderr for -v. PrintVersion(C, llvm::outs()); - - // Print registered targets. - llvm::outs() << '\n'; - llvm::TargetRegistry::printRegisteredTargetsForVersion(llvm::outs()); return false; } @@ -1299,7 +1294,7 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { std::sort(SuggestedCompletions.begin(), SuggestedCompletions.end(), [](StringRef A, StringRef B) { return A.compare_lower(B) < 0; }); - llvm::outs() << llvm::join(SuggestedCompletions, " ") << '\n'; + llvm::outs() << llvm::join(SuggestedCompletions, "\n") << '\n'; return false; } diff --git a/lib/Headers/unwind.h b/lib/Headers/unwind.h index 4f74a3478740..e94b00b57c26 100644 --- a/lib/Headers/unwind.h +++ b/lib/Headers/unwind.h @@ -76,7 +76,13 @@ typedef intptr_t _sleb128_t; typedef uintptr_t _uleb128_t; struct _Unwind_Context; +#if defined(__arm__) && !(defined(__USING_SJLJ_EXCEPTIONS__) || defined(__ARM_DWARF_EH___)) +struct _Unwind_Control_Block; +typedef struct _Unwind_Control_Block _Unwind_Exception; /* Alias */ +#else struct _Unwind_Exception; +typedef struct _Unwind_Exception _Unwind_Exception; +#endif typedef enum { _URC_NO_REASON = 0, #if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \ @@ -109,8 +115,42 @@ typedef enum { } _Unwind_Action; typedef void (*_Unwind_Exception_Cleanup_Fn)(_Unwind_Reason_Code, - struct _Unwind_Exception *); + _Unwind_Exception *); +#if defined(__arm__) && !(defined(__USING_SJLJ_EXCEPTIONS__) || defined(__ARM_DWARF_EH___)) +typedef struct _Unwind_Control_Block _Unwind_Control_Block; +typedef uint32_t _Unwind_EHT_Header; + +struct _Unwind_Control_Block { + uint64_t exception_class; + void (*exception_cleanup)(_Unwind_Reason_Code, _Unwind_Control_Block *); + /* unwinder cache (private fields for the unwinder's use) */ + struct { + uint32_t reserved1; /* forced unwind stop function, 0 if not forced */ + uint32_t reserved2; /* personality routine */ + uint32_t reserved3; /* callsite */ + uint32_t reserved4; /* forced unwind stop argument */ + uint32_t reserved5; + } unwinder_cache; + /* propagation barrier cache (valid after phase 1) */ + struct { + uint32_t sp; + uint32_t bitpattern[5]; + } barrier_cache; + /* cleanup cache (preserved over cleanup) */ + struct { + uint32_t bitpattern[4]; + } cleanup_cache; + /* personality cache (for personality's benefit) */ + struct { + uint32_t fnstart; /* function start address */ + _Unwind_EHT_Header *ehtp; /* pointer to EHT entry header word */ + uint32_t additional; /* additional data */ + uint32_t reserved1; + } pr_cache; + long long int : 0; /* force alignment of next item to 8-byte boundary */ +}; +#else struct _Unwind_Exception { _Unwind_Exception_Class exception_class; _Unwind_Exception_Cleanup_Fn exception_cleanup; @@ -120,23 +160,24 @@ struct _Unwind_Exception { * aligned". GCC has interpreted this to mean "use the maximum useful * alignment for the target"; so do we. */ } __attribute__((__aligned__)); +#endif typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)(int, _Unwind_Action, _Unwind_Exception_Class, - struct _Unwind_Exception *, + _Unwind_Exception *, struct _Unwind_Context *, void *); -typedef _Unwind_Reason_Code (*_Unwind_Personality_Fn)( - int, _Unwind_Action, _Unwind_Exception_Class, struct _Unwind_Exception *, - struct _Unwind_Context *); +typedef _Unwind_Reason_Code (*_Unwind_Personality_Fn)(int, _Unwind_Action, + _Unwind_Exception_Class, + _Unwind_Exception *, + struct _Unwind_Context *); typedef _Unwind_Personality_Fn __personality_routine; typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn)(struct _Unwind_Context *, void *); -#if defined(__arm__) && !defined(__APPLE__) - +#if defined(__arm__) && !(defined(__USING_SJLJ_EXCEPTIONS__) || defined(__ARM_DWARF_EH___)) typedef enum { _UVRSC_CORE = 0, /* integer register */ _UVRSC_VFP = 1, /* vfp */ @@ -158,14 +199,12 @@ typedef enum { _UVRSR_FAILED = 2 } _Unwind_VRS_Result; -#if !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__ARM_DWARF_EH__) typedef uint32_t _Unwind_State; #define _US_VIRTUAL_UNWIND_FRAME ((_Unwind_State)0) #define _US_UNWIND_FRAME_STARTING ((_Unwind_State)1) #define _US_UNWIND_FRAME_RESUME ((_Unwind_State)2) #define _US_ACTION_MASK ((_Unwind_State)3) #define _US_FORCE_UNWIND ((_Unwind_State)8) -#endif _Unwind_VRS_Result _Unwind_VRS_Get(struct _Unwind_Context *__context, _Unwind_VRS_RegClass __regclass, @@ -224,13 +263,12 @@ _Unwind_Ptr _Unwind_GetRegionStart(struct _Unwind_Context *); /* DWARF EH functions; currently not available on Darwin/ARM */ #if !defined(__APPLE__) || !defined(__arm__) - -_Unwind_Reason_Code _Unwind_RaiseException(struct _Unwind_Exception *); -_Unwind_Reason_Code _Unwind_ForcedUnwind(struct _Unwind_Exception *, - _Unwind_Stop_Fn, void *); -void _Unwind_DeleteException(struct _Unwind_Exception *); -void _Unwind_Resume(struct _Unwind_Exception *); -_Unwind_Reason_Code _Unwind_Resume_or_Rethrow(struct _Unwind_Exception *); +_Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception *); +_Unwind_Reason_Code _Unwind_ForcedUnwind(_Unwind_Exception *, _Unwind_Stop_Fn, + void *); +void _Unwind_DeleteException(_Unwind_Exception *); +void _Unwind_Resume(_Unwind_Exception *); +_Unwind_Reason_Code _Unwind_Resume_or_Rethrow(_Unwind_Exception *); #endif @@ -241,11 +279,11 @@ typedef struct SjLj_Function_Context *_Unwind_FunctionContext_t; void _Unwind_SjLj_Register(_Unwind_FunctionContext_t); void _Unwind_SjLj_Unregister(_Unwind_FunctionContext_t); -_Unwind_Reason_Code _Unwind_SjLj_RaiseException(struct _Unwind_Exception *); -_Unwind_Reason_Code _Unwind_SjLj_ForcedUnwind(struct _Unwind_Exception *, +_Unwind_Reason_Code _Unwind_SjLj_RaiseException(_Unwind_Exception *); +_Unwind_Reason_Code _Unwind_SjLj_ForcedUnwind(_Unwind_Exception *, _Unwind_Stop_Fn, void *); -void _Unwind_SjLj_Resume(struct _Unwind_Exception *); -_Unwind_Reason_Code _Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception *); +void _Unwind_SjLj_Resume(_Unwind_Exception *); +_Unwind_Reason_Code _Unwind_SjLj_Resume_or_Rethrow(_Unwind_Exception *); void *_Unwind_FindEnclosingFunction(void *); diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 3a53f251b096..91a8c619b26c 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -2398,6 +2398,37 @@ formatBlockPlaceholder(const PrintingPolicy &Policy, const NamedDecl *BlockDecl, return Result; } +static std::string GetDefaultValueString(const ParmVarDecl *Param, + const SourceManager &SM, + const LangOptions &LangOpts) { + const Expr *defaultArg = Param->getDefaultArg(); + if (!defaultArg) + return ""; + const SourceRange SrcRange = defaultArg->getSourceRange(); + CharSourceRange CharSrcRange = CharSourceRange::getTokenRange(SrcRange); + bool Invalid = CharSrcRange.isInvalid(); + if (Invalid) + return ""; + StringRef srcText = Lexer::getSourceText(CharSrcRange, SM, LangOpts, &Invalid); + if (Invalid) + return ""; + + if (srcText.empty() || srcText == "=") { + // Lexer can't determine the value. + // This happens if the code is incorrect (for example class is forward declared). + return ""; + } + std::string DefValue(srcText.str()); + // FIXME: remove this check if the Lexer::getSourceText value is fixed and + // this value always has (or always does not have) '=' in front of it + if (DefValue.at(0) != '=') { + // If we don't have '=' in front of value. + // Lexer returns built-in types values without '=' and user-defined types values with it. + return " = " + DefValue; + } + return " " + DefValue; +} + /// \brief Add function parameter chunks to the given code completion string. static void AddFunctionParameterChunks(Preprocessor &PP, const PrintingPolicy &Policy, @@ -2431,6 +2462,8 @@ static void AddFunctionParameterChunks(Preprocessor &PP, // Format the placeholder string. std::string PlaceholderStr = FormatFunctionParameter(Policy, Param); + if (Param->hasDefaultArg()) + PlaceholderStr += GetDefaultValueString(Param, PP.getSourceManager(), PP.getLangOpts()); if (Function->isVariadic() && P == N - 1) PlaceholderStr += ", ..."; @@ -3012,10 +3045,14 @@ static void AddOverloadParameterChunks(ASTContext &Context, // Format the placeholder string. std::string Placeholder; - if (Function) - Placeholder = FormatFunctionParameter(Policy, Function->getParamDecl(P)); - else + if (Function) { + const ParmVarDecl *Param = Function->getParamDecl(P); + Placeholder = FormatFunctionParameter(Policy, Param); + if (Param->hasDefaultArg()) + Placeholder += GetDefaultValueString(Param, Context.getSourceManager(), Context.getLangOpts()); + } else { Placeholder = Prototype->getParamType(P).getAsString(Policy); + } if (P == CurrentArg) Result.AddCurrentParameterChunk( diff --git a/test/CodeCompletion/functions.cpp b/test/CodeCompletion/functions.cpp index 036ed29e4a85..aa303f29eb04 100644 --- a/test/CodeCompletion/functions.cpp +++ b/test/CodeCompletion/functions.cpp @@ -4,5 +4,5 @@ void f(float x, float y...); void test() { :: // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:5:5 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s - // CHECK-CC1: f(<#int i#>{#, <#int j#>{#, <#int k#>#}#}) + // CHECK-CC1: f(<#int i#>{#, <#int j = 2#>{#, <#int k = 5#>#}#}) // CHECK-CC1: f(<#float x#>, <#float y, ...#>) diff --git a/test/CodeGenCXX/std-byte.cpp b/test/CodeGenCXX/std-byte.cpp new file mode 100644 index 000000000000..a3cc634221bf --- /dev/null +++ b/test/CodeGenCXX/std-byte.cpp @@ -0,0 +1,41 @@ +// RUN: %clang_cc1 -std=c++1z -Werror -triple i386-unknown-unknown -emit-llvm -O1 -disable-llvm-passes -o - %s | FileCheck %s + +// std::byte should be considered equivalent to char for aliasing. + +namespace std { +enum byte : unsigned char {}; +} + +// CHECK-LABEL: define void @test0( +extern "C" void test0(std::byte *sb, int *i) { + // CHECK: store i8 0, i8* %{{.*}} !tbaa [[TAG_CHAR:!.*]] + *sb = std::byte{0}; + + // CHECK: store i32 1, i32* %{{.*}} !tbaa [[TAG_INT:!.*]] + *i = 1; +} + +enum byte : unsigned char {}; +namespace my { +enum byte : unsigned char {}; +namespace std { +enum byte : unsigned char {}; +} // namespace std +} // namespace my + +// Make sure we don't get confused with other enums named 'byte'. + +// CHECK-LABEL: define void @test1( +extern "C" void test1(::byte *b, ::my::byte *mb, ::my::std::byte *msb) { + *b = ::byte{0}; + *mb = ::my::byte{0}; + *msb = ::my::std::byte{0}; + // CHECK-NOT: store i8 0, i8* %{{.*}} !tbaa [[TAG_CHAR]] +} + +// CHECK: !"any pointer", [[TYPE_CHAR:!.*]], +// CHECK: [[TYPE_CHAR]] = !{!"omnipotent char", [[TAG_CXX_TBAA:!.*]], +// CHECK: [[TAG_CXX_TBAA]] = !{!"Simple C++ TBAA"} +// CHECK: [[TAG_CHAR]] = !{[[TYPE_CHAR:!.*]], [[TYPE_CHAR]], i64 0} +// CHECK: [[TAG_INT]] = !{[[TYPE_INT:!.*]], [[TYPE_INT]], i64 0} +// CHECK: [[TYPE_INT]] = !{!"int", [[TYPE_CHAR]] diff --git a/test/Driver/autocomplete.c b/test/Driver/autocomplete.c index dec48bfb3596..c4d80f29f7bc 100644 --- a/test/Driver/autocomplete.c +++ b/test/Driver/autocomplete.c @@ -1,46 +1,91 @@ // RUN: %clang --autocomplete=-fsyn | FileCheck %s -check-prefix=FSYN // FSYN: -fsyntax-only -// RUN: %clang --autocomplete=-s | FileCheck %s -check-prefix=STD -// STD: -std={{.*}}-stdlib= +// RUN: %clang --autocomplete=-std= | FileCheck %s -check-prefix=STD +// STD: -std= Language standard to compile for // RUN: %clang --autocomplete=foo | FileCheck %s -check-prefix=FOO // FOO-NOT: foo // RUN: %clang --autocomplete=-stdlib=,l | FileCheck %s -check-prefix=STDLIB -// STDLIB: libc++ libstdc++ +// STDLIB: libc++ +// STDLIB-NEXT: libstdc++ // RUN: %clang --autocomplete=-stdlib=, | FileCheck %s -check-prefix=STDLIBALL -// STDLIBALL: libc++ libstdc++ platform +// STDLIBALL: libc++ +// STDLIBALL-NEXT: libstdc++ +// STDLIBALL-NEXT: platform // RUN: %clang --autocomplete=-meabi,d | FileCheck %s -check-prefix=MEABI // MEABI: default // RUN: %clang --autocomplete=-meabi, | FileCheck %s -check-prefix=MEABIALL -// MEABIALL: 4 5 default gnu +// MEABIALL: 4 +// MEABIALL-NEXT: 5 +// MEABIALL-NEXT: default +// MEABIALL-NEXT: gnu // RUN: %clang --autocomplete=-cl-std=,CL2 | FileCheck %s -check-prefix=CLSTD // CLSTD: CL2.0 // RUN: %clang --autocomplete=-cl-std=, | FileCheck %s -check-prefix=CLSTDALL -// CLSTDALL: cl CL cl1.1 CL1.1 cl1.2 CL1.2 cl2.0 CL2.0 +// CLSTDALL: cl +// CLSTDALL-NEXT: CL +// CLSTDALL-NEXT: cl1.1 +// CLSTDALL-NEXT: CL1.1 +// CLSTDALL-NEXT: cl1.2 +// CLSTDALL-NEXT: CL1.2 +// CLSTDALL-NEXT: cl2.0 +// CLSTDALL-NEXT: CL2.0 // RUN: %clang --autocomplete=-fno-sanitize-coverage=,f | FileCheck %s -check-prefix=FNOSANICOVER // FNOSANICOVER: func // RUN: %clang --autocomplete=-fno-sanitize-coverage=, | FileCheck %s -check-prefix=FNOSANICOVERALL -// FNOSANICOVERALL: 8bit-counters bb edge func indirect-calls inline-8bit-counters no-prune trace-bb trace-cmp trace-div trace-gep trace-pc trace-pc-guard +// FNOSANICOVERALL: 8bit-counters +// FNOSANICOVERALL-NEXT: bb +// FNOSANICOVERALL-NEXT: edge +// FNOSANICOVERALL-NEXT: func +// FNOSANICOVERALL-NEXT: indirect-calls +// FNOSANICOVERALL-NEXT: inline-8bit-counters +// FNOSANICOVERALL-NEXT: no-prune +// FNOSANICOVERALL-NEXT: trace-bb +// FNOSANICOVERALL-NEXT: trace-cmp +// FNOSANICOVERALL-NEXT: trace-div +// FNOSANICOVERALL-NEXT: trace-gep +// FNOSANICOVERALL-NEXT: trace-pc +// FNOSANICOVERALL-NEXT: trace-pc-guard // RUN: %clang --autocomplete=-ffp-contract=, | FileCheck %s -check-prefix=FFPALL -// FFPALL: fast off on +// FFPALL: fast +// FFPALL-NEXT: off +// FFPALL-NEXT: on // RUN: %clang --autocomplete=-flto=, | FileCheck %s -check-prefix=FLTOALL -// FLTOALL: full thin +// FLTOALL: full +// FLTOALL-NEXT: thin // RUN: %clang --autocomplete=-fveclib=, | FileCheck %s -check-prefix=FVECLIBALL -// FVECLIBALL: Accelerate none SVML +// FVECLIBALL: Accelerate +// FVECLIBALL-NEXT: none +// FVECLIBALL-NEXT: SVML // RUN: %clang --autocomplete=-fshow-overloads=, | FileCheck %s -check-prefix=FSOVERALL -// FSOVERALL: all best +// FSOVERALL: all +// FSOVERALL-NEXT: best // RUN: %clang --autocomplete=-fvisibility=, | FileCheck %s -check-prefix=FVISIBILITYALL -// FVISIBILITYALL: default hidden +// FVISIBILITYALL: default +// FVISIBILITYALL-NEXT: hidden // RUN: %clang --autocomplete=-mfloat-abi=, | FileCheck %s -check-prefix=MFLOATABIALL -// MFLOATABIALL: hard soft softfp +// MFLOATABIALL: hard +// MFLOATABIALL-NEXT: soft +// MFLOATABIALL-NEXT: softfp // RUN: %clang --autocomplete=-mthread-model, | FileCheck %s -check-prefix=MTHREADMODELALL -// MTHREADMODELALL: posix single +// MTHREADMODELALL: posix +// MTHREADMODELALL-NEXT: single // RUN: %clang --autocomplete=-mrelocation-model, | FileCheck %s -check-prefix=MRELOCMODELALL -// MRELOCMODELALL: dynamic-no-pic pic ropi ropi-rwpi rwpi static +// MRELOCMODELALL: dynamic-no-pic +// MRELOCMODELALL-NEXT: pic +// MRELOCMODELALL-NEXT: ropi +// MRELOCMODELALL-NEXT: ropi-rwpi +// MRELOCMODELALL-NEXT: rwpi +// MRELOCMODELALL-NEXT: static // RUN: %clang --autocomplete=-mrelocation-mode | FileCheck %s -check-prefix=MRELOCMODEL_CLANG // MRELOCMODEL_CLANG-NOT: -mrelocation-model // RUN: %clang --autocomplete=#-mrelocation-mode | FileCheck %s -check-prefix=MRELOCMODEL_CC1 // MRELOCMODEL_CC1: -mrelocation-model // RUN: %clang --autocomplete=-Wma | FileCheck %s -check-prefix=WARNING -// WARNING: -Wmacro-redefined -Wmain -Wmain-return-type -Wmalformed-warning-check -Wmany-braces-around-scalar-init -Wmax-unsigned-zero -// RUN: %clang --autocomplete=-Wnoinvalid-pp- | FileCheck %s -check-prefix=NOWARNING -// NOWARNING: -Wnoinvalid-pp-token +// WARNING: -Wmacro-redefined +// WARNING-NEXT: -Wmain +// WARNING-NEXT: -Wmain-return-type +// WARNING-NEXT: -Wmalformed-warning-check +// WARNING-NEXT: -Wmany-braces-around-scalar-init +// WARNING-NEXT: -Wmax-unsigned-zero +// RUN: %clang --autocomplete=-Wno-invalid-pp- | FileCheck %s -check-prefix=NOWARNING +// NOWARNING: -Wno-invalid-pp-token diff --git a/test/Index/code-completion.cpp b/test/Index/code-completion.cpp index 83aa94374438..f52bb10a35b0 100644 --- a/test/Index/code-completion.cpp +++ b/test/Index/code-completion.cpp @@ -40,7 +40,7 @@ Z::operator int() const { // CHECK-MEMBER: FieldDecl:{ResultType double}{TypedText member} // CHECK-MEMBER: FieldDecl:{ResultType int}{Text X::}{TypedText member} // CHECK-MEMBER: FieldDecl:{ResultType float}{Text Y::}{TypedText member} -// CHECK-MEMBER: CXXMethod:{ResultType void}{Informative Y::}{TypedText memfunc}{LeftParen (}{Optional {Placeholder int i}}{RightParen )} +// CHECK-MEMBER: CXXMethod:{ResultType void}{Informative Y::}{TypedText memfunc}{LeftParen (}{Optional {Placeholder int i = 17}}{RightParen )} // CHECK-MEMBER: CXXConversion:{TypedText operator int}{LeftParen (}{RightParen )}{Informative const} // CHECK-MEMBER: CXXMethod:{ResultType Z &}{TypedText operator=}{LeftParen (}{Placeholder const Z &}{RightParen )} // CHECK-MEMBER: CXXMethod:{ResultType X &}{Text X::}{TypedText operator=}{LeftParen (}{Placeholder const X &}{RightParen )} @@ -77,7 +77,7 @@ Z::operator int() const { // CHECK-EXPR: FieldDecl:{ResultType double}{TypedText member} (17) // CHECK-EXPR: FieldDecl:{ResultType int}{Text X::}{TypedText member} (9) // CHECK-EXPR: FieldDecl:{ResultType float}{Text Y::}{TypedText member} (18) -// CHECK-EXPR: CXXMethod:{ResultType void}{TypedText memfunc}{LeftParen (}{Optional {Placeholder int i}}{RightParen )} (37) +// CHECK-EXPR: CXXMethod:{ResultType void}{TypedText memfunc}{LeftParen (}{Optional {Placeholder int i = 17}}{RightParen )} (37) // CHECK-EXPR: Namespace:{TypedText N}{Text ::} (75) // CHECK-EXPR: Completion contexts: // CHECK-EXPR-NEXT: Any type diff --git a/test/Index/complete-optional-params.cpp b/test/Index/complete-optional-params.cpp index 88d810502424..1df2975300a1 100644 --- a/test/Index/complete-optional-params.cpp +++ b/test/Index/complete-optional-params.cpp @@ -6,15 +6,19 @@ void bar(int a, int b = 42, int c = 42); void baz(int a = 42, ...); struct S{ S(int a = 42, int = 42) {} }; +class Bar1 { public: Bar1() {} }; class Bar2; +void foo_2(Bar1 b1 = Bar1(), Bar2 b2 = Bar2()); + int main() { foo(42, 42); bar(42, 42, 42); baz(42, 42, 42); S s(42, 42); + foo_2(); } -// RUN: c-index-test -code-completion-at=%s:10:9 %s | FileCheck -check-prefix=CHECK-CC1 %s -// CHECK-CC1: OverloadCandidate:{ResultType void}{Text foo}{LeftParen (}{Optional {CurrentParameter int a}{Optional {Comma , }{Placeholder int}}}{RightParen )} (1) +// RUN: c-index-test -code-completion-at=%s:13:9 %s | FileCheck -check-prefix=CHECK-CC1 %s +// CHECK-CC1: OverloadCandidate:{ResultType void}{Text foo}{LeftParen (}{Optional {CurrentParameter int a = 42}{Optional {Comma , }{Placeholder int = 42}}}{RightParen )} (1) // CHECK-CC1: Completion contexts: // CHECK-CC1-NEXT: Any type // CHECK-CC1-NEXT: Any value @@ -25,8 +29,8 @@ int main() { // CHECK-CC1-NEXT: Nested name specifier // CHECK-CC1-NEXT: Objective-C interface -// RUN: c-index-test -code-completion-at=%s:11:9 %s | FileCheck -check-prefix=CHECK-CC2 %s -// CHECK-CC2: OverloadCandidate:{ResultType void}{Text bar}{LeftParen (}{CurrentParameter int a}{Optional {Comma , }{Placeholder int b}{Optional {Comma , }{Placeholder int c}}}{RightParen )} (1) +// RUN: c-index-test -code-completion-at=%s:14:9 %s | FileCheck -check-prefix=CHECK-CC2 %s +// CHECK-CC2: OverloadCandidate:{ResultType void}{Text bar}{LeftParen (}{CurrentParameter int a}{Optional {Comma , }{Placeholder int b = 42}{Optional {Comma , }{Placeholder int c = 42}}}{RightParen )} (1) // CHECK-CC2: Completion contexts: // CHECK-CC2-NEXT: Any type // CHECK-CC2-NEXT: Any value @@ -37,8 +41,8 @@ int main() { // CHECK-CC2-NEXT: Nested name specifier // CHECK-CC2-NEXT: Objective-C interface -// RUN: c-index-test -code-completion-at=%s:11:16 %s | FileCheck -check-prefix=CHECK-CC3 %s -// CHECK-CC3: OverloadCandidate:{ResultType void}{Text bar}{LeftParen (}{Placeholder int a}{Optional {Comma , }{Placeholder int b}{Optional {Comma , }{CurrentParameter int c}}}{RightParen )} (1) +// RUN: c-index-test -code-completion-at=%s:14:16 %s | FileCheck -check-prefix=CHECK-CC3 %s +// CHECK-CC3: OverloadCandidate:{ResultType void}{Text bar}{LeftParen (}{Placeholder int a}{Optional {Comma , }{Placeholder int b = 42}{Optional {Comma , }{CurrentParameter int c = 42}}}{RightParen )} (1) // CHECK-CC3: Completion contexts: // CHECK-CC3-NEXT: Any type // CHECK-CC3-NEXT: Any value @@ -49,8 +53,8 @@ int main() { // CHECK-CC3-NEXT: Nested name specifier // CHECK-CC3-NEXT: Objective-C interface -// RUN: c-index-test -code-completion-at=%s:12:16 %s | FileCheck -check-prefix=CHECK-CC4 %s -// CHECK-CC4: OverloadCandidate:{ResultType void}{Text baz}{LeftParen (}{Optional {Placeholder int a}{Optional {Comma , }{CurrentParameter ...}}}{RightParen )} (1) +// RUN: c-index-test -code-completion-at=%s:15:16 %s | FileCheck -check-prefix=CHECK-CC4 %s +// CHECK-CC4: OverloadCandidate:{ResultType void}{Text baz}{LeftParen (}{Optional {Placeholder int a = 42}{Optional {Comma , }{CurrentParameter ...}}}{RightParen )} (1) // CHECK-CC4: Completion contexts: // CHECK-CC4-NEXT: Any type // CHECK-CC4-NEXT: Any value @@ -61,8 +65,8 @@ int main() { // CHECK-CC4-NEXT: Nested name specifier // CHECK-CC4-NEXT: Objective-C interface -// RUN: c-index-test -code-completion-at=%s:13:9 %s | FileCheck -check-prefix=CHECK-CC5 %s -// CHECK-CC5: OverloadCandidate:{Text S}{LeftParen (}{Optional {CurrentParameter int a}{Optional {Comma , }{Placeholder int}}}{RightParen )} (1) +// RUN: c-index-test -code-completion-at=%s:16:9 %s | FileCheck -check-prefix=CHECK-CC5 %s +// CHECK-CC5: OverloadCandidate:{Text S}{LeftParen (}{Optional {CurrentParameter int a = 42}{Optional {Comma , }{Placeholder int = 42}}}{RightParen )} (1) // CHECK-CC5: OverloadCandidate:{Text S}{LeftParen (}{CurrentParameter const S &}{RightParen )} (1) // CHECK-CC5: Completion contexts: // CHECK-CC5-NEXT: Any type @@ -73,3 +77,15 @@ int main() { // CHECK-CC5-NEXT: Class name // CHECK-CC5-NEXT: Nested name specifier // CHECK-CC5-NEXT: Objective-C interface + +// RUN: c-index-test -code-completion-at=%s:17:11 %s | FileCheck -check-prefix=CHECK-CC6 %s +// CHECK-CC6: FunctionDecl:{ResultType void}{TypedText foo_2}{LeftParen (}{Optional {Placeholder Bar1 b1 = Bar1()}{Optional {Comma , }{Placeholder Bar2 b2}}}{RightParen )} (50) +// CHECK-CC6: Completion contexts: +// CHECK-CC6-NEXT: Any type +// CHECK-CC6-NEXT: Any value +// CHECK-CC6-NEXT: Enum tag +// CHECK-CC6-NEXT: Union tag +// CHECK-CC6-NEXT: Struct tag +// CHECK-CC6-NEXT: Class name +// CHECK-CC6-NEXT: Nested name specifier +// CHECK-CC6-NEXT: Objective-C interface diff --git a/tools/clang-format/ClangFormat.cpp b/tools/clang-format/ClangFormat.cpp index f8e2fe186b91..14bff19a1a0c 100644 --- a/tools/clang-format/ClangFormat.cpp +++ b/tools/clang-format/ClangFormat.cpp @@ -328,7 +328,8 @@ static bool format(StringRef FileName) { } // namespace format } // namespace clang -static void PrintVersion(raw_ostream &OS) { +static void PrintVersion() { + raw_ostream &OS = outs(); OS << clang::getClangToolFullVersion("clang-format") << '\n'; } diff --git a/tools/clang-offload-bundler/ClangOffloadBundler.cpp b/tools/clang-offload-bundler/ClangOffloadBundler.cpp index 95d3fdf14d5e..49cdd9546689 100644 --- a/tools/clang-offload-bundler/ClangOffloadBundler.cpp +++ b/tools/clang-offload-bundler/ClangOffloadBundler.cpp @@ -915,7 +915,8 @@ static bool UnbundleFiles() { return false; } -static void PrintVersion(raw_ostream &OS) { +static void PrintVersion() { + raw_ostream &OS = outs(); OS << clang::getClangToolFullVersion("clang-offload-bundler") << '\n'; } diff --git a/utils/bash-autocomplete.sh b/utils/bash-autocomplete.sh index 72531b99e3da..ed815d2d7ad1 100755 --- a/utils/bash-autocomplete.sh +++ b/utils/bash-autocomplete.sh @@ -57,7 +57,7 @@ _clang() # expand ~ to $HOME eval local path=${COMP_WORDS[0]} - flags=$( "$path" --autocomplete="$arg" 2>/dev/null ) + flags=$( "$path" --autocomplete="$arg" 2>/dev/null | sed -e 's/\t.*//' ) # If clang is old that it does not support --autocomplete, # fall back to the filename completion. if [[ "$?" != 0 ]]; then @@ -65,10 +65,14 @@ _clang() return fi - if [[ "$cur" == '=' ]]; then - COMPREPLY=( $( compgen -W "$flags" -- "") ) - elif [[ "$flags" == "" || "$arg" == "" ]]; then + # When clang does not emit any possible autocompletion, or user pushed tab after " ", + # just autocomplete files. + if [[ "$flags" == "$(echo -e '\n')" || "$arg" == "" ]]; then + # If -foo= and there was no possible values, autocomplete files. + [[ "$cur" == '=' || "$cur" == -*= ]] && cur="" _clang_filedir + elif [[ "$cur" == '=' ]]; then + COMPREPLY=( $( compgen -W "$flags" -- "") ) else # Bash automatically appends a space after '=' by default. # Disable it so that it works nicely for options in the form of -foo=bar. From a4233227dd3dd88590f8f4d5fdfea2e3ed286d0a Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Sat, 29 Jul 2017 21:29:58 +0000 Subject: [PATCH 08/10] Vendor import of libc++ release_50 branch r309439: https://llvm.org/svn/llvm-project/libcxx/branches/release_50@309439 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f8b24d17e24..ca5afba86d19 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,7 +23,7 @@ if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) project(libcxx CXX C) set(PACKAGE_NAME libcxx) - set(PACKAGE_VERSION 5.0.0svn) + set(PACKAGE_VERSION 5.0.0) set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") set(PACKAGE_BUGREPORT "llvm-bugs@lists.llvm.org") From 9e3ca9b3ba1e0fdf794978cb8c8ae386aad936ad Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Sat, 29 Jul 2017 21:30:27 +0000 Subject: [PATCH 09/10] Vendor import of lld release_50 branch r309439: https://llvm.org/svn/llvm-project/lld/branches/release_50@309439 --- COFF/Config.h | 2 +- COFF/Driver.cpp | 26 +++-- ELF/InputFiles.cpp | 3 +- ELF/InputFiles.h | 2 + ELF/SymbolTable.cpp | 63 ++++++----- docs/ReleaseNotes.rst | 163 ++++++++++++++++++++++++++-- lib/ReaderWriter/MachO/ObjCPass.cpp | 8 +- test/COFF/manifest.test | 9 +- test/COFF/manifestinput.test | 9 -- test/ELF/Inputs/symver-archive1.s | 6 + test/ELF/Inputs/symver-archive2.s | 1 + test/ELF/symver-archive.s | 15 +++ 12 files changed, 246 insertions(+), 61 deletions(-) create mode 100644 test/ELF/Inputs/symver-archive1.s create mode 100644 test/ELF/Inputs/symver-archive2.s create mode 100644 test/ELF/symver-archive.s diff --git a/COFF/Config.h b/COFF/Config.h index a58e7d5585f2..7f8259d016e1 100644 --- a/COFF/Config.h +++ b/COFF/Config.h @@ -130,7 +130,7 @@ struct Configuration { std::map Section; // Options for manifest files. - ManifestKind Manifest = SideBySide; + ManifestKind Manifest = No; int ManifestID = 1; StringRef ManifestDependency; bool ManifestUAC = true; diff --git a/COFF/Driver.cpp b/COFF/Driver.cpp index 35f4a04866c5..6df59e4b08df 100644 --- a/COFF/Driver.cpp +++ b/COFF/Driver.cpp @@ -899,18 +899,25 @@ void LinkerDriver::link(ArrayRef ArgsArr) { for (auto *Arg : Args.filtered(OPT_section)) parseSection(Arg->getValue()); - // Handle /manifest - if (auto *Arg = Args.getLastArg(OPT_manifest_colon)) - parseManifest(Arg->getValue()); + // Handle /manifestdependency. This enables /manifest unless /manifest:no is + // also passed. + if (auto *Arg = Args.getLastArg(OPT_manifestdependency)) { + Config->ManifestDependency = Arg->getValue(); + Config->Manifest = Configuration::SideBySide; + } + + // Handle /manifest and /manifest: + if (auto *Arg = Args.getLastArg(OPT_manifest, OPT_manifest_colon)) { + if (Arg->getOption().getID() == OPT_manifest) + Config->Manifest = Configuration::SideBySide; + else + parseManifest(Arg->getValue()); + } // Handle /manifestuac if (auto *Arg = Args.getLastArg(OPT_manifestuac)) parseManifestUAC(Arg->getValue()); - // Handle /manifestdependency - if (auto *Arg = Args.getLastArg(OPT_manifestdependency)) - Config->ManifestDependency = Arg->getValue(); - // Handle /manifestfile if (auto *Arg = Args.getLastArg(OPT_manifestfile)) Config->ManifestFile = Arg->getValue(); @@ -919,6 +926,11 @@ void LinkerDriver::link(ArrayRef ArgsArr) { for (auto *Arg : Args.filtered(OPT_manifestinput)) Config->ManifestInput.push_back(Arg->getValue()); + if (!Config->ManifestInput.empty() && + Config->Manifest != Configuration::Embed) { + fatal("/MANIFESTINPUT: requires /MANIFEST:EMBED"); + } + // Handle miscellaneous boolean flags. if (Args.hasArg(OPT_allowisolation_no)) Config->AllowIsolation = false; diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp index d3c307d5cb6b..c609615fcc2e 100644 --- a/ELF/InputFiles.cpp +++ b/ELF/InputFiles.cpp @@ -91,8 +91,7 @@ template void elf::ObjectFile::initializeDwarfLine() { template Optional elf::ObjectFile::getDILineInfo(InputSectionBase *S, uint64_t Offset) { - if (!DwarfLine) - initializeDwarfLine(); + llvm::call_once(InitDwarfLine, [this]() { initializeDwarfLine(); }); // The offset to CU is 0. const DWARFDebugLine::LineTable *Tbl = DwarfLine->getLineTable(0); diff --git a/ELF/InputFiles.h b/ELF/InputFiles.h index f6d3f907850c..006218b45d9e 100644 --- a/ELF/InputFiles.h +++ b/ELF/InputFiles.h @@ -24,6 +24,7 @@ #include "llvm/Object/Archive.h" #include "llvm/Object/ELF.h" #include "llvm/Object/IRObjectFile.h" +#include "llvm/Support/Threading.h" #include @@ -211,6 +212,7 @@ template class ObjectFile : public ELFFileBase { // single object file, so we cache debugging information in order to // parse it only once for each object file we link. std::unique_ptr DwarfLine; + llvm::once_flag InitDwarfLine; }; // LazyObjectFile is analogous to ArchiveFile in the sense that diff --git a/ELF/SymbolTable.cpp b/ELF/SymbolTable.cpp index 83091057ebed..0c932400f0ad 100644 --- a/ELF/SymbolTable.cpp +++ b/ELF/SymbolTable.cpp @@ -211,6 +211,12 @@ static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) { // Find an existing symbol or create and insert a new one. template std::pair SymbolTable::insert(StringRef Name) { + // @@ means the symbol is the default version. In that + // case @@ will be used to resolve references to . + size_t Pos = Name.find("@@"); + if (Pos != StringRef::npos) + Name = Name.take_front(Pos); + auto P = Symtab.insert( {CachedHashStringRef(Name), SymIndex((int)SymVector.size(), false)}); SymIndex &V = P.first->second; @@ -312,15 +318,36 @@ Symbol *SymbolTable::addUndefined(StringRef Name, bool IsLocal, return S; } +// Using .symver foo,foo@@VER unfortunately creates two symbols: foo and +// foo@@VER. We want to effectively ignore foo, so give precedence to +// foo@@VER. +// FIXME: If users can transition to using +// .symver foo,foo@@@VER +// we can delete this hack. +static int compareVersion(Symbol *S, StringRef Name) { + if (Name.find("@@") != StringRef::npos && + S->body()->getName().find("@@") == StringRef::npos) + return 1; + if (Name.find("@@") == StringRef::npos && + S->body()->getName().find("@@") != StringRef::npos) + return -1; + return 0; +} + // We have a new defined symbol with the specified binding. Return 1 if the new // symbol should win, -1 if the new symbol should lose, or 0 if both symbols are // strong defined symbols. -static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding) { +static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding, + StringRef Name) { if (WasInserted) return 1; SymbolBody *Body = S->body(); if (!Body->isInCurrentDSO()) return 1; + + if (int R = compareVersion(S, Name)) + return R; + if (Binding == STB_WEAK) return -1; if (S->isWeak()) @@ -333,8 +360,9 @@ static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding) { // is a conflict. If the new symbol wins, also update the binding. template static int compareDefinedNonCommon(Symbol *S, bool WasInserted, uint8_t Binding, - bool IsAbsolute, typename ELFT::uint Value) { - if (int Cmp = compareDefined(S, WasInserted, Binding)) { + bool IsAbsolute, typename ELFT::uint Value, + StringRef Name) { + if (int Cmp = compareDefined(S, WasInserted, Binding, Name)) { if (Cmp > 0) S->Binding = Binding; return Cmp; @@ -362,7 +390,7 @@ Symbol *SymbolTable::addCommon(StringRef N, uint64_t Size, bool WasInserted; std::tie(S, WasInserted) = insert(N, Type, getVisibility(StOther), /*CanOmitFromDynSym*/ false, File); - int Cmp = compareDefined(S, WasInserted, Binding); + int Cmp = compareDefined(S, WasInserted, Binding, N); if (Cmp > 0) { S->Binding = Binding; replaceBody(S, N, Size, Alignment, StOther, Type, File); @@ -439,7 +467,7 @@ Symbol *SymbolTable::addRegular(StringRef Name, uint8_t StOther, std::tie(S, WasInserted) = insert(Name, Type, getVisibility(StOther), /*CanOmitFromDynSym*/ false, File); int Cmp = compareDefinedNonCommon(S, WasInserted, Binding, - Section == nullptr, Value); + Section == nullptr, Value, Name); if (Cmp > 0) replaceBody(S, Name, /*IsLocal=*/false, StOther, Type, Value, Size, Section, File); @@ -485,7 +513,7 @@ Symbol *SymbolTable::addBitcode(StringRef Name, uint8_t Binding, std::tie(S, WasInserted) = insert(Name, Type, getVisibility(StOther), CanOmitFromDynSym, F); int Cmp = compareDefinedNonCommon(S, WasInserted, Binding, - /*IsAbs*/ false, /*Value*/ 0); + /*IsAbs*/ false, /*Value*/ 0, Name); if (Cmp > 0) replaceBody(S, Name, /*IsLocal=*/false, StOther, Type, 0, 0, nullptr, F); @@ -717,32 +745,9 @@ void SymbolTable::assignWildcardVersion(SymbolVersion Ver, B->symbol()->VersionId = VersionId; } -static bool isDefaultVersion(SymbolBody *B) { - return B->isInCurrentDSO() && B->getName().find("@@") != StringRef::npos; -} - // This function processes version scripts by updating VersionId // member of symbols. template void SymbolTable::scanVersionScript() { - // Symbol themselves might know their versions because symbols - // can contain versions in the form of @. - // Let them parse and update their names to exclude version suffix. - for (Symbol *Sym : SymVector) { - SymbolBody *Body = Sym->body(); - bool IsDefault = isDefaultVersion(Body); - Body->parseSymbolVersion(); - - if (!IsDefault) - continue; - - // @@ means the symbol is the default version. If that's the - // case, the symbol is not used only to resolve of version - // but also undefined unversioned symbols with name . - SymbolBody *S = find(Body->getName()); - if (S && S->isUndefined()) - S->copy(Body); - } - // Handle edge cases first. handleAnonymousVersion(); diff --git a/docs/ReleaseNotes.rst b/docs/ReleaseNotes.rst index 0d75311e4bce..fa6536ff46a8 100644 --- a/docs/ReleaseNotes.rst +++ b/docs/ReleaseNotes.rst @@ -1,5 +1,5 @@ ======================= -LLD 5.0.0 Release Notes +lld 5.0.0 Release Notes ======================= .. contents:: @@ -13,10 +13,16 @@ LLD 5.0.0 Release Notes Introduction ============ -This document contains the release notes for the LLD linker, release 5.0.0. -Here we describe the status of LLD, including major improvements -from the previous release. All LLD releases may be downloaded -from the `LLVM releases web site `_. +lld is a linker from the LLVM project. It supports ELF (Unix), COFF (Windows) +and Mach-O (macOS), and it is generally faster than the GNU bfd or gold linkers +or the MSVC linker. + +lld is designed to be a drop-in replacement for the system linkers, so that +users don't need to change their build systems other than swapping the linker +command. + +All lld releases may be downloaded from the `LLVM releases web site +`_. Non-comprehensive list of changes in this release ================================================= @@ -24,14 +30,153 @@ Non-comprehensive list of changes in this release ELF Improvements ---------------- -* Item 1. +* First and foremost, a lot of compatibility issues and bugs have been fixed. + Linker script support has significantly improved. As a result, we believe you + are very likely to be able to link your programs with lld without experiencing + any problem now. + +* Error message format has changed in order to improve readability. + Traditionally, linker's error messages are concise and arguably too terse. + This is an example of lld 4.0's error message (they are actually in one line):: + + /ssd/clang/bin/ld.lld: error: /ssd/llvm-project/lld/ELF/Writer.cpp:207: + undefined symbol 'lld::elf::EhFrameSection::addSection()' + + It is not easy to read because too much information is packed into a single line + and the embedded text, particularly a symbol name, is sometimes too long. + In lld 5.0, we use more vertical space to print out error messages in a more + structured manner like this:: + + bin/ld.lld: error: undefined symbol: lld::elf::EhFrameSection::addSection() + >>> Referenced by Writer.cpp:207 (/ssd/llvm-project/lld/ELF/Writer.cpp:207) + >>> Writer.cpp.o in archive lib/liblldELF.a + + As a bonus, the new error message contains source code location of the error + if it is available from debug info. + +* ``./configure`` scripts generated by GNU autoconf determines whether a linker + supports modern GNU-compatible features or not by searching for "GNU" in the + ``--help`` message. To be compatible with the scripts, we decided to add a + string "(compatible with GNU linkers)" to our ``--help`` message. This is a + hack, but just like the web browser's User-Agent string (which everyone still + claim they are "Mozilla/5.0"), we had no choice other than doing this to claim + that we accept GNU-compatible options. + +* The ``-Map`` option is added. The option is to make the linker to print out how + input files are mapped to the output file. Here is an example:: + + Address Size Align Out In Symbol + 00000000016d84d8 00000000008f8f50 8 .eh_frame + 00000000016d84d8 00000000008f8f50 8 :(.eh_frame) + 0000000001fd2000 00000000034b3bd0 16 .text + 0000000001fd2000 000000000000002a 1 /usr/lib/x86_64-linux-gnu/crt1.o:(.text) + 0000000001fd2000 0000000000000000 0 _start + 0000000001fd202a 0000000000000000 1 /usr/lib/x86_64-linux-gnu/crti.o:(.text) + 0000000001fd2030 00000000000000bd 16 /usr/lib/gcc/x86_64-linux-gnu/4.8/crtbegin.o:(.text) + 0000000001fd2030 0000000000000000 0 deregister_tm_clones + 0000000001fd2060 0000000000000000 0 register_tm_clones + + This format is not the same as GNU linkers as our linker internal data + structure is different from them but contains the same amount of information + and should be more readable than their outputs. + + As with other lld features, the ``-Map`` option is designed with speed in mind. + The option would generate a hundred megabyte text file if you link a large + program with it. lld can usually do that in a few seconds, and it is generally + a few times faster than the GNU gold's ``-Map`` option. + +* lld's ``--gdb-index`` option used to be slow, but we sped it up so that it is + at least as fast as the GNU gold. + +* Some nonstandard relocations, such as R_X86_64_8 or R_X86_64_16, are supported. + They are not used for 32/64-bit applications, but some 16-bit bootloaders need + them. + +* Paddings in executable text sections are now filled with trap instructions + (such as INT3) instead of being left as null bytes. This change improves + disassembler outputs because it now prints out trap instructions instead of + trying to decode 0x00 as an instruction. It also makes debugging of some type + of program easier because when the control reaches a padding, the program + immediately raises an error. + +* The following options are added: ``-M``, ``-Map``, + ``-compress-debug-sections``, ``-emit-relocs``, + ``-error-unresolved-symbols``, ``-exclude-libs``, ``-filter``, + ``-no-dynamic-linker``, ``-no-export-dynamic``, ``-no-fatal-warnings``, + ``-print-map``, ``-warn-unresolved-symbols``, ``-z nocopyreloc``, + ``-z notext``, ``-z rodynamic`` + COFF Improvements ----------------- * Item 1. -MachO Improvements ------------------- +Contributors to lld 5.0 +======================= -* Item 1. +We had 63 individuals contribute to lld 5.0. Thank you so much! + +- Adrian McCarthy +- Alberto Magni +- Alexander Richardson +- Andre Vieira +- Andrew Ng +- Anton Korobeynikov +- Bob Haarman +- David Blaikie +- Davide Italiano +- David L. Jones +- Dmitry Mikulin +- Ed Maste +- Ed Schouten +- Eric Beckmann +- Eric Fiselier +- Eugene Leviant +- Evgeniy Stepanov +- Galina Kistanova +- George Rimar +- Hans Wennborg +- Igor Kudrin +- Ismail Donmez +- Jake Ehrlich +- James Henderson +- Joel Jones +- Jon Chesterfield +- Kamil Rytarowski +- Kevin Enderby +- Konstantin Zhuravlyov +- Kyungwoo Lee +- Leslie Zhai +- Mark Kettenis +- Martell Malone +- Martin Storsjo +- Meador Inge +- Mehdi Amini +- Michal Gorny +- NAKAMURA Takumi +- Paul Robinson +- Pavel Labath +- Petar Jovanovic +- Peter Collingbourne +- Peter Smith +- Petr Hosek +- Rafael Espindola +- Reid Kleckner +- Richard Smith +- Robert Clarke +- Rui Ueyama +- Saleem Abdulrasool +- Sam Clegg +- Sean Eveson +- Sean Silva +- Shankar Easwaran +- Shoaib Meenai +- Simon Atanasyan +- Simon Dardis +- Simon Tatham +- Sylvestre Ledru +- Tom Stellard +- Vitaly Buka +- Yuka Takahashi +- Zachary Turner diff --git a/lib/ReaderWriter/MachO/ObjCPass.cpp b/lib/ReaderWriter/MachO/ObjCPass.cpp index 4712d8ca969c..ccea081f053d 100644 --- a/lib/ReaderWriter/MachO/ObjCPass.cpp +++ b/lib/ReaderWriter/MachO/ObjCPass.cpp @@ -11,6 +11,7 @@ #include "ArchHandler.h" #include "File.h" +#include "MachONormalizedFileBinaryUtils.h" #include "MachOPasses.h" #include "lld/Core/DefinedAtom.h" #include "lld/Core/File.h" @@ -29,7 +30,7 @@ namespace mach_o { /// class ObjCImageInfoAtom : public SimpleDefinedAtom { public: - ObjCImageInfoAtom(const File &file, + ObjCImageInfoAtom(const File &file, bool isBig, MachOLinkingContext::ObjCConstraint objCConstraint, uint32_t swiftVersion) : SimpleDefinedAtom(file) { @@ -54,6 +55,8 @@ class ObjCImageInfoAtom : public SimpleDefinedAtom { } Data.info.flags |= (swiftVersion << 8); + + normalized::write32(Data.bytes + 4, Data.info.flags, isBig); } ~ObjCImageInfoAtom() override = default; @@ -109,7 +112,8 @@ class ObjCPass : public Pass { private: const DefinedAtom* getImageInfo() { - return new (_file.allocator()) ObjCImageInfoAtom(_file, + bool IsBig = MachOLinkingContext::isBigEndian(_ctx.arch()); + return new (_file.allocator()) ObjCImageInfoAtom(_file, IsBig, _ctx.objcConstraint(), _ctx.swiftVersion()); } diff --git a/test/COFF/manifest.test b/test/COFF/manifest.test index 33e80e75a4d5..accec48d6866 100644 --- a/test/COFF/manifest.test +++ b/test/COFF/manifest.test @@ -1,6 +1,10 @@ # RUN: yaml2obj %p/Inputs/ret42.yaml > %t.obj +# RUN: rm -f %t.exe.manifest # RUN: lld-link /out:%t.exe /entry:main %t.obj +# RUN: test ! -e %t.exe.manifest + +# RUN: lld-link /manifest /out:%t.exe /entry:main %t.obj # RUN: FileCheck -check-prefix=MANIFEST %s < %t.exe.manifest MANIFEST: @@ -15,7 +19,7 @@ MANIFEST: MANIFEST: MANIFEST: -# RUN: lld-link /out:%t.exe /entry:main \ +# RUN: lld-link /out:%t.exe /entry:main /manifest \ # RUN: /manifestuac:"level='requireAdministrator' uiAccess='true'" %t.obj # RUN: FileCheck -check-prefix=UAC %s < %t.exe.manifest @@ -31,6 +35,7 @@ UAC: UAC: UAC: +# /manifestdependency implies /manifest. (/manifestuac doesn't.) # RUN: lld-link /out:%t.exe /entry:main \ # RUN: /manifestdependency:"foo='bar'" %t.obj # RUN: FileCheck -check-prefix=DEPENDENCY %s < %t.exe.manifest @@ -52,7 +57,7 @@ DEPENDENCY: DEPENDENCY: DEPENDENCY: -# RUN: lld-link /out:%t.exe /entry:main /manifestuac:no %t.obj +# RUN: lld-link /manifest /out:%t.exe /entry:main /manifestuac:no %t.obj # RUN: FileCheck -check-prefix=NOUAC %s < %t.exe.manifest NOUAC: diff --git a/test/COFF/manifestinput.test b/test/COFF/manifestinput.test index 4eb1730bb0e4..95ebc22f7410 100644 --- a/test/COFF/manifestinput.test +++ b/test/COFF/manifestinput.test @@ -1,14 +1,5 @@ # REQUIRES: win_mt -# RUN: yaml2obj %p/Inputs/ret42.yaml > %t.obj -# RUN: lld-link /out:%t.exe /entry:main \ -# RUN: /manifestuac:"level='requireAdministrator'" \ -# RUN: /manifestinput:%p/Inputs/manifestinput.test %t.obj -# RUN: FileCheck %s < %t.exe.manifest - -CHECK: -CHECK: - # RUN: yaml2obj %p/Inputs/ret42.yaml > %t.obj # RUN: lld-link /out:%t.exe /entry:main \ # RUN: /manifest:embed \ diff --git a/test/ELF/Inputs/symver-archive1.s b/test/ELF/Inputs/symver-archive1.s new file mode 100644 index 000000000000..be7c64494215 --- /dev/null +++ b/test/ELF/Inputs/symver-archive1.s @@ -0,0 +1,6 @@ +.text +.globl x +.type x, @function +x: + +.symver x, xx@@VER diff --git a/test/ELF/Inputs/symver-archive2.s b/test/ELF/Inputs/symver-archive2.s new file mode 100644 index 000000000000..a9b9d0b0a35b --- /dev/null +++ b/test/ELF/Inputs/symver-archive2.s @@ -0,0 +1 @@ +call xx@PLT diff --git a/test/ELF/symver-archive.s b/test/ELF/symver-archive.s new file mode 100644 index 000000000000..be50503a3f5d --- /dev/null +++ b/test/ELF/symver-archive.s @@ -0,0 +1,15 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1 +# RUN: rm -f %t.a +# RUN: llvm-ar rcs %t.a %t1 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/symver-archive1.s -o %t2.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/symver-archive2.s -o %t3.o +# RUN: ld.lld -o %t.out %t2.o %t3.o %t.a + +.text +.globl x +.type x, @function +x: + +.globl xx +xx = x From e74d4ea48caeee19d9d7f8223340152a0fde11ef Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Sat, 29 Jul 2017 21:31:51 +0000 Subject: [PATCH 10/10] Vendor import of lldb release_50 branch r309439: https://llvm.org/svn/llvm-project/lldb/branches/release_50@309439 --- include/lldb/API/SBAttachInfo.h | 2 +- include/lldb/API/SBBreakpoint.h | 4 ++-- include/lldb/API/SBProcess.h | 2 +- scripts/interface/SBBreakpoint.i | 2 +- scripts/interface/SBModule.i | 2 +- scripts/interface/SBSymbol.i | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/lldb/API/SBAttachInfo.h b/include/lldb/API/SBAttachInfo.h index 0c52218f57cd..7ae006908ccc 100644 --- a/include/lldb/API/SBAttachInfo.h +++ b/include/lldb/API/SBAttachInfo.h @@ -162,7 +162,7 @@ class LLDB_API SBAttachInfo { /// Get the listener that will be used to receive process events. /// /// If no listener has been set via a call to - /// SBLaunchInfo::SetListener(), then an invalid SBListener will be + /// SBAttachInfo::SetListener(), then an invalid SBListener will be /// returned (SBListener::IsValid() will return false). If a listener /// has been set, then the valid listener object will be returned. //---------------------------------------------------------------------- diff --git a/include/lldb/API/SBBreakpoint.h b/include/lldb/API/SBBreakpoint.h index d3f22f39ab00..9abc9cd39dcb 100644 --- a/include/lldb/API/SBBreakpoint.h +++ b/include/lldb/API/SBBreakpoint.h @@ -154,9 +154,9 @@ class LLDB_API SBBreakpointList { SBBreakpoint FindBreakpointByID(lldb::break_id_t); - void Append(const SBBreakpoint &sb_file); + void Append(const SBBreakpoint &sb_bkpt); - bool AppendIfUnique(const SBBreakpoint &sb_file); + bool AppendIfUnique(const SBBreakpoint &sb_bkpt); void AppendByID(lldb::break_id_t id); diff --git a/include/lldb/API/SBProcess.h b/include/lldb/API/SBProcess.h index 0ee3a989d1b6..d57d5ce04f59 100644 --- a/include/lldb/API/SBProcess.h +++ b/include/lldb/API/SBProcess.h @@ -350,7 +350,7 @@ class LLDB_API SBProcess { bool IsInstrumentationRuntimePresent(InstrumentationRuntimeType type); - // Save the state of the process in a core file (or mini dump on Windows). + /// Save the state of the process in a core file (or mini dump on Windows). lldb::SBError SaveCore(const char *file_name); //------------------------------------------------------------------ diff --git a/scripts/interface/SBBreakpoint.i b/scripts/interface/SBBreakpoint.i index 22c4c2174f3b..95bc0cda0051 100644 --- a/scripts/interface/SBBreakpoint.i +++ b/scripts/interface/SBBreakpoint.i @@ -70,7 +70,7 @@ SBBreakpoint supports breakpoint location iteration, for example, print('breakpoint location load addr: %s' % hex(bl.GetLoadAddress())) print('breakpoint location condition: %s' % hex(bl.GetCondition())) -and rich comparion methods which allow the API program to use, +and rich comparison methods which allow the API program to use, if aBreakpoint == bBreakpoint: ... diff --git a/scripts/interface/SBModule.i b/scripts/interface/SBModule.i index b1b6d2a7ca3d..71a2198609d6 100644 --- a/scripts/interface/SBModule.i +++ b/scripts/interface/SBModule.i @@ -26,7 +26,7 @@ SBModule supports symbol iteration, for example, saddr = symbol.GetStartAddress() eaddr = symbol.GetEndAddress() -and rich comparion methods which allow the API program to use, +and rich comparison methods which allow the API program to use, if thisModule == thatModule: print('This module is the same as that module') diff --git a/scripts/interface/SBSymbol.i b/scripts/interface/SBSymbol.i index b6717055e486..a61fda4920dd 100644 --- a/scripts/interface/SBSymbol.i +++ b/scripts/interface/SBSymbol.i @@ -11,7 +11,7 @@ namespace lldb { %feature("docstring", "Represents the symbol possibly associated with a stack frame. -SBModule contains SBSymbol(s). SBSymbol can also be retrived from SBFrame. +SBModule contains SBSymbol(s). SBSymbol can also be retrieved from SBFrame. See also SBModule and SBFrame." ) SBSymbol;