mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 20:23:11 +01:00
[llvm-elfabi] Add flag to preserve timestamp when output is the same
This change adds '--write-if-changed' flag to llvm-elfabi tool. When enabled, llvm-elfabi will not overwrite the existing file if the content of the file will not be changed, which preserves the timestamp. Differential Revision: https://reviews.llvm.org/D92902
This commit is contained in:
parent
0eb92dbbca
commit
1e70786482
@ -16,6 +16,7 @@
|
|||||||
#include "llvm/InterfaceStub/ELFStub.h"
|
#include "llvm/InterfaceStub/ELFStub.h"
|
||||||
#include "llvm/Object/ELFObjectFile.h"
|
#include "llvm/Object/ELFObjectFile.h"
|
||||||
#include "llvm/Object/ELFTypes.h"
|
#include "llvm/Object/ELFTypes.h"
|
||||||
|
#include "llvm/Support/FileSystem.h"
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
@ -35,8 +36,10 @@ Expected<std::unique_ptr<ELFStub>> readELFFile(MemoryBufferRef Buf);
|
|||||||
/// @param FilePath File path for writing the ELF binary.
|
/// @param FilePath File path for writing the ELF binary.
|
||||||
/// @param Stub Source ELFStub to generate a binary ELF stub from.
|
/// @param Stub Source ELFStub to generate a binary ELF stub from.
|
||||||
/// @param OutputFormat Target ELFType to write binary as.
|
/// @param OutputFormat Target ELFType to write binary as.
|
||||||
|
/// @param WriteIfChanged Whether or not to preserve timestamp if
|
||||||
|
/// the output stays the same.
|
||||||
Error writeBinaryStub(StringRef FilePath, const ELFStub &Stub,
|
Error writeBinaryStub(StringRef FilePath, const ELFStub &Stub,
|
||||||
ELFTarget OutputFormat);
|
ELFTarget OutputFormat, bool WriteIfChanged = false);
|
||||||
|
|
||||||
} // end namespace elfabi
|
} // end namespace elfabi
|
||||||
} // end namespace llvm
|
} // end namespace llvm
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "llvm/Support/FileOutputBuffer.h"
|
#include "llvm/Support/FileOutputBuffer.h"
|
||||||
#include "llvm/Support/MathExtras.h"
|
#include "llvm/Support/MathExtras.h"
|
||||||
#include "llvm/Support/MemoryBuffer.h"
|
#include "llvm/Support/MemoryBuffer.h"
|
||||||
|
#include "llvm/Support/Process.h"
|
||||||
|
|
||||||
using llvm::MemoryBufferRef;
|
using llvm::MemoryBufferRef;
|
||||||
using llvm::object::ELFObjectFile;
|
using llvm::object::ELFObjectFile;
|
||||||
@ -663,8 +664,25 @@ buildStub(const ELFObjectFile<ELFT> &ElfObj) {
|
|||||||
/// @param FilePath File path for writing the ELF binary.
|
/// @param FilePath File path for writing the ELF binary.
|
||||||
/// @param Stub Source ELFStub to generate a binary ELF stub from.
|
/// @param Stub Source ELFStub to generate a binary ELF stub from.
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
static Error writeELFBinaryToFile(StringRef FilePath, const ELFStub &Stub) {
|
static Error writeELFBinaryToFile(StringRef FilePath, const ELFStub &Stub,
|
||||||
|
bool WriteIfChanged) {
|
||||||
ELFStubBuilder<ELFT> Builder{Stub};
|
ELFStubBuilder<ELFT> Builder{Stub};
|
||||||
|
// Write Stub to memory first.
|
||||||
|
std::vector<uint8_t> Buf(Builder.getSize());
|
||||||
|
Builder.write(Buf.data());
|
||||||
|
|
||||||
|
if (WriteIfChanged) {
|
||||||
|
if (ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrError =
|
||||||
|
MemoryBuffer::getFile(FilePath)) {
|
||||||
|
// Compare Stub output with existing Stub file.
|
||||||
|
// If Stub file unchanged, abort updating.
|
||||||
|
if ((*BufOrError)->getBufferSize() == Builder.getSize() &&
|
||||||
|
!memcmp((*BufOrError)->getBufferStart(), Buf.data(),
|
||||||
|
Builder.getSize()))
|
||||||
|
return Error::success();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Expected<std::unique_ptr<FileOutputBuffer>> BufOrError =
|
Expected<std::unique_ptr<FileOutputBuffer>> BufOrError =
|
||||||
FileOutputBuffer::create(FilePath, Builder.getSize());
|
FileOutputBuffer::create(FilePath, Builder.getSize());
|
||||||
if (!BufOrError)
|
if (!BufOrError)
|
||||||
@ -674,13 +692,10 @@ static Error writeELFBinaryToFile(StringRef FilePath, const ELFStub &Stub) {
|
|||||||
"` for writing");
|
"` for writing");
|
||||||
|
|
||||||
// Write binary to file.
|
// Write binary to file.
|
||||||
std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufOrError);
|
std::unique_ptr<FileOutputBuffer> FileBuf = std::move(*BufOrError);
|
||||||
Builder.write(Buf->getBufferStart());
|
memcpy(FileBuf->getBufferStart(), Buf.data(), Buf.size());
|
||||||
|
|
||||||
if (Error E = Buf->commit())
|
return FileBuf->commit();
|
||||||
return E;
|
|
||||||
|
|
||||||
return Error::success();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Expected<std::unique_ptr<ELFStub>> readELFFile(MemoryBufferRef Buf) {
|
Expected<std::unique_ptr<ELFStub>> readELFFile(MemoryBufferRef Buf) {
|
||||||
@ -705,15 +720,15 @@ Expected<std::unique_ptr<ELFStub>> readELFFile(MemoryBufferRef Buf) {
|
|||||||
// This function wraps the ELFT writeELFBinaryToFile() so writeBinaryStub()
|
// This function wraps the ELFT writeELFBinaryToFile() so writeBinaryStub()
|
||||||
// can be called without having to use ELFType templates directly.
|
// can be called without having to use ELFType templates directly.
|
||||||
Error writeBinaryStub(StringRef FilePath, const ELFStub &Stub,
|
Error writeBinaryStub(StringRef FilePath, const ELFStub &Stub,
|
||||||
ELFTarget OutputFormat) {
|
ELFTarget OutputFormat, bool WriteIfChanged) {
|
||||||
if (OutputFormat == ELFTarget::ELF32LE)
|
if (OutputFormat == ELFTarget::ELF32LE)
|
||||||
return writeELFBinaryToFile<ELF32LE>(FilePath, Stub);
|
return writeELFBinaryToFile<ELF32LE>(FilePath, Stub, WriteIfChanged);
|
||||||
if (OutputFormat == ELFTarget::ELF32BE)
|
if (OutputFormat == ELFTarget::ELF32BE)
|
||||||
return writeELFBinaryToFile<ELF32BE>(FilePath, Stub);
|
return writeELFBinaryToFile<ELF32BE>(FilePath, Stub, WriteIfChanged);
|
||||||
if (OutputFormat == ELFTarget::ELF64LE)
|
if (OutputFormat == ELFTarget::ELF64LE)
|
||||||
return writeELFBinaryToFile<ELF64LE>(FilePath, Stub);
|
return writeELFBinaryToFile<ELF64LE>(FilePath, Stub, WriteIfChanged);
|
||||||
if (OutputFormat == ELFTarget::ELF64BE)
|
if (OutputFormat == ELFTarget::ELF64BE)
|
||||||
return writeELFBinaryToFile<ELF64BE>(FilePath, Stub);
|
return writeELFBinaryToFile<ELF64BE>(FilePath, Stub, WriteIfChanged);
|
||||||
llvm_unreachable("invalid binary output target");
|
llvm_unreachable("invalid binary output target");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
19
test/tools/llvm-elfabi/preserve-dates-stub.test
Normal file
19
test/tools/llvm-elfabi/preserve-dates-stub.test
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
## Test writing unchanged content to ELF Stub file with --write-if-changed flag.
|
||||||
|
|
||||||
|
# RUN: llvm-elfabi %s --output-target=elf64-little %t
|
||||||
|
# RUN: touch -m -d "1970-01-01 00:00:00" %t
|
||||||
|
# RUN: llvm-elfabi %s --output-target=elf64-little %t --write-if-changed
|
||||||
|
# RUN: ls -l %t | FileCheck %s
|
||||||
|
|
||||||
|
--- !tapi-tbe
|
||||||
|
TbeVersion: 1.0
|
||||||
|
Arch: x86_64
|
||||||
|
NeededLibs:
|
||||||
|
- libc.so.6
|
||||||
|
Symbols:
|
||||||
|
bar: { Type: Object, Size: 42 }
|
||||||
|
baz: { Type: TLS, Size: 3 }
|
||||||
|
plus: { Type: Func }
|
||||||
|
...
|
||||||
|
|
||||||
|
# CHECK: {{[[:space:]]1970}}
|
8
test/tools/llvm-elfabi/preserve-dates-tbe.test
Normal file
8
test/tools/llvm-elfabi/preserve-dates-tbe.test
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
## Test writing unchanged content to TBE file with --write-if-changed flag.
|
||||||
|
|
||||||
|
# RUN: llvm-elfabi --elf %p/Inputs/gnu_hash.so --emit-tbe=%t
|
||||||
|
# RUN: touch -m -d "1970-01-01 00:00:00" %t
|
||||||
|
# RUN: llvm-elfabi --elf %p/Inputs/gnu_hash.so --emit-tbe=%t --write-if-changed
|
||||||
|
# RUN: ls -l %t | FileCheck %s
|
||||||
|
|
||||||
|
# CHECK: {{[[:space:]]1970}}
|
@ -57,22 +57,37 @@ cl::opt<ELFTarget> BinaryOutputTarget(
|
|||||||
clEnumValN(ELFTarget::ELF64BE, "elf64-big",
|
clEnumValN(ELFTarget::ELF64BE, "elf64-big",
|
||||||
"64-bit big-endian ELF stub")));
|
"64-bit big-endian ELF stub")));
|
||||||
cl::opt<std::string> BinaryOutputFilePath(cl::Positional, cl::desc("output"));
|
cl::opt<std::string> BinaryOutputFilePath(cl::Positional, cl::desc("output"));
|
||||||
|
cl::opt<bool> WriteIfChanged(
|
||||||
|
"write-if-changed",
|
||||||
|
cl::desc("Write the output file only if it is new or has changed."));
|
||||||
|
|
||||||
/// writeTBE() writes a Text-Based ELF stub to a file using the latest version
|
/// writeTBE() writes a Text-Based ELF stub to a file using the latest version
|
||||||
/// of the YAML parser.
|
/// of the YAML parser.
|
||||||
static Error writeTBE(StringRef FilePath, ELFStub &Stub) {
|
static Error writeTBE(StringRef FilePath, ELFStub &Stub) {
|
||||||
std::error_code SysErr;
|
// Write TBE to memory first.
|
||||||
|
std::string TBEStr;
|
||||||
|
raw_string_ostream OutStr(TBEStr);
|
||||||
|
Error YAMLErr = writeTBEToOutputStream(OutStr, Stub);
|
||||||
|
if (YAMLErr)
|
||||||
|
return YAMLErr;
|
||||||
|
OutStr.flush();
|
||||||
|
|
||||||
// Open file for writing.
|
if (WriteIfChanged) {
|
||||||
|
if (ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrError =
|
||||||
|
MemoryBuffer::getFile(FilePath)) {
|
||||||
|
// Compare TBE output with existing TBE file.
|
||||||
|
// If TBE file unchanged, abort updating.
|
||||||
|
if ((*BufOrError)->getBuffer() == TBEStr)
|
||||||
|
return Error::success();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Open TBE file for writing.
|
||||||
|
std::error_code SysErr;
|
||||||
raw_fd_ostream Out(FilePath, SysErr);
|
raw_fd_ostream Out(FilePath, SysErr);
|
||||||
if (SysErr)
|
if (SysErr)
|
||||||
return createStringError(SysErr, "Couldn't open `%s` for writing",
|
return createStringError(SysErr, "Couldn't open `%s` for writing",
|
||||||
FilePath.data());
|
FilePath.data());
|
||||||
// Write file.
|
Out << TBEStr;
|
||||||
Error YAMLErr = writeTBEToOutputStream(Out, Stub);
|
|
||||||
if (YAMLErr)
|
|
||||||
return YAMLErr;
|
|
||||||
|
|
||||||
return Error::success();
|
return Error::success();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,8 +168,8 @@ int main(int argc, char *argv[]) {
|
|||||||
if (BinaryOutputTarget.getNumOccurrences() == 0)
|
if (BinaryOutputTarget.getNumOccurrences() == 0)
|
||||||
fatalError(createStringError(errc::not_supported,
|
fatalError(createStringError(errc::not_supported,
|
||||||
"no binary output target specified."));
|
"no binary output target specified."));
|
||||||
Error BinaryWriteError =
|
Error BinaryWriteError = writeBinaryStub(
|
||||||
writeBinaryStub(BinaryOutputFilePath, *TargetStub, BinaryOutputTarget);
|
BinaryOutputFilePath, *TargetStub, BinaryOutputTarget, WriteIfChanged);
|
||||||
if (BinaryWriteError)
|
if (BinaryWriteError)
|
||||||
fatalError(std::move(BinaryWriteError));
|
fatalError(std::move(BinaryWriteError));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user