mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
cf42e497aa
This commit introduces the Function Isolation Pass. We use the information provided by the Function Boundaries Detection Pass to organize the code that `revamb` places inside the `root` function in different LLVM functions. To do this we obviously need to introduce some changes and tricks to handle the execution of the translated program. The main idea is to have two different realms (one where the isolated functions live, one in which we have basically the old root function). We start the execution from the realm of the *non isolated* functions, and we transfer, as soon as possible, the execution to the *isolated functions* realm. We then have a fallback mechanism to restore the execution in the right place in the *non isolated* functions realm, and so on. The largest change, besides the re-organization of the code in different functions, is the use of the exception handling mechanism provided by the LLVM framework in order to be able to manage the switch between the two realms. We also introduce the `support.h` header file, which contains a couple of definitions used by `support.c` and that need to be shared with some of the components involved in the translation process. We have defined some helper functions, directly in C, that we use both for handling the exception mechanism and for giving extra debug informations when an exception is raised. The `revamb-dump` utility now supports the `-i` option to specify the path were to save the new LLVM module. The `translate` utility now supports the `-i` option that produces a binary in which the function isolation has been applied. We also introduced some tests that apply the function isolation pass to the `Runtime/` tests already present. In this way we can verify that the translation and the following function isolation preserve the behavior of the program. When serializing the new LLVM module we regenerate the metadata used for debug purposes, and for doing this, since we not longer have only the `root` function, we have changed some details in the `DebugHelper` class in order to be able to emit the metadata for all the functions of our interest in a single shot.
112 lines
3.5 KiB
C++
112 lines
3.5 KiB
C++
#ifndef _DEBUGHELPER_H
|
|
#define _DEBUGHELPER_H
|
|
|
|
//
|
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
|
//
|
|
|
|
// Standard includes
|
|
#include <memory>
|
|
#include <ostream>
|
|
#include <string>
|
|
|
|
// LLVM includes
|
|
#include "llvm/IR/DIBuilder.h"
|
|
|
|
// Local includes
|
|
#include "revamb.h"
|
|
|
|
namespace llvm {
|
|
class DIBuilder;
|
|
class Module;
|
|
class DICompileUnit;
|
|
class DISubprogram;
|
|
class Function;
|
|
}
|
|
|
|
/// \brief AssemblyAnnotationWriter decorating the output withe debug
|
|
/// information
|
|
///
|
|
/// AssemblyAnnotationWriter implementation inserting in the generated LLVM IR
|
|
/// comments containing the original assembly and the PTC. It can also decorate
|
|
/// the IR with debug information (i.e. DILocations) refered to the generated
|
|
/// LLVM IR itself.
|
|
class DebugAnnotationWriter : public llvm::AssemblyAnnotationWriter {
|
|
public:
|
|
/// \brief Create a new DebugAnnotationWriter
|
|
///
|
|
/// \warning If \p DebugInfo is `true`, the produced output should be
|
|
/// discarded since it will contain errors. \p DebugInfo should be
|
|
/// set to `true` in a first run to produce the metadata, and then a
|
|
/// new DebugAnnotationWriter with `DebugInfo = false` should be
|
|
/// created and run to produce an output without errors.
|
|
///
|
|
/// \param Context the LLVM context.
|
|
/// \param Scope the scope, typically a `DISubprogram`.
|
|
/// \param DebugInfo whether to decorate the IR being serialized with debug
|
|
/// metadata refering to the produce IR itself or not.
|
|
DebugAnnotationWriter(llvm::LLVMContext& Context,
|
|
bool DebugInfo);
|
|
|
|
virtual void emitInstructionAnnot(const llvm::Instruction *TheInstruction,
|
|
llvm::formatted_raw_ostream &Output);
|
|
|
|
private:
|
|
llvm::LLVMContext &Context;
|
|
unsigned OriginalInstrMDKind;
|
|
unsigned PTCInstrMDKind;
|
|
unsigned DbgMDKind;
|
|
bool DebugInfo;
|
|
};
|
|
|
|
/// \brief Handle printing the IR in textual form, possibly with debug
|
|
/// information
|
|
class DebugHelper {
|
|
public:
|
|
/// \brief Create a new DebugHelper
|
|
///
|
|
/// \param Output path where the LLVM IR should be stored.
|
|
/// \param Debug path where the debug output should be stored. If empty, \p
|
|
/// Output will be used along with a suffix, e.g. `.pts` if \p Type is
|
|
/// DebugInfoType::PTC, `.S` if it's DebugInfoType::OriginalAssembly or
|
|
/// will match \p Output if \p Type is DebugInfoType::LLVMIR.
|
|
/// \param TheModule the LLVM module to print out.
|
|
/// \param Type type of debug information requested.
|
|
DebugHelper(std::string Output,
|
|
std::string Debug,
|
|
llvm::Module *TheModule,
|
|
DebugInfoType Type);
|
|
|
|
/// Decorates the root and the isolated functions with the requested debug
|
|
/// info
|
|
void generateDebugInfo();
|
|
|
|
/// Serializes to the given stream the module, with or without debug info
|
|
void print(std::ostream& Output, bool DebugInfo);
|
|
|
|
/// Copy the debug file to the output path, if they are the same
|
|
bool copySource();
|
|
|
|
private:
|
|
/// Create a new AssemblyAnnotationWriter
|
|
///
|
|
/// \param DebugInfo whether to create an annotator producing with debug
|
|
/// information referred to itself or not.
|
|
DebugAnnotationWriter *annotator(bool DebugInfo);
|
|
|
|
private:
|
|
std::string OutputPath;
|
|
std::string DebugPath;
|
|
llvm::DIBuilder Builder;
|
|
DebugInfoType Type;
|
|
llvm::Module *TheModule;
|
|
llvm::DICompileUnit *CompileUnit;
|
|
std::unique_ptr<DebugAnnotationWriter> Annotator;
|
|
|
|
unsigned OriginalInstrMDKind;
|
|
unsigned PTCInstrMDKind;
|
|
unsigned DbgMDKind;
|
|
};
|
|
|
|
#endif // _DEBUGHELPER_H
|