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 
29 SymbolContext::SymbolContext()
30     : target_sp(), module_sp(), comp_unit(nullptr), function(nullptr),
31       block(nullptr), line_entry(), symbol(nullptr), variable(nullptr) {}
32 
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 
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 
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 
56 SymbolContext::~SymbolContext() {}
57 
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 
70 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 
181 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, target);
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 
280 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 
301 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 
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 
370 bool lldb_private::operator!=(const SymbolContext &lhs,
371                               const SymbolContext &rhs) {
372   return !(lhs == rhs);
373 }
374 
375 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 
413 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 
432 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 
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 
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 
556 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
649 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 
670 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 
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 
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 
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 
924 SymbolContextSpecifier::~SymbolContextSpecifier() {}
925 
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 
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 
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 
1013 bool SymbolContextSpecifier::SymbolContextMatches(const SymbolContext &sc) {
1014   if (m_type == eNothingSpecified)
1015     return true;
1016 
1017   // Only compare targets if this specifier has one and it's not the Dummy
1018   // target.  Otherwise if a specifier gets made in the dummy target and
1019   // copied over we'll artificially fail the comparision.
1020   if (m_target_sp && !m_target_sp->IsDummyTarget() &&
1021       m_target_sp != sc.target_sp)
1022     return false;
1023 
1024   if (m_type & eModuleSpecified) {
1025     if (sc.module_sp) {
1026       if (m_module_sp.get() != nullptr) {
1027         if (m_module_sp.get() != sc.module_sp.get())
1028           return false;
1029       } else {
1030         FileSpec module_file_spec(m_module_spec);
1031         if (!FileSpec::Match(module_file_spec, sc.module_sp->GetFileSpec()))
1032           return false;
1033       }
1034     }
1035   }
1036   if (m_type & eFileSpecified) {
1037     if (m_file_spec_up) {
1038       // If we don't have a block or a comp_unit, then we aren't going to match
1039       // a source file.
1040       if (sc.block == nullptr && sc.comp_unit == nullptr)
1041         return false;
1042 
1043       // Check if the block is present, and if so is it inlined:
1044       bool was_inlined = false;
1045       if (sc.block != nullptr) {
1046         const InlineFunctionInfo *inline_info =
1047             sc.block->GetInlinedFunctionInfo();
1048         if (inline_info != nullptr) {
1049           was_inlined = true;
1050           if (!FileSpec::Match(*m_file_spec_up,
1051                                inline_info->GetDeclaration().GetFile()))
1052             return false;
1053         }
1054       }
1055 
1056       // Next check the comp unit, but only if the SymbolContext was not
1057       // inlined.
1058       if (!was_inlined && sc.comp_unit != nullptr) {
1059         if (!FileSpec::Match(*m_file_spec_up, sc.comp_unit->GetPrimaryFile()))
1060           return false;
1061       }
1062     }
1063   }
1064   if (m_type & eLineStartSpecified || m_type & eLineEndSpecified) {
1065     if (sc.line_entry.line < m_start_line || sc.line_entry.line > m_end_line)
1066       return false;
1067   }
1068 
1069   if (m_type & eFunctionSpecified) {
1070     // First check the current block, and if it is inlined, get the inlined
1071     // function name:
1072     bool was_inlined = false;
1073     ConstString func_name(m_function_spec.c_str());
1074 
1075     if (sc.block != nullptr) {
1076       const InlineFunctionInfo *inline_info =
1077           sc.block->GetInlinedFunctionInfo();
1078       if (inline_info != nullptr) {
1079         was_inlined = true;
1080         const Mangled &name = inline_info->GetMangled();
1081         if (!name.NameMatches(func_name))
1082           return false;
1083       }
1084     }
1085     //  If it wasn't inlined, check the name in the function or symbol:
1086     if (!was_inlined) {
1087       if (sc.function != nullptr) {
1088         if (!sc.function->GetMangled().NameMatches(func_name))
1089           return false;
1090       } else if (sc.symbol != nullptr) {
1091         if (!sc.symbol->GetMangled().NameMatches(func_name))
1092           return false;
1093       }
1094     }
1095   }
1096 
1097   return true;
1098 }
1099 
1100 bool SymbolContextSpecifier::AddressMatches(lldb::addr_t addr) {
1101   if (m_type & eAddressRangeSpecified) {
1102 
1103   } else {
1104     Address match_address(addr, nullptr);
1105     SymbolContext sc;
1106     m_target_sp->GetImages().ResolveSymbolContextForAddress(
1107         match_address, eSymbolContextEverything, sc);
1108     return SymbolContextMatches(sc);
1109   }
1110   return true;
1111 }
1112 
1113 void SymbolContextSpecifier::GetDescription(
1114     Stream *s, lldb::DescriptionLevel level) const {
1115   char path_str[PATH_MAX + 1];
1116 
1117   if (m_type == eNothingSpecified) {
1118     s->Printf("Nothing specified.\n");
1119   }
1120 
1121   if (m_type == eModuleSpecified) {
1122     s->Indent();
1123     if (m_module_sp) {
1124       m_module_sp->GetFileSpec().GetPath(path_str, PATH_MAX);
1125       s->Printf("Module: %s\n", path_str);
1126     } else
1127       s->Printf("Module: %s\n", m_module_spec.c_str());
1128   }
1129 
1130   if (m_type == eFileSpecified && m_file_spec_up != nullptr) {
1131     m_file_spec_up->GetPath(path_str, PATH_MAX);
1132     s->Indent();
1133     s->Printf("File: %s", path_str);
1134     if (m_type == eLineStartSpecified) {
1135       s->Printf(" from line %" PRIu64 "", (uint64_t)m_start_line);
1136       if (m_type == eLineEndSpecified)
1137         s->Printf("to line %" PRIu64 "", (uint64_t)m_end_line);
1138       else
1139         s->Printf("to end");
1140     } else if (m_type == eLineEndSpecified) {
1141       s->Printf(" from start to line %" PRIu64 "", (uint64_t)m_end_line);
1142     }
1143     s->Printf(".\n");
1144   }
1145 
1146   if (m_type == eLineStartSpecified) {
1147     s->Indent();
1148     s->Printf("From line %" PRIu64 "", (uint64_t)m_start_line);
1149     if (m_type == eLineEndSpecified)
1150       s->Printf("to line %" PRIu64 "", (uint64_t)m_end_line);
1151     else
1152       s->Printf("to end");
1153     s->Printf(".\n");
1154   } else if (m_type == eLineEndSpecified) {
1155     s->Printf("From start to line %" PRIu64 ".\n", (uint64_t)m_end_line);
1156   }
1157 
1158   if (m_type == eFunctionSpecified) {
1159     s->Indent();
1160     s->Printf("Function: %s.\n", m_function_spec.c_str());
1161   }
1162 
1163   if (m_type == eClassOrNamespaceSpecified) {
1164     s->Indent();
1165     s->Printf("Class name: %s.\n", m_class_name.c_str());
1166   }
1167 
1168   if (m_type == eAddressRangeSpecified && m_address_range_up != nullptr) {
1169     s->Indent();
1170     s->PutCString("Address range: ");
1171     m_address_range_up->Dump(s, m_target_sp.get(),
1172                              Address::DumpStyleLoadAddress,
1173                              Address::DumpStyleFileAddress);
1174     s->PutCString("\n");
1175   }
1176 }
1177 
1178 //
1179 //  SymbolContextList
1180 //
1181 
1182 SymbolContextList::SymbolContextList() : m_symbol_contexts() {}
1183 
1184 SymbolContextList::~SymbolContextList() {}
1185 
1186 void SymbolContextList::Append(const SymbolContext &sc) {
1187   m_symbol_contexts.push_back(sc);
1188 }
1189 
1190 void SymbolContextList::Append(const SymbolContextList &sc_list) {
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     m_symbol_contexts.push_back(*pos);
1194 }
1195 
1196 uint32_t SymbolContextList::AppendIfUnique(const SymbolContextList &sc_list,
1197                                            bool merge_symbol_into_function) {
1198   uint32_t unique_sc_add_count = 0;
1199   collection::const_iterator pos, end = sc_list.m_symbol_contexts.end();
1200   for (pos = sc_list.m_symbol_contexts.begin(); pos != end; ++pos) {
1201     if (AppendIfUnique(*pos, merge_symbol_into_function))
1202       ++unique_sc_add_count;
1203   }
1204   return unique_sc_add_count;
1205 }
1206 
1207 bool SymbolContextList::AppendIfUnique(const SymbolContext &sc,
1208                                        bool merge_symbol_into_function) {
1209   collection::iterator pos, end = m_symbol_contexts.end();
1210   for (pos = m_symbol_contexts.begin(); pos != end; ++pos) {
1211     if (*pos == sc)
1212       return false;
1213   }
1214   if (merge_symbol_into_function && sc.symbol != nullptr &&
1215       sc.comp_unit == nullptr && sc.function == nullptr &&
1216       sc.block == nullptr && !sc.line_entry.IsValid()) {
1217     if (sc.symbol->ValueIsAddress()) {
1218       for (pos = m_symbol_contexts.begin(); pos != end; ++pos) {
1219         // Don't merge symbols into inlined function symbol contexts
1220         if (pos->block && pos->block->GetContainingInlinedBlock())
1221           continue;
1222 
1223         if (pos->function) {
1224           if (pos->function->GetAddressRange().GetBaseAddress() ==
1225               sc.symbol->GetAddressRef()) {
1226             // Do we already have a function with this symbol?
1227             if (pos->symbol == sc.symbol)
1228               return false;
1229             if (pos->symbol == nullptr) {
1230               pos->symbol = sc.symbol;
1231               return false;
1232             }
1233           }
1234         }
1235       }
1236     }
1237   }
1238   m_symbol_contexts.push_back(sc);
1239   return true;
1240 }
1241 
1242 void SymbolContextList::Clear() { m_symbol_contexts.clear(); }
1243 
1244 void SymbolContextList::Dump(Stream *s, Target *target) const {
1245 
1246   *s << this << ": ";
1247   s->Indent();
1248   s->PutCString("SymbolContextList");
1249   s->EOL();
1250   s->IndentMore();
1251 
1252   collection::const_iterator pos, end = m_symbol_contexts.end();
1253   for (pos = m_symbol_contexts.begin(); pos != end; ++pos) {
1254     // pos->Dump(s, target);
1255     pos->GetDescription(s, eDescriptionLevelVerbose, target);
1256   }
1257   s->IndentLess();
1258 }
1259 
1260 bool SymbolContextList::GetContextAtIndex(size_t idx, SymbolContext &sc) const {
1261   if (idx < m_symbol_contexts.size()) {
1262     sc = m_symbol_contexts[idx];
1263     return true;
1264   }
1265   return false;
1266 }
1267 
1268 bool SymbolContextList::RemoveContextAtIndex(size_t idx) {
1269   if (idx < m_symbol_contexts.size()) {
1270     m_symbol_contexts.erase(m_symbol_contexts.begin() + idx);
1271     return true;
1272   }
1273   return false;
1274 }
1275 
1276 uint32_t SymbolContextList::GetSize() const { return m_symbol_contexts.size(); }
1277 
1278 bool SymbolContextList::IsEmpty() const { return m_symbol_contexts.empty(); }
1279 
1280 uint32_t SymbolContextList::NumLineEntriesWithLine(uint32_t line) const {
1281   uint32_t match_count = 0;
1282   const size_t size = m_symbol_contexts.size();
1283   for (size_t idx = 0; idx < size; ++idx) {
1284     if (m_symbol_contexts[idx].line_entry.line == line)
1285       ++match_count;
1286   }
1287   return match_count;
1288 }
1289 
1290 void SymbolContextList::GetDescription(Stream *s, lldb::DescriptionLevel level,
1291                                        Target *target) const {
1292   const size_t size = m_symbol_contexts.size();
1293   for (size_t idx = 0; idx < size; ++idx)
1294     m_symbol_contexts[idx].GetDescription(s, level, target);
1295 }
1296 
1297 bool lldb_private::operator==(const SymbolContextList &lhs,
1298                               const SymbolContextList &rhs) {
1299   const uint32_t size = lhs.GetSize();
1300   if (size != rhs.GetSize())
1301     return false;
1302 
1303   SymbolContext lhs_sc;
1304   SymbolContext rhs_sc;
1305   for (uint32_t i = 0; i < size; ++i) {
1306     lhs.GetContextAtIndex(i, lhs_sc);
1307     rhs.GetContextAtIndex(i, rhs_sc);
1308     if (lhs_sc != rhs_sc)
1309       return false;
1310   }
1311   return true;
1312 }
1313 
1314 bool lldb_private::operator!=(const SymbolContextList &lhs,
1315                               const SymbolContextList &rhs) {
1316   return !(lhs == rhs);
1317 }
1318