Files
revng-revng/lib/Lift/IRAnnotators.cpp
Alessandro Di Federico 1429b526ab Introduce libtcg
This commit drops libptc in favor of its new form libtcg.

It brings several improvements, among which:

* The QEMU version we work on has been upgraded.
* CPUStateAccessAnalysis has been reimplemented in a way that makes it
  easier to debug and solves some limitations (e.g., tracking leaking
  pointers).
* Identification of pieces of the CPU state that are read by each helper
  and fixing access to the CPU state is now performed at build-time.
* We no longer mmap the code we need to translate, dropping all the
  issues related to code that needed to be mapped where something is
  already present.
* We now have two distinct flavors of helper modules: the full one and
  the "slim" one. The latter contains the definition only of functions
  we intend to inline. It is used in most of the pipeline, a good thing
  since we spend less time optimizing code we don't really care about.
  The full module is only used on the re-compilation branch of the
  pipeline.
* We no longer split the `cpu_loop` function.
* We change MetaAddress to rely on architectures from `model::` as
  opposed to the LLVM ones.
* We no longer attach debug info to LLVM IR containing the original
  assembly.
* We now verify that the lifted code only contains code we expect.
2025-10-31 17:25:03 +01:00

132 lines
4.6 KiB
C++

/// \file IRAnnotators.cpp
/// This file handles debugging information generation.
//
// This file is distributed under the MIT License. See LICENSE.md for details.
//
#include <fstream>
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/DIBuilder.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/raw_os_ostream.h"
#include "revng/Lift/IRAnnotators.h"
#include "revng/Lift/SelfReferencingDbgAnnotationWriter.h"
#include "revng/Model/FunctionTags.h"
#include "revng/Support/Assert.h"
#include "revng/Support/IRHelpers.h"
using namespace llvm;
/// Add a module flag, if not already present, using name and value provided.
/// Used for creating the Dwarf compliant debug info.
static void addModuleFlag(Module *M, StringRef Flag, uint32_t Value) {
if (M->getModuleFlag(Flag) == nullptr) {
M->addModuleFlag(Module::Warning, Flag, Value);
}
}
static void createModuleDebugInfo(Module *M, llvm::StringRef SourcePath) {
DIBuilder Builder(*M);
auto File = Builder.createFile(SourcePath, "");
DICompileUnit *CompileUnit = nullptr;
CompileUnit = Builder.createCompileUnit(dwarf::DW_LANG_C,
File,
"revng",
false,
"",
0 /* Runtime version */);
// Add the current debug info version into the module after checking if it
// is already present.
addModuleFlag(M, "Debug Info Version", DEBUG_METADATA_VERSION);
addModuleFlag(M, "Dwarf Version", 4);
for (Function &F : M->functions()) {
if (isRootOrLifted(&F)) {
DISubroutineType *EmptyType = nullptr;
DITypeRefArray EmptyArrayType = Builder.getOrCreateTypeArray({});
EmptyType = Builder.createSubroutineType(EmptyArrayType);
revng_assert(CompileUnit != nullptr);
DISubprogram *Subprogram = nullptr;
auto SPFlags = DISubprogram::toSPFlags(false, /* isLocalToUnit */
true, /* isDefinition */
false /* isOptimized */);
Subprogram = Builder.createFunction(CompileUnit->getFile(), // Scope
F.getName(), // Name
StringRef(), // LinkageName
CompileUnit->getFile(), // File
1, // LineNo
EmptyType, // Ty (subroutine type)
1, // ScopeLine
DINode::FlagPrototyped, // Flags
SPFlags);
F.setSubprogram(Subprogram);
}
}
Builder.finalize();
}
void createSelfReferencingDebugInfo(Module *M,
StringRef SourcePath,
AssemblyAnnotationWriter *InnerAAW) {
createModuleDebugInfo(M, SourcePath);
SelfReferencingDbgAnnotationWriter Annotator(M->getContext(), InnerAAW);
raw_null_ostream NullStream;
M->print(NullStream, &Annotator);
}
static void createDebugInfoFromMetadata(Module *M,
StringRef SourcePath,
StringRef MetadataName) {
createModuleDebugInfo(M, SourcePath);
std::ofstream SourceOutputStream(SourcePath.str());
raw_os_ostream SourceOutput(SourceOutputStream);
// Generate the source file and the debugging information in tandem
unsigned LineIndex = 1;
unsigned MetadataKind = M->getContext().getMDKindID(MetadataName);
unsigned DbgKind = M->getContext().getMDKindID("dbg");
StringRef Last;
for (Function &F : M->functions()) {
if (not isRootOrLifted(&F))
continue;
if (DISubprogram *CurrentSubprogram = F.getSubprogram()) {
for (BasicBlock &Block : F) {
for (Instruction &I : Block) {
StringRef Body = getText(&I, MetadataKind);
if (Body.size() != 0 && Last != Body) {
Last = Body;
SourceOutput << Body.data();
auto *Location = DILocation::get(M->getContext(),
LineIndex,
0,
CurrentSubprogram);
I.setMetadata(DbgKind, Location);
LineIndex += std::count(Body.begin(), Body.end(), '\n');
}
}
}
}
}
}
void createPTCDebugInfo(Module *M, StringRef SourcePath) {
createDebugInfoFromMetadata(M, SourcePath, "pi");
}