-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[BOLT] Introduce binary analysis tool based on BOLT #115330
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
40e0029
2c5293f
0ee65f5
1185846
bf8de12
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# BOLT-based binary analysis | ||
|
||
As part of post-link-time optimizing, BOLT needs to perform a range of analyses | ||
on binaries such as recontructing control flow graphs, and more. | ||
|
||
The `llvm-bolt-binary-analysis` tool enables running requested binary analyses | ||
on binaries, and generating reports. It does this by building on top of the | ||
analyses implemented in the BOLT libraries. | ||
|
||
## Which binary analyses are implemented? | ||
|
||
At the moment, no binary analyses are implemented. | ||
|
||
The goal is to make it easy using a plug-in framework to add your own analyses. | ||
|
||
## How to add your own binary analysis | ||
|
||
_TODO: this section needs to be written. Ideally, we should have a simple | ||
"example" or "template" analysis that can be the starting point for implementing | ||
custom analyses_ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
dummy |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# This file tests error messages produced on invalid command line arguments. | ||
# It also checks that help messages are generated as expected. | ||
|
||
# Verify that an error message is provided if an input file is missing or incorrect | ||
|
||
RUN: not llvm-bolt-binary-analysis 2>&1 | FileCheck -check-prefix=NOFILEARG %s | ||
NOFILEARG: llvm-bolt-binary-analysis: Not enough positional command line arguments specified! | ||
NOFILEARG-NEXT: Must specify at least 1 positional argument: See: {{.*}}llvm-bolt-binary-analysis --help | ||
|
||
RUN: not llvm-bolt-binary-analysis non-existing-file 2>&1 | FileCheck -check-prefix=NONEXISTINGFILEARG %s | ||
NONEXISTINGFILEARG: llvm-bolt-binary-analysis: 'non-existing-file': No such file or directory. | ||
|
||
RUN: not llvm-bolt-binary-analysis %p/Inputs/dummy.txt 2>&1 | FileCheck -check-prefix=NOELFFILEARG %s | ||
NOELFFILEARG: llvm-bolt-binary-analysis: '{{.*}}/Inputs/dummy.txt': The file was not recognized as a valid object file. | ||
|
||
RUN: %clang %cflags %p/../../Inputs/asm_foo.s %p/../../Inputs/asm_main.c -o %t.exe | ||
RUN: llvm-bolt-binary-analysis %t.exe 2>&1 | FileCheck -check-prefix=VALIDELFFILEARG --allow-empty %s | ||
# Check that there are no BOLT-WARNING or BOLT-ERROR output lines | ||
VALIDELFFILEARG: BOLT-INFO: | ||
VALIDELFFILEARG-NOT: BOLT-WARNING: | ||
VALIDELFFILEARG-NOT: BOLT-ERROR: | ||
|
||
# Check --help output | ||
|
||
RUN: llvm-bolt-binary-analysis --help 2>&1 | FileCheck -check-prefix=HELP %s | ||
|
||
HELP: OVERVIEW: BinaryAnalysis | ||
HELP-EMPTY: | ||
HELP-NEXT: USAGE: llvm-bolt-binary-analysis [options] <executable> | ||
HELP-EMPTY: | ||
HELP-NEXT: OPTIONS: | ||
HELP-EMPTY: | ||
HELP-NEXT: Generic Options: |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
if "AArch64" not in config.root.targets: | ||
config.unsupported = True | ||
|
||
flags = "--target=aarch64-linux-gnu -nostartfiles -nostdlib -ffreestanding -Wl,--emit-relocs" | ||
|
||
config.substitutions.insert(0, ("%cflags", f"%cflags {flags}")) | ||
config.substitutions.insert(0, ("%cxxflags", f"%cxxflags {flags}")) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
set(LLVM_LINK_COMPONENTS | ||
${LLVM_TARGETS_TO_BUILD} | ||
MC | ||
Object | ||
Support | ||
) | ||
|
||
add_bolt_tool(llvm-bolt-binary-analysis | ||
binary-analysis.cpp | ||
DISABLE_LLVM_LINK_LLVM_DYLIB | ||
) | ||
|
||
target_link_libraries(llvm-bolt-binary-analysis | ||
PRIVATE | ||
LLVMBOLTRewrite | ||
LLVMBOLTUtils | ||
) | ||
|
||
add_dependencies(bolt llvm-bolt-binary-analysis) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
//===- bolt/tools/binary-analysis/binary-analysis.cpp ---------------------===// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This is a generic binary analysis tool, where multiple different specific | ||
// binary analyses can be plugged in to. The binary analyses are mostly built | ||
// on top of BOLT components. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "bolt/Rewrite/RewriteInstance.h" | ||
#include "bolt/Utils/CommandLineOpts.h" | ||
#include "llvm/MC/TargetRegistry.h" | ||
#include "llvm/Object/Binary.h" | ||
#include "llvm/Object/ELFObjectFile.h" | ||
#include "llvm/Support/CommandLine.h" | ||
#include "llvm/Support/Errc.h" | ||
#include "llvm/Support/ManagedStatic.h" | ||
#include "llvm/Support/PrettyStackTrace.h" | ||
#include "llvm/Support/Program.h" | ||
#include "llvm/Support/Signals.h" | ||
#include "llvm/Support/TargetSelect.h" | ||
#include "llvm/Support/VirtualFileSystem.h" | ||
|
||
#define DEBUG_TYPE "bolt" | ||
|
||
using namespace llvm; | ||
using namespace object; | ||
using namespace bolt; | ||
|
||
namespace opts { | ||
|
||
static cl::OptionCategory *BinaryAnalysisCategories[] = { | ||
&BinaryAnalysisCategory}; | ||
|
||
Comment on lines
+37
to
+39
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tried out adding the
After doing so, the output for the same command is:
It seems the majority of the options in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Interestingly, it looks like most of the options relevant for the analysis use-case are only printed with
Maybe creating an issue is a good idea - it should be rather straightforward to implement this but still requires some amount of familiarization with BOLT to better understand which option is relevant for the "read-only" use case and which only influences the code generation. |
||
static cl::opt<std::string> InputFilename(cl::Positional, | ||
cl::desc("<executable>"), | ||
cl::Required, | ||
cl::cat(BinaryAnalysisCategory), | ||
cl::sub(cl::SubCommand::getAll())); | ||
|
||
} // namespace opts | ||
|
||
static StringRef ToolName = "llvm-bolt-binary-analysis"; | ||
|
||
static void report_error(StringRef Message, std::error_code EC) { | ||
assert(EC); | ||
errs() << ToolName << ": '" << Message << "': " << EC.message() << ".\n"; | ||
exit(1); | ||
} | ||
|
||
static void report_error(StringRef Message, Error E) { | ||
assert(E); | ||
errs() << ToolName << ": '" << Message << "': " << toString(std::move(E)) | ||
<< ".\n"; | ||
exit(1); | ||
} | ||
|
||
void ParseCommandLine(int argc, char **argv) { | ||
cl::HideUnrelatedOptions(ArrayRef(opts::BinaryAnalysisCategories)); | ||
// Register the target printer for --version. | ||
cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion); | ||
|
||
cl::ParseCommandLineOptions(argc, argv, "BinaryAnalysis\n"); | ||
} | ||
|
||
static std::string GetExecutablePath(const char *Argv0) { | ||
SmallString<256> ExecutablePath(Argv0); | ||
// Do a PATH lookup if Argv0 isn't a valid path. | ||
if (!llvm::sys::fs::exists(ExecutablePath)) | ||
if (llvm::ErrorOr<std::string> P = | ||
llvm::sys::findProgramByName(ExecutablePath)) | ||
ExecutablePath = *P; | ||
return std::string(ExecutablePath.str()); | ||
} | ||
|
||
int main(int argc, char **argv) { | ||
// Print a stack trace if we signal out. | ||
sys::PrintStackTraceOnErrorSignal(argv[0]); | ||
PrettyStackTraceProgram X(argc, argv); | ||
|
||
std::string ToolPath = GetExecutablePath(argv[0]); | ||
|
||
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. | ||
|
||
// Initialize targets and assembly printers/parsers. | ||
llvm::InitializeAllTargetInfos(); | ||
llvm::InitializeAllTargetMCs(); | ||
llvm::InitializeAllAsmParsers(); | ||
llvm::InitializeAllDisassemblers(); | ||
|
||
llvm::InitializeAllTargets(); | ||
llvm::InitializeAllAsmPrinters(); | ||
|
||
ParseCommandLine(argc, argv); | ||
|
||
opts::BinaryAnalysisMode = true; | ||
|
||
if (!sys::fs::exists(opts::InputFilename)) | ||
report_error(opts::InputFilename, errc::no_such_file_or_directory); | ||
|
||
Expected<OwningBinary<Binary>> BinaryOrErr = | ||
createBinary(opts::InputFilename); | ||
if (Error E = BinaryOrErr.takeError()) | ||
report_error(opts::InputFilename, std::move(E)); | ||
Binary &Binary = *BinaryOrErr.get().getBinary(); | ||
|
||
if (auto *e = dyn_cast<ELFObjectFileBase>(&Binary)) { | ||
auto RIOrErr = RewriteInstance::create(e, argc, argv, ToolPath); | ||
if (Error E = RIOrErr.takeError()) | ||
report_error(opts::InputFilename, std::move(E)); | ||
RewriteInstance &RI = *RIOrErr.get(); | ||
if (Error E = RI.run()) | ||
report_error(opts::InputFilename, std::move(E)); | ||
} | ||
|
||
return EXIT_SUCCESS; | ||
} |
Uh oh!
There was an error while loading. Please reload this page.