zequanwu updated this revision to Diff 385903.
zequanwu marked an inline comment as done.
zequanwu added a comment.

Use empty callsite_file or name if index is out of range.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D113330/new/

https://reviews.llvm.org/D113330

Files:
  lldb/include/lldb/Symbol/Block.h
  lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp
  lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.h
  lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp
  lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp
  lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h
  lldb/source/Symbol/Block.cpp
  lldb/test/Shell/SymbolFile/Breakpad/Inputs/inline-record.syms
  lldb/test/Shell/SymbolFile/Breakpad/inline-record.test
  lldb/unittests/ObjectFile/Breakpad/BreakpadRecordsTest.cpp

Index: lldb/unittests/ObjectFile/Breakpad/BreakpadRecordsTest.cpp
===================================================================
--- lldb/unittests/ObjectFile/Breakpad/BreakpadRecordsTest.cpp
+++ lldb/unittests/ObjectFile/Breakpad/BreakpadRecordsTest.cpp
@@ -18,6 +18,8 @@
   EXPECT_EQ(Record::Info, Record::classify("INFO"));
   EXPECT_EQ(Record::File, Record::classify("FILE"));
   EXPECT_EQ(Record::Func, Record::classify("FUNC"));
+  EXPECT_EQ(Record::Inline, Record::classify("INLINE"));
+  EXPECT_EQ(Record::InlineOrigin, Record::classify("INLINE_ORIGIN"));
   EXPECT_EQ(Record::Public, Record::classify("PUBLIC"));
   EXPECT_EQ(Record::StackCFI, Record::classify("STACK CFI"));
   EXPECT_EQ(Record::StackWin, Record::classify("STACK WIN"));
@@ -76,6 +78,27 @@
   EXPECT_EQ(llvm::None, FuncRecord::parse("FUNC"));
 }
 
