Home | History | Annotate | Download | only in DebugInfo
      1 //===-- DWARFContext.cpp --------------------------------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #include "DWARFContext.h"
     11 #include "llvm/Support/Dwarf.h"
     12 #include "llvm/Support/Format.h"
     13 #include "llvm/Support/raw_ostream.h"
     14 #include <algorithm>
     15 using namespace llvm;
     16 using namespace dwarf;
     17 
     18 void DWARFContext::dump(raw_ostream &OS) {
     19   OS << ".debug_abbrev contents:\n";
     20   getDebugAbbrev()->dump(OS);
     21 
     22   OS << "\n.debug_info contents:\n";
     23   for (unsigned i = 0, e = getNumCompileUnits(); i != e; ++i)
     24     getCompileUnitAtIndex(i)->dump(OS);
     25 
     26   OS << "\n.debug_aranges contents:\n";
     27   DataExtractor arangesData(getARangeSection(), isLittleEndian(), 0);
     28   uint32_t offset = 0;
     29   DWARFDebugArangeSet set;
     30   while (set.extract(arangesData, &offset))
     31     set.dump(OS);
     32 
     33   OS << "\n.debug_lines contents:\n";
     34   for (unsigned i = 0, e = getNumCompileUnits(); i != e; ++i) {
     35     DWARFCompileUnit *cu = getCompileUnitAtIndex(i);
     36     unsigned stmtOffset =
     37       cu->getCompileUnitDIE()->getAttributeValueAsUnsigned(cu, DW_AT_stmt_list,
     38                                                            -1U);
     39     if (stmtOffset != -1U) {
     40       DataExtractor lineData(getLineSection(), isLittleEndian(),
     41                              cu->getAddressByteSize());
     42       DWARFDebugLine::DumpingState state(OS);
     43       DWARFDebugLine::parseStatementTable(lineData, &stmtOffset, state);
     44     }
     45   }
     46 
     47   OS << "\n.debug_str contents:\n";
     48   DataExtractor strData(getStringSection(), isLittleEndian(), 0);
     49   offset = 0;
     50   uint32_t lastOffset = 0;
     51   while (const char *s = strData.getCStr(&offset)) {
     52     OS << format("0x%8.8x: \"%s\"\n", lastOffset, s);
     53     lastOffset = offset;
     54   }
     55 }
     56 
     57 const DWARFDebugAbbrev *DWARFContext::getDebugAbbrev() {
     58   if (Abbrev)
     59     return Abbrev.get();
     60 
     61   DataExtractor abbrData(getAbbrevSection(), isLittleEndian(), 0);
     62 
     63   Abbrev.reset(new DWARFDebugAbbrev());
     64   Abbrev->parse(abbrData);
     65   return Abbrev.get();
     66 }
     67 
     68 const DWARFDebugAranges *DWARFContext::getDebugAranges() {
     69   if (Aranges)
     70     return Aranges.get();
     71 
     72   DataExtractor arangesData(getARangeSection(), isLittleEndian(), 0);
     73 
     74   Aranges.reset(new DWARFDebugAranges());
     75   Aranges->extract(arangesData);
     76   if (Aranges->isEmpty()) // No aranges in file, generate them from the DIEs.
     77     Aranges->generate(this);
     78   return Aranges.get();
     79 }
     80 
     81 const DWARFDebugLine::LineTable *
     82 DWARFContext::getLineTableForCompileUnit(DWARFCompileUnit *cu) {
     83   if (!Line)
     84     Line.reset(new DWARFDebugLine());
     85 
     86   unsigned stmtOffset =
     87     cu->getCompileUnitDIE()->getAttributeValueAsUnsigned(cu, DW_AT_stmt_list,
     88                                                          -1U);
     89   if (stmtOffset == -1U)
     90     return 0; // No line table for this compile unit.
     91 
     92   // See if the line table is cached.
     93   if (const DWARFDebugLine::LineTable *lt = Line->getLineTable(stmtOffset))
     94     return lt;
     95 
     96   // We have to parse it first.
     97   DataExtractor lineData(getLineSection(), isLittleEndian(),
     98                          cu->getAddressByteSize());
     99   return Line->getOrParseLineTable(lineData, stmtOffset);
    100 }
    101 
    102 void DWARFContext::parseCompileUnits() {
    103   uint32_t offset = 0;
    104   const DataExtractor &debug_info_data = DataExtractor(getInfoSection(),
    105                                                        isLittleEndian(), 0);
    106   while (debug_info_data.isValidOffset(offset)) {
    107     CUs.push_back(DWARFCompileUnit(*this));
    108     if (!CUs.back().extract(debug_info_data, &offset)) {
    109       CUs.pop_back();
    110       break;
    111     }
    112 
    113     offset = CUs.back().getNextCompileUnitOffset();
    114   }
    115 }
    116 
    117 namespace {
    118   struct OffsetComparator {
    119     bool operator()(const DWARFCompileUnit &LHS,
    120                     const DWARFCompileUnit &RHS) const {
    121       return LHS.getOffset() < RHS.getOffset();
    122     }
    123     bool operator()(const DWARFCompileUnit &LHS, uint32_t RHS) const {
    124       return LHS.getOffset() < RHS;
    125     }
    126     bool operator()(uint32_t LHS, const DWARFCompileUnit &RHS) const {
    127       return LHS < RHS.getOffset();
    128     }
    129   };
    130 }
    131 
    132 DWARFCompileUnit *DWARFContext::getCompileUnitForOffset(uint32_t offset) {
    133   if (CUs.empty())
    134     parseCompileUnits();
    135 
    136   DWARFCompileUnit *i = std::lower_bound(CUs.begin(), CUs.end(), offset,
    137                                          OffsetComparator());
    138   if (i != CUs.end())
    139     return &*i;
    140   return 0;
    141 }
    142 
    143 DILineInfo DWARFContext::getLineInfoForAddress(uint64_t address) {
    144   // First, get the offset of the compile unit.
    145   uint32_t cuOffset = getDebugAranges()->findAddress(address);
    146   // Retrieve the compile unit.
    147   DWARFCompileUnit *cu = getCompileUnitForOffset(cuOffset);
    148   if (!cu)
    149     return DILineInfo("<invalid>", 0, 0);
    150   // Get the line table for this compile unit.
    151   const DWARFDebugLine::LineTable *lineTable = getLineTableForCompileUnit(cu);
    152   if (!lineTable)
    153     return DILineInfo("<invalid>", 0, 0);
    154   // Get the index of the row we're looking for in the line table.
    155   uint64_t hiPC =
    156     cu->getCompileUnitDIE()->getAttributeValueAsUnsigned(cu, DW_AT_high_pc,
    157                                                          -1ULL);
    158   uint32_t rowIndex = lineTable->lookupAddress(address, hiPC);
    159   if (rowIndex == -1U)
    160     return DILineInfo("<invalid>", 0, 0);
    161 
    162   // From here, contruct the DILineInfo.
    163   const DWARFDebugLine::Row &row = lineTable->Rows[rowIndex];
    164   const std::string &fileName = lineTable->Prologue.FileNames[row.File-1].Name;
    165 
    166   return DILineInfo(fileName.c_str(), row.Line, row.Column);
    167 }
    168