From 8ecd31572aae60ed50f487bccaad6abb7b346528 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Sun, 14 Sep 2014 15:01:05 -0700 Subject: [Module] Try harder to associate each instruction with source level debug info. - This makes KCachegrind output look nicer, as otherwise it assumes instructions without debug info were inlined and shows some message to that effect. - This does however we might be lying a bit about the source line that an instruction came from. - This also adds a test case for our istats output, yay! --- lib/Module/InstructionInfoTable.cpp | 31 +++++++++++++-------- test/Feature/SourceMapping.c | 55 +++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 11 deletions(-) create mode 100644 test/Feature/SourceMapping.c diff --git a/lib/Module/InstructionInfoTable.cpp b/lib/Module/InstructionInfoTable.cpp index 8d27e426..eca1ae1d 100644 --- a/lib/Module/InstructionInfoTable.cpp +++ b/lib/Module/InstructionInfoTable.cpp @@ -110,22 +110,31 @@ InstructionInfoTable::InstructionInfoTable(Module *m) for (Module::iterator fnIt = m->begin(), fn_ie = m->end(); fnIt != fn_ie; ++fnIt) { + // We want to ensure that as all instructions have source information, if + // available. Clang sometimes will not write out debug information on the + // initial instructions in a function (correspond to the formal parameters), + // so we first search forward to find the first instruction with debug info, + // if any. + const std::string *initialFile = &dummyString; + unsigned initialLine = 0; + for (inst_iterator it = inst_begin(fnIt), ie = inst_end(fnIt); it != ie; + ++it) { + if (getInstructionDebugInfo(&*it, initialFile, initialLine)) + break; + } + + const std::string *file = initialFile; + unsigned line = initialLine; for (inst_iterator it = inst_begin(fnIt), ie = inst_end(fnIt); it != ie; ++it) { - const std::string *initialFile = &dummyString; - unsigned initialLine = 0; Instruction *instr = &*it; - unsigned assemblyLine = 0; + unsigned assemblyLine = lineTable[instr]; + + // Update our source level debug information. + getInstructionDebugInfo(instr, file, line); - std::map::const_iterator ltit = - lineTable.find(instr); - if (ltit!=lineTable.end()) - assemblyLine = ltit->second; - getInstructionDebugInfo(instr, initialFile, initialLine); infos.insert(std::make_pair(instr, - InstructionInfo(id++, - *initialFile, - initialLine, + InstructionInfo(id++, *file, line, assemblyLine))); } } diff --git a/test/Feature/SourceMapping.c b/test/Feature/SourceMapping.c new file mode 100644 index 00000000..0462ba0b --- /dev/null +++ b/test/Feature/SourceMapping.c @@ -0,0 +1,55 @@ +// Check that we properly associate instruction level statistics with source +// file and line. +// +// RUN: %llvmgcc %s -emit-llvm -g -O0 -c -o %t1.bc +// RUN: rm -rf %t.klee-out +// RUN: %klee --output-dir=%t.klee-out --exit-on-error %t1.bc +// RUN: FileCheck < %t.klee-out/run.istats %s + +// CHECK: positions: instr line +// CHECK: ob={{.*}}/SourceMapping.c{{.*}}/assembly.ll + +// Assuming the compiler doesn't reorder things, f0 should be first. +// CHECK: fn=f0 + +// Ensure we have a known position for the first instruction (instr and line +// should be non-zero). + +// CHECK-NEXT: fl={{.*}}/SourceMapping.c +// CHECK-NEXT: {{[1-9][0-9]*}} {{[1-9][0-9]*}} + + +// Ensure we have the right line number (and check called function markers). +// CHECK: fn=f1 +// CHECK: cfn=f0 +// CHECK-NEXT: calls=1 {{[1-9][0-9]*}} +// CHECK-NEXT: {{[1-9][0-9]*}} 48 {{.*}} + +// This check just brackets the checks above, to make sure they fall in the +// appropriate region of the run.istats file. +// +// CHECK: fn=main + + + + + + + + +// KEEP THIS AS LINE 40 + +int f0(int a, int b) { + return a + b; +} + +int f1(int a, int b) { + // f0 is called on line 48 + return f0(a, b); +} + +int main() { + int x = f1(1, 2); + + return x; +} -- cgit 1.4.1