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

source code of lldb/source/Symbol/SymbolContext.cpp