xref: /freebsd/contrib/llvm-project/lldb/source/Symbol/SymbolContext.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1  //===-- SymbolContext.cpp -------------------------------------------------===//
2  //
3  // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4  // See https://llvm.org/LICENSE.txt for license information.
5  // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6  //
7  //===----------------------------------------------------------------------===//
8  
9  #include "lldb/Symbol/SymbolContext.h"
10  
11  #include "lldb/Core/Address.h"
12  #include "lldb/Core/Debugger.h"
13  #include "lldb/Core/Module.h"
14  #include "lldb/Core/ModuleSpec.h"
15  #include "lldb/Host/Host.h"
16  #include "lldb/Symbol/Block.h"
17  #include "lldb/Symbol/CompileUnit.h"
18  #include "lldb/Symbol/ObjectFile.h"
19  #include "lldb/Symbol/Symbol.h"
20  #include "lldb/Symbol/SymbolFile.h"
21  #include "lldb/Symbol/SymbolVendor.h"
22  #include "lldb/Symbol/Variable.h"
23  #include "lldb/Target/Language.h"
24  #include "lldb/Target/Target.h"
25  #include "lldb/Utility/LLDBLog.h"
26  #include "lldb/Utility/Log.h"
27  #include "lldb/Utility/Stream.h"
28  #include "lldb/Utility/StreamString.h"
29  #include "lldb/lldb-enumerations.h"
30  
31  using namespace lldb;
32  using namespace lldb_private;
33  
SymbolContext()34  SymbolContext::SymbolContext() : target_sp(), module_sp(), line_entry() {}
35  
SymbolContext(const ModuleSP & m,CompileUnit * cu,Function * f,Block * b,LineEntry * le,Symbol * s)36  SymbolContext::SymbolContext(const ModuleSP &m, CompileUnit *cu, Function *f,
37                               Block *b, LineEntry *le, Symbol *s)
38      : target_sp(), module_sp(m), comp_unit(cu), function(f), block(b),
39        line_entry(), symbol(s) {
40    if (le)
41      line_entry = *le;
42  }
43  
SymbolContext(const TargetSP & t,const ModuleSP & m,CompileUnit * cu,Function * f,Block * b,LineEntry * le,Symbol * s)44  SymbolContext::SymbolContext(const TargetSP &t, const ModuleSP &m,
45                               CompileUnit *cu, Function *f, Block *b,
46                               LineEntry *le, Symbol *s)
47      : target_sp(t), module_sp(m), comp_unit(cu), function(f), block(b),
48        line_entry(), symbol(s) {
49    if (le)
50      line_entry = *le;
51  }
52  
SymbolContext(SymbolContextScope * sc_scope)53  SymbolContext::SymbolContext(SymbolContextScope *sc_scope)
54      : target_sp(), module_sp(), line_entry() {
55    sc_scope->CalculateSymbolContext(this);
56  }
57  
58  SymbolContext::~SymbolContext() = default;
59  
Clear(bool clear_target)60  void SymbolContext::Clear(bool clear_target) {
61    if (clear_target)
62      target_sp.reset();
63    module_sp.reset();
64    comp_unit = nullptr;
65    function = nullptr;
66    block = nullptr;
67    line_entry.Clear();
68    symbol = nullptr;
69    variable = nullptr;
70  }
71  
DumpStopContext(Stream * s,ExecutionContextScope * exe_scope,const Address & addr,bool show_fullpaths,bool show_module,bool show_inlined_frames,bool show_function_arguments,bool show_function_name,bool show_function_display_name,std::optional<Stream::HighlightSettings> settings) const72  bool SymbolContext::DumpStopContext(
73      Stream *s, ExecutionContextScope *exe_scope, const Address &addr,
74      bool show_fullpaths, bool show_module, bool show_inlined_frames,
75      bool show_function_arguments, bool show_function_name,
76      bool show_function_display_name,
77      std::optional<Stream::HighlightSettings> settings) const {
78    bool dumped_something = false;
79    if (show_module && module_sp) {
80      if (show_fullpaths)
81        *s << module_sp->GetFileSpec();
82      else
83        *s << module_sp->GetFileSpec().GetFilename();
84      s->PutChar('`');
85      dumped_something = true;
86    }
87    if (function != nullptr) {
88      SymbolContext inline_parent_sc;
89      Address inline_parent_addr;
90      if (!show_function_name) {
91        s->Printf("<");
92        dumped_something = true;
93      } else {
94        ConstString name;
95        if (!show_function_arguments)
96          name = function->GetNameNoArguments();
97        if (!name && show_function_display_name)
98          name = function->GetDisplayName();
99        if (!name)
100          name = function->GetName();
101        if (name)
102          s->PutCStringColorHighlighted(name.GetStringRef(), settings);
103      }
104  
105      if (addr.IsValid()) {
106        const addr_t function_offset =
107            addr.GetOffset() -
108            function->GetAddressRange().GetBaseAddress().GetOffset();
109        if (!show_function_name) {
110          // Print +offset even if offset is 0
111          dumped_something = true;
112          s->Printf("+%" PRIu64 ">", function_offset);
113        } else if (function_offset) {
114          dumped_something = true;
115          s->Printf(" + %" PRIu64, function_offset);
116        }
117      }
118  
119      if (GetParentOfInlinedScope(addr, inline_parent_sc, inline_parent_addr)) {
120        dumped_something = true;
121        Block *inlined_block = block->GetContainingInlinedBlock();
122        const InlineFunctionInfo *inlined_block_info =
123            inlined_block->GetInlinedFunctionInfo();
124        s->Printf(" [inlined] %s", inlined_block_info->GetName().GetCString());
125  
126        lldb_private::AddressRange block_range;
127        if (inlined_block->GetRangeContainingAddress(addr, block_range)) {
128          const addr_t inlined_function_offset =
129              addr.GetOffset() - block_range.GetBaseAddress().GetOffset();
130          if (inlined_function_offset) {
131            s->Printf(" + %" PRIu64, inlined_function_offset);
132          }
133        }
134        // "line_entry" will always be valid as GetParentOfInlinedScope(...) will
135        // fill it in correctly with the calling file and line. Previous code
136        // was extracting the calling file and line from inlined_block_info and
137        // using it right away which is not correct. On the first call to this
138        // function "line_entry" will contain the actual line table entry. On
139        // susequent calls "line_entry" will contain the calling file and line
140        // from the previous inline info.
141        if (line_entry.IsValid()) {
142          s->PutCString(" at ");
143          line_entry.DumpStopContext(s, show_fullpaths);
144        }
145  
146        if (show_inlined_frames) {
147          s->EOL();
148          s->Indent();
149          const bool show_function_name = true;
150          return inline_parent_sc.DumpStopContext(
151              s, exe_scope, inline_parent_addr, show_fullpaths, show_module,
152              show_inlined_frames, show_function_arguments, show_function_name,
153              show_function_display_name);
154        }
155      } else {
156        if (line_entry.IsValid()) {
157          dumped_something = true;
158          s->PutCString(" at ");
159          if (line_entry.DumpStopContext(s, show_fullpaths))
160            dumped_something = true;
161        }
162      }
163    } else if (symbol != nullptr) {
164      if (!show_function_name) {
165        s->Printf("<");
166        dumped_something = true;
167      } else if (symbol->GetName()) {
168        dumped_something = true;
169        if (symbol->GetType() == eSymbolTypeTrampoline)
170          s->PutCString("symbol stub for: ");
171        ConstString name;
172        if (show_function_display_name)
173          name = symbol->GetDisplayName();
174        if (!name)
175          name = symbol->GetName();
176        s->PutCStringColorHighlighted(name.GetStringRef(), settings);
177      }
178  
179      if (addr.IsValid() && symbol->ValueIsAddress()) {
180        const addr_t symbol_offset =
181            addr.GetOffset() - symbol->GetAddressRef().GetOffset();
182        if (!show_function_name) {
183          // Print +offset even if offset is 0
184          dumped_something = true;
185          s->Printf("+%" PRIu64 ">", symbol_offset);
186        } else if (symbol_offset) {
187          dumped_something = true;
188          s->Printf(" + %" PRIu64, symbol_offset);
189        }
190      }
191    } else if (addr.IsValid()) {
192      addr.Dump(s, exe_scope, Address::DumpStyleModuleWithFileAddress);
193      dumped_something = true;
194    }
195    return dumped_something;
196  }
197  
GetDescription(Stream * s,lldb::DescriptionLevel level,Target * target,std::optional<Stream::HighlightSettings> settings) const198  void SymbolContext::GetDescription(
199      Stream *s, lldb::DescriptionLevel level, Target *target,
200      std::optional<Stream::HighlightSettings> settings) const {
201    if (module_sp) {
202      s->Indent("     Module: file = \"");
203      module_sp->GetFileSpec().Dump(s->AsRawOstream());
204      *s << '"';
205      if (module_sp->GetArchitecture().IsValid())
206        s->Printf(", arch = \"%s\"",
207                  module_sp->GetArchitecture().GetArchitectureName());
208      s->EOL();
209    }
210  
211    if (comp_unit != nullptr) {
212      s->Indent("CompileUnit: ");
213      comp_unit->GetDescription(s, level);
214      s->EOL();
215    }
216  
217    if (function != nullptr) {
218      s->Indent("   Function: ");
219      function->GetDescription(s, level, target);
220      s->EOL();
221  
222      Type *func_type = function->GetType();
223      if (func_type) {
224        s->Indent("   FuncType: ");
225        func_type->GetDescription(s, level, false, target);
226        s->EOL();
227      }
228    }
229  
230    if (block != nullptr) {
231      std::vector<Block *> blocks;
232      blocks.push_back(block);
233      Block *parent_block = block->GetParent();
234  
235      while (parent_block) {
236        blocks.push_back(parent_block);
237        parent_block = parent_block->GetParent();
238      }
239      std::vector<Block *>::reverse_iterator pos;
240      std::vector<Block *>::reverse_iterator begin = blocks.rbegin();
241      std::vector<Block *>::reverse_iterator end = blocks.rend();
242      for (pos = begin; pos != end; ++pos) {
243        if (pos == begin)
244          s->Indent("     Blocks: ");
245        else
246          s->Indent("             ");
247        (*pos)->GetDescription(s, function, level, target);
248        s->EOL();
249      }
250    }
251  
252    if (line_entry.IsValid()) {
253      s->Indent("  LineEntry: ");
254      line_entry.GetDescription(s, level, comp_unit, target, false);
255      s->EOL();
256    }
257  
258    if (symbol != nullptr) {
259      s->Indent("     Symbol: ");
260      symbol->GetDescription(s, level, target, settings);
261      s->EOL();
262    }
263  
264    if (variable != nullptr) {
265      s->Indent("   Variable: ");
266  
267      s->Printf("id = {0x%8.8" PRIx64 "}, ", variable->GetID());
268  
269      switch (variable->GetScope()) {
270      case eValueTypeVariableGlobal:
271        s->PutCString("kind = global, ");
272        break;
273  
274      case eValueTypeVariableStatic:
275        s->PutCString("kind = static, ");
276        break;
277  
278      case eValueTypeVariableArgument:
279        s->PutCString("kind = argument, ");
280        break;
281  
282      case eValueTypeVariableLocal:
283        s->PutCString("kind = local, ");
284        break;
285  
286      case eValueTypeVariableThreadLocal:
287        s->PutCString("kind = thread local, ");
288        break;
289  
290      default:
291        break;
292      }
293  
294      s->Printf("name = \"%s\"\n", variable->GetName().GetCString());
295    }
296  }
297  
GetResolvedMask() const298  uint32_t SymbolContext::GetResolvedMask() const {
299    uint32_t resolved_mask = 0;
300    if (target_sp)
301      resolved_mask |= eSymbolContextTarget;
302    if (module_sp)
303      resolved_mask |= eSymbolContextModule;
304    if (comp_unit)
305      resolved_mask |= eSymbolContextCompUnit;
306    if (function)
307      resolved_mask |= eSymbolContextFunction;
308    if (block)
309      resolved_mask |= eSymbolContextBlock;
310    if (line_entry.IsValid())
311      resolved_mask |= eSymbolContextLineEntry;
312    if (symbol)
313      resolved_mask |= eSymbolContextSymbol;
314    if (variable)
315      resolved_mask |= eSymbolContextVariable;
316    return resolved_mask;
317  }
318  
Dump(Stream * s,Target * target) const319  void SymbolContext::Dump(Stream *s, Target *target) const {
320    *s << this << ": ";
321    s->Indent();
322    s->PutCString("SymbolContext");
323    s->IndentMore();
324    s->EOL();
325    s->IndentMore();
326    s->Indent();
327    *s << "Module       = " << module_sp.get() << ' ';
328    if (module_sp)
329      module_sp->GetFileSpec().Dump(s->AsRawOstream());
330    s->EOL();
331    s->Indent();
332    *s << "CompileUnit  = " << comp_unit;
333    if (comp_unit != nullptr)
334      s->Format(" {{{0:x-16}} {1}", comp_unit->GetID(),
335                comp_unit->GetPrimaryFile());
336    s->EOL();
337    s->Indent();
338    *s << "Function     = " << function;
339    if (function != nullptr) {
340      s->Format(" {{{0:x-16}} {1}, address-range = ", function->GetID(),
341                function->GetType()->GetName());
342      function->GetAddressRange().Dump(s, target, Address::DumpStyleLoadAddress,
343                                       Address::DumpStyleModuleWithFileAddress);
344      s->EOL();
345      s->Indent();
346      Type *func_type = function->GetType();
347      if (func_type) {
348        *s << "        Type = ";
349        func_type->Dump(s, false);
350      }
351    }
352    s->EOL();
353    s->Indent();
354    *s << "Block        = " << block;
355    if (block != nullptr)
356      s->Format(" {{{0:x-16}}", block->GetID());
357    s->EOL();
358    s->Indent();
359    *s << "LineEntry    = ";
360    line_entry.Dump(s, target, true, Address::DumpStyleLoadAddress,
361                    Address::DumpStyleModuleWithFileAddress, true);
362    s->EOL();
363    s->Indent();
364    *s << "Symbol       = " << symbol;
365    if (symbol != nullptr && symbol->GetMangled())
366      *s << ' ' << symbol->GetName().AsCString();
367    s->EOL();
368    *s << "Variable     = " << variable;
369    if (variable != nullptr) {
370      s->Format(" {{{0:x-16}} {1}", variable->GetID(),
371                variable->GetType()->GetName());
372      s->EOL();
373    }
374    s->IndentLess();
375    s->IndentLess();
376  }
377  
operator ==(const SymbolContext & lhs,const SymbolContext & rhs)378  bool lldb_private::operator==(const SymbolContext &lhs,
379                                const SymbolContext &rhs) {
380    return lhs.function == rhs.function && lhs.symbol == rhs.symbol &&
381           lhs.module_sp.get() == rhs.module_sp.get() &&
382           lhs.comp_unit == rhs.comp_unit &&
383           lhs.target_sp.get() == rhs.target_sp.get() &&
384           LineEntry::Compare(lhs.line_entry, rhs.line_entry) == 0 &&
385           lhs.variable == rhs.variable;
386  }
387  
operator !=(const SymbolContext & lhs,const SymbolContext & rhs)388  bool lldb_private::operator!=(const SymbolContext &lhs,
389                                const SymbolContext &rhs) {
390    return !(lhs == rhs);
391  }
392  
GetAddressRange(uint32_t scope,uint32_t range_idx,bool use_inline_block_range,AddressRange & range) const393  bool SymbolContext::GetAddressRange(uint32_t scope, uint32_t range_idx,
394                                      bool use_inline_block_range,
395                                      AddressRange &range) const {
396    if ((scope & eSymbolContextLineEntry) && line_entry.IsValid()) {
397      range = line_entry.range;
398      return true;
399    }
400  
401    if ((scope & eSymbolContextBlock) && (block != nullptr)) {
402      if (use_inline_block_range) {
403        Block *inline_block = block->GetContainingInlinedBlock();
404        if (inline_block)
405          return inline_block->GetRangeAtIndex(range_idx, range);
406      } else {
407        return block->GetRangeAtIndex(range_idx, range);
408      }
409    }
410  
411    if ((scope & eSymbolContextFunction) && (function != nullptr)) {
412      if (range_idx == 0) {
413        range = function->GetAddressRange();
414        return true;
415      }
416    }
417  
418    if ((scope & eSymbolContextSymbol) && (symbol != nullptr)) {
419      if (range_idx == 0) {
420        if (symbol->ValueIsAddress()) {
421          range.GetBaseAddress() = symbol->GetAddressRef();
422          range.SetByteSize(symbol->GetByteSize());
423          return true;
424        }
425      }
426    }
427    range.Clear();
428    return false;
429  }
430  
GetLanguage() const431  LanguageType SymbolContext::GetLanguage() const {
432    LanguageType lang;
433    if (function && (lang = function->GetLanguage()) != eLanguageTypeUnknown) {
434      return lang;
435    } else if (variable &&
436               (lang = variable->GetLanguage()) != eLanguageTypeUnknown) {
437      return lang;
438    } else if (symbol && (lang = symbol->GetLanguage()) != eLanguageTypeUnknown) {
439      return lang;
440    } else if (comp_unit &&
441               (lang = comp_unit->GetLanguage()) != eLanguageTypeUnknown) {
442      return lang;
443    } else if (symbol) {
444      // If all else fails, try to guess the language from the name.
445      return symbol->GetMangled().GuessLanguage();
446    }
447    return eLanguageTypeUnknown;
448  }
449  
GetParentOfInlinedScope(const Address & curr_frame_pc,SymbolContext & next_frame_sc,Address & next_frame_pc) const450  bool SymbolContext::GetParentOfInlinedScope(const Address &curr_frame_pc,
451                                              SymbolContext &next_frame_sc,
452                                              Address &next_frame_pc) const {
453    next_frame_sc.Clear(false);
454    next_frame_pc.Clear();
455  
456    if (block) {
457      // const addr_t curr_frame_file_addr = curr_frame_pc.GetFileAddress();
458  
459      // In order to get the parent of an inlined function we first need to see
460      // if we are in an inlined block as "this->block" could be an inlined
461      // block, or a parent of "block" could be. So lets check if this block or
462      // one of this blocks parents is an inlined function.
463      Block *curr_inlined_block = block->GetContainingInlinedBlock();
464      if (curr_inlined_block) {
465        // "this->block" is contained in an inline function block, so to get the
466        // scope above the inlined block, we get the parent of the inlined block
467        // itself
468        Block *next_frame_block = curr_inlined_block->GetParent();
469        // Now calculate the symbol context of the containing block
470        next_frame_block->CalculateSymbolContext(&next_frame_sc);
471  
472        // If we get here we weren't able to find the return line entry using the
473        // nesting of the blocks and the line table.  So just use the call site
474        // info from our inlined block.
475  
476        AddressRange range;
477        if (curr_inlined_block->GetRangeContainingAddress(curr_frame_pc, range)) {
478          // To see there this new frame block it, we need to look at the call
479          // site information from
480          const InlineFunctionInfo *curr_inlined_block_inlined_info =
481              curr_inlined_block->GetInlinedFunctionInfo();
482          next_frame_pc = range.GetBaseAddress();
483          next_frame_sc.line_entry.range.GetBaseAddress() = next_frame_pc;
484          next_frame_sc.line_entry.file_sp = std::make_shared<SupportFile>(
485              curr_inlined_block_inlined_info->GetCallSite().GetFile());
486          next_frame_sc.line_entry.original_file_sp =
487              std::make_shared<SupportFile>(
488                  curr_inlined_block_inlined_info->GetCallSite().GetFile());
489          next_frame_sc.line_entry.line =
490              curr_inlined_block_inlined_info->GetCallSite().GetLine();
491          next_frame_sc.line_entry.column =
492              curr_inlined_block_inlined_info->GetCallSite().GetColumn();
493          return true;
494        } else {
495          Log *log = GetLog(LLDBLog::Symbols);
496  
497          if (log) {
498            LLDB_LOGF(
499                log,
500                "warning: inlined block 0x%8.8" PRIx64
501                " doesn't have a range that contains file address 0x%" PRIx64,
502                curr_inlined_block->GetID(), curr_frame_pc.GetFileAddress());
503          }
504  #ifdef LLDB_CONFIGURATION_DEBUG
505          else {
506            ObjectFile *objfile = nullptr;
507            if (module_sp) {
508              if (SymbolFile *symbol_file = module_sp->GetSymbolFile())
509                objfile = symbol_file->GetObjectFile();
510            }
511            if (objfile) {
512              Debugger::ReportWarning(llvm::formatv(
513                  "inlined block {0:x} doesn't have a range that contains file "
514                  "address {1:x} in {2}",
515                  curr_inlined_block->GetID(), curr_frame_pc.GetFileAddress(),
516                  objfile->GetFileSpec().GetPath()));
517            } else {
518              Debugger::ReportWarning(llvm::formatv(
519                  "inlined block {0:x} doesn't have a range that contains file "
520                  "address {1:x}",
521                  curr_inlined_block->GetID(), curr_frame_pc.GetFileAddress()));
522            }
523          }
524  #endif
525        }
526      }
527    }
528  
529    return false;
530  }
531  
GetFunctionBlock()532  Block *SymbolContext::GetFunctionBlock() {
533    if (function) {
534      if (block) {
535        // If this symbol context has a block, check to see if this block is
536        // itself, or is contained within a block with inlined function
537        // information. If so, then the inlined block is the block that defines
538        // the function.
539        Block *inlined_block = block->GetContainingInlinedBlock();
540        if (inlined_block)
541          return inlined_block;
542  
543        // The block in this symbol context is not inside an inlined block, so
544        // the block that defines the function is the function's top level block,
545        // which is returned below.
546      }
547  
548      // There is no block information in this symbol context, so we must assume
549      // that the block that is desired is the top level block of the function
550      // itself.
551      return &function->GetBlock(true);
552    }
553    return nullptr;
554  }
555  
GetInstanceVariableName()556  llvm::StringRef SymbolContext::GetInstanceVariableName() {
557    LanguageType lang_type = eLanguageTypeUnknown;
558  
559    if (Block *function_block = GetFunctionBlock())
560      if (CompilerDeclContext decl_ctx = function_block->GetDeclContext())
561        lang_type = decl_ctx.GetLanguage();
562  
563    if (lang_type == eLanguageTypeUnknown)
564      lang_type = GetLanguage();
565  
566    if (auto *lang = Language::FindPlugin(lang_type))
567      return lang->GetInstanceVariableName();
568  
569    return {};
570  }
571  
SortTypeList(TypeMap & type_map,TypeList & type_list) const572  void SymbolContext::SortTypeList(TypeMap &type_map, TypeList &type_list) const {
573    Block *curr_block = block;
574    bool isInlinedblock = false;
575    if (curr_block != nullptr &&
576        curr_block->GetContainingInlinedBlock() != nullptr)
577      isInlinedblock = true;
578  
579    // Find all types that match the current block if we have one and put them
580    // first in the list. Keep iterating up through all blocks.
581    while (curr_block != nullptr && !isInlinedblock) {
582      type_map.ForEach(
583          [curr_block, &type_list](const lldb::TypeSP &type_sp) -> bool {
584            SymbolContextScope *scs = type_sp->GetSymbolContextScope();
585            if (scs && curr_block == scs->CalculateSymbolContextBlock())
586              type_list.Insert(type_sp);
587            return true; // Keep iterating
588          });
589  
590      // Remove any entries that are now in "type_list" from "type_map" since we
591      // can't remove from type_map while iterating
592      type_list.ForEach([&type_map](const lldb::TypeSP &type_sp) -> bool {
593        type_map.Remove(type_sp);
594        return true; // Keep iterating
595      });
596      curr_block = curr_block->GetParent();
597    }
598    // Find all types that match the current function, if we have onem, and put
599    // them next in the list.
600    if (function != nullptr && !type_map.Empty()) {
601      const size_t old_type_list_size = type_list.GetSize();
602      type_map.ForEach([this, &type_list](const lldb::TypeSP &type_sp) -> bool {
603        SymbolContextScope *scs = type_sp->GetSymbolContextScope();
604        if (scs && function == scs->CalculateSymbolContextFunction())
605          type_list.Insert(type_sp);
606        return true; // Keep iterating
607      });
608  
609      // Remove any entries that are now in "type_list" from "type_map" since we
610      // can't remove from type_map while iterating
611      const size_t new_type_list_size = type_list.GetSize();
612      if (new_type_list_size > old_type_list_size) {
613        for (size_t i = old_type_list_size; i < new_type_list_size; ++i)
614          type_map.Remove(type_list.GetTypeAtIndex(i));
615      }
616    }
617    // Find all types that match the current compile unit, if we have one, and
618    // put them next in the list.
619    if (comp_unit != nullptr && !type_map.Empty()) {
620      const size_t old_type_list_size = type_list.GetSize();
621  
622      type_map.ForEach([this, &type_list](const lldb::TypeSP &type_sp) -> bool {
623        SymbolContextScope *scs = type_sp->GetSymbolContextScope();
624        if (scs && comp_unit == scs->CalculateSymbolContextCompileUnit())
625          type_list.Insert(type_sp);
626        return true; // Keep iterating
627      });
628  
629      // Remove any entries that are now in "type_list" from "type_map" since we
630      // can't remove from type_map while iterating
631      const size_t new_type_list_size = type_list.GetSize();
632      if (new_type_list_size > old_type_list_size) {
633        for (size_t i = old_type_list_size; i < new_type_list_size; ++i)
634          type_map.Remove(type_list.GetTypeAtIndex(i));
635      }
636    }
637    // Find all types that match the current module, if we have one, and put them
638    // next in the list.
639    if (module_sp && !type_map.Empty()) {
640      const size_t old_type_list_size = type_list.GetSize();
641      type_map.ForEach([this, &type_list](const lldb::TypeSP &type_sp) -> bool {
642        SymbolContextScope *scs = type_sp->GetSymbolContextScope();
643        if (scs && module_sp == scs->CalculateSymbolContextModule())
644          type_list.Insert(type_sp);
645        return true; // Keep iterating
646      });
647      // Remove any entries that are now in "type_list" from "type_map" since we
648      // can't remove from type_map while iterating
649      const size_t new_type_list_size = type_list.GetSize();
650      if (new_type_list_size > old_type_list_size) {
651        for (size_t i = old_type_list_size; i < new_type_list_size; ++i)
652          type_map.Remove(type_list.GetTypeAtIndex(i));
653      }
654    }
655    // Any types that are left get copied into the list an any order.
656    if (!type_map.Empty()) {
657      type_map.ForEach([&type_list](const lldb::TypeSP &type_sp) -> bool {
658        type_list.Insert(type_sp);
659        return true; // Keep iterating
660      });
661    }
662  }
663  
664  ConstString
GetFunctionName(Mangled::NamePreference preference) const665  SymbolContext::GetFunctionName(Mangled::NamePreference preference) const {
666    if (function) {
667      if (block) {
668        Block *inlined_block = block->GetContainingInlinedBlock();
669  
670        if (inlined_block) {
671          const InlineFunctionInfo *inline_info =
672              inlined_block->GetInlinedFunctionInfo();
673          if (inline_info)
674            return inline_info->GetName();
675        }
676      }
677      return function->GetMangled().GetName(preference);
678    } else if (symbol && symbol->ValueIsAddress()) {
679      return symbol->GetMangled().GetName(preference);
680    } else {
681      // No function, return an empty string.
682      return ConstString();
683    }
684  }
685  
GetFunctionStartLineEntry() const686  LineEntry SymbolContext::GetFunctionStartLineEntry() const {
687    LineEntry line_entry;
688    Address start_addr;
689    if (block) {
690      Block *inlined_block = block->GetContainingInlinedBlock();
691      if (inlined_block) {
692        if (inlined_block->GetStartAddress(start_addr)) {
693          if (start_addr.CalculateSymbolContextLineEntry(line_entry))
694            return line_entry;
695        }
696        return LineEntry();
697      }
698    }
699  
700    if (function) {
701      if (function->GetAddressRange()
702              .GetBaseAddress()
703              .CalculateSymbolContextLineEntry(line_entry))
704        return line_entry;
705    }
706    return LineEntry();
707  }
708  
GetAddressRangeFromHereToEndLine(uint32_t end_line,AddressRange & range,Status & error)709  bool SymbolContext::GetAddressRangeFromHereToEndLine(uint32_t end_line,
710                                                       AddressRange &range,
711                                                       Status &error) {
712    if (!line_entry.IsValid()) {
713      error.SetErrorString("Symbol context has no line table.");
714      return false;
715    }
716  
717    range = line_entry.range;
718    if (line_entry.line > end_line) {
719      error.SetErrorStringWithFormat(
720          "end line option %d must be after the current line: %d", end_line,
721          line_entry.line);
722      return false;
723    }
724  
725    uint32_t line_index = 0;
726    bool found = false;
727    while (true) {
728      LineEntry this_line;
729      line_index = comp_unit->FindLineEntry(line_index, line_entry.line, nullptr,
730                                            false, &this_line);
731      if (line_index == UINT32_MAX)
732        break;
733      if (LineEntry::Compare(this_line, line_entry) == 0) {
734        found = true;
735        break;
736      }
737    }
738  
739    LineEntry end_entry;
740    if (!found) {
741      // Can't find the index of the SymbolContext's line entry in the
742      // SymbolContext's CompUnit.
743      error.SetErrorString(
744          "Can't find the current line entry in the CompUnit - can't process "
745          "the end-line option");
746      return false;
747    }
748  
749    line_index = comp_unit->FindLineEntry(line_index, end_line, nullptr, false,
750                                          &end_entry);
751    if (line_index == UINT32_MAX) {
752      error.SetErrorStringWithFormat(
753          "could not find a line table entry corresponding "
754          "to end line number %d",
755          end_line);
756      return false;
757    }
758  
759    Block *func_block = GetFunctionBlock();
760    if (func_block && func_block->GetRangeIndexContainingAddress(
761                          end_entry.range.GetBaseAddress()) == UINT32_MAX) {
762      error.SetErrorStringWithFormat(
763          "end line number %d is not contained within the current function.",
764          end_line);
765      return false;
766    }
767  
768    lldb::addr_t range_size = end_entry.range.GetBaseAddress().GetFileAddress() -
769                              range.GetBaseAddress().GetFileAddress();
770    range.SetByteSize(range_size);
771    return true;
772  }
773  
FindBestGlobalDataSymbol(ConstString name,Status & error)774  const Symbol *SymbolContext::FindBestGlobalDataSymbol(ConstString name,
775                                                        Status &error) {
776    error.Clear();
777  
778    if (!target_sp) {
779      return nullptr;
780    }
781  
782    Target &target = *target_sp;
783    Module *module = module_sp.get();
784  
785    auto ProcessMatches = [this, &name, &target,
786                           module](const SymbolContextList &sc_list,
787                                   Status &error) -> const Symbol * {
788      llvm::SmallVector<const Symbol *, 1> external_symbols;
789      llvm::SmallVector<const Symbol *, 1> internal_symbols;
790      for (const SymbolContext &sym_ctx : sc_list) {
791        if (sym_ctx.symbol) {
792          const Symbol *symbol = sym_ctx.symbol;
793          const Address sym_address = symbol->GetAddress();
794  
795          if (sym_address.IsValid()) {
796            switch (symbol->GetType()) {
797            case eSymbolTypeData:
798            case eSymbolTypeRuntime:
799            case eSymbolTypeAbsolute:
800            case eSymbolTypeObjCClass:
801            case eSymbolTypeObjCMetaClass:
802            case eSymbolTypeObjCIVar:
803              if (symbol->GetDemangledNameIsSynthesized()) {
804                // If the demangled name was synthesized, then don't use it for
805                // expressions. Only let the symbol match if the mangled named
806                // matches for these symbols.
807                if (symbol->GetMangled().GetMangledName() != name)
808                  break;
809              }
810              if (symbol->IsExternal()) {
811                external_symbols.push_back(symbol);
812              } else {
813                internal_symbols.push_back(symbol);
814              }
815              break;
816            case eSymbolTypeReExported: {
817              ConstString reexport_name = symbol->GetReExportedSymbolName();
818              if (reexport_name) {
819                ModuleSP reexport_module_sp;
820                ModuleSpec reexport_module_spec;
821                reexport_module_spec.GetPlatformFileSpec() =
822                    symbol->GetReExportedSymbolSharedLibrary();
823                if (reexport_module_spec.GetPlatformFileSpec()) {
824                  reexport_module_sp =
825                      target.GetImages().FindFirstModule(reexport_module_spec);
826                  if (!reexport_module_sp) {
827                    reexport_module_spec.GetPlatformFileSpec().ClearDirectory();
828                    reexport_module_sp =
829                        target.GetImages().FindFirstModule(reexport_module_spec);
830                  }
831                }
832                // Don't allow us to try and resolve a re-exported symbol if it
833                // is the same as the current symbol
834                if (name == symbol->GetReExportedSymbolName() &&
835                    module == reexport_module_sp.get())
836                  return nullptr;
837  
838                return FindBestGlobalDataSymbol(symbol->GetReExportedSymbolName(),
839                                                error);
840              }
841            } break;
842  
843            case eSymbolTypeCode: // We already lookup functions elsewhere
844            case eSymbolTypeVariable:
845            case eSymbolTypeLocal:
846            case eSymbolTypeParam:
847            case eSymbolTypeTrampoline:
848            case eSymbolTypeInvalid:
849            case eSymbolTypeException:
850            case eSymbolTypeSourceFile:
851            case eSymbolTypeHeaderFile:
852            case eSymbolTypeObjectFile:
853            case eSymbolTypeCommonBlock:
854            case eSymbolTypeBlock:
855            case eSymbolTypeVariableType:
856            case eSymbolTypeLineEntry:
857            case eSymbolTypeLineHeader:
858            case eSymbolTypeScopeBegin:
859            case eSymbolTypeScopeEnd:
860            case eSymbolTypeAdditional:
861            case eSymbolTypeCompiler:
862            case eSymbolTypeInstrumentation:
863            case eSymbolTypeUndefined:
864            case eSymbolTypeResolver:
865              break;
866            }
867          }
868        }
869      }
870  
871      if (external_symbols.size() > 1) {
872        StreamString ss;
873        ss.Printf("Multiple external symbols found for '%s'\n", name.AsCString());
874        for (const Symbol *symbol : external_symbols) {
875          symbol->GetDescription(&ss, eDescriptionLevelFull, &target);
876        }
877        ss.PutChar('\n');
878        error.SetErrorString(ss.GetData());
879        return nullptr;
880      } else if (external_symbols.size()) {
881        return external_symbols[0];
882      } else if (internal_symbols.size() > 1) {
883        StreamString ss;
884        ss.Printf("Multiple internal symbols found for '%s'\n", name.AsCString());
885        for (const Symbol *symbol : internal_symbols) {
886          symbol->GetDescription(&ss, eDescriptionLevelVerbose, &target);
887          ss.PutChar('\n');
888        }
889        error.SetErrorString(ss.GetData());
890        return nullptr;
891      } else if (internal_symbols.size()) {
892        return internal_symbols[0];
893      } else {
894        return nullptr;
895      }
896    };
897  
898    if (module) {
899      SymbolContextList sc_list;
900      module->FindSymbolsWithNameAndType(name, eSymbolTypeAny, sc_list);
901      const Symbol *const module_symbol = ProcessMatches(sc_list, error);
902  
903      if (!error.Success()) {
904        return nullptr;
905      } else if (module_symbol) {
906        return module_symbol;
907      }
908    }
909  
910    {
911      SymbolContextList sc_list;
912      target.GetImages().FindSymbolsWithNameAndType(name, eSymbolTypeAny,
913                                                    sc_list);
914      const Symbol *const target_symbol = ProcessMatches(sc_list, error);
915  
916      if (!error.Success()) {
917        return nullptr;
918      } else if (target_symbol) {
919        return target_symbol;
920      }
921    }
922  
923    return nullptr; // no error; we just didn't find anything
924  }
925  
926  //
927  //  SymbolContextSpecifier
928  //
929  
SymbolContextSpecifier(const TargetSP & target_sp)930  SymbolContextSpecifier::SymbolContextSpecifier(const TargetSP &target_sp)
931      : m_target_sp(target_sp), m_module_spec(), m_module_sp(), m_file_spec_up(),
932        m_start_line(0), m_end_line(0), m_function_spec(), m_class_name(),
933        m_address_range_up(), m_type(eNothingSpecified) {}
934  
935  SymbolContextSpecifier::~SymbolContextSpecifier() = default;
936  
AddLineSpecification(uint32_t line_no,SpecificationType type)937  bool SymbolContextSpecifier::AddLineSpecification(uint32_t line_no,
938                                                    SpecificationType type) {
939    bool return_value = true;
940    switch (type) {
941    case eNothingSpecified:
942      Clear();
943      break;
944    case eLineStartSpecified:
945      m_start_line = line_no;
946      m_type |= eLineStartSpecified;
947      break;
948    case eLineEndSpecified:
949      m_end_line = line_no;
950      m_type |= eLineEndSpecified;
951      break;
952    default:
953      return_value = false;
954      break;
955    }
956    return return_value;
957  }
958  
AddSpecification(const char * spec_string,SpecificationType type)959  bool SymbolContextSpecifier::AddSpecification(const char *spec_string,
960                                                SpecificationType type) {
961    bool return_value = true;
962    switch (type) {
963    case eNothingSpecified:
964      Clear();
965      break;
966    case eModuleSpecified: {
967      // See if we can find the Module, if so stick it in the SymbolContext.
968      FileSpec module_file_spec(spec_string);
969      ModuleSpec module_spec(module_file_spec);
970      lldb::ModuleSP module_sp =
971          m_target_sp ? m_target_sp->GetImages().FindFirstModule(module_spec)
972                      : nullptr;
973      m_type |= eModuleSpecified;
974      if (module_sp)
975        m_module_sp = module_sp;
976      else
977        m_module_spec.assign(spec_string);
978    } break;
979    case eFileSpecified:
980      // CompUnits can't necessarily be resolved here, since an inlined function
981      // might show up in a number of CompUnits.  Instead we just convert to a
982      // FileSpec and store it away.
983      m_file_spec_up = std::make_unique<FileSpec>(spec_string);
984      m_type |= eFileSpecified;
985      break;
986    case eLineStartSpecified:
987      if ((return_value = llvm::to_integer(spec_string, m_start_line)))
988        m_type |= eLineStartSpecified;
989      break;
990    case eLineEndSpecified:
991      if ((return_value = llvm::to_integer(spec_string, m_end_line)))
992        m_type |= eLineEndSpecified;
993      break;
994    case eFunctionSpecified:
995      m_function_spec.assign(spec_string);
996      m_type |= eFunctionSpecified;
997      break;
998    case eClassOrNamespaceSpecified:
999      Clear();
1000      m_class_name.assign(spec_string);
1001      m_type = eClassOrNamespaceSpecified;
1002      break;
1003    case eAddressRangeSpecified:
1004      // Not specified yet...
1005      break;
1006    }
1007  
1008    return return_value;
1009  }
1010  
Clear()1011  void SymbolContextSpecifier::Clear() {
1012    m_module_spec.clear();
1013    m_file_spec_up.reset();
1014    m_function_spec.clear();
1015    m_class_name.clear();
1016    m_start_line = 0;
1017    m_end_line = 0;
1018    m_address_range_up.reset();
1019  
1020    m_type = eNothingSpecified;
1021  }
1022  
SymbolContextMatches(const SymbolContext & sc)1023  bool SymbolContextSpecifier::SymbolContextMatches(const SymbolContext &sc) {
1024    if (m_type == eNothingSpecified)
1025      return true;
1026  
1027    // Only compare targets if this specifier has one and it's not the Dummy
1028    // target.  Otherwise if a specifier gets made in the dummy target and
1029    // copied over we'll artificially fail the comparision.
1030    if (m_target_sp && !m_target_sp->IsDummyTarget() &&
1031        m_target_sp != sc.target_sp)
1032      return false;
1033  
1034    if (m_type & eModuleSpecified) {
1035      if (sc.module_sp) {
1036        if (m_module_sp.get() != nullptr) {
1037          if (m_module_sp.get() != sc.module_sp.get())
1038            return false;
1039        } else {
1040          FileSpec module_file_spec(m_module_spec);
1041          if (!FileSpec::Match(module_file_spec, sc.module_sp->GetFileSpec()))
1042            return false;
1043        }
1044      }
1045    }
1046    if (m_type & eFileSpecified) {
1047      if (m_file_spec_up) {
1048        // If we don't have a block or a comp_unit, then we aren't going to match
1049        // a source file.
1050        if (sc.block == nullptr && sc.comp_unit == nullptr)
1051          return false;
1052  
1053        // Check if the block is present, and if so is it inlined:
1054        bool was_inlined = false;
1055        if (sc.block != nullptr) {
1056          const InlineFunctionInfo *inline_info =
1057              sc.block->GetInlinedFunctionInfo();
1058          if (inline_info != nullptr) {
1059            was_inlined = true;
1060            if (!FileSpec::Match(*m_file_spec_up,
1061                                 inline_info->GetDeclaration().GetFile()))
1062              return false;
1063          }
1064        }
1065  
1066        // Next check the comp unit, but only if the SymbolContext was not
1067        // inlined.
1068        if (!was_inlined && sc.comp_unit != nullptr) {
1069          if (!FileSpec::Match(*m_file_spec_up, sc.comp_unit->GetPrimaryFile()))
1070            return false;
1071        }
1072      }
1073    }
1074    if (m_type & eLineStartSpecified || m_type & eLineEndSpecified) {
1075      if (sc.line_entry.line < m_start_line || sc.line_entry.line > m_end_line)
1076        return false;
1077    }
1078  
1079    if (m_type & eFunctionSpecified) {
1080      // First check the current block, and if it is inlined, get the inlined
1081      // function name:
1082      bool was_inlined = false;
1083      ConstString func_name(m_function_spec.c_str());
1084  
1085      if (sc.block != nullptr) {
1086        const InlineFunctionInfo *inline_info =
1087            sc.block->GetInlinedFunctionInfo();
1088        if (inline_info != nullptr) {
1089          was_inlined = true;
1090          const Mangled &name = inline_info->GetMangled();
1091          if (!name.NameMatches(func_name))
1092            return false;
1093        }
1094      }
1095      //  If it wasn't inlined, check the name in the function or symbol:
1096      if (!was_inlined) {
1097        if (sc.function != nullptr) {
1098          if (!sc.function->GetMangled().NameMatches(func_name))
1099            return false;
1100        } else if (sc.symbol != nullptr) {
1101          if (!sc.symbol->GetMangled().NameMatches(func_name))
1102            return false;
1103        }
1104      }
1105    }
1106  
1107    return true;
1108  }
1109  
AddressMatches(lldb::addr_t addr)1110  bool SymbolContextSpecifier::AddressMatches(lldb::addr_t addr) {
1111    if (m_type & eAddressRangeSpecified) {
1112  
1113    } else {
1114      Address match_address(addr, nullptr);
1115      SymbolContext sc;
1116      m_target_sp->GetImages().ResolveSymbolContextForAddress(
1117          match_address, eSymbolContextEverything, sc);
1118      return SymbolContextMatches(sc);
1119    }
1120    return true;
1121  }
1122  
GetDescription(Stream * s,lldb::DescriptionLevel level) const1123  void SymbolContextSpecifier::GetDescription(
1124      Stream *s, lldb::DescriptionLevel level) const {
1125    char path_str[PATH_MAX + 1];
1126  
1127    if (m_type == eNothingSpecified) {
1128      s->Printf("Nothing specified.\n");
1129    }
1130  
1131    if (m_type == eModuleSpecified) {
1132      s->Indent();
1133      if (m_module_sp) {
1134        m_module_sp->GetFileSpec().GetPath(path_str, PATH_MAX);
1135        s->Printf("Module: %s\n", path_str);
1136      } else
1137        s->Printf("Module: %s\n", m_module_spec.c_str());
1138    }
1139  
1140    if (m_type == eFileSpecified && m_file_spec_up != nullptr) {
1141      m_file_spec_up->GetPath(path_str, PATH_MAX);
1142      s->Indent();
1143      s->Printf("File: %s", path_str);
1144      if (m_type == eLineStartSpecified) {
1145        s->Printf(" from line %" PRIu64 "", (uint64_t)m_start_line);
1146        if (m_type == eLineEndSpecified)
1147          s->Printf("to line %" PRIu64 "", (uint64_t)m_end_line);
1148        else
1149          s->Printf("to end");
1150      } else if (m_type == eLineEndSpecified) {
1151        s->Printf(" from start to line %" PRIu64 "", (uint64_t)m_end_line);
1152      }
1153      s->Printf(".\n");
1154    }
1155  
1156    if (m_type == eLineStartSpecified) {
1157      s->Indent();
1158      s->Printf("From line %" PRIu64 "", (uint64_t)m_start_line);
1159      if (m_type == eLineEndSpecified)
1160        s->Printf("to line %" PRIu64 "", (uint64_t)m_end_line);
1161      else
1162        s->Printf("to end");
1163      s->Printf(".\n");
1164    } else if (m_type == eLineEndSpecified) {
1165      s->Printf("From start to line %" PRIu64 ".\n", (uint64_t)m_end_line);
1166    }
1167  
1168    if (m_type == eFunctionSpecified) {
1169      s->Indent();
1170      s->Printf("Function: %s.\n", m_function_spec.c_str());
1171    }
1172  
1173    if (m_type == eClassOrNamespaceSpecified) {
1174      s->Indent();
1175      s->Printf("Class name: %s.\n", m_class_name.c_str());
1176    }
1177  
1178    if (m_type == eAddressRangeSpecified && m_address_range_up != nullptr) {
1179      s->Indent();
1180      s->PutCString("Address range: ");
1181      m_address_range_up->Dump(s, m_target_sp.get(),
1182                               Address::DumpStyleLoadAddress,
1183                               Address::DumpStyleFileAddress);
1184      s->PutCString("\n");
1185    }
1186  }
1187  
1188  //
1189  //  SymbolContextList
1190  //
1191  
SymbolContextList()1192  SymbolContextList::SymbolContextList() : m_symbol_contexts() {}
1193  
1194  SymbolContextList::~SymbolContextList() = default;
1195  
Append(const SymbolContext & sc)1196  void SymbolContextList::Append(const SymbolContext &sc) {
1197    m_symbol_contexts.push_back(sc);
1198  }
1199  
Append(const SymbolContextList & sc_list)1200  void SymbolContextList::Append(const SymbolContextList &sc_list) {
1201    collection::const_iterator pos, end = sc_list.m_symbol_contexts.end();
1202    for (pos = sc_list.m_symbol_contexts.begin(); pos != end; ++pos)
1203      m_symbol_contexts.push_back(*pos);
1204  }
1205  
AppendIfUnique(const SymbolContextList & sc_list,bool merge_symbol_into_function)1206  uint32_t SymbolContextList::AppendIfUnique(const SymbolContextList &sc_list,
1207                                             bool merge_symbol_into_function) {
1208    uint32_t unique_sc_add_count = 0;
1209    collection::const_iterator pos, end = sc_list.m_symbol_contexts.end();
1210    for (pos = sc_list.m_symbol_contexts.begin(); pos != end; ++pos) {
1211      if (AppendIfUnique(*pos, merge_symbol_into_function))
1212        ++unique_sc_add_count;
1213    }
1214    return unique_sc_add_count;
1215  }
1216  
AppendIfUnique(const SymbolContext & sc,bool merge_symbol_into_function)1217  bool SymbolContextList::AppendIfUnique(const SymbolContext &sc,
1218                                         bool merge_symbol_into_function) {
1219    collection::iterator pos, end = m_symbol_contexts.end();
1220    for (pos = m_symbol_contexts.begin(); pos != end; ++pos) {
1221      if (*pos == sc)
1222        return false;
1223    }
1224    if (merge_symbol_into_function && sc.symbol != nullptr &&
1225        sc.comp_unit == nullptr && sc.function == nullptr &&
1226        sc.block == nullptr && !sc.line_entry.IsValid()) {
1227      if (sc.symbol->ValueIsAddress()) {
1228        for (pos = m_symbol_contexts.begin(); pos != end; ++pos) {
1229          // Don't merge symbols into inlined function symbol contexts
1230          if (pos->block && pos->block->GetContainingInlinedBlock())
1231            continue;
1232  
1233          if (pos->function) {
1234            if (pos->function->GetAddressRange().GetBaseAddress() ==
1235                sc.symbol->GetAddressRef()) {
1236              // Do we already have a function with this symbol?
1237              if (pos->symbol == sc.symbol)
1238                return false;
1239              if (pos->symbol == nullptr) {
1240                pos->symbol = sc.symbol;
1241                return false;
1242              }
1243            }
1244          }
1245        }
1246      }
1247    }
1248    m_symbol_contexts.push_back(sc);
1249    return true;
1250  }
1251  
Clear()1252  void SymbolContextList::Clear() { m_symbol_contexts.clear(); }
1253  
Dump(Stream * s,Target * target) const1254  void SymbolContextList::Dump(Stream *s, Target *target) const {
1255  
1256    *s << this << ": ";
1257    s->Indent();
1258    s->PutCString("SymbolContextList");
1259    s->EOL();
1260    s->IndentMore();
1261  
1262    collection::const_iterator pos, end = m_symbol_contexts.end();
1263    for (pos = m_symbol_contexts.begin(); pos != end; ++pos) {
1264      // pos->Dump(s, target);
1265      pos->GetDescription(s, eDescriptionLevelVerbose, target);
1266    }
1267    s->IndentLess();
1268  }
1269  
GetContextAtIndex(size_t idx,SymbolContext & sc) const1270  bool SymbolContextList::GetContextAtIndex(size_t idx, SymbolContext &sc) const {
1271    if (idx < m_symbol_contexts.size()) {
1272      sc = m_symbol_contexts[idx];
1273      return true;
1274    }
1275    return false;
1276  }
1277  
RemoveContextAtIndex(size_t idx)1278  bool SymbolContextList::RemoveContextAtIndex(size_t idx) {
1279    if (idx < m_symbol_contexts.size()) {
1280      m_symbol_contexts.erase(m_symbol_contexts.begin() + idx);
1281      return true;
1282    }
1283    return false;
1284  }
1285  
GetSize() const1286  uint32_t SymbolContextList::GetSize() const { return m_symbol_contexts.size(); }
1287  
IsEmpty() const1288  bool SymbolContextList::IsEmpty() const { return m_symbol_contexts.empty(); }
1289  
NumLineEntriesWithLine(uint32_t line) const1290  uint32_t SymbolContextList::NumLineEntriesWithLine(uint32_t line) const {
1291    uint32_t match_count = 0;
1292    const size_t size = m_symbol_contexts.size();
1293    for (size_t idx = 0; idx < size; ++idx) {
1294      if (m_symbol_contexts[idx].line_entry.line == line)
1295        ++match_count;
1296    }
1297    return match_count;
1298  }
1299  
GetDescription(Stream * s,lldb::DescriptionLevel level,Target * target) const1300  void SymbolContextList::GetDescription(Stream *s, lldb::DescriptionLevel level,
1301                                         Target *target) const {
1302    const size_t size = m_symbol_contexts.size();
1303    for (size_t idx = 0; idx < size; ++idx)
1304      m_symbol_contexts[idx].GetDescription(s, level, target);
1305  }
1306  
operator ==(const SymbolContextList & lhs,const SymbolContextList & rhs)1307  bool lldb_private::operator==(const SymbolContextList &lhs,
1308                                const SymbolContextList &rhs) {
1309    const uint32_t size = lhs.GetSize();
1310    if (size != rhs.GetSize())
1311      return false;
1312  
1313    SymbolContext lhs_sc;
1314    SymbolContext rhs_sc;
1315    for (uint32_t i = 0; i < size; ++i) {
1316      lhs.GetContextAtIndex(i, lhs_sc);
1317      rhs.GetContextAtIndex(i, rhs_sc);
1318      if (lhs_sc != rhs_sc)
1319        return false;
1320    }
1321    return true;
1322  }
1323  
operator !=(const SymbolContextList & lhs,const SymbolContextList & rhs)1324  bool lldb_private::operator!=(const SymbolContextList &lhs,
1325                                const SymbolContextList &rhs) {
1326    return !(lhs == rhs);
1327  }
1328