+TEST(InlineOriginRecord, parse) {
+  EXPECT_EQ(InlineOriginRecord(47, "foo"),
+            InlineOriginRecord::parse("INLINE_ORIGIN 47 foo"));
+  EXPECT_EQ(llvm::None, InlineOriginRecord::parse("INLINE_ORIGIN 47"));
+  EXPECT_EQ(llvm::None, InlineOriginRecord::parse("INLINE_ORIGIN"));
+  EXPECT_EQ(llvm::None, InlineOriginRecord::parse(""));
+}
+
+TEST(InlineRecord, parse) {
+  InlineRecord record1 = InlineRecord(0, 1, 2, 3);
+  record1.Ranges.emplace_back(4, 5);
+  EXPECT_EQ(record1, InlineRecord::parse("INLINE 0 1 2 3 4 5"));
+  record1.Ranges.emplace_back(6, 7);
+  EXPECT_EQ(record1, InlineRecord::parse("INLINE 0 1 2 3 4 5 6 7"));
+  EXPECT_EQ(llvm::None, InlineRecord::parse("INLINE 0 1 2 3"));
+  EXPECT_EQ(llvm::None, InlineRecord::parse("INLINE 0 1 2 3 4 5 6"));
+  EXPECT_EQ(llvm::None, InlineRecord::parse("INLNIE 0"));
+  EXPECT_EQ(llvm::None, InlineRecord::parse(""));
+  EXPECT_EQ(llvm::None, InlineRecord::parse("FUNC"));
+}
+
 TEST(LineRecord, parse) {
   EXPECT_EQ(LineRecord(0x47, 0x74, 47, 74), LineRecord::parse("47 74 47 74"));
   EXPECT_EQ(llvm::None, LineRecord::parse("47 74 47"));
Index: lldb/test/Shell/SymbolFile/Breakpad/inline-record.test
===================================================================
--- /dev/null
+++ lldb/test/Shell/SymbolFile/Breakpad/inline-record.test
@@ -0,0 +1,29 @@
+# RUN: yaml2obj %S/Inputs/basic-elf.yaml -o %T/inline-record.out
+# RUN: %lldb %T/inline-record.out -o "target symbols add -s inline-record.out %S/Inputs/inline-record.syms" \
+# RUN:   -s %s | FileCheck %s
+
+# CHECK-LABEL: (lldb) image lookup -a 0x400010 -v
+# CHECK:      Function: id = {0x00000000}, name = "f1", range = [0x0000000000400010-0x0000000000400020)
+# CHECK-NEXT:   Blocks: id = {0x00000000}, range = [0x00400010-0x00400020)
+# CHECK-NEXT:           id = {0x00000010}, ranges = [0x00400010-0x00400015)[0x00400017-0x0040001b), name = "inlined_f1"
+
+# CHECK-LABEL: (lldb) image lookup -a 0x400016 -v
+# CHECK:      Function: id = {0x00000000}, name = "f1", range = [0x0000000000400010-0x0000000000400020)
+# CHECK-NEXT:   Blocks: id = {0x00000000}, range = [0x00400010-0x00400020)
+
+# CHECK-LABEL: (lldb) image lookup -a 0x400023 -v
+# CHECK:      Function: id = {0x00000001}, name = "f2", range = [0x0000000000400020-0x0000000000400030)
+# CHECK-NEXT:   Blocks: id = {0x00000001}, range = [0x00400020-0x00400030)
+# CHECK-NEXT:           id = {0x00000043}, range = [0x00400023-0x0040002d), name = "inlined_f1"
+# CHECK-NEXT:           id = {0x00000057}, range = [0x00400023-0x00400028), name = "inlined_f2"
+
+# CHECK-LABEL: (lldb) image lookup -a 0x400029 -v
+# CHECK:      Function: id = {0x00000001}, name = "f2", range = [0x0000000000400020-0x0000000000400030)
+# CHECK-NEXT:   Blocks: id = {0x00000001}, range = [0x00400020-0x00400030)
+# CHECK-NEXT:           id = {0x00000043}, range = [0x00400023-0x0040002d), name = "inlined_f1"
+
+image lookup -a 0x400010 -v
+image lookup -a 0x400016 -v
+image lookup -a 0x400023 -v
+image lookup -a 0x400029 -v
+exit
Index: lldb/test/Shell/SymbolFile/Breakpad/Inputs/inline-record.syms
===================================================================
--- /dev/null
+++ lldb/test/Shell/SymbolFile/Breakpad/Inputs/inline-record.syms
@@ -0,0 +1,13 @@
+MODULE Linux x86_64 761550E08086333960A9074A9CE2895C0 a.out
+INFO CODE_ID E05015768680393360A9074A9CE2895C
+FILE 0 /tmp/a.c
+FILE 1 /tmp/b.c
+INLINE_ORIGIN 0 inlined_f1
+INLINE_ORIGIN 1 inlined_f2
+FUNC 10 10 0 f1
+INLINE 0 8 0 0 10 5 17 4
+10 10 3 0
+FUNC 20 10 0 f2
+INLINE 0 3 0 0 23 a
+INLINE 1 4 1 1 23 5
+20 10 2 1
Index: lldb/source/Symbol/Block.cpp
===================================================================
--- lldb/source/Symbol/Block.cpp
+++ lldb/source/Symbol/Block.cpp
@@ -122,6 +122,16 @@
   return matching_block;
 }
 
+Block *Block::FindInnermostBlockByOffset(const lldb::addr_t offset) {
+  if (!Contains(offset))
+    return nullptr;
+  for (const BlockSP &block_sp : m_children) {
+    if (Block *block = block_sp->FindInnermostBlockByOffset(offset))
+      return block;
+  }
+  return this;
+}
+
 void Block::CalculateSymbolContext(SymbolContext *sc) {
   if (m_parent_scope)
     m_parent_scope->CalculateSymbolContext(sc);
Index: lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h
===================================================================
--- lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h
+++ lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h
@@ -81,7 +81,7 @@
     return false;
   }
 
