Add .bolt_info notes section containing BOLT revision and command line args.

Summary:
Optinally add a .bolt_info notes section containing BOLT revision and command line args.
The new section is controlled by the -add-bolt-info flag which is on by default.

(cherry picked from FBD5125890)
This commit is contained in:
Bill Nell 2017-05-24 14:14:16 -07:00 committed by Maksim Panchenko
parent 2ee4bbd3c1
commit 5cd58961a9
4 changed files with 111 additions and 3 deletions

View File

@ -1,6 +1,49 @@
add_subdirectory(merge-fdata) add_subdirectory(merge-fdata)
add_subdirectory(Passes) add_subdirectory(Passes)
# Get the current git revision for BOLT.
function(get_version ofn)
find_program(git_executable NAMES git git.exe git.cmd)
if (git_executable)
execute_process(COMMAND ${git_executable} rev-parse HEAD
WORKING_DIRECTORY ${LLVM_MAIN_SRC_DIR}
TIMEOUT 5
RESULT_VARIABLE git_result
OUTPUT_VARIABLE git_output)
if( git_result EQUAL 0 )
string(STRIP "${git_output}" git_ref_id)
set(BOLT_REVISION "${git_ref_id}")
endif()
endif()
# If we can't find a revision, set it to "<unknown>".
if (NOT BOLT_REVISION)
set(BOLT_REVISION "<unknown>")
endif()
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${ofn}
COMMAND echo '"${BOLT_REVISION}"' > ${CMAKE_CURRENT_BINARY_DIR}/${ofn}
COMMENT "Generating bogus ${ofn}..."
)
set(VERSION_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${ofn} PARENT_SCOPE)
# `make clean' must remove all those generated files:
set_property(DIRECTORY APPEND
PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${ofn})
set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/${ofn} PROPERTIES
GENERATED 1)
endfunction()
# Creates a public target for generating the revision file.
function(add_public_gen_version_target target)
add_custom_target(${target} DEPENDS ${VERSION_OUTPUT})
set(LLVM_COMMON_DEPENDS ${LLVM_COMMON_DEPENDS} ${target} PARENT_SCOPE)
endfunction()
get_version(BoltRevision.inc)
add_public_gen_version_target(GenBoltRevision)
set(LLVM_LINK_COMPONENTS set(LLVM_LINK_COMPONENTS
${LLVM_TARGETS_TO_BUILD} ${LLVM_TARGETS_TO_BUILD}
BOLTPasses BOLTPasses

View File

@ -51,6 +51,7 @@
#include "llvm/Support/TargetSelect.h" #include "llvm/Support/TargetSelect.h"
#include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/ToolOutputFile.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetMachine.h"
#include <algorithm> #include <algorithm>
#include <fstream> #include <fstream>
@ -311,6 +312,13 @@ Verbosity("v",
cl::ZeroOrMore, cl::ZeroOrMore,
cl::cat(BoltCategory)); cl::cat(BoltCategory));
static cl::opt<bool>
AddBoltInfo("add-bolt-info",
cl::desc("add BOLT version and command line argument information to "
"processed binaries"),
cl::init(true),
cl::cat(BoltCategory));
// Check against lists of functions from options if we should // Check against lists of functions from options if we should
// optimize the function with a given name. // optimize the function with a given name.
bool shouldProcess(const BinaryFunction &Function) { bool shouldProcess(const BinaryFunction &Function) {
@ -392,6 +400,12 @@ const std::string RewriteInstance::OrgSecPrefix = ".bolt.org";
const std::string RewriteInstance::BOLTSecPrefix = ".bolt"; const std::string RewriteInstance::BOLTSecPrefix = ".bolt";
namespace llvm {
namespace bolt {
extern const char *BoltRevision;
}
}
static void report_error(StringRef Message, std::error_code EC) { static void report_error(StringRef Message, std::error_code EC) {
assert(EC); assert(EC);
errs() << "BOLT-ERROR: '" << Message << "': " << EC.message() << ".\n"; errs() << "BOLT-ERROR: '" << Message << "': " << EC.message() << ".\n";
@ -597,8 +611,12 @@ std::unique_ptr<BinaryContext> createBinaryContext(
} // namespace } // namespace
RewriteInstance::RewriteInstance(ELFObjectFileBase *File, RewriteInstance::RewriteInstance(ELFObjectFileBase *File,
const DataReader &DR) const DataReader &DR,
const int Argc,
const char *const *Argv)
: InputFile(File), : InputFile(File),
Argc(Argc),
Argv(Argv),
BC(createBinaryContext("x86-64", "x86_64-unknown-linux", DR, BC(createBinaryContext("x86-64", "x86_64-unknown-linux", DR,
std::unique_ptr<DWARFContext>( std::unique_ptr<DWARFContext>(
new DWARFContextInMemory(*InputFile, nullptr, true)))) { new DWARFContextInMemory(*InputFile, nullptr, true)))) {
@ -796,6 +814,8 @@ void RewriteInstance::run() {
if (opts::UpdateDebugSections) if (opts::UpdateDebugSections)
updateDebugInfo(); updateDebugInfo();
addBoltInfoSection();
// Copy allocatable part of the input. // Copy allocatable part of the input.
std::error_code EC; std::error_code EC;
Out = llvm::make_unique<tool_output_file>(opts::OutputFilename, EC, Out = llvm::make_unique<tool_output_file>(opts::OutputFilename, EC,
@ -2765,6 +2785,30 @@ void RewriteInstance::finalizeSectionStringTable(ELFObjectFile<ELFT> *File) {
EFMM->NoteSectionInfo[".shstrtab"].IsStrTab = true; EFMM->NoteSectionInfo[".shstrtab"].IsStrTab = true;
} }
void RewriteInstance::addBoltInfoSection() {
if (opts::AddBoltInfo) {
std::string Str;
raw_string_ostream OS(Str);
OS << "BOLT revision: " << BoltRevision << ", " << "command line:";
for (auto I = 0; I < Argc; ++I) {
OS << " " << Argv[I];
}
const auto BoltInfo = OS.str();
const auto SectionSize = BoltInfo.size();
uint8_t *SectionData = new uint8_t[SectionSize];
memcpy(SectionData, BoltInfo.data(), SectionSize);
EFMM->NoteSectionInfo[".bolt_info"] =
SectionInfo(reinterpret_cast<uint64_t>(SectionData),
SectionSize,
/*Alignment=*/1,
/*IsCode=*/false,
/*IsReadOnly=*/true,
/*IsLocal=*/false);
}
}
// Rewrite section header table inserting new entries as needed. The sections // Rewrite section header table inserting new entries as needed. The sections
// header table size itself may affect the offsets of other sections, // header table size itself may affect the offsets of other sections,
// so we are placing it at the end of the binary. // so we are placing it at the end of the binary.

View File

@ -146,7 +146,8 @@ public:
/// events. /// events.
class RewriteInstance { class RewriteInstance {
public: public:
RewriteInstance(llvm::object::ELFObjectFileBase *File, const DataReader &DR); RewriteInstance(llvm::object::ELFObjectFileBase *File, const DataReader &DR,
const int Argc, const char *const *Argv);
~RewriteInstance(); ~RewriteInstance();
/// Reset all state except for split hints. Used to run a second pass with /// Reset all state except for split hints. Used to run a second pass with
@ -320,6 +321,9 @@ private:
/// Finalize memory image of section header string table. /// Finalize memory image of section header string table.
ELF_FUNCTION(finalizeSectionStringTable); ELF_FUNCTION(finalizeSectionStringTable);
/// Add a notes section containing the BOLT revision and command line options.
void addBoltInfoSection();
/// Computes output .debug_line line table offsets for each compile unit, /// Computes output .debug_line line table offsets for each compile unit,
/// and updates stmt_list for a corresponding compile unit. /// and updates stmt_list for a corresponding compile unit.
void updateLineTableOffsets(); void updateLineTableOffsets();
@ -388,6 +392,10 @@ private:
/// An instance of the input binary we are processing, externally owned. /// An instance of the input binary we are processing, externally owned.
llvm::object::ELFObjectFileBase *InputFile; llvm::object::ELFObjectFileBase *InputFile;
/// Command line args used to process binary.
const int Argc;
const char *const *Argv;
std::unique_ptr<BinaryContext> BC; std::unique_ptr<BinaryContext> BC;
std::unique_ptr<CFIReaderWriter> CFIRdWrt; std::unique_ptr<CFIReaderWriter> CFIRdWrt;

View File

@ -69,6 +69,18 @@ static void report_error(StringRef Message, std::error_code EC) {
exit(1); exit(1);
} }
namespace llvm {
namespace bolt {
const char *BoltRevision =
#include "BoltRevision.inc"
;
}
}
static void printBoltRevision() {
errs() << "BOLT revision " << BoltRevision << "\n";
}
int main(int argc, char **argv) { int main(int argc, char **argv) {
// Print a stack trace if we signal out. // Print a stack trace if we signal out.
sys::PrintStackTraceOnErrorSignal(); sys::PrintStackTraceOnErrorSignal();
@ -88,6 +100,7 @@ int main(int argc, char **argv) {
cl::HideUnrelatedOptions(makeArrayRef(opts::BoltCategories)); cl::HideUnrelatedOptions(makeArrayRef(opts::BoltCategories));
// Register the target printer for --version. // Register the target printer for --version.
cl::AddExtraVersionPrinter(printBoltRevision);
cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion); cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);
cl::ParseCommandLineOptions(argc, argv, cl::ParseCommandLineOptions(argc, argv,
@ -122,7 +135,7 @@ int main(int argc, char **argv) {
Binary &Binary = *BinaryOrErr.get().getBinary(); Binary &Binary = *BinaryOrErr.get().getBinary();
if (auto *e = dyn_cast<ELFObjectFileBase>(&Binary)) { if (auto *e = dyn_cast<ELFObjectFileBase>(&Binary)) {
RewriteInstance RI(e, *DR.get()); RewriteInstance RI(e, *DR.get(), argc, argv);
RI.run(); RI.run();
} else { } else {
report_error(opts::InputFilename, object_error::invalid_file_type); report_error(opts::InputFilename, object_error::invalid_file_type);