about summary refs log tree commit diff homepage
diff options
context:
space:
mode:
authorDaniel Dunbar <daniel@zuster.org>2014-09-14 15:01:05 -0700
committerDaniel Dunbar <daniel@zuster.org>2014-09-14 15:01:05 -0700
commit8ecd31572aae60ed50f487bccaad6abb7b346528 (patch)
tree0c84d99c29c250def2c29baab6981af2a1e2912e
parente90e1ab38617253f67e7c6fa682e972b1c605b78 (diff)
downloadklee-8ecd31572aae60ed50f487bccaad6abb7b346528.tar.gz
[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!
-rw-r--r--lib/Module/InstructionInfoTable.cpp31
-rw-r--r--test/Feature/SourceMapping.c55
2 files changed, 75 insertions, 11 deletions
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 Instruction*, unsigned>::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;
+}