-  size_t ParseBlocksRecursive(Function &func) override { return 0; }
+  size_t ParseBlocksRecursive(Function &func) override;
 
   void FindGlobalVariables(ConstString name,
                            const CompilerDeclContext &parent_decl_ctx,
@@ -223,11 +223,13 @@
                          UnwindPlan::Row &row);
   lldb::UnwindPlanSP ParseWinUnwindPlan(const Bookmark &bookmark,
                                         const RegisterInfoResolver &resolver);
+  void ParseInlineOriginRecords();
 
   using CompUnitMap = RangeDataVector<lldb::addr_t, lldb::addr_t, CompUnitData>;
 
   llvm::Optional<std::vector<FileSpec>> m_files;
   llvm::Optional<CompUnitMap> m_cu_data;
+  llvm::Optional<std::vector<llvm::StringRef>> m_inline_origins;
 
   using UnwindMap = RangeDataVector<lldb::addr_t, lldb::addr_t, Bookmark>;
   struct UnwindData {
Index: lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp
===================================================================
--- lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp
+++ lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp
@@ -204,6 +204,10 @@
       End(*m_objfile_sp);
   assert(Record::classify(*It) == Record::Func);
   ++It; // Skip FUNC record.
+  // Skip INLINE records.
+  while (It != End && Record::classify(*It) == Record::Inline)
+    ++It;
+
   if (It != End) {
     auto record = LineRecord::parse(*It);
     if (record && record->FileNum < m_files->size())
@@ -280,13 +284,88 @@
   return true;
 }
 
+size_t SymbolFileBreakpad::ParseBlocksRecursive(Function &func) {
+  std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+  CompileUnit *comp_unit = func.GetCompileUnit();
+  lldbassert(comp_unit);
+  ParseInlineOriginRecords();
+  // A vector of current each level's parent block. For example, when parsing
+  // "INLINE 0 ...", the current level is 0 and its parent block is the
+  // funciton block at index 0.
+  std::vector<Block *> blocks;
+  Block &block = func.GetBlock(false);
+  block.AddRange(Block::Range(0, func.GetAddressRange().GetByteSize()));
+  blocks.push_back(&block);
+
+  size_t blocks_added = 0;
+  addr_t func_base = func.GetAddressRange().GetBaseAddress().GetOffset();
+  CompUnitData &data = m_cu_data->GetEntryRef(comp_unit->GetID()).data;
+  LineIterator It(*m_objfile_sp, Record::Func, data.bookmark),
+      End(*m_objfile_sp);
+  ++It; // Skip the FUNC record.
+  size_t last_added_nest_level = 0;
+  while (It != End && Record::classify(*It) == Record::Inline) {
+    if (auto record = InlineRecord::parse(*It)) {
+      if (record->InlineNestLevel == 0 ||
+          record->InlineNestLevel <= last_added_nest_level + 1) {
+        last_added_nest_level = record->InlineNestLevel;
+        BlockSP block_sp = std::make_shared<Block>(It.GetBookmark().offset);
+        FileSpec callsite_file;
+        if (record->CallSiteFileNum < m_files->size())
+          callsite_file = (*m_files)[record->CallSiteFileNum];
+        llvm::StringRef name;
+        if (record->OriginNum < m_inline_origins->size())
+          name = (*m_inline_origins)[record->OriginNum];
+
+        Declaration callsite(callsite_file, record->CallSiteLineNum);
+        block_sp->SetInlinedFunctionInfo(name.str().c_str(),
+                                         /*mangled=*/nullptr,
+                                         /*decl_ptr=*/nullptr, &callsite);
+        for (const auto &range : record->Ranges) {
+          block_sp->AddRange(
+              Block::Range(range.first - func_base, range.second));
+        }
+        block_sp->FinalizeRanges();
+
+        blocks[record->InlineNestLevel]->AddChild(block_sp);
+        if (record->InlineNestLevel + 1 >= blocks.size()) {
+          blocks.resize(blocks.size() + 1);
+        }
+        blocks[record->InlineNestLevel + 1] = block_sp.get();
+        ++blocks_added;
+      }
+    }
+    ++It;
+  }
+  return blocks_added;
+}
+
+void SymbolFileBreakpad::ParseInlineOriginRecords() {
+  if (m_inline_origins)
+    return;
+  m_inline_origins.emplace();
+
+  Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS);
+  for (llvm::StringRef line : lines(Record::InlineOrigin)) {
+    auto record = InlineOriginRecord::parse(line);
+    if (!record) {
+      LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", line);
+      continue;
+    }
+
+    if (record->Number >= m_inline_origins->size())
+      m_inline_origins->resize(record->Number + 1);
+    (*m_inline_origins)[record->Number] = record->Name;
+  }
+}
+
 uint32_t
 SymbolFileBreakpad::ResolveSymbolContext(const Address &so_addr,
                                          SymbolContextItem resolve_scope,
                                          SymbolContext &sc) {
   std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
   if (!(resolve_scope & (eSymbolContextCompUnit | eSymbolContextLineEntry |
-                         eSymbolContextFunction)))
+                         eSymbolContextFunction | eSymbolContextBlock)))
     return 0;
 
   ParseCUData();
