Files
revng-revng/lib/Support/IRAnnotators.cpp
Ivan Krysak 7d235f4fd0 Enforce licence header consistency
Also do some basic cleanup: capitalize first letters, add `.`
at the end of the sentences, and so on.
2023-07-03 15:23:10 +00:00

136 lines
4.8 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/Support/Assert.h"
#include "revng/Support/FunctionTags.h"
#include "revng/Support/IRAnnotators.h"
#include "revng/Support/IRHelpers.h"
#include "revng/Support/SelfReferencingDbgAnnotationWriter.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");
}
void createOriginalAssemblyDebugInfo(Module *M, StringRef SourcePath) {
createDebugInfoFromMetadata(M, SourcePath, "oi");
}