Index: include/llvm/Support/FileSystem.h =================================================================== --- include/llvm/Support/FileSystem.h +++ include/llvm/Support/FileSystem.h @@ -285,7 +285,8 @@ /// specific error_code. If IgnoreExisting is false, also returns /// error if the directory already existed. std::error_code create_directories(const Twine &path, - bool IgnoreExisting = true); + bool IgnoreExisting = true, + perms Perms = owner_all | group_all); /// @brief Create the directory in path. /// @@ -293,7 +294,8 @@ /// @returns errc::success if is_directory(path), otherwise a platform /// specific error_code. If IgnoreExisting is false, also returns /// error if the directory already existed. -std::error_code create_directory(const Twine &path, bool IgnoreExisting = true); +std::error_code create_directory(const Twine &path, bool IgnoreExisting = true, + perms Perms = owner_all | group_all); /// @brief Create a link from \a from to \a to. /// Index: lib/CodeGen/AsmPrinter/DwarfAccelTable.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfAccelTable.h +++ lib/CodeGen/AsmPrinter/DwarfAccelTable.h @@ -165,20 +165,13 @@ // HashData[hash_data_count] public: struct HashDataContents { - const DIE *Die; // Offsets - char Flags; // Specific flags to output - - HashDataContents(const DIE *D, char Flags) : Die(D), Flags(Flags) {} -#ifndef NDEBUG - void print(raw_ostream &O) const { - O << " Offset: " << Die->getOffset() << "\n"; - O << " Tag: " << dwarf::TagString(Die->getTag()) << "\n"; - O << " Flags: " << Flags << "\n"; - } -#endif + virtual void emit(AsmPrinter *Asm, DwarfDebug *D) const = 0; + virtual bool less(const HashDataContents *Other) const = 0; + virtual void print(raw_ostream &OS) const = 0; + virtual ~HashDataContents(); }; -private: +protected: // String Data struct DataArray { DwarfStringPoolEntryRef Name; @@ -204,11 +197,8 @@ else O << ""; O << "\n"; - for (HashDataContents *C : Data.Values) { - O << " Offset: " << C->Die->getOffset() << "\n"; - O << " Tag: " << dwarf::TagString(C->Die->getTag()) << "\n"; - O << " Flags: " << C->Flags << "\n"; - } + for (auto *C : Data.Values) + C->print(O); } void dump() { print(dbgs()); } #endif @@ -224,6 +214,7 @@ void emitOffsets(AsmPrinter *, const MCSymbol *); void EmitData(AsmPrinter *, DwarfDebug *D); +protected: // Allocator for HashData and HashDataContents. BumpPtrAllocator Allocator; @@ -232,6 +223,7 @@ TableHeaderData HeaderData; std::vector Data; + // This map needs to be filled by subclasses. typedef StringMap StringEntries; StringEntries Entries; @@ -241,10 +233,9 @@ BucketList Buckets; HashList Hashes; - // Public Implementation -public: DwarfAccelTable(ArrayRef); - void AddName(DwarfStringPoolEntryRef Name, const DIE *Die, char Flags = 0); + +public: void FinalizeTable(AsmPrinter *, StringRef); void emit(AsmPrinter *, const MCSymbol *, DwarfDebug *); #ifndef NDEBUG @@ -252,5 +243,16 @@ void dump() { print(dbgs()); } #endif }; + +class DIEDwarfAccelTable : public DwarfAccelTable { + bool IsType; + +public: + /// Construct a DIE accelerator table. \p IsType is true if it will + /// be emitted as a type accelerator table. + DIEDwarfAccelTable(bool IsType = false); + + void AddName(DwarfStringPoolEntryRef Name, const DIE *Die); +}; } #endif Index: lib/CodeGen/AsmPrinter/DwarfAccelTable.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfAccelTable.cpp +++ lib/CodeGen/AsmPrinter/DwarfAccelTable.cpp @@ -25,22 +25,72 @@ using namespace llvm; -// The length of the header data is always going to be 4 + 4 + 4*NumAtoms. -DwarfAccelTable::DwarfAccelTable(ArrayRef atomList) - : Header(8 + (atomList.size() * 4)), HeaderData(atomList), - Entries(Allocator) {} +DwarfAccelTable::HashDataContents::~HashDataContents() {} -void DwarfAccelTable::AddName(DwarfStringPoolEntryRef Name, const DIE *die, - char Flags) { +template +class DIEHashDataContents : public DwarfAccelTable::HashDataContents { + const DIE *Die; + +public: + DIEHashDataContents(const DIE *Die) : Die(Die) {} + + void emit(AsmPrinter *Asm, DwarfDebug *D) const override { + // Emit the DIE offset + DwarfCompileUnit *CU = D->lookupUnit(Die->getUnit()); + assert(CU && "Accelerated DIE should belong to a CU."); + Asm->EmitInt32(Die->getOffset() + CU->getDebugInfoOffset()); + if (IsType) { + Asm->EmitInt16(Die->getTag()); + Asm->EmitInt8(0); // Flags + } + } + + bool less(const HashDataContents *Other) const override { + return Die->getOffset() < HD->Die->getOffset(); + } + + void print(raw_ostream &OS) const override { + OS << " Offset: " << Die->getOffset() << "\n"; + if (IsType) { + OS << " Tag: " << dwarf::TagString(Die->getTag()) << "\n"; + OS << " Flags: 0\n"; + } + } +}; + +static LLVM_CONSTEXPR DwarfAccelTable::Atom DieAtoms[] = { + DwarfAccelTable::Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4)}; + +static LLVM_CONSTEXPR DwarfAccelTable::Atom TypeAtoms[] = { + DwarfAccelTable::Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4), + DwarfAccelTable::Atom(dwarf::DW_ATOM_die_tag, dwarf::DW_FORM_data2), + DwarfAccelTable::Atom(dwarf::DW_ATOM_type_flags, dwarf::DW_FORM_data1)}; + +DIEDwarfAccelTable::DIEDwarfAccelTable(bool IsType) + : DwarfAccelTable(IsType ? makeArrayRef(TypeAtoms) + : makeArrayRef(DieAtoms)), + IsType(IsType) {} + +void DIEDwarfAccelTable::AddName(DwarfStringPoolEntryRef Name, const DIE *Die) { assert(Data.empty() && "Already finalized!"); // If the string is in the list already then add this die to the list // otherwise add a new one. DataArray &DIEs = Entries[Name.getString()]; assert(!DIEs.Name || DIEs.Name == Name); DIEs.Name = Name; - DIEs.Values.push_back(new (Allocator) HashDataContents(die, Flags)); + HashDataContents *HD; + if (IsType) + HD = new (Allocator) DIEHashDataContents(Die); + else + HD = new (Allocator) DIEHashDataContents(Die); + DIEs.Values.push_back(HD); } +// The length of the header data is always going to be 4 + 4 + 4*NumAtoms. +DwarfAccelTable::DwarfAccelTable(ArrayRef atomList) + : Header(8 + (atomList.size() * 4)), HeaderData(atomList), + Entries(Allocator) {} + void DwarfAccelTable::ComputeBucketCount(void) { // First get the number of unique hashes. std::vector uniques(Data.size()); @@ -62,12 +112,6 @@ Header.hashes_count = num; } -// compareDIEs - comparison predicate that sorts DIEs by their offset. -static bool compareDIEs(const DwarfAccelTable::HashDataContents *A, - const DwarfAccelTable::HashDataContents *B) { - return A->Die->getOffset() < B->Die->getOffset(); -} - void DwarfAccelTable::FinalizeTable(AsmPrinter *Asm, StringRef Prefix) { // Create the individual hash data outputs. Data.reserve(Entries.size()); @@ -75,7 +119,10 @@ EI != EE; ++EI) { // Unique the entries. - std::stable_sort(EI->second.Values.begin(), EI->second.Values.end(), compareDIEs); + std::stable_sort( + EI->second.Values.begin(), EI->second.Values.end(), + [](const DwarfAccelTable::HashDataContents *A, + const DwarfAccelTable::HashDataContents *B) { return A->less(B); }); EI->second.Values.erase( std::unique(EI->second.Values.begin(), EI->second.Values.end()), EI->second.Values.end()); @@ -219,18 +266,8 @@ Asm->emitDwarfStringOffset((*HI)->Data.Name); Asm->OutStreamer->AddComment("Num DIEs"); Asm->EmitInt32((*HI)->Data.Values.size()); - for (HashDataContents *HD : (*HI)->Data.Values) { - // Emit the DIE offset - DwarfCompileUnit *CU = D->lookupUnit(HD->Die->getUnit()); - assert(CU && "Accelerated DIE should belong to a CU."); - Asm->EmitInt32(HD->Die->getOffset() + CU->getDebugInfoOffset()); - // If we have multiple Atoms emit that info too. - // FIXME: A bit of a hack, we either emit only one atom or all info. - if (HeaderData.Atoms.size() > 1) { - Asm->EmitInt16(HD->Die->getTag()); - Asm->EmitInt8(HD->Flags); - } - } + for (HashDataContents *HD : (*HI)->Data.Values) + HD->emit(Asm, D); PrevHash = (*HI)->HashValue; } // Emit the final end marker for the bucket. Index: lib/CodeGen/AsmPrinter/DwarfDebug.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.h +++ lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -366,10 +366,10 @@ AddressPool AddrPool; - DwarfAccelTable AccelNames; - DwarfAccelTable AccelObjC; - DwarfAccelTable AccelNamespace; - DwarfAccelTable AccelTypes; + DIEDwarfAccelTable AccelNames; + DIEDwarfAccelTable AccelObjC; + DIEDwarfAccelTable AccelNamespace; + DIEDwarfAccelTable AccelTypes; DenseMap FunctionDIs; @@ -423,7 +423,7 @@ void emitAbbreviations(); /// Emit a specified accelerator table. - void emitAccel(DwarfAccelTable &Accel, MCSection *Section, + void emitAccel(DIEDwarfAccelTable &Accel, MCSection *Section, StringRef TableName); /// Emit visible names into a hashed accelerator table section. Index: lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -197,24 +197,14 @@ return Ty; } -static LLVM_CONSTEXPR DwarfAccelTable::Atom TypeAtoms[] = { - DwarfAccelTable::Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4), - DwarfAccelTable::Atom(dwarf::DW_ATOM_die_tag, dwarf::DW_FORM_data2), - DwarfAccelTable::Atom(dwarf::DW_ATOM_type_flags, dwarf::DW_FORM_data1)}; - DwarfDebug::DwarfDebug(AsmPrinter *A, Module *M) : Asm(A), MMI(Asm->MMI), DebugLocs(A->OutStreamer->isVerboseAsm()), PrevLabel(nullptr), InfoHolder(A, "info_string", DIEValueAllocator), UsedNonDefaultText(false), SkeletonHolder(A, "skel_string", DIEValueAllocator), - IsDarwin(Triple(A->getTargetTriple()).isOSDarwin()), - AccelNames(DwarfAccelTable::Atom(dwarf::DW_ATOM_die_offset, - dwarf::DW_FORM_data4)), - AccelObjC(DwarfAccelTable::Atom(dwarf::DW_ATOM_die_offset, - dwarf::DW_FORM_data4)), - AccelNamespace(DwarfAccelTable::Atom(dwarf::DW_ATOM_die_offset, - dwarf::DW_FORM_data4)), - AccelTypes(TypeAtoms), DebuggerTuning(DebuggerKind::Default) { + IsDarwin(Triple(A->getTargetTriple()).isOSDarwin()), AccelNames(), + AccelObjC(), AccelNamespace(), AccelTypes(/* IsType =*/true), + DebuggerTuning(DebuggerKind::Default) { CurFn = nullptr; CurMI = nullptr; @@ -1314,7 +1304,7 @@ Holder.emitAbbrevs(Asm->getObjFileLowering().getDwarfAbbrevSection()); } -void DwarfDebug::emitAccel(DwarfAccelTable &Accel, MCSection *Section, +void DwarfDebug::emitAccel(DIEDwarfAccelTable &Accel, MCSection *Section, StringRef TableName) { Accel.FinalizeTable(Asm, TableName); Asm->OutStreamer->SwitchSection(Section); Index: lib/Support/Path.cpp =================================================================== --- lib/Support/Path.cpp +++ lib/Support/Path.cpp @@ -785,12 +785,13 @@ "occurred above!"); } -std::error_code create_directories(const Twine &Path, bool IgnoreExisting) { +std::error_code create_directories(const Twine &Path, bool IgnoreExisting, + perms Perms) { SmallString<128> PathStorage; StringRef P = Path.toStringRef(PathStorage); // Be optimistic and try to create the directory - std::error_code EC = create_directory(P, IgnoreExisting); + std::error_code EC = create_directory(P, IgnoreExisting, Perms); // If we succeeded, or had any error other than the parent not existing, just // return it. if (EC != errc::no_such_file_or_directory) @@ -802,10 +803,10 @@ if (Parent.empty()) return EC; - if ((EC = create_directories(Parent))) + if ((EC = create_directories(Parent, IgnoreExisting, Perms))) return EC; - return create_directory(P, IgnoreExisting); + return create_directory(P, IgnoreExisting, Perms); } std::error_code copy_file(const Twine &From, const Twine &To) { Index: lib/Support/Unix/Path.inc =================================================================== --- lib/Support/Unix/Path.inc +++ lib/Support/Unix/Path.inc @@ -219,11 +219,12 @@ return std::error_code(); } -std::error_code create_directory(const Twine &path, bool IgnoreExisting) { +std::error_code create_directory(const Twine &path, bool IgnoreExisting, + perms Perms) { SmallString<128> path_storage; StringRef p = path.toNullTerminatedStringRef(path_storage); - if (::mkdir(p.begin(), S_IRWXU | S_IRWXG) == -1) { + if (::mkdir(p.begin(), Perms) == -1) { if (errno != EEXIST || !IgnoreExisting) return std::error_code(errno, std::generic_category()); } Index: lib/Support/Windows/Path.inc =================================================================== --- lib/Support/Windows/Path.inc +++ lib/Support/Windows/Path.inc @@ -182,7 +182,8 @@ return UTF16ToUTF8(cur_path.begin(), cur_path.size(), result); } -std::error_code create_directory(const Twine &path, bool IgnoreExisting) { +std::error_code create_directory(const Twine &path, bool IgnoreExisting, + perms Perms) { SmallVector path_utf16; if (std::error_code ec = widenPath(path, path_utf16)) Index: unittests/Support/Path.cpp =================================================================== --- unittests/Support/Path.cpp +++ unittests/Support/Path.cpp @@ -20,6 +20,10 @@ #include #endif +#ifdef LLVM_ON_UNIX +#include +#endif + using namespace llvm; using namespace llvm::sys; @@ -458,6 +462,38 @@ errc::file_exists); ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "foo")); +#ifdef LLVM_ON_UNIX + // Set a 0000 umask so that we can test our directory permissions. + mode_t OldUmask = ::umask(0000); + + fs::file_status Status; + ASSERT_NO_ERROR( + fs::create_directory(Twine(TestDirectory) + "baz500", false, + fs::perms::owner_read | fs::perms::owner_exe)); + ASSERT_NO_ERROR(fs::status(Twine(TestDirectory) + "baz500", Status)); + ASSERT_EQ(Status.permissions() & fs::perms::all_all, + fs::perms::owner_read | fs::perms::owner_exe); + ASSERT_NO_ERROR( + fs::create_directory(Twine(TestDirectory) + "baz050", false, + fs::perms::group_read | fs::perms::group_exe)); + ASSERT_NO_ERROR(fs::status(Twine(TestDirectory) + "baz050", Status)); + ASSERT_EQ(Status.permissions() & fs::perms::all_all, + fs::perms::group_read | fs::perms::group_exe); + ASSERT_NO_ERROR( + fs::create_directory(Twine(TestDirectory) + "baz005", false, + fs::perms::others_read | fs::perms::others_exe)); + ASSERT_NO_ERROR(fs::status(Twine(TestDirectory) + "baz005", Status)); + ASSERT_EQ(Status.permissions() & fs::perms::all_all, + fs::perms::others_read | fs::perms::others_exe); + ASSERT_NO_ERROR(fs::create_directory(Twine(TestDirectory) + "baz777", false, + fs::perms::all_all)); + ASSERT_NO_ERROR(fs::status(Twine(TestDirectory) + "baz777", Status)); + ASSERT_EQ(Status.permissions() & fs::perms::all_all, fs::perms::all_all); + + // Restore umask to be safe. + ::umask(OldUmask); +#endif + #ifdef LLVM_ON_WIN32 // Prove that create_directories() can handle a pathname > 248 characters, // which is the documented limit for CreateDirectory().