[Lldb-commits] [lldb] 945aa52 - [LLDB][NativePDB] Add support for inlined functions

Zequan Wu via lldb-commits lldb-commits at lists.llvm.org
Tue Jan 11 16:10:53 PST 2022


Author: Zequan Wu
Date: 2022-01-11T16:10:39-08:00
New Revision: 945aa520ef07a3edb655f3f38e4c3023658dd623

URL: https://github.com/llvm/llvm-project/commit/945aa520ef07a3edb655f3f38e4c3023658dd623
DIFF: https://github.com/llvm/llvm-project/commit/945aa520ef07a3edb655f3f38e4c3023658dd623.diff

LOG: [LLDB][NativePDB] Add support for inlined functions

This adds inline function support to NativePDB by parsing S_INLINESITE records
to retrieve inlinee line info and add them into line table at `ParseLineTable`.

Differential Revision: https://reviews.llvm.org/D116845

Added: 
    lldb/test/Shell/SymbolFile/NativePDB/Inputs/inline_sites.lldbinit
    lldb/test/Shell/SymbolFile/NativePDB/inline_sites.s

Modified: 
    lldb/include/lldb/Symbol/LineTable.h
    lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp
    lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h
    lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
    lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h

Removed: 
    


################################################################################
diff  --git a/lldb/include/lldb/Symbol/LineTable.h b/lldb/include/lldb/Symbol/LineTable.h
index 5cd22bd831eef..b5121b29fe028 100644
--- a/lldb/include/lldb/Symbol/LineTable.h
+++ b/lldb/include/lldb/Symbol/LineTable.h
@@ -206,7 +206,6 @@ class LineTable {
 
   LineTable *LinkLineTable(const FileRangeMap &file_range_map);
 
-protected:
   struct Entry {
     Entry()
         : line(0), is_start_of_statement(false), is_start_of_basic_block(false),
@@ -303,6 +302,7 @@ class LineTable {
     uint16_t file_idx = 0;
   };
 
+protected:
   struct EntrySearchInfo {
     LineTable *line_table;
     lldb_private::Section *a_section;

diff  --git a/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp
index 9f09c0accc876..d8f737612c257 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp
@@ -106,6 +106,24 @@ static void ParseExtendedInfo(PdbIndex &index, CompilandIndexItem &item) {
   }
 }
 
+static void ParseInlineeLineTableForCompileUnit(CompilandIndexItem &item) {
+  for (const auto &ss : item.m_debug_stream.getSubsectionsArray()) {
+    if (ss.kind() != DebugSubsectionKind::InlineeLines)
+      continue;
+
+    DebugInlineeLinesSubsectionRef inlinee_lines;
+    llvm::BinaryStreamReader reader(ss.getRecordData());
+    if (llvm::Error error = inlinee_lines.initialize(reader)) {
+      consumeError(std::move(error));
+      continue;
+    }
+
+    for (const InlineeSourceLine &Line : inlinee_lines) {
+      item.m_inline_map[Line.Header->Inlinee] = Line;
+    }
+  }
+}
+
 CompilandIndexItem::CompilandIndexItem(
     PdbCompilandId id, llvm::pdb::ModuleDebugStreamRef debug_stream,
     llvm::pdb::DbiModuleDescriptor descriptor)
@@ -142,6 +160,7 @@ CompilandIndexItem &CompileUnitIndex::GetOrCreateCompiland(uint16_t modi) {
   cci = std::make_unique<CompilandIndexItem>(
       PdbCompilandId{modi}, std::move(debug_stream), std::move(descriptor));
   ParseExtendedInfo(m_index, *cci);
+  ParseInlineeLineTableForCompileUnit(*cci);
 
   cci->m_strings.initialize(debug_stream.getSubsectionsArray());
   PDBStringTable &strings = cantFail(m_index.pdb().getStringTable());

diff  --git a/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h b/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h
index 088de970cbf32..4ad27de986954 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h
@@ -9,10 +9,12 @@
 #ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_COMPILEUNITINDEX_H
 #define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_COMPILEUNITINDEX_H
 
+#include "lldb/Utility/RangeMap.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/IntervalMap.h"
 #include "llvm/ADT/Optional.h"
+#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
 #include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"
 #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
@@ -69,6 +71,17 @@ struct CompilandIndexItem {
   // command line, etc.  This usually contains exactly 5 items which
   // are references to other strings.
   llvm::SmallVector<llvm::codeview::TypeIndex, 5> m_build_info;
+
+  // Inlinee lines table in this compile unit.
+  std::map<llvm::codeview::TypeIndex, llvm::codeview::InlineeSourceLine>
+      m_inline_map;
+
+  // It's the line table parsed from DEBUG_S_LINES sections, mapping the file
+  // address range to file index and source line number.
+  using GlobalLineTable =
+      lldb_private::RangeDataVector<lldb::addr_t, uint32_t,
+                                    std::pair<uint32_t, uint32_t>>;
+  GlobalLineTable m_global_line_table;
 };
 
 /// Indexes information about all compile units.  This is really just a map of

diff  --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
index e859b1d5a86cf..578b369945d01 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -330,31 +330,65 @@ uint32_t SymbolFileNativePDB::CalculateNumCompileUnits() {
 Block &SymbolFileNativePDB::CreateBlock(PdbCompilandSymId block_id) {
   CompilandIndexItem *cii = m_index->compilands().GetCompiland(block_id.modi);
   CVSymbol sym = cii->m_debug_stream.readSymbolAtOffset(block_id.offset);
-
-  if (sym.kind() == S_GPROC32 || sym.kind() == S_LPROC32) {
-    // This is a function.  It must be global.  Creating the Function entry for
-    // it automatically creates a block for it.
-    CompUnitSP comp_unit = GetOrCreateCompileUnit(*cii);
-    return GetOrCreateFunction(block_id, *comp_unit)->GetBlock(false);
-  }
-
-  lldbassert(sym.kind() == S_BLOCK32);
-
-  // This is a block.  Its parent is either a function or another block.  In
-  // either case, its parent can be viewed as a block (e.g. a function contains
-  // 1 big block.  So just get the parent block and add this block to it.
-  BlockSym block(static_cast<SymbolRecordKind>(sym.kind()));
-  cantFail(SymbolDeserializer::deserializeAs<BlockSym>(sym, block));
-  lldbassert(block.Parent != 0);
-  PdbCompilandSymId parent_id(block_id.modi, block.Parent);
-  Block &parent_block = GetOrCreateBlock(parent_id);
+  CompUnitSP comp_unit = GetOrCreateCompileUnit(*cii);
   lldb::user_id_t opaque_block_uid = toOpaqueUid(block_id);
   BlockSP child_block = std::make_shared<Block>(opaque_block_uid);
-  parent_block.AddChild(child_block);
 
-  m_ast->GetOrCreateBlockDecl(block_id);
+  switch (sym.kind()) {
+  case S_GPROC32:
+  case S_LPROC32: {
+    // This is a function.  It must be global.  Creating the Function entry
+    // for it automatically creates a block for it.
+    FunctionSP func = GetOrCreateFunction(block_id, *comp_unit);
+    Block &block = func->GetBlock(false);
+    if (block.GetNumRanges() == 0)
+      block.AddRange(Block::Range(0, func->GetAddressRange().GetByteSize()));
+    return block;
+  }
+  case S_BLOCK32: {
+    // This is a block.  Its parent is either a function or another block.  In
+    // either case, its parent can be viewed as a block (e.g. a function
+    // contains 1 big block.  So just get the parent block and add this block
+    // to it.
+    BlockSym block(static_cast<SymbolRecordKind>(sym.kind()));
+    cantFail(SymbolDeserializer::deserializeAs<BlockSym>(sym, block));
+    lldbassert(block.Parent != 0);
+    PdbCompilandSymId parent_id(block_id.modi, block.Parent);
+    Block &parent_block = GetOrCreateBlock(parent_id);
+    parent_block.AddChild(child_block);
+    m_ast->GetOrCreateBlockDecl(block_id);
+    m_blocks.insert({opaque_block_uid, child_block});
+    break;
+  }
+  case S_INLINESITE: {
+    // This ensures line table is parsed first so we have inline sites info.
+    comp_unit->GetLineTable();
+
+    std::shared_ptr<InlineSite> inline_site = m_inline_sites[opaque_block_uid];
+    Block &parent_block = GetOrCreateBlock(inline_site->parent_id);
+    parent_block.AddChild(child_block);
+
+    // Copy ranges from InlineSite to Block.
+    for (size_t i = 0; i < inline_site->ranges.GetSize(); ++i) {
+      auto *entry = inline_site->ranges.GetEntryAtIndex(i);
+      child_block->AddRange(
+          Block::Range(entry->GetRangeBase(), entry->GetByteSize()));
+    }
+    child_block->FinalizeRanges();
+
+    // Get the inlined function callsite info.
+    Declaration &decl = inline_site->inline_function_info->GetDeclaration();
+    Declaration &callsite = inline_site->inline_function_info->GetCallSite();
+    child_block->SetInlinedFunctionInfo(
+        inline_site->inline_function_info->GetName().GetCString(), nullptr,
+        &decl, &callsite);
+    m_blocks.insert({opaque_block_uid, child_block});
+    break;
+  }
+  default:
+    lldbassert(false && "Symbol is not a block!");
+  }
 
-  m_blocks.insert({opaque_block_uid, child_block});
   return *child_block;
 }
 
@@ -971,16 +1005,22 @@ uint32_t SymbolFileNativePDB::ResolveSymbolContext(
         continue;
       if (type == PDB_SymType::Function) {
         sc.function = GetOrCreateFunction(csid, *sc.comp_unit).get();
-        sc.block = sc.GetFunctionBlock();
+        Block &block = sc.function->GetBlock(true);
+        addr_t func_base =
+            sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
+        addr_t offset = file_addr - func_base;
+        sc.block = block.FindInnermostBlockByOffset(offset);
       }
 
       if (type == PDB_SymType::Block) {
         sc.block = &GetOrCreateBlock(csid);
         sc.function = sc.block->CalculateSymbolContextFunction();
       }
-    resolved_flags |= eSymbolContextFunction;
-    resolved_flags |= eSymbolContextBlock;
-    break;
+      if (sc.function)
+        resolved_flags |= eSymbolContextFunction;
+      if (sc.block)
+        resolved_flags |= eSymbolContextBlock;
+      break;
     }
   }
 
@@ -998,43 +1038,24 @@ uint32_t SymbolFileNativePDB::ResolveSymbolContext(
 uint32_t SymbolFileNativePDB::ResolveSymbolContext(
     const SourceLocationSpec &src_location_spec,
     lldb::SymbolContextItem resolve_scope, SymbolContextList &sc_list) {
-  return 0;
-}
-
-static void AppendLineEntryToSequence(LineTable &table, LineSequence &sequence,
-                                      const CompilandIndexItem &cci,
-                                      lldb::addr_t base_addr,
-                                      uint32_t file_number,
-                                      const LineFragmentHeader &block,
-                                      const LineNumberEntry &cur) {
-  LineInfo cur_info(cur.Flags);
-
-  if (cur_info.isAlwaysStepInto() || cur_info.isNeverStepInto())
-    return;
-
-  uint64_t addr = base_addr + cur.Offset;
-
-  bool is_statement = cur_info.isStatement();
-  bool is_prologue = IsFunctionPrologue(cci, addr);
-  bool is_epilogue = IsFunctionEpilogue(cci, addr);
-
-  uint32_t lno = cur_info.getStartLine();
-
-  table.AppendLineEntryToSequence(&sequence, addr, lno, 0, file_number,
-                                  is_statement, false, is_prologue, is_epilogue,
-                                  false);
-}
+  std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+  const uint32_t prev_size = sc_list.GetSize();
+  if (resolve_scope & eSymbolContextCompUnit) {
+    for (uint32_t cu_idx = 0, num_cus = GetNumCompileUnits(); cu_idx < num_cus;
+         ++cu_idx) {
+      CompileUnit *cu = ParseCompileUnitAtIndex(cu_idx).get();
+      if (!cu)
+        continue;
 
-static void TerminateLineSequence(LineTable &table,
-                                  const LineFragmentHeader &block,
-                                  lldb::addr_t base_addr, uint32_t file_number,
-                                  uint32_t last_line,
-                                  std::unique_ptr<LineSequence> seq) {
-  // The end is always a terminal entry, so insert it regardless.
-  table.AppendLineEntryToSequence(seq.get(), base_addr + block.CodeSize,
-                                  last_line, 0, file_number, false, false,
-                                  false, false, true);
-  table.InsertSequence(seq.get());
+      bool file_spec_matches_cu_file_spec = FileSpec::Match(
+          src_location_spec.GetFileSpec(), cu->GetPrimaryFile());
+      if (file_spec_matches_cu_file_spec) {
+        cu->ResolveSymbolContext(src_location_spec, resolve_scope, sc_list);
+        break;
+      }
+    }
+  }
+  return sc_list.GetSize() - prev_size;
 }
 
 bool SymbolFileNativePDB::ParseLineTable(CompileUnit &comp_unit) {
@@ -1045,16 +1066,21 @@ bool SymbolFileNativePDB::ParseLineTable(CompileUnit &comp_unit) {
   std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
   PdbSymUid cu_id(comp_unit.GetID());
   lldbassert(cu_id.kind() == PdbSymUidKind::Compiland);
-  CompilandIndexItem *cci =
-      m_index->compilands().GetCompiland(cu_id.asCompiland().modi);
-  lldbassert(cci);
-  auto line_table = std::make_unique<LineTable>(&comp_unit);
+  uint16_t modi = cu_id.asCompiland().modi;
+  CompilandIndexItem *cii = m_index->compilands().GetCompiland(modi);
+  lldbassert(cii);
+
+  // Parse DEBUG_S_LINES subsections first, then parse all S_INLINESITE records
+  // in this CU. Add line entries into the set first so that if there are line
+  // entries with same addres, the later is always more accurate than the
+  // former.
+  std::set<LineTable::Entry, LineTableEntryComparator> line_set;
 
   // This is basically a copy of the .debug$S subsections from all original COFF
   // object files merged together with address relocations applied.  We are
   // looking for all DEBUG_S_LINES subsections.
   for (const DebugSubsectionRecord &dssr :
-       cci->m_debug_stream.getSubsectionsArray()) {
+       cii->m_debug_stream.getSubsectionsArray()) {
     if (dssr.kind() != DebugSubsectionKind::Lines)
       continue;
 
@@ -1069,42 +1095,111 @@ bool SymbolFileNativePDB::ParseLineTable(CompileUnit &comp_unit) {
     uint64_t virtual_addr =
         m_index->MakeVirtualAddress(lfh->RelocSegment, lfh->RelocOffset);
 
-    const auto &checksums = cci->m_strings.checksums().getArray();
-    const auto &strings = cci->m_strings.strings();
     for (const LineColumnEntry &group : lines) {
-      // Indices in this structure are actually offsets of records in the
-      // DEBUG_S_FILECHECKSUMS subsection.  Those entries then have an index
-      // into the global PDB string table.
-      auto iter = checksums.at(group.NameIndex);
-      if (iter == checksums.end())
+      llvm::Expected<uint32_t> file_index_or_err =
+          GetFileIndex(*cii, group.NameIndex);
+      if (!file_index_or_err)
         continue;
+      uint32_t file_index = file_index_or_err.get();
+      lldbassert(!group.LineNumbers.empty());
+      CompilandIndexItem::GlobalLineTable::Entry line_entry(
+          LLDB_INVALID_ADDRESS, 0);
+      for (const LineNumberEntry &entry : group.LineNumbers) {
+        LineInfo cur_info(entry.Flags);
 
-      llvm::Expected<llvm::StringRef> efn =
-          strings.getString(iter->FileNameOffset);
-      if (!efn) {
-        llvm::consumeError(efn.takeError());
-        continue;
-      }
+        if (cur_info.isAlwaysStepInto() || cur_info.isNeverStepInto())
+          continue;
 
-      // LLDB wants the index of the file in the list of support files.
-      auto fn_iter = llvm::find(cci->m_file_list, *efn);
-      lldbassert(fn_iter != cci->m_file_list.end());
-      uint32_t file_index = std::distance(cci->m_file_list.begin(), fn_iter);
+        uint64_t addr = virtual_addr + entry.Offset;
 
-      std::unique_ptr<LineSequence> sequence(
-          line_table->CreateLineSequenceContainer());
-      lldbassert(!group.LineNumbers.empty());
+        bool is_statement = cur_info.isStatement();
+        bool is_prologue = IsFunctionPrologue(*cii, addr);
+        bool is_epilogue = IsFunctionEpilogue(*cii, addr);
 
-      for (const LineNumberEntry &entry : group.LineNumbers) {
-        AppendLineEntryToSequence(*line_table, *sequence, *cci, virtual_addr,
-                                  file_index, *lfh, entry);
+        uint32_t lno = cur_info.getStartLine();
+
+        line_set.emplace(addr, lno, 0, file_index, is_statement, false,
+                         is_prologue, is_epilogue, false);
+
+        if (line_entry.GetRangeBase() != LLDB_INVALID_ADDRESS) {
+          line_entry.SetRangeEnd(addr);
+          cii->m_global_line_table.Append(line_entry);
+        }
+        line_entry.SetRangeBase(addr);
+        line_entry.data = {file_index, lno};
       }
       LineInfo last_line(group.LineNumbers.back().Flags);
-      TerminateLineSequence(*line_table, *lfh, virtual_addr, file_index,
-                            last_line.getEndLine(), std::move(sequence));
+      line_set.emplace(virtual_addr + lfh->CodeSize, last_line.getEndLine(), 0,
+                       file_index, false, false, false, false, true);
+
+      if (line_entry.GetRangeBase() != LLDB_INVALID_ADDRESS) {
+        line_entry.SetRangeEnd(virtual_addr + lfh->CodeSize);
+        cii->m_global_line_table.Append(line_entry);
+      }
     }
   }
 
+  cii->m_global_line_table.Sort();
+
+  // Parse all S_INLINESITE in this CU.
+  const CVSymbolArray &syms = cii->m_debug_stream.getSymbolArray();
+  for (auto iter = syms.begin(); iter != syms.end();) {
+    if (iter->kind() != S_LPROC32 && iter->kind() != S_GPROC32) {
+      ++iter;
+      continue;
+    }
+
+    uint32_t record_offset = iter.offset();
+    CVSymbol func_record =
+        cii->m_debug_stream.readSymbolAtOffset(record_offset);
+    SegmentOffsetLength sol = GetSegmentOffsetAndLength(func_record);
+    addr_t file_vm_addr = m_index->MakeVirtualAddress(sol.so);
+    AddressRange func_range(file_vm_addr, sol.length,
+                            comp_unit.GetModule()->GetSectionList());
+    Address func_base = func_range.GetBaseAddress();
+    PdbCompilandSymId func_id{modi, record_offset};
+
+    // Iterate all S_INLINESITEs in the function.
+    auto parse_inline_sites = [&](SymbolKind kind, PdbCompilandSymId id) {
+      if (kind != S_INLINESITE)
+        return false;
+
+      ParseInlineSite(id, func_base);
+
+      for (const auto &line_entry :
+           m_inline_sites[toOpaqueUid(id)]->line_entries) {
+        // If line_entry is not terminal entry, remove previous line entry at
+        // the same address and insert new one. Terminal entry inside an inline
+        // site might not be terminal entry for its parent.
+        if (!line_entry.is_terminal_entry)
+          line_set.erase(line_entry);
+        line_set.insert(line_entry);
+      }
+      // No longer useful after adding to line_set.
+      m_inline_sites[toOpaqueUid(id)]->line_entries.clear();
+      return true;
+    };
+    ParseSymbolArrayInScope(func_id, parse_inline_sites);
+    // Jump to the end of the function record.
+    iter = syms.at(getScopeEndOffset(func_record));
+  }
+
+  cii->m_global_line_table.Clear();
+
+  // Add line entries in line_set to line_table.
+  auto line_table = std::make_unique<LineTable>(&comp_unit);
+  std::unique_ptr<LineSequence> sequence(
+      line_table->CreateLineSequenceContainer());
+  for (const auto &line_entry : line_set) {
+    line_table->AppendLineEntryToSequence(
+        sequence.get(), line_entry.file_addr, line_entry.line,
+        line_entry.column, line_entry.file_idx,
+        line_entry.is_start_of_statement, line_entry.is_start_of_basic_block,
+        line_entry.is_prologue_end, line_entry.is_epilogue_begin,
+        line_entry.is_terminal_entry);
+  }
+  line_table->InsertSequence(sequence.get());
+
   if (line_table->GetSize() == 0)
     return false;
 
@@ -1117,6 +1212,33 @@ bool SymbolFileNativePDB::ParseDebugMacros(CompileUnit &comp_unit) {
   return false;
 }
 
+llvm::Expected<uint32_t>
+SymbolFileNativePDB::GetFileIndex(const CompilandIndexItem &cii,
+                                  uint32_t file_id) {
+  auto index_iter = m_file_indexes.find(file_id);
+  if (index_iter != m_file_indexes.end())
+    return index_iter->getSecond();
+  const auto &checksums = cii.m_strings.checksums().getArray();
+  const auto &strings = cii.m_strings.strings();
+  // Indices in this structure are actually offsets of records in the
+  // DEBUG_S_FILECHECKSUMS subsection.  Those entries then have an index
+  // into the global PDB string table.
+  auto iter = checksums.at(file_id);
+  if (iter == checksums.end())
+    return llvm::make_error<RawError>(raw_error_code::no_entry);
+
+  llvm::Expected<llvm::StringRef> efn = strings.getString(iter->FileNameOffset);
+  if (!efn) {
+    return efn.takeError();
+  }
+
+  // LLDB wants the index of the file in the list of support files.
+  auto fn_iter = llvm::find(cii.m_file_list, *efn);
+  lldbassert(fn_iter != cii.m_file_list.end());
+  m_file_indexes[file_id] = std::distance(cii.m_file_list.begin(), fn_iter);
+  return m_file_indexes[file_id];
+}
+
 bool SymbolFileNativePDB::ParseSupportFiles(CompileUnit &comp_unit,
                                             FileSpecList &support_files) {
   std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
@@ -1141,11 +1263,220 @@ bool SymbolFileNativePDB::ParseImportedModules(
   return false;
 }
 
+void SymbolFileNativePDB::ParseInlineSite(PdbCompilandSymId id,
+                                          Address func_addr) {
+  lldb::user_id_t opaque_uid = toOpaqueUid(id);
+  if (m_inline_sites.find(opaque_uid) != m_inline_sites.end())
+    return;
+
+  addr_t func_base = func_addr.GetFileAddress();
+  CompilandIndexItem *cii = m_index->compilands().GetCompiland(id.modi);
+  CVSymbol sym = cii->m_debug_stream.readSymbolAtOffset(id.offset);
+  CompUnitSP comp_unit = GetOrCreateCompileUnit(*cii);
+
+  InlineSiteSym inline_site(static_cast<SymbolRecordKind>(sym.kind()));
+  cantFail(SymbolDeserializer::deserializeAs<InlineSiteSym>(sym, inline_site));
+  PdbCompilandSymId parent_id(id.modi, inline_site.Parent);
+
+  std::shared_ptr<InlineSite> inline_site_sp =
+      std::make_shared<InlineSite>(parent_id);
+
+  // Get the inlined function declaration info.
+  auto iter = cii->m_inline_map.find(inline_site.Inlinee);
+  if (iter == cii->m_inline_map.end())
+    return;
+  InlineeSourceLine inlinee_line = iter->second;
+
+  const FileSpecList &files = comp_unit->GetSupportFiles();
+  FileSpec decl_file;
+  llvm::Expected<uint32_t> file_index_or_err =
+      GetFileIndex(*cii, inlinee_line.Header->FileID);
+  if (!file_index_or_err)
+    return;
+  uint32_t decl_file_idx = file_index_or_err.get();
+  decl_file = files.GetFileSpecAtIndex(decl_file_idx);
+  uint32_t decl_line = inlinee_line.Header->SourceLineNum;
+  std::unique_ptr<Declaration> decl_up =
+      std::make_unique<Declaration>(decl_file, decl_line);
+
+  // Parse range and line info.
+  uint32_t code_offset = 0;
+  int32_t line_offset = 0;
+  bool has_base = false;
+  bool is_new_line_offset = false;
+
+  bool is_start_of_statement = false;
+  // The first instruction is the prologue end.
+  bool is_prologue_end = true;
+
+  auto change_code_offset = [&](uint32_t code_delta) {
+    if (has_base) {
+      inline_site_sp->ranges.Append(RangeSourceLineVector::Entry(
+          code_offset, code_delta, decl_line + line_offset));
+      is_prologue_end = false;
+      is_start_of_statement = false;
+    } else {
+      is_start_of_statement = true;
+    }
+    has_base = true;
+    code_offset += code_delta;
+
+    if (is_new_line_offset) {
+      LineTable::Entry line_entry(func_base + code_offset,
+                                  decl_line + line_offset, 0, decl_file_idx,
+                                  true, false, is_prologue_end, false, false);
+      inline_site_sp->line_entries.push_back(line_entry);
+      is_new_line_offset = false;
+    }
+  };
+  auto change_code_length = [&](uint32_t length) {
+    inline_site_sp->ranges.Append(RangeSourceLineVector::Entry(
+        code_offset, length, decl_line + line_offset));
+    has_base = false;
+
+    LineTable::Entry end_line_entry(func_base + code_offset + length,
+                                    decl_line + line_offset, 0, decl_file_idx,
+                                    false, false, false, false, true);
+    inline_site_sp->line_entries.push_back(end_line_entry);
+  };
+  auto change_line_offset = [&](int32_t line_delta) {
+    line_offset += line_delta;
+    if (has_base) {
+      LineTable::Entry line_entry(
+          func_base + code_offset, decl_line + line_offset, 0, decl_file_idx,
+          is_start_of_statement, false, is_prologue_end, false, false);
+      inline_site_sp->line_entries.push_back(line_entry);
+    } else {
+      // Add line entry in next call to change_code_offset.
+      is_new_line_offset = true;
+    }
+  };
+
+  for (auto &annot : inline_site.annotations()) {
+    switch (annot.OpCode) {
+    case BinaryAnnotationsOpCode::CodeOffset:
+    case BinaryAnnotationsOpCode::ChangeCodeOffset:
+    case BinaryAnnotationsOpCode::ChangeCodeOffsetBase:
+      change_code_offset(annot.U1);
+      break;
+    case BinaryAnnotationsOpCode::ChangeLineOffset:
+      change_line_offset(annot.S1);
+      break;
+    case BinaryAnnotationsOpCode::ChangeCodeLength:
+      change_code_length(annot.U1);
+      code_offset += annot.U1;
+      break;
+    case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset:
+      change_code_offset(annot.U1);
+      change_line_offset(annot.S1);
+      break;
+    case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset:
+      change_code_offset(annot.U2);
+      change_code_length(annot.U1);
+      break;
+    default:
+      break;
+    }
+  }
+
+  inline_site_sp->ranges.Sort();
+  inline_site_sp->ranges.CombineConsecutiveEntriesWithEqualData();
+
+  // Get the inlined function callsite info.
+  std::unique_ptr<Declaration> callsite_up;
+  if (!inline_site_sp->ranges.IsEmpty()) {
+    auto *entry = inline_site_sp->ranges.GetEntryAtIndex(0);
+    addr_t base_offset = entry->GetRangeBase();
+    if (cii->m_debug_stream.readSymbolAtOffset(parent_id.offset).kind() ==
+        S_INLINESITE) {
+      // Its parent is another inline site, lookup parent site's range vector
+      // for callsite line.
+      ParseInlineSite(parent_id, func_base);
+      std::shared_ptr<InlineSite> parent_site =
+          m_inline_sites[toOpaqueUid(parent_id)];
+      FileSpec &parent_decl_file =
+          parent_site->inline_function_info->GetDeclaration().GetFile();
+      if (auto *parent_entry =
+              parent_site->ranges.FindEntryThatContains(base_offset)) {
+        callsite_up =
+            std::make_unique<Declaration>(parent_decl_file, parent_entry->data);
+      }
+    } else {
+      // Its parent is a function, lookup global line table for callsite.
+      if (auto *entry = cii->m_global_line_table.FindEntryThatContains(
+              func_base + base_offset)) {
+        const FileSpec &callsite_file =
+            files.GetFileSpecAtIndex(entry->data.first);
+        callsite_up =
+            std::make_unique<Declaration>(callsite_file, entry->data.second);
+      }
+    }
+  }
+
+  // Get the inlined function name.
+  CVType inlinee_cvt = m_index->ipi().getType(inline_site.Inlinee);
+  std::string inlinee_name;
+  if (inlinee_cvt.kind() == LF_MFUNC_ID) {
+    MemberFuncIdRecord mfr;
+    cantFail(
+        TypeDeserializer::deserializeAs<MemberFuncIdRecord>(inlinee_cvt, mfr));
+    LazyRandomTypeCollection &types = m_index->tpi().typeCollection();
+    inlinee_name.append(std::string(types.getTypeName(mfr.ClassType)));
+    inlinee_name.append("::");
+    inlinee_name.append(mfr.getName().str());
+  } else if (inlinee_cvt.kind() == LF_FUNC_ID) {
+    FuncIdRecord fir;
+    cantFail(TypeDeserializer::deserializeAs<FuncIdRecord>(inlinee_cvt, fir));
+    TypeIndex parent_idx = fir.getParentScope();
+    if (!parent_idx.isNoneType()) {
+      LazyRandomTypeCollection &ids = m_index->ipi().typeCollection();
+      inlinee_name.append(std::string(ids.getTypeName(parent_idx)));
+      inlinee_name.append("::");
+    }
+    inlinee_name.append(fir.getName().str());
+  }
+  inline_site_sp->inline_function_info = std::make_shared<InlineFunctionInfo>(
+      inlinee_name.c_str(), llvm::StringRef(), decl_up.get(),
+      callsite_up.get());
+
+  m_inline_sites[opaque_uid] = inline_site_sp;
+}
+
 size_t SymbolFileNativePDB::ParseBlocksRecursive(Function &func) {
   std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
-  GetOrCreateBlock(PdbSymUid(func.GetID()).asCompilandSym());
-  // FIXME: Parse child blocks
-  return 1;
+  PdbCompilandSymId func_id = PdbSymUid(func.GetID()).asCompilandSym();
+  // After we iterate through inline sites inside the function, we already get
+  // all the info needed, removing from the map to save memory.
+  std::set<uint64_t> remove_uids;
+  auto parse_inline_sites = [&](SymbolKind kind, PdbCompilandSymId id) {
+    if (kind != S_INLINESITE)
+      return false;
+    GetOrCreateBlock(id);
+    remove_uids.insert(toOpaqueUid(id));
+    return true;
+  };
+  size_t count = ParseSymbolArrayInScope(func_id, parse_inline_sites);
+  for (uint64_t uid : remove_uids) {
+    m_inline_sites.erase(uid);
+  }
+  return count;
+}
+
+size_t SymbolFileNativePDB::ParseSymbolArrayInScope(
+    PdbCompilandSymId parent_id,
+    llvm::function_ref<bool(SymbolKind, PdbCompilandSymId)> fn) {
+  CompilandIndexItem *cii = m_index->compilands().GetCompiland(parent_id.modi);
+  CVSymbolArray syms =
+      cii->m_debug_stream.getSymbolArrayForScope(parent_id.offset);
+
+  size_t count = 1;
+  for (auto iter = syms.begin(); iter != syms.end(); ++iter) {
+    PdbCompilandSymId child_id(parent_id.modi, iter.offset());
+    if (fn(iter->kind(), child_id))
+      ++count;
+  }
+
+  return count;
 }
 
 void SymbolFileNativePDB::DumpClangAST(Stream &s) { m_ast->Dump(s); }
@@ -1396,6 +1727,9 @@ size_t SymbolFileNativePDB::ParseVariablesForBlock(PdbCompilandSymId block_id) {
   }
   case S_BLOCK32:
     break;
+  case S_INLINESITE:
+    // TODO: Handle inline site case.
+    return 0;
   default:
     lldbassert(false && "Symbol is not a block!");
     return 0;

diff  --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
index 56a5ec0a464d7..f1b6e34ca346b 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
@@ -9,6 +9,7 @@
 #ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_SYMBOLFILENATIVEPDB_H
 #define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_SYMBOLFILENATIVEPDB_H
 
+#include "lldb/Symbol/LineTable.h"
 #include "lldb/Symbol/SymbolFile.h"
 
 #include "llvm/ADT/DenseMap.h"
@@ -161,6 +162,25 @@ class SymbolFileNativePDB : public SymbolFile {
   void DumpClangAST(Stream &s) override;
 
 private:
+  struct LineTableEntryComparator {
+    bool operator()(const lldb_private::LineTable::Entry &lhs,
+                    const lldb_private::LineTable::Entry &rhs) const {
+      return lhs.file_addr < rhs.file_addr;
+    }
+  };
+
+  // From address range relative to function base to source line number.
+  using RangeSourceLineVector =
+      lldb_private::RangeDataVector<uint32_t, uint32_t, int32_t>;
+  // InlineSite contains information in a S_INLINESITE record.
+  struct InlineSite {
+    PdbCompilandSymId parent_id;
+    std::shared_ptr<InlineFunctionInfo> inline_function_info;
+    RangeSourceLineVector ranges;
+    std::vector<lldb_private::LineTable::Entry> line_entries;
+    InlineSite(PdbCompilandSymId parent_id) : parent_id(parent_id){};
+  };
+
   uint32_t CalculateNumCompileUnits() override;
 
   lldb::CompUnitSP ParseCompileUnitAtIndex(uint32_t index) override;
@@ -225,6 +245,16 @@ class SymbolFileNativePDB : public SymbolFile {
                                       VariableList &variables);
   size_t ParseVariablesForBlock(PdbCompilandSymId block_id);
 
+  llvm::Expected<uint32_t> GetFileIndex(const CompilandIndexItem &cii,
+                                        uint32_t file_id);
+
+  size_t ParseSymbolArrayInScope(
+      PdbCompilandSymId parent,
+      llvm::function_ref<bool(llvm::codeview::SymbolKind, PdbCompilandSymId)>
+          fn);
+
+  void ParseInlineSite(PdbCompilandSymId inline_site_id, Address func_addr);
+
   llvm::BumpPtrAllocator m_allocator;
 
   lldb::addr_t m_obj_load_address = 0;
@@ -241,6 +271,9 @@ class SymbolFileNativePDB : public SymbolFile {
   llvm::DenseMap<lldb::user_id_t, lldb::FunctionSP> m_functions;
   llvm::DenseMap<lldb::user_id_t, lldb::CompUnitSP> m_compilands;
   llvm::DenseMap<lldb::user_id_t, lldb::TypeSP> m_types;
+  llvm::DenseMap<lldb::user_id_t, std::shared_ptr<InlineSite>> m_inline_sites;
+  // A map from file id in records to file index in support files.
+  llvm::DenseMap<uint32_t, uint32_t> m_file_indexes;
 };
 
 } // namespace npdb

diff  --git a/lldb/test/Shell/SymbolFile/NativePDB/Inputs/inline_sites.lldbinit b/lldb/test/Shell/SymbolFile/NativePDB/Inputs/inline_sites.lldbinit
new file mode 100644
index 0000000000000..362e79252e66b
--- /dev/null
+++ b/lldb/test/Shell/SymbolFile/NativePDB/Inputs/inline_sites.lldbinit
@@ -0,0 +1,17 @@
+image dump line-table a.cpp -v
+
+b a.cpp:5
+b a.h:5
+b a.h:6
+b a.h:7
+b b.h:6
+b c.h:6
+
+image lookup -a 0x140001003 -v
+image lookup -a 0x140001004 -v
+image lookup -a 0x140001014 -v
+image lookup -a 0x14000101a -v
+image lookup -a 0x140001021 -v
+image lookup -a 0x140001028 -v
+
+quit
\ No newline at end of file

diff  --git a/lldb/test/Shell/SymbolFile/NativePDB/inline_sites.s b/lldb/test/Shell/SymbolFile/NativePDB/inline_sites.s
new file mode 100644
index 0000000000000..efe266e23a6ad
--- /dev/null
+++ b/lldb/test/Shell/SymbolFile/NativePDB/inline_sites.s
@@ -0,0 +1,667 @@
+# clang-format off
+# REQUIRES: lld, x86
+
+# RUN: llvm-mc -triple=x86_64-windows-msvc --filetype=obj %s > %t.obj
+# RUN: lld-link -debug:full -nodefaultlib -entry:main %t.obj  -out:%t.exe
+# RUN: env LLDB_USE_NATIVE_PDB_READER=1 %lldb -f %t.exe -s \
+# RUN:     %p/Inputs/inline_sites.lldbinit 2>&1 | FileCheck %s
+
+# Compiled from the following files, but replaced the call to abort with nop.
+# a.cpp:
+# #include "stdlib.h"
+# #include "a.h"
+# int main(int argc, char** argv) {
+#   Namespace1::foo(2);
+#   return 0;
+# }
+# a.h:
+# #include "b.h"
+# namespace Namespace1 {
+# inline void foo(int x) {
+#   static volatile int gv_foo;
+#   ++gv_foo;
+#   if (!gv_foo)
+#     abort();
+#   Class1::bar(x + 1);
+# }
+# }
+# b.h:
+# #include "c.h"
+# class Class1 {
+# public:
+#   inline static void bar(int x) {
+#     static volatile int gv_bar;
+#     ++gv_bar;
+#     Namespace2::Class2::func(x + 1);
+#   }
+# };
+# c.h:
+# namespace Namespace2{
+#   class Class2{
+#     public:
+#     inline static void func(int x) {
+#       static volatile int gv_func;
+#       gv_func += x;
+#     }
+#   };
+# }
+
+# CHECK:      (lldb) image dump line-table a.cpp -v
+# CHECK-NEXT: Line table for /tmp/a.cpp in
+# CHECK-NEXT: 0x0000000140001000: /tmp/a.cpp:3
+# CHECK-NEXT: 0x0000000140001004: /tmp/a.h:5, is_start_of_statement = TRUE, is_prologue_end = TRUE
+# CHECK-NEXT: 0x000000014000100a: /tmp/a.h:6
+# CHECK-NEXT: 0x0000000140001014: /tmp/b.h:6, is_start_of_statement = TRUE, is_prologue_end = TRUE
+# CHECK-NEXT: 0x000000014000101a: /tmp/c.h:6, is_start_of_statement = TRUE, is_prologue_end = TRUE
+# CHECK-NEXT: 0x0000000140001021: /tmp/a.cpp:5
+# CHECK-NEXT: 0x0000000140001028: /tmp/a.h:7, is_start_of_statement = TRUE
+# CHECK-NEXT: 0x000000014000102a: /tmp/a.cpp:5, is_terminal_entry = TRUE
+
+# CEHCK: (lldb) b a.cpp:5
+# CHECK: Breakpoint 1: where = {{.*}}`main + 33 at a.cpp:5, address = 0x0000000140001021
+# CEHCK: (lldb) b a.h:5
+# CHECK: Breakpoint 2: where = {{.*}}`main + 4 [inlined] Namespace1::foo at a.h:5, address = 0x0000000140001004
+# CEHCK: (lldb) b a.h:6
+# CHECK: Breakpoint 3: where = {{.*}}`main + 10 [inlined] Namespace1::foo + 6 at a.h:6, address = 0x000000014000100a
+# CEHCK: (lldb) b a.h:7
+# CHECK: Breakpoint 4: where = {{.*}}`main + 40 [inlined] Namespace1::foo at a.h:7, address = 0x0000000140001028
+# CEHCK: (lldb) b b.h:6
+# CHECK: Breakpoint 5: where = {{.*}}`main + 20 [inlined] Class1::bar at b.h:6, address = 0x0000000140001014
+# CEHCK: (lldb) b c.h:6
+# CHECK: Breakpoint 6: where = {{.*}}`main + 26 [inlined] Namespace2::Class2::func at c.h:6, address = 0x000000014000101a
+
+# CEHCK-LABEL: (lldb) image lookup -a 0x140001003 -v
+# CHECK:      Summary: {{.*}}`main + 3 at a.cpp:3
+# CHECK:     Function: id = {{.*}}, name = "main", range = [0x0000000140001000-0x000000014000102a)
+# CHECK:       Blocks: id = {{.*}}, range = [0x140001000-0x14000102a)
+# CHECK:    LineEntry: [0x0000000140001000-0x0000000140001004): /tmp/a.cpp:3
+
+# CEHCK-LABEL: (lldb) image lookup -a 0x140001004 -v
+# CHECK:      Summary: {{.*}}`main + 4 [inlined] Namespace1::foo at a.h:5
+# CHECK-NEXT:          {{.*}}`main + 4 at a.cpp:4
+# CHECK:     Function: id = {{.*}}, name = "main", range = [0x0000000140001000-0x000000014000102a)
+# CHECK:       Blocks: id = {{.*}}, range = [0x140001000-0x14000102a)
+# CHECK-NEXT:          id = {{.*}}, ranges = [0x140001004-0x140001021)[0x140001028-0x14000102a), name = "Namespace1::foo", decl = a.h:3
+# CHECK:    LineEntry: [0x0000000140001004-0x000000014000100a): /tmp/a.h:5
+
+# CEHCK-LABEL: (lldb) image lookup -a 0x140001014 -v
+# CHECK:      Summary: {{.*}}`main + 20 [inlined] Class1::bar at b.h:6
+# CHECK-NEXT:          {{.*}}`main + 20 [inlined] Namespace1::foo + 16 at a.h:8
+# CHECK-NEXT:          {{.*}}`main + 4 at a.cpp:4
+# CHECK:     Function: id = {{.*}}, name = "main", range = [0x0000000140001000-0x000000014000102a)
+# CHECK:       Blocks: id = {{.*}}, range = [0x140001000-0x14000102a)
+# CHECK-NEXT:          id = {{.*}}, ranges = [0x140001004-0x140001021)[0x140001028-0x14000102a), name = "Namespace1::foo", decl = a.h:3
+# CHECK-NEXT:          id = {{.*}}, range = [0x140001014-0x140001021), name = "Class1::bar", decl = b.h:4
+# CHECK:    LineEntry: [0x0000000140001014-0x000000014000101a): /tmp/b.h:6
+
+# CEHCK-LABEL: (lldb) image lookup -a 0x14000101a -v
+# CHECK:      Summary: {{.*}}`main + 26 [inlined] Namespace2::Class2::func at c.h:6
+# CHECK-NEXT:          {{.*}}`main + 26 [inlined] Class1::bar + 6 at b.h:7
+# CHECK-NEXT:          {{.*}}`main + 20 [inlined] Namespace1::foo + 16 at a.h:8
+# CHECK-NEXT:          {{.*}}`main + 4 at a.cpp:4
+# CHECK:     Function: id = {{.*}}, name = "main", range = [0x0000000140001000-0x000000014000102a)
+# CHECK:       Blocks: id = {{.*}}, range = [0x140001000-0x14000102a)
+# CHECK-NEXT:          id = {{.*}}, ranges = [0x140001004-0x140001021)[0x140001028-0x14000102a), name = "Namespace1::foo", decl = a.h:3
+# CHECK-NEXT:          id = {{.*}}, range = [0x140001014-0x140001021), name = "Class1::bar", decl = b.h:4
+# CHECK-NEXT:          id = {{.*}}, range = [0x14000101a-0x140001021), name = "Namespace2::Class2::func", decl = c.h:4
+# CHECK:    LineEntry: [0x000000014000101a-0x0000000140001021): /tmp/c.h:6
+
+# CEHCK-LABEL: (lldb) image lookup -a 0x140001021 -v
+# CHECK:      Summary: {{.*}}`main + 33 at a.cpp:5
+# CHECK:     Function: id = {{.*}}, name = "main", range = [0x0000000140001000-0x000000014000102a)
+# CHECK:       Blocks: id = {{.*}}, range = [0x140001000-0x14000102a)
+# CHECK:    LineEntry: [0x0000000140001021-0x0000000140001028): /tmp/a.cpp:5
+
+# CEHCK-LABEL: (lldb) image lookup -a 0x140001028 -v
+# CHECK:      Summary: {{.*}}`main + 40 [inlined] Namespace1::foo at a.h:7
+# CHECK-NEXT:          {{.*}}`main + 40 at a.cpp:4
+# CHECK:     Function: id = {{.*}}, name = "main", range = [0x0000000140001000-0x000000014000102a)
+# CHECK:       Blocks: id = {{.*}}, range = [0x140001000-0x14000102a)
+# CHECK-NEXT:          id = {{.*}}, ranges = [0x140001004-0x140001021)[0x140001028-0x14000102a), name = "Namespace1::foo", decl = a.h:3
+# CHECK:    LineEntry: [0x0000000140001028-0x000000014000102a): /tmp/a.h:7
+
+	.text
+	.def	 @feat.00;
+	.scl	3;
+	.type	0;
+	.endef
+	.globl	@feat.00
+.set @feat.00, 0
+	.intel_syntax noprefix
+	.file	"a.cpp"
+	.def	 main;
+	.scl	2;
+	.type	32;
+	.endef
+	.section	.text,"xr",one_only,main
+	.globl	main                            # -- Begin function main
+main:                                   # @main
+.Lfunc_begin0:
+	.cv_func_id 0
+	.cv_file	1 "/tmp/a.cpp" "4ECCDD2814054DCF80EA72F4349036C4" 1
+	.cv_loc	0 1 3 0                         # a.cpp:3:0
+.seh_proc main
+# %bb.0:                                # %entry
+	#DEBUG_VALUE: main:argv <- $rdx
+	#DEBUG_VALUE: main:argc <- $ecx
+	#DEBUG_VALUE: foo:x <- 2
+	sub	rsp, 40
+	.seh_stackalloc 40
+	.seh_endprologue
+.Ltmp0:
+	.cv_file	2 "/tmp/./a.h" "9E656AFA1B1B681265C87EEA8BBE073E" 1
+	.cv_inline_site_id 1 within 0 inlined_at 1 4 0
+	.cv_loc	1 2 5 0                         # ./a.h:5:0
+	inc	dword ptr [rip + "?gv_foo@?1??foo at Namespace1@@YAXH at Z@4HC"]
+	.cv_loc	1 2 6 0                         # ./a.h:6:0
+	mov	eax, dword ptr [rip + "?gv_foo@?1??foo at Namespace1@@YAXH at Z@4HC"]
+	test	eax, eax
+	je	.LBB0_2
+.Ltmp1:
+# %bb.1:                                # %"?foo at Namespace1@@YAXH at Z.exit"
+	#DEBUG_VALUE: foo:x <- 2
+	#DEBUG_VALUE: main:argc <- $ecx
+	#DEBUG_VALUE: main:argv <- $rdx
+	#DEBUG_VALUE: bar:x <- [DW_OP_plus_uconst 1, DW_OP_stack_value] 2
+	.cv_file	3 "/tmp/./b.h" "BE52983EB17A3B0DA14E68A5CCBC4399" 1
+	.cv_inline_site_id 2 within 1 inlined_at 2 8 0
+	.cv_loc	2 3 6 0                         # ./b.h:6:0
+	inc	dword ptr [rip + "?gv_bar@?1??bar at Class1@@SAXH at Z@4HC"]
+.Ltmp2:
+	#DEBUG_VALUE: func:x <- 4
+	.cv_file	4 "/tmp/./c.h" "D1B76A1C2A54DBEA648F3A11496166B8" 1
+	.cv_inline_site_id 3 within 2 inlined_at 3 7 0
+	.cv_loc	3 4 6 0                         # ./c.h:6:0
+	add	dword ptr [rip + "?gv_func@?1??func at Class2@Namespace2@@SAXH at Z@4HC"], 4
+.Ltmp3:
+	.cv_loc	0 1 5 0                         # a.cpp:5:0
+	xor	eax, eax
+	add	rsp, 40
+	ret
+.Ltmp4:
+.LBB0_2:                                # %if.then.i
+	#DEBUG_VALUE: foo:x <- 2
+	#DEBUG_VALUE: main:argc <- $ecx
+	#DEBUG_VALUE: main:argv <- $rdx
+	.cv_loc	1 2 7 0                         # ./a.h:7:0
+	nop
+.Ltmp5:
+	int3
+.Ltmp6:
+	#DEBUG_VALUE: main:argv <- [DW_OP_LLVM_entry_value 1] $rdx
+	#DEBUG_VALUE: main:argc <- [DW_OP_LLVM_entry_value 1] $ecx
+.Lfunc_end0:
+	.seh_endproc
+                                        # -- End function
+	.section	.bss,"bw",discard,"?gv_foo@?1??foo at Namespace1@@YAXH at Z@4HC"
+	.globl	"?gv_foo@?1??foo at Namespace1@@YAXH at Z@4HC" # @"?gv_foo@?1??foo at Namespace1@@YAXH at Z@4HC"
+	.p2align	2
+"?gv_foo@?1??foo at Namespace1@@YAXH at Z@4HC":
+	.long	0                               # 0x0
+
+	.section	.bss,"bw",discard,"?gv_bar@?1??bar at Class1@@SAXH at Z@4HC"
+	.globl	"?gv_bar@?1??bar at Class1@@SAXH at Z@4HC" # @"?gv_bar@?1??bar at Class1@@SAXH at Z@4HC"
+	.p2align	2
+"?gv_bar@?1??bar at Class1@@SAXH at Z@4HC":
+	.long	0                               # 0x0
+
+	.section	.bss,"bw",discard,"?gv_func@?1??func at Class2@Namespace2@@SAXH at Z@4HC"
+	.globl	"?gv_func@?1??func at Class2@Namespace2@@SAXH at Z@4HC" # @"?gv_func@?1??func at Class2@Namespace2@@SAXH at Z@4HC"
+	.p2align	2
+"?gv_func@?1??func at Class2@Namespace2@@SAXH at Z@4HC":
+	.long	0                               # 0x0
+
+	.section	.drectve,"yn"
+	.ascii	" /DEFAULTLIB:libcmt.lib"
+	.ascii	" /DEFAULTLIB:oldnames.lib"
+	.section	.debug$S,"dr"
+	.p2align	2
+	.long	4                               # Debug section magic
+	.long	241
+	.long	.Ltmp8-.Ltmp7                   # Subsection size
+.Ltmp7:
+	.short	.Ltmp10-.Ltmp9                  # Record length
+.Ltmp9:
+	.short	4353                            # Record kind: S_OBJNAME
+	.long	0                               # Signature
+	.asciz	"/tmp/a-e5dd01.obj"             # Object name
+	.p2align	2
+.Ltmp10:
+	.short	.Ltmp12-.Ltmp11                 # Record length
+.Ltmp11:
+	.short	4412                            # Record kind: S_COMPILE3
+	.long	1                               # Flags and language
+	.short	208                             # CPUType
+	.short	14                              # Frontend version
+	.short	0
+	.short	0
+	.short	0
+	.short	14000                           # Backend version
+	.short	0
+	.short	0
+	.short	0
+	.asciz	"clang version 14.0.0"          # Null-terminated compiler version string
+	.p2align	2
+.Ltmp12:
+.Ltmp8:
+	.p2align	2
+	.long	246                             # Inlinee lines subsection
+	.long	.Ltmp14-.Ltmp13                 # Subsection size
+.Ltmp13:
+	.long	0                               # Inlinee lines signature
+
+                                        # Inlined function foo starts at ./a.h:3
+	.long	4099                            # Type index of inlined function
+	.cv_filechecksumoffset	2               # Offset into filechecksum table
+	.long	3                               # Starting line number
+
+                                        # Inlined function bar starts at ./b.h:4
+	.long	4106                            # Type index of inlined function
+	.cv_filechecksumoffset	3               # Offset into filechecksum table
+	.long	4                               # Starting line number
+
+                                        # Inlined function func starts at ./c.h:4
+	.long	4113                            # Type index of inlined function
+	.cv_filechecksumoffset	4               # Offset into filechecksum table
+	.long	4                               # Starting line number
+.Ltmp14:
+	.p2align	2
+	.section	.debug$S,"dr",associative,main
+	.p2align	2
+	.long	4                               # Debug section magic
+	.long	241                             # Symbol subsection for main
+	.long	.Ltmp16-.Ltmp15                 # Subsection size
+.Ltmp15:
+	.short	.Ltmp18-.Ltmp17                 # Record length
+.Ltmp17:
+	.short	4423                            # Record kind: S_GPROC32_ID
+	.long	0                               # PtrParent
+	.long	0                               # PtrEnd
+	.long	0                               # PtrNext
+	.long	.Lfunc_end0-main                # Code size
+	.long	0                               # Offset after prologue
+	.long	0                               # Offset before epilogue
+	.long	4117                            # Function type index
+	.secrel32	main                    # Function section relative address
+	.secidx	main                            # Function section index
+	.byte	0                               # Flags
+	.asciz	"main"                          # Function name
+	.p2align	2
+.Ltmp18:
+	.short	.Ltmp20-.Ltmp19                 # Record length
+.Ltmp19:
+	.short	4114                            # Record kind: S_FRAMEPROC
+	.long	40                              # FrameSize
+	.long	0                               # Padding
+	.long	0                               # Offset of padding
+	.long	0                               # Bytes of callee saved registers
+	.long	0                               # Exception handler offset
+	.short	0                               # Exception handler section
+	.long	81920                           # Flags (defines frame register)
+	.p2align	2
+.Ltmp20:
+	.short	.Ltmp22-.Ltmp21                 # Record length
+.Ltmp21:
+	.short	4414                            # Record kind: S_LOCAL
+	.long	116                             # TypeIndex
+	.short	1                               # Flags
+	.asciz	"argc"
+	.p2align	2
+.Ltmp22:
+	.cv_def_range	 .Lfunc_begin0 .Ltmp5, reg, 18
+	.short	.Ltmp24-.Ltmp23                 # Record length
+.Ltmp23:
+	.short	4414                            # Record kind: S_LOCAL
+	.long	4114                            # TypeIndex
+	.short	1                               # Flags
+	.asciz	"argv"
+	.p2align	2
+.Ltmp24:
+	.cv_def_range	 .Lfunc_begin0 .Ltmp5, reg, 331
+	.short	.Ltmp26-.Ltmp25                 # Record length
+.Ltmp25:
+	.short	4365                            # Record kind: S_GDATA32
+	.long	4118                            # Type
+	.secrel32	"?gv_foo@?1??foo at Namespace1@@YAXH at Z@4HC" # DataOffset
+	.secidx	"?gv_foo@?1??foo at Namespace1@@YAXH at Z@4HC" # Segment
+	.asciz	"Namespace1::foo::gv_foo"       # Name
+	.p2align	2
+.Ltmp26:
+	.short	.Ltmp28-.Ltmp27                 # Record length
+.Ltmp27:
+	.short	4365                            # Record kind: S_GDATA32
+	.long	4118                            # Type
+	.secrel32	"?gv_bar@?1??bar at Class1@@SAXH at Z@4HC" # DataOffset
+	.secidx	"?gv_bar@?1??bar at Class1@@SAXH at Z@4HC" # Segment
+	.asciz	"Class1::bar::gv_bar"           # Name
+	.p2align	2
+.Ltmp28:
+	.short	.Ltmp30-.Ltmp29                 # Record length
+.Ltmp29:
+	.short	4365                            # Record kind: S_GDATA32
+	.long	4118                            # Type
+	.secrel32	"?gv_func@?1??func at Class2@Namespace2@@SAXH at Z@4HC" # DataOffset
+	.secidx	"?gv_func@?1??func at Class2@Namespace2@@SAXH at Z@4HC" # Segment
+	.asciz	"Namespace2::Class2::func::gv_func" # Name
+	.p2align	2
+.Ltmp30:
+	.short	.Ltmp32-.Ltmp31                 # Record length
+.Ltmp31:
+	.short	4429                            # Record kind: S_INLINESITE
+	.long	0                               # PtrParent
+	.long	0                               # PtrEnd
+	.long	4099                            # Inlinee type index
+	.cv_inline_linetable	1 2 3 .Lfunc_begin0 .Lfunc_end0
+	.p2align	2
+.Ltmp32:
+	.short	.Ltmp34-.Ltmp33                 # Record length
+.Ltmp33:
+	.short	4414                            # Record kind: S_LOCAL
+	.long	116                             # TypeIndex
+	.short	257                             # Flags
+	.asciz	"x"
+	.p2align	2
+.Ltmp34:
+	.short	.Ltmp36-.Ltmp35                 # Record length
+.Ltmp35:
+	.short	4429                            # Record kind: S_INLINESITE
+	.long	0                               # PtrParent
+	.long	0                               # PtrEnd
+	.long	4106                            # Inlinee type index
+	.cv_inline_linetable	2 3 4 .Lfunc_begin0 .Lfunc_end0
+	.p2align	2
+.Ltmp36:
+	.short	.Ltmp38-.Ltmp37                 # Record length
+.Ltmp37:
+	.short	4414                            # Record kind: S_LOCAL
+	.long	116                             # TypeIndex
+	.short	257                             # Flags
+	.asciz	"x"
+	.p2align	2
+.Ltmp38:
+	.short	.Ltmp40-.Ltmp39                 # Record length
+.Ltmp39:
+	.short	4429                            # Record kind: S_INLINESITE
+	.long	0                               # PtrParent
+	.long	0                               # PtrEnd
+	.long	4113                            # Inlinee type index
+	.cv_inline_linetable	3 4 4 .Lfunc_begin0 .Lfunc_end0
+	.p2align	2
+.Ltmp40:
+	.short	.Ltmp42-.Ltmp41                 # Record length
+.Ltmp41:
+	.short	4414                            # Record kind: S_LOCAL
+	.long	116                             # TypeIndex
+	.short	257                             # Flags
+	.asciz	"x"
+	.p2align	2
+.Ltmp42:
+	.short	2                               # Record length
+	.short	4430                            # Record kind: S_INLINESITE_END
+	.short	2                               # Record length
+	.short	4430                            # Record kind: S_INLINESITE_END
+	.short	2                               # Record length
+	.short	4430                            # Record kind: S_INLINESITE_END
+	.short	2                               # Record length
+	.short	4431                            # Record kind: S_PROC_ID_END
+.Ltmp16:
+	.p2align	2
+	.cv_linetable	0, main, .Lfunc_end0
+	.section	.debug$S,"dr"
+	.long	241
+	.long	.Ltmp44-.Ltmp43                 # Subsection size
+.Ltmp43:
+	.short	.Ltmp46-.Ltmp45                 # Record length
+.Ltmp45:
+	.short	4360                            # Record kind: S_UDT
+	.long	4103                            # Type
+	.asciz	"Class1"
+	.p2align	2
+.Ltmp46:
+	.short	.Ltmp48-.Ltmp47                 # Record length
+.Ltmp47:
+	.short	4360                            # Record kind: S_UDT
+	.long	4110                            # Type
+	.asciz	"Namespace2::Class2"
+	.p2align	2
+.Ltmp48:
+.Ltmp44:
+	.p2align	2
+	.cv_filechecksums                       # File index to string table offset subsection
+	.cv_stringtable                         # String table
+	.long	241
+	.long	.Ltmp50-.Ltmp49                 # Subsection size
+.Ltmp49:
+	.short	.Ltmp52-.Ltmp51                 # Record length
+.Ltmp51:
+	.short	4428                            # Record kind: S_BUILDINFO
+	.long	4121                            # LF_BUILDINFO index
+	.p2align	2
+.Ltmp52:
+.Ltmp50:
+	.p2align	2
+	.section	.debug$T,"dr"
+	.p2align	2
+	.long	4                               # Debug section magic
+	# StringId (0x1000)
+	.short	0x12                            # Record length
+	.short	0x1605                          # Record kind: LF_STRING_ID
+	.long	0x0                             # Id
+	.asciz	"Namespace1"                    # StringData
+	.byte	241
+	# ArgList (0x1001)
+	.short	0xa                             # Record length
+	.short	0x1201                          # Record kind: LF_ARGLIST
+	.long	0x1                             # NumArgs
+	.long	0x74                            # Argument: int
+	# Procedure (0x1002)
+	.short	0xe                             # Record length
+	.short	0x1008                          # Record kind: LF_PROCEDURE
+	.long	0x3                             # ReturnType: void
+	.byte	0x0                             # CallingConvention: NearC
+	.byte	0x0                             # FunctionOptions
+	.short	0x1                             # NumParameters
+	.long	0x1001                          # ArgListType: (int)
+	# FuncId (0x1003)
+	.short	0xe                             # Record length
+	.short	0x1601                          # Record kind: LF_FUNC_ID
+	.long	0x1000                          # ParentScope: Namespace1
+	.long	0x1002                          # FunctionType: void (int)
+	.asciz	"foo"                           # Name
+	# Class (0x1004)
+	.short	0x2a                            # Record length
+	.short	0x1504                          # Record kind: LF_CLASS
+	.short	0x0                             # MemberCount
+	.short	0x280                           # Properties ( ForwardReference (0x80) | HasUniqueName (0x200) )
+	.long	0x0                             # FieldList
+	.long	0x0                             # DerivedFrom
+	.long	0x0                             # VShape
+	.short	0x0                             # SizeOf
+	.asciz	"Class1"                        # Name
+	.asciz	".?AVClass1@@"                  # LinkageName
+	.byte	242
+	.byte	241
+	# MemberFunction (0x1005)
+	.short	0x1a                            # Record length
+	.short	0x1009                          # Record kind: LF_MFUNCTION
+	.long	0x3                             # ReturnType: void
+	.long	0x1004                          # ClassType: Class1
+	.long	0x0                             # ThisType
+	.byte	0x0                             # CallingConvention: NearC
+	.byte	0x0                             # FunctionOptions
+	.short	0x1                             # NumParameters
+	.long	0x1001                          # ArgListType: (int)
+	.long	0x0                             # ThisAdjustment
+	# FieldList (0x1006)
+	.short	0xe                             # Record length
+	.short	0x1203                          # Record kind: LF_FIELDLIST
+	.short	0x1511                          # Member kind: OneMethod ( LF_ONEMETHOD )
+	.short	0xb                             # Attrs: Public, Static
+	.long	0x1005                          # Type: void Class1::(int)
+	.asciz	"bar"                           # Name
+	# Class (0x1007)
+	.short	0x2a                            # Record length
+	.short	0x1504                          # Record kind: LF_CLASS
+	.short	0x1                             # MemberCount
+	.short	0x200                           # Properties ( HasUniqueName (0x200) )
+	.long	0x1006                          # FieldList: <field list>
+	.long	0x0                             # DerivedFrom
+	.long	0x0                             # VShape
+	.short	0x1                             # SizeOf
+	.asciz	"Class1"                        # Name
+	.asciz	".?AVClass1@@"                  # LinkageName
+	.byte	242
+	.byte	241
+	# StringId (0x1008)
+	.short	0x12                            # Record length
+	.short	0x1605                          # Record kind: LF_STRING_ID
+	.long	0x0                             # Id
+	.asciz	"/tmp/./b.h"                    # StringData
+	.byte	241
+	# UdtSourceLine (0x1009)
+	.short	0xe                             # Record length
+	.short	0x1606                          # Record kind: LF_UDT_SRC_LINE
+	.long	0x1007                          # UDT: Class1
+	.long	0x1008                          # SourceFile: /tmp/./b.h
+	.long	0x2                             # LineNumber
+	# MemberFuncId (0x100A)
+	.short	0xe                             # Record length
+	.short	0x1602                          # Record kind: LF_MFUNC_ID
+	.long	0x1004                          # ClassType: Class1
+	.long	0x1005                          # FunctionType: void Class1::(int)
+	.asciz	"bar"                           # Name
+	# Class (0x100B)
+	.short	0x42                            # Record length
+	.short	0x1504                          # Record kind: LF_CLASS
+	.short	0x0                             # MemberCount
+	.short	0x280                           # Properties ( ForwardReference (0x80) | HasUniqueName (0x200) )
+	.long	0x0                             # FieldList
+	.long	0x0                             # DerivedFrom
+	.long	0x0                             # VShape
+	.short	0x0                             # SizeOf
+	.asciz	"Namespace2::Class2"            # Name
+	.asciz	".?AVClass2 at Namespace2@@"       # LinkageName
+	.byte	243
+	.byte	242
+	.byte	241
+	# MemberFunction (0x100C)
+	.short	0x1a                            # Record length
+	.short	0x1009                          # Record kind: LF_MFUNCTION
+	.long	0x3                             # ReturnType: void
+	.long	0x100b                          # ClassType: Namespace2::Class2
+	.long	0x0                             # ThisType
+	.byte	0x0                             # CallingConvention: NearC
+	.byte	0x0                             # FunctionOptions
+	.short	0x1                             # NumParameters
+	.long	0x1001                          # ArgListType: (int)
+	.long	0x0                             # ThisAdjustment
+	# FieldList (0x100D)
+	.short	0x12                            # Record length
+	.short	0x1203                          # Record kind: LF_FIELDLIST
+	.short	0x1511                          # Member kind: OneMethod ( LF_ONEMETHOD )
+	.short	0xb                             # Attrs: Public, Static
+	.long	0x100c                          # Type: void Namespace2::Class2::(int)
+	.asciz	"func"                          # Name
+	.byte	243
+	.byte	242
+	.byte	241
+	# Class (0x100E)
+	.short	0x42                            # Record length
+	.short	0x1504                          # Record kind: LF_CLASS
+	.short	0x1                             # MemberCount
+	.short	0x200                           # Properties ( HasUniqueName (0x200) )
+	.long	0x100d                          # FieldList: <field list>
+	.long	0x0                             # DerivedFrom
+	.long	0x0                             # VShape
+	.short	0x1                             # SizeOf
+	.asciz	"Namespace2::Class2"            # Name
+	.asciz	".?AVClass2 at Namespace2@@"       # LinkageName
+	.byte	243
+	.byte	242
+	.byte	241
+	# StringId (0x100F)
+	.short	0x12                            # Record length
+	.short	0x1605                          # Record kind: LF_STRING_ID
+	.long	0x0                             # Id
+	.asciz	"/tmp/./c.h"                    # StringData
+	.byte	241
+	# UdtSourceLine (0x1010)
+	.short	0xe                             # Record length
+	.short	0x1606                          # Record kind: LF_UDT_SRC_LINE
+	.long	0x100e                          # UDT: Namespace2::Class2
+	.long	0x100f                          # SourceFile: /tmp/./c.h
+	.long	0x2                             # LineNumber
+	# MemberFuncId (0x1011)
+	.short	0x12                            # Record length
+	.short	0x1602                          # Record kind: LF_MFUNC_ID
+	.long	0x100b                          # ClassType: Namespace2::Class2
+	.long	0x100c                          # FunctionType: void Namespace2::Class2::(int)
+	.asciz	"func"                          # Name
+	.byte	243
+	.byte	242
+	.byte	241
+	# Pointer (0x1012)
+	.short	0xa                             # Record length
+	.short	0x1002                          # Record kind: LF_POINTER
+	.long	0x670                           # PointeeType: char*
+	.long	0x1000c                         # Attrs: [ Type: Near64, Mode: Pointer, SizeOf: 8 ]
+	# ArgList (0x1013)
+	.short	0xe                             # Record length
+	.short	0x1201                          # Record kind: LF_ARGLIST
+	.long	0x2                             # NumArgs
+	.long	0x74                            # Argument: int
+	.long	0x1012                          # Argument: char**
+	# Procedure (0x1014)
+	.short	0xe                             # Record length
+	.short	0x1008                          # Record kind: LF_PROCEDURE
+	.long	0x74                            # ReturnType: int
+	.byte	0x0                             # CallingConvention: NearC
+	.byte	0x0                             # FunctionOptions
+	.short	0x2                             # NumParameters
+	.long	0x1013                          # ArgListType: (int, char**)
+	# FuncId (0x1015)
+	.short	0x12                            # Record length
+	.short	0x1601                          # Record kind: LF_FUNC_ID
+	.long	0x0                             # ParentScope
+	.long	0x1014                          # FunctionType: int (int, char**)
+	.asciz	"main"                          # Name
+	.byte	243
+	.byte	242
+	.byte	241
+	# Modifier (0x1016)
+	.short	0xa                             # Record length
+	.short	0x1001                          # Record kind: LF_MODIFIER
+	.long	0x74                            # ModifiedType: int
+	.short	0x2                             # Modifiers ( Volatile (0x2) )
+	.byte	242
+	.byte	241
+	# StringId (0x1017)
+	.short	0xe                             # Record length
+	.short	0x1605                          # Record kind: LF_STRING_ID
+	.long	0x0                             # Id
+	.asciz	"/tmp"                          # StringData
+	.byte	243
+	.byte	242
+	.byte	241
+	# StringId (0x1018)
+	.short	0xe                             # Record length
+	.short	0x1605                          # Record kind: LF_STRING_ID
+	.long	0x0                             # Id
+	.asciz	"a.cpp"                         # StringData
+	.byte	242
+	.byte	241
+	# BuildInfo (0x1019)
+	.short	0x1a                            # Record length
+	.short	0x1603                          # Record kind: LF_BUILDINFO
+	.short	0x5                             # NumArgs
+	.long	0x1017                          # Argument: /tmp
+	.long	0x0                             # Argument
+	.long	0x1018                          # Argument: a.cpp
+	.long	0x0                             # Argument
+	.long	0x0                             # Argument
+	.byte	242
+	.byte	241
+	.addrsig
+	.addrsig_sym "?gv_foo@?1??foo at Namespace1@@YAXH at Z@4HC"
+	.addrsig_sym "?gv_bar@?1??bar at Class1@@SAXH at Z@4HC"
+	.addrsig_sym "?gv_func@?1??func at Class2@Namespace2@@SAXH at Z@4HC"


        


More information about the lldb-commits mailing list