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