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