Add support for fetching inlining context (stack of source code locations)
[oota-llvm.git] / lib / DebugInfo / DWARFContext.cpp
index 3f9edd305b9624a5a77c7cba594b478f5b56811e..241f55eaed2de2ea881c23138951953c4617e67c 100644 (file)
@@ -183,15 +183,11 @@ static bool getFileNameForCompileUnit(
   return true;
 }
 
-bool
-DWARFContext::getFileLineInfoForCompileUnit(DWARFCompileUnit *CU,
-                                            uint64_t Address,
-                                            bool NeedsAbsoluteFilePath,
-                                            std::string &FileName,
-                                            uint32_t &Line, uint32_t &Column) {
-  // Get the line table for this compile unit.
-  const DWARFDebugLine::LineTable *LineTable = getLineTableForCompileUnit(CU);
-  if (!LineTable)
+static bool getFileLineInfoForCompileUnit(
+    DWARFCompileUnit *CU, const DWARFDebugLine::LineTable *LineTable,
+    uint64_t Address, bool NeedsAbsoluteFilePath, std::string &FileName,
+    uint32_t &Line, uint32_t &Column) {
+  if (CU == 0 || LineTable == 0)
     return false;
   // Get the index of row we're looking for in the line table.
   uint32_t RowIndex = LineTable->lookupAddress(Address);
@@ -217,21 +213,84 @@ DILineInfo DWARFContext::getLineInfoForAddress(uint64_t Address,
   uint32_t Line = 0;
   uint32_t Column = 0;
   if (Specifier.needs(DILineInfoSpecifier::FunctionName)) {
-    const DWARFDebugInfoEntryMinimal *FunctionDIE =
-        CU->getFunctionDIEForAddress(Address);
-    if (FunctionDIE) {
-      if (const char *Name = FunctionDIE->getSubprogramName(CU))
+    // The address may correspond to instruction in some inlined function,
+    // so we have to build the chain of inlined functions and take the
+    // name of the topmost function in it.
+    const DWARFDebugInfoEntryMinimal::InlinedChain &InlinedChain =
+        CU->getInlinedChainForAddress(Address);
+    if (InlinedChain.size() > 0) {
+      const DWARFDebugInfoEntryMinimal &TopFunctionDIE = InlinedChain[0];
+      if (const char *Name = TopFunctionDIE.getSubroutineName(CU))
         FunctionName = Name;
     }
   }
   if (Specifier.needs(DILineInfoSpecifier::FileLineInfo)) {
+    const DWARFDebugLine::LineTable *LineTable =
+        getLineTableForCompileUnit(CU);
     const bool NeedsAbsoluteFilePath =
         Specifier.needs(DILineInfoSpecifier::AbsoluteFilePath);
-    getFileLineInfoForCompileUnit(CU, Address, NeedsAbsoluteFilePath,
+    getFileLineInfoForCompileUnit(CU, LineTable, Address,
+                                  NeedsAbsoluteFilePath,
                                   FileName, Line, Column);
   }
   return DILineInfo(StringRef(FileName), StringRef(FunctionName),
                     Line, Column);
 }
 
+DIInliningInfo DWARFContext::getInliningInfoForAddress(uint64_t Address,
+    DILineInfoSpecifier Specifier) {
+  DWARFCompileUnit *CU = getCompileUnitForAddress(Address);
+  if (!CU)
+    return DIInliningInfo();
+
+  const DWARFDebugInfoEntryMinimal::InlinedChain &InlinedChain =
+      CU->getInlinedChainForAddress(Address);
+  if (InlinedChain.size() == 0)
+    return DIInliningInfo();
+
+  DIInliningInfo InliningInfo;
+  uint32_t CallFile = 0, CallLine = 0, CallColumn = 0;
+  const DWARFDebugLine::LineTable *LineTable = 0;
+  for (uint32_t i = 0, n = InlinedChain.size(); i != n; i++) {
+    const DWARFDebugInfoEntryMinimal &FunctionDIE = InlinedChain[i];
+    std::string FileName = "<invalid>";
+    std::string FunctionName = "<invalid>";
+    uint32_t Line = 0;
+    uint32_t Column = 0;
+    // Get function name if necessary.
+    if (Specifier.needs(DILineInfoSpecifier::FunctionName)) {
+      if (const char *Name = FunctionDIE.getSubroutineName(CU))
+        FunctionName = Name;
+    }
+    if (Specifier.needs(DILineInfoSpecifier::FileLineInfo)) {
+      const bool NeedsAbsoluteFilePath =
+          Specifier.needs(DILineInfoSpecifier::AbsoluteFilePath);
+      if (i == 0) {
+        // For the topmost frame, initialize the line table of this
+        // compile unit and fetch file/line info from it.
+        LineTable = getLineTableForCompileUnit(CU);
+        // For the topmost routine, get file/line info from line table.
+        getFileLineInfoForCompileUnit(CU, LineTable, Address,
+                                      NeedsAbsoluteFilePath,
+                                      FileName, Line, Column);
+      } else {
+        // Otherwise, use call file, call line and call column from
+        // previous DIE in inlined chain.
+        getFileNameForCompileUnit(CU, LineTable, CallFile,
+                                  NeedsAbsoluteFilePath, FileName);
+        Line = CallLine;
+        Column = CallColumn;
+      }
+      // Get call file/line/column of a current DIE.
+      if (i + 1 < n) {
+        FunctionDIE.getCallerFrame(CU, CallFile, CallLine, CallColumn);
+      }
+    }
+    DILineInfo Frame(StringRef(FileName), StringRef(FunctionName),
+                     Line, Column);
+    InliningInfo.addFrame(Frame);
+  }
+  return InliningInfo;
+}
+
 void DWARFContextInMemory::anchor() { }