[llvm-symbolizer] -print-source-context-lines option to print source code around...
authorMike Aizatsky <aizatsky@chromium.org>
Sat, 9 Jan 2016 00:14:35 +0000 (00:14 +0000)
committerMike Aizatsky <aizatsky@chromium.org>
Sat, 9 Jan 2016 00:14:35 +0000 (00:14 +0000)
Differential Revision: http://reviews.llvm.org/D15909

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@257236 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/DebugInfo/Symbolize/DIPrinter.h
lib/DebugInfo/Symbolize/DIPrinter.cpp
test/lit.cfg
test/tools/llvm-symbolizer/print_context.c [new file with mode: 0644]
tools/llvm-symbolizer/llvm-symbolizer.cpp

index 0703fb1..3098199 100644 (file)
@@ -28,13 +28,16 @@ class DIPrinter {
   raw_ostream &OS;
   bool PrintFunctionNames;
   bool PrintPretty;
-  void printName(const DILineInfo &Info, bool Inlined);
+  int PrintSourceContext;
+
+  void print(const DILineInfo &Info, bool Inlined);
+  void printContext(std::string FileName, int64_t Line);
 
 public:
   DIPrinter(raw_ostream &OS, bool PrintFunctionNames = true,
-            bool PrintPretty = false)
+            bool PrintPretty = false, int PrintSourceContext = 0)
       : OS(OS), PrintFunctionNames(PrintFunctionNames),
-        PrintPretty(PrintPretty) {}
+        PrintPretty(PrintPretty), PrintSourceContext(PrintSourceContext) {}
 
   DIPrinter &operator<<(const DILineInfo &Info);
   DIPrinter &operator<<(const DIInliningInfo &Info);
index c6bfbc0..7d7ace0 100644 (file)
@@ -15,6 +15,7 @@
 #include "llvm/DebugInfo/Symbolize/DIPrinter.h"
 
 #include "llvm/DebugInfo/DIContext.h"
+#include "llvm/Support/LineIterator.h"
 
 namespace llvm {
 namespace symbolize {
@@ -24,7 +25,36 @@ namespace symbolize {
 static const char kDILineInfoBadString[] = "<invalid>";
 static const char kBadString[] = "??";
 
-void DIPrinter::printName(const DILineInfo &Info, bool Inlined) {
+// Prints source code around in the FileName the Line.
+void DIPrinter::printContext(std::string FileName, int64_t Line) {
+  if (PrintSourceContext <= 0)
+    return;
+
+  ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
+      MemoryBuffer::getFile(FileName);
+  if (!BufOrErr)
+    return;
+
+  std::unique_ptr<MemoryBuffer> Buf = std::move(BufOrErr.get());
+  int64_t FirstLine = std::max(1l, Line - PrintSourceContext / 2);
+  int64_t LastLine = FirstLine + PrintSourceContext;
+  size_t MaxLineNumberWidth = std::ceil(std::log10(LastLine));
+
+  for (line_iterator I = line_iterator(*Buf, false);
+       !I.is_at_eof() && I.line_number() <= LastLine; ++I) {
+    int64_t L = I.line_number();
+    if (L >= FirstLine && L <= LastLine) {
+      OS << format_decimal(L, MaxLineNumberWidth);
+      if (L == Line)
+        OS << " >: ";
+      else
+        OS << "  : ";
+      OS << *I << "\n";
+    }
+  }
+}
+
+void DIPrinter::print(const DILineInfo &Info, bool Inlined) {
   if (PrintFunctionNames) {
     std::string FunctionName = Info.FunctionName;
     if (FunctionName == kDILineInfoBadString)
@@ -38,21 +68,22 @@ void DIPrinter::printName(const DILineInfo &Info, bool Inlined) {
   if (Filename == kDILineInfoBadString)
     Filename = kBadString;
   OS << Filename << ":" << Info.Line << ":" << Info.Column << "\n";
+  printContext(Filename, Info.Line);
 }
 
 DIPrinter &DIPrinter::operator<<(const DILineInfo &Info) {
-  printName(Info, false);
+  print(Info, false);
   return *this;
 }
 
 DIPrinter &DIPrinter::operator<<(const DIInliningInfo &Info) {
   uint32_t FramesNum = Info.getNumberOfFrames();
   if (FramesNum == 0) {
-    printName(DILineInfo(), false);
+    print(DILineInfo(), false);
     return *this;
   }
   for (uint32_t i = 0; i < FramesNum; i++)
-    printName(Info.getFrame(i), i > 0);
+    print(Info.getFrame(i), i > 0);
   return *this;
 }
 
index 5cc4d6e..e06c10f 100644 (file)
@@ -194,6 +194,7 @@ config.substitutions.append( ('%llvmshlibdir', config.llvm_shlib_dir) )
 config.substitutions.append( ('%shlibext', config.llvm_shlib_ext) )
 config.substitutions.append( ('%exeext', config.llvm_exe_ext) )
 config.substitutions.append( ('%python', config.python_executable) )
+config.substitutions.append( ('%host_cc', config.host_cc) )
 
 # OCaml substitutions.
 # Support tests for both native and bytecode builds.
@@ -276,6 +277,7 @@ for pattern in [r"\bbugpoint\b(?!-)",
                 r"\bllvm-split\b",
                 r"\bllvm-tblgen\b",
                 r"\bllvm-c-test\b",
+                NOJUNK + r"\bllvm-symbolizer\b",
                 NOJUNK + r"\bopt\b",
                 r"\bFileCheck\b",
                 r"\bobj2yaml\b",
diff --git a/test/tools/llvm-symbolizer/print_context.c b/test/tools/llvm-symbolizer/print_context.c
new file mode 100644 (file)
index 0000000..f1860e9
--- /dev/null
@@ -0,0 +1,22 @@
+// REQUIRES: x86_64-linux
+// RUN: %host_cc -O0 -g %s -o %t 2>&1
+// RUN: %t 2>&1 | llvm-symbolizer -print-source-context-lines=5 -obj=%t | FileCheck %s --check-prefix=CHECK
+
+#include <stdio.h>
+
+int inc(int a) {
+  return a + 1;
+}
+
+int main() {
+  printf("%p\n", inc);
+  return 0;
+}
+
+// CHECK: inc
+// CHECK: print_context.c:7
+// CHECK: 5  : #include
+// CHECK: 6  :
+// CHECK: 7 >: int inc
+// CHECK: 8  :   return
+// CHECK: 9  : }
index a4dfc2e..9503493 100644 (file)
@@ -82,6 +82,10 @@ static cl::opt<bool>
     ClPrettyPrint("pretty-print", cl::init(false),
                   cl::desc("Make the output more human friendly"));
 
+static cl::opt<int> ClPrintSourceContextLines(
+    "print-source-context-lines", cl::init(0),
+    cl::desc("Print N number of source file context"));
+
 static bool error(std::error_code ec) {
   if (!ec)
     return false;
@@ -155,7 +159,7 @@ int main(int argc, char **argv) {
   LLVMSymbolizer Symbolizer(Opts);
 
   DIPrinter Printer(outs(), ClPrintFunctions != FunctionNameKind::None,
-                    ClPrettyPrint);
+                    ClPrettyPrint, ClPrintSourceContextLines);
 
   const int kMaxInputStringLength = 1024;
   char InputString[kMaxInputStringLength];