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