@@ -303,11 +382,20 @@
       result |= eSymbolContextLineEntry;
     }
   }
-  if (resolve_scope & eSymbolContextFunction) {
+
+  if (resolve_scope & (eSymbolContextFunction | eSymbolContextBlock)) {
     FunctionSP func_sp = GetOrCreateFunction(*sc.comp_unit);
     if (func_sp) {
       sc.function = func_sp.get();
       result |= eSymbolContextFunction;
+      if (resolve_scope & eSymbolContextBlock) {
+        Block &block = func_sp->GetBlock(true);
+        sc.block = block.FindInnermostBlockByOffset(
+            so_addr.GetFileAddress() -
+            sc.function->GetAddressRange().GetBaseAddress().GetFileAddress());
+        if (sc.block)
+          result |= eSymbolContextBlock;
+      }
     }
   }
 
@@ -773,6 +861,10 @@
       End(*m_objfile_sp);
   assert(Record::classify(*It) == Record::Func);
   for (++It; It != End; ++It) {
+    // Skip INLINE records
+    if (Record::classify(*It) == Record::Inline)
+      continue;
+
     auto record = LineRecord::parse(*It);
     if (!record)
       break;
Index: lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp
===================================================================
--- lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp
+++ lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp
@@ -148,9 +148,9 @@
     std::tie(line, text) = text.split('\n');
 
     llvm::Optional<Record::Kind> next_section = Record::classify(line);
-    if (next_section == Record::Line) {
-      // Line records logically belong to the preceding Func record, so we put
-      // them in the same section.
+    if (next_section == Record::Line || next_section == Record::Inline) {
+      // Line/Inline records logically belong to the preceding Func record, so
+      // we put them in the same section.
       next_section = Record::Func;
     }
     if (next_section == current_section)
Index: lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.h
===================================================================
--- lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.h
+++ lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.h
@@ -20,7 +20,18 @@
 
 class Record {
 public:
-  enum Kind { Module, Info, File, Func, Line, Public, StackCFI, StackWin };
+  enum Kind {
+    Module,
+    Info,
+    File,
+    Func,
+    Inline,
+    InlineOrigin,
+    Line,
+    Public,
+    StackCFI,
+    StackWin
+  };
 
   /// Attempt to guess the kind of the record present in the argument without
   /// doing a full parse. The returned kind will always be correct for valid
@@ -89,6 +100,23 @@
 }
 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const FileRecord &R);
 
+class InlineOriginRecord : public Record {
+public:
+  static llvm::Optional<InlineOriginRecord> parse(llvm::StringRef Line);
+  InlineOriginRecord(size_t Number, llvm::StringRef Name)
+      : Record(InlineOrigin), Number(Number), Name(Name) {}
+
+  size_t Number;
+  llvm::StringRef Name;
+};
+
+inline bool operator==(const InlineOriginRecord &L,
+                       const InlineOriginRecord &R) {
+  return L.Number == R.Number && L.Name == R.Name;
+}
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+                              const InlineOriginRecord &R);
+
 class FuncRecord : public Record {
 public:
   static llvm::Optional<FuncRecord> parse(llvm::StringRef Line);
@@ -107,6 +135,26 @@
 bool operator==(const FuncRecord &L, const FuncRecord &R);
 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const FuncRecord &R);
 
+class InlineRecord : public Record {
+public:
+  static llvm::Optional<InlineRecord> parse(llvm::StringRef Line);
+  InlineRecord(size_t InlineNestLevel, uint32_t CallSiteLineNum,
+               size_t CallSiteFileNum, size_t OriginNum)
+      : Record(Inline), InlineNestLevel(InlineNestLevel),
+        CallSiteLineNum(CallSiteLineNum), CallSiteFileNum(CallSiteFileNum),
+        OriginNum(OriginNum) {}
+
+  size_t InlineNestLevel;
+  uint32_t CallSiteLineNum;
+  size_t CallSiteFileNum;
+  size_t OriginNum;
+  // A vector of address range covered by this inline
+  std::vector<std::pair<lldb::addr_t, lldb::addr_t>> Ranges;
+};
+
+bool operator==(const InlineRecord &L, const InlineRecord &R);
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const InlineRecord &R);
+
 class LineRecord : public Record {
 public:
   static llvm::Optional<LineRecord> parse(llvm::StringRef Line);
Index: lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp
===================================================================
--- lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp
+++ lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp
@@ -23,6 +23,8 @@
   CodeID,
   File,
   Func,
+  Inline,
+  InlineOrigin,
   Public,
   Stack,
   CFI,
@@ -41,6 +43,8 @@
       .Case("CODE_ID", Token::CodeID)
       .Case("FILE", Token::File)
       .Case("FUNC", Token::Func)
+      .Case("INLINE", Token::Inline)
+      .Case("INLINE_ORIGIN", Token::InlineOrigin)
       .Case("PUBLIC", Token::Public)
       .Case("STACK", Token::Stack)
       .Case("CFI", Token::CFI)
@@ -145,7 +149,10 @@
     default:
       return llvm::None;
     }
