[lld-macho] Add archive name and file modtime to STABS output

We should also set the modtime when running LTO. That will be done in a
future diff, together with support for the `-object_path_lto` flag.

Reviewed By: clayborg

Differential Revision: https://reviews.llvm.org/D91318
This commit is contained in:
Jez Ng 2020-12-01 14:45:11 -08:00
parent d0c4be42e3
commit b768d57b36
8 changed files with 85 additions and 27 deletions

View File

@ -212,21 +212,32 @@ getFrameworkSearchPaths(opt::InputArgList &args,
{"/Library/Frameworks", "/System/Library/Frameworks"});
}
namespace {
struct ArchiveMember {
MemoryBufferRef mbref;
uint32_t modTime;
};
} // namespace
// Returns slices of MB by parsing MB as an archive file.
// Each slice consists of a member file in the archive.
static std::vector<MemoryBufferRef> getArchiveMembers(MemoryBufferRef mb) {
static std::vector<ArchiveMember> getArchiveMembers(MemoryBufferRef mb) {
std::unique_ptr<Archive> file =
CHECK(Archive::create(mb),
mb.getBufferIdentifier() + ": failed to parse archive");
std::vector<MemoryBufferRef> v;
std::vector<ArchiveMember> v;
Error err = Error::success();
for (const Archive::Child &c : file->children(err)) {
MemoryBufferRef mbref =
CHECK(c.getMemoryBufferRef(),
mb.getBufferIdentifier() +
": could not get the buffer for a child of the archive");
v.push_back(mbref);
uint32_t modTime = toTimeT(
CHECK(c.getLastModified(), mb.getBufferIdentifier() +
": could not get the modification "
"time for a child of the archive"));
v.push_back({mbref, modTime});
}
if (err)
fatal(mb.getBufferIdentifier() +
@ -235,6 +246,16 @@ static std::vector<MemoryBufferRef> getArchiveMembers(MemoryBufferRef mb) {
return v;
}
static void forceLoadArchive(StringRef path) {
if (Optional<MemoryBufferRef> buffer = readFile(path)) {
for (const ArchiveMember &member : getArchiveMembers(*buffer)) {
auto file = make<ObjFile>(member.mbref, member.modTime);
file->archiveName = buffer->getBufferIdentifier();
inputFiles.push_back(file);
}
}
}
static InputFile *addFile(StringRef path) {
Optional<MemoryBufferRef> buffer = readFile(path);
if (!buffer)
@ -251,9 +272,7 @@ static InputFile *addFile(StringRef path) {
error(path + ": archive has no index; run ranlib to add one");
if (config->allLoad) {
if (Optional<MemoryBufferRef> buffer = readFile(path))
for (MemoryBufferRef member : getArchiveMembers(*buffer))
inputFiles.push_back(make<ObjFile>(member));
forceLoadArchive(path);
} else if (config->forceLoadObjC) {
for (const object::Archive::Symbol &sym : file->symbols())
if (sym.getName().startswith(objc::klass))
@ -264,16 +283,16 @@ static InputFile *addFile(StringRef path) {
// consider creating a LazyObjFile class in order to avoid double-loading
// these files here and below (as part of the ArchiveFile).
if (Optional<MemoryBufferRef> buffer = readFile(path))
for (MemoryBufferRef member : getArchiveMembers(*buffer))
if (hasObjCSection(member))
inputFiles.push_back(make<ObjFile>(member));
for (const ArchiveMember &member : getArchiveMembers(*buffer))
if (hasObjCSection(member.mbref))
inputFiles.push_back(make<ObjFile>(member.mbref, member.modTime));
}
newFile = make<ArchiveFile>(std::move(file));
break;
}
case file_magic::macho_object:
newFile = make<ObjFile>(mbref);
newFile = make<ObjFile>(mbref, getModTime(path));
break;
case file_magic::macho_dynamically_linked_shared_lib:
case file_magic::macho_dynamically_linked_shared_lib_stub:
@ -304,12 +323,6 @@ static void addFileList(StringRef path) {
addFile(path);
}
static void forceLoadArchive(StringRef path) {
if (Optional<MemoryBufferRef> buffer = readFile(path))
for (MemoryBufferRef member : getArchiveMembers(*buffer))
inputFiles.push_back(make<ObjFile>(member));
}
static std::array<StringRef, 6> archNames{"arm", "arm64", "i386",
"x86_64", "ppc", "ppc64"};
static bool isArchString(StringRef s) {

View File

@ -43,6 +43,8 @@ llvm::Optional<std::string> resolveDylibPath(llvm::StringRef path);
llvm::Optional<DylibFile *> makeDylibFromTAPI(llvm::MemoryBufferRef mbref,
DylibFile *umbrella = nullptr);
uint32_t getModTime(llvm::StringRef path);
} // namespace macho
} // namespace lld

View File

@ -175,3 +175,13 @@ Optional<DylibFile *> macho::makeDylibFromTAPI(MemoryBufferRef mbref,
}
return make<DylibFile>(**result, umbrella);
}
uint32_t macho::getModTime(StringRef path) {
fs::file_status stat;
if (!fs::status(path, stat))
if (fs::exists(stat))
return toTimeT(stat.getLastModificationTime());
warn("failed to get modification time of " + path);
return 0;
}

View File

@ -364,7 +364,8 @@ OpaqueFile::OpaqueFile(MemoryBufferRef mb, StringRef segName,
subsections.push_back({{0, isec}});
}
ObjFile::ObjFile(MemoryBufferRef mb) : InputFile(ObjKind, mb) {
ObjFile::ObjFile(MemoryBufferRef mb, uint32_t modTime)
: InputFile(ObjKind, mb), modTime(modTime) {
auto *buf = reinterpret_cast<const uint8_t *>(mb.getBufferStart());
auto *hdr = reinterpret_cast<const mach_header_64 *>(mb.getBufferStart());
@ -592,7 +593,16 @@ void ArchiveFile::fetch(const object::Archive::Symbol &sym) {
toString(this) +
": could not get the buffer for the member defining symbol " +
sym.getName());
auto file = make<ObjFile>(mb);
uint32_t modTime = toTimeT(
CHECK(c.getLastModified(), toString(this) +
": could not get the modification time "
"for the member defining symbol " +
sym.getName()));
auto file = make<ObjFile>(mb, modTime);
file->archiveName = getName();
symbols.insert(symbols.end(), file->symbols.begin(), file->symbols.end());
subsections.insert(subsections.end(), file->subsections.begin(),
file->subsections.end());

View File

@ -90,10 +90,12 @@ private:
// .o file
class ObjFile : public InputFile {
public:
explicit ObjFile(MemoryBufferRef mb);
explicit ObjFile(MemoryBufferRef mb, uint32_t modTime);
static bool classof(const InputFile *f) { return f->kind() == ObjKind; }
llvm::DWARFUnit *compileUnit = nullptr;
StringRef archiveName = "";
const uint32_t modTime;
private:
void parseDebugInfo();

View File

@ -73,10 +73,12 @@ std::vector<ObjFile *> BitcodeCompiler::compile() {
saveBuffer(buf[i], config->outputFile + Twine(i) + ".lto.o");
}
// TODO: set modTime properly
std::vector<ObjFile *> ret;
for (unsigned i = 0; i != maxTasks; ++i)
if (!buf[i].empty())
ret.push_back(make<ObjFile>(MemoryBufferRef(buf[i], "lto.tmp")));
ret.push_back(
make<ObjFile>(MemoryBufferRef(buf[i], "lto.tmp"), /*modTime=*/0));
return ret;
}

View File

@ -602,13 +602,18 @@ void SymtabSection::emitEndSourceStab() {
void SymtabSection::emitObjectFileStab(ObjFile *file) {
StabsEntry stab(MachO::N_OSO);
stab.sect = target->cpuSubtype;
SmallString<261> path(file->getName());
SmallString<261> path(!file->archiveName.empty() ? file->archiveName
: file->getName());
std::error_code ec = sys::fs::make_absolute(path);
if (ec)
fatal("failed to get absolute path for " + file->getName());
fatal("failed to get absolute path for " + path);
if (!file->archiveName.empty())
path.append({"(", file->getName(), ")"});
stab.strx = stringTableSection.addString(saver.save(path.str()));
stab.desc = 1;
stab.value = file->modTime;
stabs.emplace_back(std::move(stab));
}

View File

@ -3,22 +3,35 @@
# RUN: split-file %s %t
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/test.s -o %t/test.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/foo.s -o %t/foo.o
## Set modtimes of the files for deterministic test output.
# RUN: env TZ=UTC touch -t "197001010000.16" %t/test.o
# RUN: env TZ=UTC touch -t "197001010000.32" %t/foo.o
# RUN: rm -f %t/foo.a
# RUN: llvm-ar rcsU %t/foo.a %t/foo.o
# RUN: %lld -lSystem %t/test.o %t/foo.o -o %t/test
# RUN: llvm-nm -pa %t/test | FileCheck %s -DDIR=%t
# RUN: llvm-nm -pa %t/test | FileCheck %s -DDIR=%t -DFOO_PATH=%t/foo.o
## Check that we emit the right modtime even when the object file is in an
## archive.
# RUN: %lld -lSystem %t/test.o %t/foo.a -o %t/test
# RUN: llvm-nm -pa %t/test | FileCheck %s -DDIR=%t -DFOO_PATH=%t/foo.a\(foo.o\)
## Check that we emit absolute paths to the object files in our OSO entries
## even if our inputs are relative paths.
# RUN: cd %t && %lld -lSystem test.o foo.o -o test
# RUN: llvm-nm -pa %t/test | FileCheck %s -DDIR=%t
# RUN: llvm-nm -pa %t/test | FileCheck %s -DDIR=%t -DFOO_PATH=%t/foo.o
# RUN: cd %t && %lld -lSystem %t/test.o %t/foo.a -o %t/test
# RUN: llvm-nm -pa %t/test | FileCheck %s -DDIR=%t -DFOO_PATH=%t/foo.a\(foo.o\)
# CHECK: 0000000000000000 - 00 0000 SO /tmp/test.cpp
# CHECK-NEXT: 0000000000000000 - 03 0001 OSO [[DIR]]/test.o
# CHECK-NEXT: 0000000000000010 - 03 0001 OSO [[DIR]]/test.o
# CHECK-NEXT: [[#%x, MAIN:]] - 01 0000 FUN _main
# CHECK-NEXT: 0000000000000001 - 00 0000 FUN
# CHECK-NEXT: 0000000000000006 - 00 0000 FUN
# CHECK-NEXT: 0000000000000000 - 01 0000 SO
# CHECK-NEXT: 0000000000000000 - 00 0000 SO /foo.cpp
# CHECK-NEXT: 0000000000000000 - 03 0001 OSO [[DIR]]/foo.o
# CHECK-NEXT: 0000000000000020 - 03 0001 OSO [[FOO_PATH]]
# CHECK-NEXT: [[#%x, FOO:]] - 01 0000 FUN _foo
# CHECK-NEXT: 0000000000000001 - 00 0000 FUN
# CHECK-NEXT: 0000000000000000 - 01 0000 SO
@ -30,6 +43,7 @@
.globl _main
_main:
Lfunc_begin0:
callq _foo
retq
Lfunc_end0: