Files
revng-revng/codegenerator.h
T
Alessandro Di Federico 61cfbdfc56 Introduce support for dynamic binaries
This commit introduces support for dynamic programs. The current
implementation translate the main binary and uses native libraries. This
works only if the target architecture is the same as the source
one. Currently we only handle x86-64.

* The `ExternalJumpsHandler` class has been introduced. It basically
  takes care of extending the dispatcher handling the case in which the
  program counter is an address outside the range of executable
  addresses of the input program. In this case, a `setjmp` is perfomed,
  the CPU state is serialized to physical registers and jump to the
  value of the program counter is performed.

  Once the target code will try to return to the translated program, a
  segmentation fault will be triggered, a `longjmp` is performed and the
  CPU state is deserialized so that the execution can resume (from the
  dispatcher).

* `early-linked.c` has been introduced. Its purposes is to provide
  declarations of variables and functions defined in `support.c`. In the
  past, we had to manually create these definitions, a cumbersome and
  error prone we now avoid by letting `clang` compile `early-linked.c`
  and then linking it in.

* The old `support.h` is now known as `commonconstants.h`. `support.h`
  now contains declarations that have to be consumed by
  `early-linked.c`.

* Each architecture now provides additional information:

  1. Which registers are part of the ABI and have to be preserved. If
     necessary the QEMU name can be provided. For each register it's
     also possible to provide their position within the `mcontext_t`
     structure, provided by the signal handler.
  2. Three assembly snippets, one to write a register, one to read it
     and one perform an indirect jump.

  Some of this information is also exposed in the output module as
  metadata.

* `support.c` now installs a SIGSEGV signal handler. Since pages that
  were originally executable are no longer executable, jumping there
  (typically, from a library) will trigger a SIGSEGV that we will
  handle. This allows us to properly deserialize the CPU state and
  resume execution of the translate code.

* Now also a dynamic version of each test program is translated and
  tested.

* The `merge-dynamic.py` script has been introduced: it takes case of
  rewriting the translated binary so to tell the linker to performe both
  the relocations of the translate program and the relocations of the
  original program. It does so by rewriting a large portion of the
  sections employed by the dynamic linker such as `.dynamic`, `.dynsym`
  and so on.

* The `compile-time-constants.py` script has been introduced: it a
  user-specified compiler on a source file producing an object
  file. This object file is inspected and the value of global read-only
  variables is produced in a CSV.
2018-05-29 15:10:51 +02:00

138 lines
4.4 KiB
C++

#ifndef _CODEGENERATOR_H
#define _CODEGENERATOR_H
//
// This file is distributed under the MIT License. See LICENSE.md for details.
//
// Standard includes
#include <cstdint>
#include <string>
#include <memory>
// LLVM includes
#include "llvm/ADT/ArrayRef.h"
// Local includes
#include "binaryfile.h"
#include "revamb.h"
// Forward declarations
namespace llvm {
class LLVMContext;
class Function;
class GlobalVariable;
class Module;
class Value;
class StructType;
class DataLayout;
namespace object {
class ObjectFile;
};
};
class DebugHelper;
/// Translator from binary code to LLVM IR.
class CodeGenerator {
public:
/// Create a new code generator translating code from an architecture to
/// another, writing the corresponding LLVM IR and other useful information to
/// the specified paths.
///
/// \param Binary reference to a BinaryFile object describing the input.
/// \param Target target architecture.
/// \param Output path where the generate LLVM IR must be saved.
/// \param Helpers path of the LLVM IR file containing the QEMU helpers.
/// \param DebugInfo type of debug information to generate.
/// \param Debug path where the debugging source file must be written. If an
/// empty string, the output file name plus ".S", if \p DebugInfo is
/// DebugInfoType::OriginalAssembly, or ".ptc", if \p DebugInfo is
/// DebugInfoType::PTC.
/// \param LinkingInfo path where the information about how the linking should
/// be stored. If an empty string, the output file name with a
/// ".li.csv" suffix will be used.
/// \param Coverage path where the information about instruction coverage
/// should be stored. If an empty string, the output file name with a
/// ".coverage.csv" suffix will be used.
/// \param EnableOSRA specify whether OSRA should be used to discover
/// additional jump targets or not.
/// \param EnableLinking specifying whether linking to QEMU helpers should be
/// performed or not.
CodeGenerator(BinaryFile &Binary,
Architecture &Target,
std::string Output,
std::string Helpers,
std::string EarlyLinked,
DebugInfoType DebugInfo,
std::string Debug,
std::string LinkingInfo,
std::string Coverage,
std::string BBSummary,
bool EnableOSRA,
bool DetectFunctionBoundaries,
bool EnableLinking,
bool ExternalCSVs);
~CodeGenerator();
/// \brief Creates an LLVM function for the code in the specified memory area.
/// If debug information has been requested, the debug source files will be
/// create in this phase.
///
/// \param VirtualAddress the address from where the translation should start.
void translate(uint64_t VirtualAddress);
/// Serialize the generated LLVM IR to the specified output path.
void serialize();
private:
/// \brief Parse the ELF headers.
/// Collect useful information such as the segments' boundaries, their
/// permissions, the address of program headers and the like.
/// From this information it produces the .li.csv file containing information
/// useful for linking.
/// This function parametric w.r.t. endianess and pointer size.
///
/// \param TheBinary the LLVM ObjectFile representing the ELF file.
/// \param LinkingInfo path where the .li.csv file should be created.
template<typename T>
void parseELF(llvm::object::ObjectFile *TheBinary,
std::string LinkingInfo,
bool UseSections);
/// \brief Import a helper function definition
///
/// Queries the HelpersModule for a function and adds it to TheModule.
///
/// \param Name name of the imported function
llvm::Function *importHelperFunctionDefinition(llvm::StringRef Name);
private:
Architecture TargetArchitecture;
llvm::LLVMContext& Context;
std::unique_ptr<llvm::Module> TheModule;
std::unique_ptr<llvm::Module> HelpersModule;
std::unique_ptr<llvm::Module> EarlyLinkedModule;
std::string OutputPath;
std::unique_ptr<DebugHelper> Debug;
BinaryFile &Binary;
unsigned OriginalInstrMDKind;
unsigned PTCInstrMDKind;
unsigned DbgMDKind;
std::string CoveragePath;
bool EnableOSRA;
std::string BBSummaryPath;
std::string FunctionListPath;
bool DetectFunctionBoundaries;
bool EnableLinking;
bool ExternalCSVs;
};
#endif // _CODEGENERATOR_H