-
+  case Token::Inline:
+    return Record::Inline;
+  case Token::InlineOrigin:
+    return Record::InlineOrigin;
   case Token::Unknown:
     // Optimistically assume that any unrecognised token means this is a line
     // record, those don't have a special keyword and start directly with a
@@ -216,9 +223,11 @@
   return OS << "INFO CODE_ID " << R.ID.GetAsString();
 }
 
-llvm::Optional<FileRecord> FileRecord::parse(llvm::StringRef Line) {
-  // FILE number name
-  if (consume<Token>(Line) != Token::File)
+template <typename T>
+static llvm::Optional<T> parseNumberName(llvm::StringRef Line,
+                                         Token TokenType) {
+  // TOKEN number name
+  if (consume<Token>(Line) != TokenType)
     return llvm::None;
 
   llvm::StringRef Str;
@@ -231,7 +240,12 @@
   if (Name.empty())
     return llvm::None;
 
-  return FileRecord(Number, Name);
+  return T(Number, Name);
+}
+
+llvm::Optional<FileRecord> FileRecord::parse(llvm::StringRef Line) {
+  // FILE number name
+  return parseNumberName<FileRecord>(Line, Token::File);
 }
 
 llvm::raw_ostream &breakpad::operator<<(llvm::raw_ostream &OS,
@@ -239,6 +253,17 @@
   return OS << "FILE " << R.Number << " " << R.Name;
 }
 
+llvm::Optional<InlineOriginRecord>
+InlineOriginRecord::parse(llvm::StringRef Line) {
+  // INLINE_ORIGIN number name
+  return parseNumberName<InlineOriginRecord>(Line, Token::InlineOrigin);
+}
+
+llvm::raw_ostream &breakpad::operator<<(llvm::raw_ostream &OS,
+                                        const InlineOriginRecord &R) {
+  return OS << "INLINE_ORIGIN " << R.Number << " " << R.Name;
+}
+
 static bool parsePublicOrFunc(llvm::StringRef Line, bool &Multiple,
                               lldb::addr_t &Address, lldb::addr_t *Size,
                               lldb::addr_t &ParamSize, llvm::StringRef &Name) {
@@ -299,6 +324,58 @@
                              R.ParamSize, R.Name);
 }
 
