klee
InstructionInfoTable.cpp
Go to the documentation of this file.
1//===-- InstructionInfoTable.cpp ------------------------------------------===//
2//
3// The KLEE Symbolic Virtual Machine
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
11#include "klee/Config/Version.h"
12
13#include "llvm/Analysis/ValueTracking.h"
14#include "llvm/IR/AssemblyAnnotationWriter.h"
15#include "llvm/IR/DebugInfo.h"
16#include "llvm/IR/DebugInfoMetadata.h"
17#include "llvm/IR/Function.h"
18#include "llvm/IR/InstIterator.h"
19#include "llvm/IR/Instructions.h"
20#include "llvm/IR/IntrinsicInst.h"
21#include "llvm/IR/LLVMContext.h"
22#include "llvm/IR/Module.h"
23#include "llvm/Linker/Linker.h"
24#include "llvm/Support/ErrorHandling.h"
25#include "llvm/Support/FormattedStream.h"
26#include "llvm/Support/Path.h"
27#include "llvm/Support/raw_ostream.h"
28
29#include <cstdint>
30#include <map>
31#include <string>
32
33using namespace klee;
34
35class InstructionToLineAnnotator : public llvm::AssemblyAnnotationWriter {
36public:
37 void emitInstructionAnnot(const llvm::Instruction *i,
38 llvm::formatted_raw_ostream &os) {
39 os << "%%%";
40 os << reinterpret_cast<std::uintptr_t>(i);
41 }
42
43 void emitFunctionAnnot(const llvm::Function *f,
44 llvm::formatted_raw_ostream &os) {
45 os << "%%%";
46 os << reinterpret_cast<std::uintptr_t>(f);
47 }
48};
49
50static std::map<uintptr_t, uint64_t>
51buildInstructionToLineMap(const llvm::Module &m) {
52
53 std::map<uintptr_t, uint64_t> mapping;
55 std::string str;
56
57 llvm::raw_string_ostream os(str);
58 m.print(os, &a);
59 os.flush();
60
61 const char *s;
62
63 unsigned line = 1;
64 for (s=str.c_str(); *s; s++) {
65 if (*s != '\n')
66 continue;
67
68 line++;
69 if (s[1] != '%' || s[2] != '%' || s[3] != '%')
70 continue;
71
72 s += 4;
73 char *end;
74 uint64_t value = strtoull(s, &end, 10);
75 if (end != s) {
76 mapping.insert(std::make_pair(value, line));
77 }
78 s = end;
79 }
80
81 return mapping;
82}
83
85 std::vector<std::unique_ptr<std::string>> &internedStrings;
86 std::map<uintptr_t, uint64_t> lineTable;
87
88 const llvm::Module &module;
89
90public:
92 std::vector<std::unique_ptr<std::string>> &_internedStrings,
93 const llvm::Module &_module)
94 : internedStrings(_internedStrings), module(_module) {
96 }
97
98 std::string &getInternedString(const std::string &s) {
99 auto found = std::find_if(internedStrings.begin(), internedStrings.end(),
100 [&s](const std::unique_ptr<std::string> &item) {
101 return *item.get() == s;
102 });
103 if (found != internedStrings.end())
104 return *found->get();
105
106 auto newItem = std::unique_ptr<std::string>(new std::string(s));
107 auto result = newItem.get();
108
109 internedStrings.emplace_back(std::move(newItem));
110 return *result;
111 }
112
113 std::unique_ptr<FunctionInfo> getFunctionInfo(const llvm::Function &Func) {
114 auto asmLine = lineTable.at(reinterpret_cast<std::uintptr_t>(&Func));
115 auto dsub = Func.getSubprogram();
116
117 if (dsub != nullptr) {
118 auto path = dsub->getFilename();
119 return std::make_unique<FunctionInfo>(FunctionInfo(
120 0, getInternedString(path.str()), dsub->getLine(), asmLine));
121 }
122
123 // Fallback: Mark as unknown
124 return std::make_unique<FunctionInfo>(
125 FunctionInfo(0, getInternedString(""), 0, asmLine));
126 }
127
128 std::unique_ptr<InstructionInfo>
129 getInstructionInfo(const llvm::Instruction &Inst, const FunctionInfo *f) {
130 auto asmLine = lineTable.at(reinterpret_cast<std::uintptr_t>(&Inst));
131
132 // Retrieve debug information associated with instruction
133 auto dl = Inst.getDebugLoc();
134
135 // Check if a valid debug location is assigned to the instruction.
136 if (dl.get() != nullptr) {
137 auto full_path = dl.get()->getFilename();
138 auto line = dl.getLine();
139 auto column = dl.getCol();
140
141 // Still, if the line is unknown, take the context of the instruction to
142 // narrow it down
143 if (line == 0) {
144 if (auto LexicalBlock =
145 llvm::dyn_cast<llvm::DILexicalBlock>(dl.getScope())) {
146 line = LexicalBlock->getLine();
147 column = LexicalBlock->getColumn();
148 }
149 }
150 return std::make_unique<InstructionInfo>(InstructionInfo(
151 0, getInternedString(full_path.str()), line, column, asmLine));
152 }
153
154 if (f != nullptr)
155 // If nothing found, use the surrounding function
156 return std::make_unique<InstructionInfo>(
157 InstructionInfo(0, f->file, f->line, 0, asmLine));
158 // If nothing found, use the surrounding function
159 return std::make_unique<InstructionInfo>(
160 InstructionInfo(0, getInternedString(""), 0, 0, asmLine));
161 }
162};
163
164InstructionInfoTable::InstructionInfoTable(const llvm::Module &m) {
165 // Generate all debug instruction information
167 for (const auto &Func : m) {
168 auto F = DI.getFunctionInfo(Func);
169 auto FR = F.get();
170 functionInfos.insert(std::make_pair(&Func, std::move(F)));
171
172 for (auto it = llvm::inst_begin(Func), ie = llvm::inst_end(Func); it != ie;
173 ++it) {
174 auto instr = &*it;
175 infos.insert(std::make_pair(instr, DI.getInstructionInfo(*instr, FR)));
176 }
177 }
178
179 // Make sure that every item has a unique ID
180 size_t idCounter = 0;
181 for (auto &item : infos)
182 item.second->id = idCounter++;
183 for (auto &item : functionInfos)
184 item.second->id = idCounter++;
185}
186
188 return infos.size() + functionInfos.size();
189}
190
191const InstructionInfo &
192InstructionInfoTable::getInfo(const llvm::Instruction &inst) const {
193 auto it = infos.find(&inst);
194 if (it == infos.end())
195 llvm::report_fatal_error("invalid instruction, not present in "
196 "initial module!");
197 return *it->second.get();
198}
199
200const FunctionInfo &
201InstructionInfoTable::getFunctionInfo(const llvm::Function &f) const {
202 auto found = functionInfos.find(&f);
203 if (found == functionInfos.end())
204 llvm::report_fatal_error("invalid instruction, not present in "
205 "initial module!");
206
207 return *found->second.get();
208}
static std::map< uintptr_t, uint64_t > buildInstructionToLineMap(const llvm::Module &m)
DebugInfoExtractor(std::vector< std::unique_ptr< std::string > > &_internedStrings, const llvm::Module &_module)
const llvm::Module & module
std::map< uintptr_t, uint64_t > lineTable
std::unique_ptr< FunctionInfo > getFunctionInfo(const llvm::Function &Func)
std::string & getInternedString(const std::string &s)
std::vector< std::unique_ptr< std::string > > & internedStrings
std::unique_ptr< InstructionInfo > getInstructionInfo(const llvm::Instruction &Inst, const FunctionInfo *f)
void emitFunctionAnnot(const llvm::Function *f, llvm::formatted_raw_ostream &os)
void emitInstructionAnnot(const llvm::Instruction *i, llvm::formatted_raw_ostream &os)
std::unordered_map< const llvm::Instruction *, std::unique_ptr< InstructionInfo > > infos
const FunctionInfo & getFunctionInfo(const llvm::Function &) const
const InstructionInfo & getInfo(const llvm::Instruction &) const
std::unordered_map< const llvm::Function *, std::unique_ptr< FunctionInfo > > functionInfos
std::vector< std::unique_ptr< std::string > > internedStrings
int line
Definition: klee.h:74
Definition: main.cpp:291
FunctionInfo stores debug information for a KFunction.
unsigned line
Line number in source file.
const std::string & file
Source file name.
InstructionInfo stores debug information for a KInstruction.