+llvm::Optional<InlineRecord> InlineRecord::parse(llvm::StringRef Line) {
+  // INLINE inline_nest_level call_site_line call_site_file_num origin_num
+  // [address size]+
+  if (consume<Token>(Line) != Token::Inline)
+    return llvm::None;
+
+  llvm::SmallVector<llvm::StringRef> Tokens;
+  SplitString(Line, Tokens, " ");
+  if (Tokens.size() < 6 || Tokens.size() % 2 == 1)
+    return llvm::None;
+
+  size_t InlineNestLevel;
+  uint32_t CallSiteLineNum;
+  size_t CallSiteFileNum;
+  size_t OriginNum;
+  if (!(to_integer(Tokens[0], InlineNestLevel) &&
+        to_integer(Tokens[1], CallSiteLineNum) &&
+        to_integer(Tokens[2], CallSiteFileNum) &&
+        to_integer(Tokens[3], OriginNum)))
+    return llvm::None;
+
+  InlineRecord Record = InlineRecord(InlineNestLevel, CallSiteLineNum,
+                                     CallSiteFileNum, OriginNum);
+  for (size_t i = 4; i < Tokens.size(); i += 2) {
+    lldb::addr_t Address;
+    if (!to_integer(Tokens[i], Address, 16))
+      return llvm::None;
+    lldb::addr_t Size;
+    if (!to_integer(Tokens[i + 1].trim(), Size, 16))
+      return llvm::None;
+    Record.Ranges.emplace_back(Address, Size);
+  }
+  return Record;
+}
+
+bool breakpad::operator==(const InlineRecord &L, const InlineRecord &R) {
+  return L.InlineNestLevel == R.InlineNestLevel &&
+         L.CallSiteLineNum == R.CallSiteLineNum &&
+         L.CallSiteFileNum == R.CallSiteFileNum && L.OriginNum == R.OriginNum &&
+         L.Ranges == R.Ranges;
+}
+
+llvm::raw_ostream &breakpad::operator<<(llvm::raw_ostream &OS,
+                                        const InlineRecord &R) {
+  OS << llvm::formatv("INLINE {0} {1} {2} {3}", R.InlineNestLevel,
+                      R.CallSiteLineNum, R.CallSiteFileNum, R.OriginNum);
+  for (const auto &range : R.Ranges) {
+    OS << llvm::formatv(" {0:x-} {1:x-}", range.first, range.second);
+  }
+  return OS;
+}
+
 llvm::Optional<LineRecord> LineRecord::parse(llvm::StringRef Line) {
   lldb::addr_t Address;
   llvm::StringRef Str;
@@ -490,6 +567,10 @@
     return "FILE";
   case Record::Func:
     return "FUNC";
+  case Record::Inline:
+    return "INLINE";
+  case Record::InlineOrigin:
+    return "INLINE_ORIGIN";
   case Record::Line:
     return "LINE";
   case Record::Public:
Index: lldb/include/lldb/Symbol/Block.h
===================================================================
--- lldb/include/lldb/Symbol/Block.h
+++ lldb/include/lldb/Symbol/Block.h
@@ -338,6 +338,8 @@
 
   Block *FindBlockByID(lldb::user_id_t block_id);
 
+  Block *FindInnermostBlockByOffset(const lldb::addr_t offset);
+
   size_t GetNumRanges() const { return m_ranges.GetSize(); }
 
   bool GetRangeContainingOffset(const lldb::addr_t offset, Range &range);
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to