1 //===-- SymbolContext.cpp -------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "lldb/Symbol/SymbolContext.h"
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"
32 using namespace lldb_private
;
34 SymbolContext::SymbolContext() : target_sp(), module_sp(), line_entry() {}
36 SymbolContext::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
) {
44 SymbolContext::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
) {
53 SymbolContext::SymbolContext(SymbolContextScope
*sc_scope
)
54 : target_sp(), module_sp(), line_entry() {
55 sc_scope
->CalculateSymbolContext(this);
58 SymbolContext::~SymbolContext() = default;
60 void SymbolContext::Clear(bool clear_target
) {
72 bool 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 bool show_function_display_name
,
77 std::optional
<Stream::HighlightSettings
> settings
) const {
78 bool dumped_something
= false;
79 if (show_module
&& module_sp
) {
81 *s
<< module_sp
->GetFileSpec();
83 *s
<< module_sp
->GetFileSpec().GetFilename();
85 dumped_something
= true;
87 if (function
!= nullptr) {
88 SymbolContext inline_parent_sc
;
89 Address inline_parent_addr
;
90 if (!show_function_name
) {
92 dumped_something
= true;
95 if (!show_function_arguments
)
96 name
= function
->GetNameNoArguments();
97 if (!name
&& show_function_display_name
)
98 name
= function
->GetDisplayName();
100 name
= function
->GetName();
102 s
->PutCStringColorHighlighted(name
.GetStringRef(), settings
);
105 if (addr
.IsValid()) {
106 const addr_t function_offset
=
108 function
->GetAddressRange().GetBaseAddress().GetOffset();
109 if (!show_function_name
) {
110 // Print +offset even if offset is 0
111 dumped_something
= true;
112 s
->Printf("+%" PRIu64
">", function_offset
);
113 } else if (function_offset
) {
114 dumped_something
= true;
115 s
->Printf(" + %" PRIu64
, function_offset
);
119 if (GetParentOfInlinedScope(addr
, inline_parent_sc
, inline_parent_addr
)) {
120 dumped_something
= true;
121 Block
*inlined_block
= block
->GetContainingInlinedBlock();
122 const InlineFunctionInfo
*inlined_block_info
=
123 inlined_block
->GetInlinedFunctionInfo();
124 s
->Printf(" [inlined] %s", inlined_block_info
->GetName().GetCString());
126 lldb_private::AddressRange block_range
;
127 if (inlined_block
->GetRangeContainingAddress(addr
, block_range
)) {
128 const addr_t inlined_function_offset
=
129 addr
.GetOffset() - block_range
.GetBaseAddress().GetOffset();
130 if (inlined_function_offset
) {
131 s
->Printf(" + %" PRIu64
, inlined_function_offset
);
134 // "line_entry" will always be valid as GetParentOfInlinedScope(...) will
135 // fill it in correctly with the calling file and line. Previous code
136 // was extracting the calling file and line from inlined_block_info and
137 // using it right away which is not correct. On the first call to this
138 // function "line_entry" will contain the actual line table entry. On
139 // susequent calls "line_entry" will contain the calling file and line
140 // from the previous inline info.
141 if (line_entry
.IsValid()) {
142 s
->PutCString(" at ");
143 line_entry
.DumpStopContext(s
, show_fullpaths
);
146 if (show_inlined_frames
) {
149 const bool show_function_name
= true;
150 return inline_parent_sc
.DumpStopContext(
151 s
, exe_scope
, inline_parent_addr
, show_fullpaths
, show_module
,
152 show_inlined_frames
, show_function_arguments
, show_function_name
,
153 show_function_display_name
);
156 if (line_entry
.IsValid()) {
157 dumped_something
= true;
158 s
->PutCString(" at ");
159 if (line_entry
.DumpStopContext(s
, show_fullpaths
))
160 dumped_something
= true;
163 } else if (symbol
!= nullptr) {
164 if (!show_function_name
) {
166 dumped_something
= true;
167 } else if (symbol
->GetName()) {
168 dumped_something
= true;
169 if (symbol
->GetType() == eSymbolTypeTrampoline
)
170 s
->PutCString("symbol stub for: ");
172 if (show_function_display_name
)
173 name
= symbol
->GetDisplayName();
175 name
= symbol
->GetName();
176 s
->PutCStringColorHighlighted(name
.GetStringRef(), settings
);
179 if (addr
.IsValid() && symbol
->ValueIsAddress()) {
180 const addr_t symbol_offset
=
181 addr
.GetOffset() - symbol
->GetAddressRef().GetOffset();
182 if (!show_function_name
) {
183 // Print +offset even if offset is 0
184 dumped_something
= true;
185 s
->Printf("+%" PRIu64
">", symbol_offset
);
186 } else if (symbol_offset
) {
187 dumped_something
= true;
188 s
->Printf(" + %" PRIu64
, symbol_offset
);
191 } else if (addr
.IsValid()) {
192 addr
.Dump(s
, exe_scope
, Address::DumpStyleModuleWithFileAddress
);
193 dumped_something
= true;
195 return dumped_something
;
198 void SymbolContext::GetDescription(
199 Stream
*s
, lldb::DescriptionLevel level
, Target
*target
,
200 std::optional
<Stream::HighlightSettings
> settings
) const {
202 s
->Indent(" Module: file = \"");
203 module_sp
->GetFileSpec().Dump(s
->AsRawOstream());
205 if (module_sp
->GetArchitecture().IsValid())
206 s
->Printf(", arch = \"%s\"",
207 module_sp
->GetArchitecture().GetArchitectureName());
211 if (comp_unit
!= nullptr) {
212 s
->Indent("CompileUnit: ");
213 comp_unit
->GetDescription(s
, level
);
217 if (function
!= nullptr) {
218 s
->Indent(" Function: ");
219 function
->GetDescription(s
, level
, target
);
222 Type
*func_type
= function
->GetType();
224 s
->Indent(" FuncType: ");
225 func_type
->GetDescription(s
, level
, false, target
);
230 if (block
!= nullptr) {
231 std::vector
<Block
*> blocks
;
232 blocks
.push_back(block
);
233 Block
*parent_block
= block
->GetParent();
235 while (parent_block
) {
236 blocks
.push_back(parent_block
);
237 parent_block
= parent_block
->GetParent();
239 std::vector
<Block
*>::reverse_iterator pos
;
240 std::vector
<Block
*>::reverse_iterator begin
= blocks
.rbegin();
241 std::vector
<Block
*>::reverse_iterator end
= blocks
.rend();
242 for (pos
= begin
; pos
!= end
; ++pos
) {
244 s
->Indent(" Blocks: ");
247 (*pos
)->GetDescription(s
, function
, level
, target
);
252 if (line_entry
.IsValid()) {
253 s
->Indent(" LineEntry: ");
254 line_entry
.GetDescription(s
, level
, comp_unit
, target
, false);
258 if (symbol
!= nullptr) {
259 s
->Indent(" Symbol: ");
260 symbol
->GetDescription(s
, level
, target
, settings
);
264 if (variable
!= nullptr) {
265 s
->Indent(" Variable: ");
267 s
->Printf("id = {0x%8.8" PRIx64
"}, ", variable
->GetID());
269 switch (variable
->GetScope()) {
270 case eValueTypeVariableGlobal
:
271 s
->PutCString("kind = global, ");
274 case eValueTypeVariableStatic
:
275 s
->PutCString("kind = static, ");
278 case eValueTypeVariableArgument
:
279 s
->PutCString("kind = argument, ");
282 case eValueTypeVariableLocal
:
283 s
->PutCString("kind = local, ");
286 case eValueTypeVariableThreadLocal
:
287 s
->PutCString("kind = thread local, ");
294 s
->Printf("name = \"%s\"\n", variable
->GetName().GetCString());
298 uint32_t SymbolContext::GetResolvedMask() const {
299 uint32_t resolved_mask
= 0;
301 resolved_mask
|= eSymbolContextTarget
;
303 resolved_mask
|= eSymbolContextModule
;
305 resolved_mask
|= eSymbolContextCompUnit
;
307 resolved_mask
|= eSymbolContextFunction
;
309 resolved_mask
|= eSymbolContextBlock
;
310 if (line_entry
.IsValid())
311 resolved_mask
|= eSymbolContextLineEntry
;
313 resolved_mask
|= eSymbolContextSymbol
;
315 resolved_mask
|= eSymbolContextVariable
;
316 return resolved_mask
;
319 void SymbolContext::Dump(Stream
*s
, Target
*target
) const {
322 s
->PutCString("SymbolContext");
327 *s
<< "Module = " << module_sp
.get() << ' ';
329 module_sp
->GetFileSpec().Dump(s
->AsRawOstream());
332 *s
<< "CompileUnit = " << comp_unit
;
333 if (comp_unit
!= nullptr)
334 s
->Format(" {{{0:x-16}} {1}", comp_unit
->GetID(),
335 comp_unit
->GetPrimaryFile());
338 *s
<< "Function = " << function
;
339 if (function
!= nullptr) {
340 s
->Format(" {{{0:x-16}} {1}, address-range = ", function
->GetID(),
341 function
->GetType()->GetName());
342 function
->GetAddressRange().Dump(s
, target
, Address::DumpStyleLoadAddress
,
343 Address::DumpStyleModuleWithFileAddress
);
346 Type
*func_type
= function
->GetType();
349 func_type
->Dump(s
, false);
354 *s
<< "Block = " << block
;
355 if (block
!= nullptr)
356 s
->Format(" {{{0:x-16}}", block
->GetID());
359 *s
<< "LineEntry = ";
360 line_entry
.Dump(s
, target
, true, Address::DumpStyleLoadAddress
,
361 Address::DumpStyleModuleWithFileAddress
, true);
364 *s
<< "Symbol = " << symbol
;
365 if (symbol
!= nullptr && symbol
->GetMangled())
366 *s
<< ' ' << symbol
->GetName().AsCString();
368 *s
<< "Variable = " << variable
;
369 if (variable
!= nullptr) {
370 s
->Format(" {{{0:x-16}} {1}", variable
->GetID(),
371 variable
->GetType()->GetName());
378 bool lldb_private::operator==(const SymbolContext
&lhs
,
379 const SymbolContext
&rhs
) {
380 return lhs
.function
== rhs
.function
&& lhs
.symbol
== rhs
.symbol
&&
381 lhs
.module_sp
.get() == rhs
.module_sp
.get() &&
382 lhs
.comp_unit
== rhs
.comp_unit
&&
383 lhs
.target_sp
.get() == rhs
.target_sp
.get() &&
384 LineEntry::Compare(lhs
.line_entry
, rhs
.line_entry
) == 0 &&
385 lhs
.variable
== rhs
.variable
;
388 bool lldb_private::operator!=(const SymbolContext
&lhs
,
389 const SymbolContext
&rhs
) {
390 return !(lhs
== rhs
);
393 bool SymbolContext::GetAddressRange(uint32_t scope
, uint32_t range_idx
,
394 bool use_inline_block_range
,
395 AddressRange
&range
) const {
396 if ((scope
& eSymbolContextLineEntry
) && line_entry
.IsValid()) {
397 range
= line_entry
.range
;
401 if ((scope
& eSymbolContextBlock
) && (block
!= nullptr)) {
402 if (use_inline_block_range
) {
403 Block
*inline_block
= block
->GetContainingInlinedBlock();
405 return inline_block
->GetRangeAtIndex(range_idx
, range
);
407 return block
->GetRangeAtIndex(range_idx
, range
);
411 if ((scope
& eSymbolContextFunction
) && (function
!= nullptr)) {
412 if (range_idx
== 0) {
413 range
= function
->GetAddressRange();
418 if ((scope
& eSymbolContextSymbol
) && (symbol
!= nullptr)) {
419 if (range_idx
== 0) {
420 if (symbol
->ValueIsAddress()) {
421 range
.GetBaseAddress() = symbol
->GetAddressRef();
422 range
.SetByteSize(symbol
->GetByteSize());
431 LanguageType
SymbolContext::GetLanguage() const {
433 if (function
&& (lang
= function
->GetLanguage()) != eLanguageTypeUnknown
) {
435 } else if (variable
&&
436 (lang
= variable
->GetLanguage()) != eLanguageTypeUnknown
) {
438 } else if (symbol
&& (lang
= symbol
->GetLanguage()) != eLanguageTypeUnknown
) {
440 } else if (comp_unit
&&
441 (lang
= comp_unit
->GetLanguage()) != eLanguageTypeUnknown
) {
444 // If all else fails, try to guess the language from the name.
445 return symbol
->GetMangled().GuessLanguage();
447 return eLanguageTypeUnknown
;
450 bool SymbolContext::GetParentOfInlinedScope(const Address
&curr_frame_pc
,
451 SymbolContext
&next_frame_sc
,
452 Address
&next_frame_pc
) const {
453 next_frame_sc
.Clear(false);
454 next_frame_pc
.Clear();
457 // const addr_t curr_frame_file_addr = curr_frame_pc.GetFileAddress();
459 // In order to get the parent of an inlined function we first need to see
460 // if we are in an inlined block as "this->block" could be an inlined
461 // block, or a parent of "block" could be. So lets check if this block or
462 // one of this blocks parents is an inlined function.
463 Block
*curr_inlined_block
= block
->GetContainingInlinedBlock();
464 if (curr_inlined_block
) {
465 // "this->block" is contained in an inline function block, so to get the
466 // scope above the inlined block, we get the parent of the inlined block
468 Block
*next_frame_block
= curr_inlined_block
->GetParent();
469 // Now calculate the symbol context of the containing block
470 next_frame_block
->CalculateSymbolContext(&next_frame_sc
);
472 // If we get here we weren't able to find the return line entry using the
473 // nesting of the blocks and the line table. So just use the call site
474 // info from our inlined block.
477 if (curr_inlined_block
->GetRangeContainingAddress(curr_frame_pc
, range
)) {
478 // To see there this new frame block it, we need to look at the call
479 // site information from
480 const InlineFunctionInfo
*curr_inlined_block_inlined_info
=
481 curr_inlined_block
->GetInlinedFunctionInfo();
482 next_frame_pc
= range
.GetBaseAddress();
483 next_frame_sc
.line_entry
.range
.GetBaseAddress() = next_frame_pc
;
484 next_frame_sc
.line_entry
.file_sp
= std::make_shared
<SupportFile
>(
485 curr_inlined_block_inlined_info
->GetCallSite().GetFile());
486 next_frame_sc
.line_entry
.original_file_sp
=
487 std::make_shared
<SupportFile
>(
488 curr_inlined_block_inlined_info
->GetCallSite().GetFile());
489 next_frame_sc
.line_entry
.line
=
490 curr_inlined_block_inlined_info
->GetCallSite().GetLine();
491 next_frame_sc
.line_entry
.column
=
492 curr_inlined_block_inlined_info
->GetCallSite().GetColumn();
495 Log
*log
= GetLog(LLDBLog::Symbols
);
500 "warning: inlined block 0x%8.8" PRIx64
501 " doesn't have a range that contains file address 0x%" PRIx64
,
502 curr_inlined_block
->GetID(), curr_frame_pc
.GetFileAddress());
504 #ifdef LLDB_CONFIGURATION_DEBUG
506 ObjectFile
*objfile
= nullptr;
508 if (SymbolFile
*symbol_file
= module_sp
->GetSymbolFile())
509 objfile
= symbol_file
->GetObjectFile();
512 Debugger::ReportWarning(llvm::formatv(
513 "inlined block {0:x} doesn't have a range that contains file "
514 "address {1:x} in {2}",
515 curr_inlined_block
->GetID(), curr_frame_pc
.GetFileAddress(),
516 objfile
->GetFileSpec().GetPath()));
518 Debugger::ReportWarning(llvm::formatv(
519 "inlined block {0:x} doesn't have a range that contains file "
521 curr_inlined_block
->GetID(), curr_frame_pc
.GetFileAddress()));
532 Block
*SymbolContext::GetFunctionBlock() {
535 // If this symbol context has a block, check to see if this block is
536 // itself, or is contained within a block with inlined function
537 // information. If so, then the inlined block is the block that defines
539 Block
*inlined_block
= block
->GetContainingInlinedBlock();
541 return inlined_block
;
543 // The block in this symbol context is not inside an inlined block, so
544 // the block that defines the function is the function's top level block,
545 // which is returned below.
548 // There is no block information in this symbol context, so we must assume
549 // that the block that is desired is the top level block of the function
551 return &function
->GetBlock(true);
556 llvm::StringRef
SymbolContext::GetInstanceVariableName() {
557 LanguageType lang_type
= eLanguageTypeUnknown
;
559 if (Block
*function_block
= GetFunctionBlock())
560 if (CompilerDeclContext decl_ctx
= function_block
->GetDeclContext())
561 lang_type
= decl_ctx
.GetLanguage();
563 if (lang_type
== eLanguageTypeUnknown
)
564 lang_type
= GetLanguage();
566 if (auto *lang
= Language::FindPlugin(lang_type
))
567 return lang
->GetInstanceVariableName();
572 void SymbolContext::SortTypeList(TypeMap
&type_map
, TypeList
&type_list
) const {
573 Block
*curr_block
= block
;
574 bool isInlinedblock
= false;
575 if (curr_block
!= nullptr &&
576 curr_block
->GetContainingInlinedBlock() != nullptr)
577 isInlinedblock
= true;
579 // Find all types that match the current block if we have one and put them
580 // first in the list. Keep iterating up through all blocks.
581 while (curr_block
!= nullptr && !isInlinedblock
) {
583 [curr_block
, &type_list
](const lldb::TypeSP
&type_sp
) -> bool {
584 SymbolContextScope
*scs
= type_sp
->GetSymbolContextScope();
585 if (scs
&& curr_block
== scs
->CalculateSymbolContextBlock())
586 type_list
.Insert(type_sp
);
587 return true; // Keep iterating
590 // Remove any entries that are now in "type_list" from "type_map" since we
591 // can't remove from type_map while iterating
592 type_list
.ForEach([&type_map
](const lldb::TypeSP
&type_sp
) -> bool {
593 type_map
.Remove(type_sp
);
594 return true; // Keep iterating
596 curr_block
= curr_block
->GetParent();
598 // Find all types that match the current function, if we have onem, and put
599 // them next in the list.
600 if (function
!= nullptr && !type_map
.Empty()) {
601 const size_t old_type_list_size
= type_list
.GetSize();
602 type_map
.ForEach([this, &type_list
](const lldb::TypeSP
&type_sp
) -> bool {
603 SymbolContextScope
*scs
= type_sp
->GetSymbolContextScope();
604 if (scs
&& function
== scs
->CalculateSymbolContextFunction())
605 type_list
.Insert(type_sp
);
606 return true; // Keep iterating
609 // Remove any entries that are now in "type_list" from "type_map" since we
610 // can't remove from type_map while iterating
611 const size_t new_type_list_size
= type_list
.GetSize();
612 if (new_type_list_size
> old_type_list_size
) {
613 for (size_t i
= old_type_list_size
; i
< new_type_list_size
; ++i
)
614 type_map
.Remove(type_list
.GetTypeAtIndex(i
));
617 // Find all types that match the current compile unit, if we have one, and
618 // put them next in the list.
619 if (comp_unit
!= nullptr && !type_map
.Empty()) {
620 const size_t old_type_list_size
= type_list
.GetSize();
622 type_map
.ForEach([this, &type_list
](const lldb::TypeSP
&type_sp
) -> bool {
623 SymbolContextScope
*scs
= type_sp
->GetSymbolContextScope();
624 if (scs
&& comp_unit
== scs
->CalculateSymbolContextCompileUnit())
625 type_list
.Insert(type_sp
);
626 return true; // Keep iterating
629 // Remove any entries that are now in "type_list" from "type_map" since we
630 // can't remove from type_map while iterating
631 const size_t new_type_list_size
= type_list
.GetSize();
632 if (new_type_list_size
> old_type_list_size
) {
633 for (size_t i
= old_type_list_size
; i
< new_type_list_size
; ++i
)
634 type_map
.Remove(type_list
.GetTypeAtIndex(i
));
637 // Find all types that match the current module, if we have one, and put them
639 if (module_sp
&& !type_map
.Empty()) {
640 const size_t old_type_list_size
= type_list
.GetSize();
641 type_map
.ForEach([this, &type_list
](const lldb::TypeSP
&type_sp
) -> bool {
642 SymbolContextScope
*scs
= type_sp
->GetSymbolContextScope();
643 if (scs
&& module_sp
== scs
->CalculateSymbolContextModule())
644 type_list
.Insert(type_sp
);
645 return true; // Keep iterating
647 // Remove any entries that are now in "type_list" from "type_map" since we
648 // can't remove from type_map while iterating
649 const size_t new_type_list_size
= type_list
.GetSize();
650 if (new_type_list_size
> old_type_list_size
) {
651 for (size_t i
= old_type_list_size
; i
< new_type_list_size
; ++i
)
652 type_map
.Remove(type_list
.GetTypeAtIndex(i
));
655 // Any types that are left get copied into the list an any order.
656 if (!type_map
.Empty()) {
657 type_map
.ForEach([&type_list
](const lldb::TypeSP
&type_sp
) -> bool {
658 type_list
.Insert(type_sp
);
659 return true; // Keep iterating
665 SymbolContext::GetFunctionName(Mangled::NamePreference preference
) const {
668 Block
*inlined_block
= block
->GetContainingInlinedBlock();
671 const InlineFunctionInfo
*inline_info
=
672 inlined_block
->GetInlinedFunctionInfo();
674 return inline_info
->GetName();
677 return function
->GetMangled().GetName(preference
);
678 } else if (symbol
&& symbol
->ValueIsAddress()) {
679 return symbol
->GetMangled().GetName(preference
);
681 // No function, return an empty string.
682 return ConstString();
686 LineEntry
SymbolContext::GetFunctionStartLineEntry() const {
687 LineEntry line_entry
;
690 Block
*inlined_block
= block
->GetContainingInlinedBlock();
692 if (inlined_block
->GetStartAddress(start_addr
)) {
693 if (start_addr
.CalculateSymbolContextLineEntry(line_entry
))
701 if (function
->GetAddressRange()
703 .CalculateSymbolContextLineEntry(line_entry
))
710 SymbolContext::GetAddressRangeFromHereToEndLine(uint32_t end_line
,
711 AddressRange
&range
) {
712 if (!line_entry
.IsValid()) {
713 return llvm::createStringError("Symbol context has no line table.");
716 range
= line_entry
.range
;
717 if (line_entry
.line
> end_line
) {
718 return llvm::createStringError(
719 "end line option %d must be after the current line: %d", end_line
,
723 uint32_t line_index
= 0;
727 line_index
= comp_unit
->FindLineEntry(line_index
, line_entry
.line
, nullptr,
729 if (line_index
== UINT32_MAX
)
731 if (LineEntry::Compare(this_line
, line_entry
) == 0) {
739 // Can't find the index of the SymbolContext's line entry in the
740 // SymbolContext's CompUnit.
741 return llvm::createStringError(
742 "Can't find the current line entry in the CompUnit - can't process "
743 "the end-line option");
746 line_index
= comp_unit
->FindLineEntry(line_index
, end_line
, nullptr, false,
748 if (line_index
== UINT32_MAX
) {
749 return llvm::createStringError(
750 "could not find a line table entry corresponding "
751 "to end line number %d",
755 Block
*func_block
= GetFunctionBlock();
756 if (func_block
&& func_block
->GetRangeIndexContainingAddress(
757 end_entry
.range
.GetBaseAddress()) == UINT32_MAX
) {
758 return llvm::createStringError(
759 "end line number %d is not contained within the current function.",
763 lldb::addr_t range_size
= end_entry
.range
.GetBaseAddress().GetFileAddress() -
764 range
.GetBaseAddress().GetFileAddress();
765 range
.SetByteSize(range_size
);
766 return llvm::Error::success();
769 const Symbol
*SymbolContext::FindBestGlobalDataSymbol(ConstString name
,
777 Target
&target
= *target_sp
;
778 Module
*module
= module_sp
.get();
780 auto ProcessMatches
= [this, &name
, &target
,
781 module
](const SymbolContextList
&sc_list
,
782 Status
&error
) -> const Symbol
* {
783 llvm::SmallVector
<const Symbol
*, 1> external_symbols
;
784 llvm::SmallVector
<const Symbol
*, 1> internal_symbols
;
785 for (const SymbolContext
&sym_ctx
: sc_list
) {
786 if (sym_ctx
.symbol
) {
787 const Symbol
*symbol
= sym_ctx
.symbol
;
788 const Address sym_address
= symbol
->GetAddress();
790 if (sym_address
.IsValid()) {
791 switch (symbol
->GetType()) {
792 case eSymbolTypeData
:
793 case eSymbolTypeRuntime
:
794 case eSymbolTypeAbsolute
:
795 case eSymbolTypeObjCClass
:
796 case eSymbolTypeObjCMetaClass
:
797 case eSymbolTypeObjCIVar
:
798 if (symbol
->GetDemangledNameIsSynthesized()) {
799 // If the demangled name was synthesized, then don't use it for
800 // expressions. Only let the symbol match if the mangled named
801 // matches for these symbols.
802 if (symbol
->GetMangled().GetMangledName() != name
)
805 if (symbol
->IsExternal()) {
806 external_symbols
.push_back(symbol
);
808 internal_symbols
.push_back(symbol
);
811 case eSymbolTypeReExported
: {
812 ConstString reexport_name
= symbol
->GetReExportedSymbolName();
814 ModuleSP reexport_module_sp
;
815 ModuleSpec reexport_module_spec
;
816 reexport_module_spec
.GetPlatformFileSpec() =
817 symbol
->GetReExportedSymbolSharedLibrary();
818 if (reexport_module_spec
.GetPlatformFileSpec()) {
820 target
.GetImages().FindFirstModule(reexport_module_spec
);
821 if (!reexport_module_sp
) {
822 reexport_module_spec
.GetPlatformFileSpec().ClearDirectory();
824 target
.GetImages().FindFirstModule(reexport_module_spec
);
827 // Don't allow us to try and resolve a re-exported symbol if it
828 // is the same as the current symbol
829 if (name
== symbol
->GetReExportedSymbolName() &&
830 module
== reexport_module_sp
.get())
833 return FindBestGlobalDataSymbol(symbol
->GetReExportedSymbolName(),
838 case eSymbolTypeCode
: // We already lookup functions elsewhere
839 case eSymbolTypeVariable
:
840 case eSymbolTypeLocal
:
841 case eSymbolTypeParam
:
842 case eSymbolTypeTrampoline
:
843 case eSymbolTypeInvalid
:
844 case eSymbolTypeException
:
845 case eSymbolTypeSourceFile
:
846 case eSymbolTypeHeaderFile
:
847 case eSymbolTypeObjectFile
:
848 case eSymbolTypeCommonBlock
:
849 case eSymbolTypeBlock
:
850 case eSymbolTypeVariableType
:
851 case eSymbolTypeLineEntry
:
852 case eSymbolTypeLineHeader
:
853 case eSymbolTypeScopeBegin
:
854 case eSymbolTypeScopeEnd
:
855 case eSymbolTypeAdditional
:
856 case eSymbolTypeCompiler
:
857 case eSymbolTypeInstrumentation
:
858 case eSymbolTypeUndefined
:
859 case eSymbolTypeResolver
:
866 if (external_symbols
.size() > 1) {
868 ss
.Printf("Multiple external symbols found for '%s'\n", name
.AsCString());
869 for (const Symbol
*symbol
: external_symbols
) {
870 symbol
->GetDescription(&ss
, eDescriptionLevelFull
, &target
);
873 error
= Status::FromErrorString(ss
.GetData());
875 } else if (external_symbols
.size()) {
876 return external_symbols
[0];
877 } else if (internal_symbols
.size() > 1) {
879 ss
.Printf("Multiple internal symbols found for '%s'\n", name
.AsCString());
880 for (const Symbol
*symbol
: internal_symbols
) {
881 symbol
->GetDescription(&ss
, eDescriptionLevelVerbose
, &target
);
884 error
= Status::FromErrorString(ss
.GetData());
886 } else if (internal_symbols
.size()) {
887 return internal_symbols
[0];
894 SymbolContextList sc_list
;
895 module
->FindSymbolsWithNameAndType(name
, eSymbolTypeAny
, sc_list
);
896 const Symbol
*const module_symbol
= ProcessMatches(sc_list
, error
);
898 if (!error
.Success()) {
900 } else if (module_symbol
) {
901 return module_symbol
;
906 SymbolContextList sc_list
;
907 target
.GetImages().FindSymbolsWithNameAndType(name
, eSymbolTypeAny
,
909 const Symbol
*const target_symbol
= ProcessMatches(sc_list
, error
);
911 if (!error
.Success()) {
913 } else if (target_symbol
) {
914 return target_symbol
;
918 return nullptr; // no error; we just didn't find anything
922 // SymbolContextSpecifier
925 SymbolContextSpecifier::SymbolContextSpecifier(const TargetSP
&target_sp
)
926 : m_target_sp(target_sp
), m_module_spec(), m_module_sp(), m_file_spec_up(),
927 m_start_line(0), m_end_line(0), m_function_spec(), m_class_name(),
928 m_address_range_up(), m_type(eNothingSpecified
) {}
930 SymbolContextSpecifier::~SymbolContextSpecifier() = default;
932 bool SymbolContextSpecifier::AddLineSpecification(uint32_t line_no
,
933 SpecificationType type
) {
934 bool return_value
= true;
936 case eNothingSpecified
:
939 case eLineStartSpecified
:
940 m_start_line
= line_no
;
941 m_type
|= eLineStartSpecified
;
943 case eLineEndSpecified
:
944 m_end_line
= line_no
;
945 m_type
|= eLineEndSpecified
;
948 return_value
= false;
954 bool SymbolContextSpecifier::AddSpecification(const char *spec_string
,
955 SpecificationType type
) {
956 bool return_value
= true;
958 case eNothingSpecified
:
961 case eModuleSpecified
: {
962 // See if we can find the Module, if so stick it in the SymbolContext.
963 FileSpec
module_file_spec(spec_string
);
964 ModuleSpec
module_spec(module_file_spec
);
965 lldb::ModuleSP module_sp
=
966 m_target_sp
? m_target_sp
->GetImages().FindFirstModule(module_spec
)
968 m_type
|= eModuleSpecified
;
970 m_module_sp
= module_sp
;
972 m_module_spec
.assign(spec_string
);
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
;
981 case eLineStartSpecified
:
982 if ((return_value
= llvm::to_integer(spec_string
, m_start_line
)))
983 m_type
|= eLineStartSpecified
;
985 case eLineEndSpecified
:
986 if ((return_value
= llvm::to_integer(spec_string
, m_end_line
)))
987 m_type
|= eLineEndSpecified
;
989 case eFunctionSpecified
:
990 m_function_spec
.assign(spec_string
);
991 m_type
|= eFunctionSpecified
;
993 case eClassOrNamespaceSpecified
:
995 m_class_name
.assign(spec_string
);
996 m_type
= eClassOrNamespaceSpecified
;
998 case eAddressRangeSpecified
:
999 // Not specified yet...
1003 return return_value
;
1006 void SymbolContextSpecifier::Clear() {
1007 m_module_spec
.clear();
1008 m_file_spec_up
.reset();
1009 m_function_spec
.clear();
1010 m_class_name
.clear();
1013 m_address_range_up
.reset();
1015 m_type
= eNothingSpecified
;
1018 bool SymbolContextSpecifier::SymbolContextMatches(const SymbolContext
&sc
) {
1019 if (m_type
== eNothingSpecified
)
1022 // Only compare targets if this specifier has one and it's not the Dummy
1023 // target. Otherwise if a specifier gets made in the dummy target and
1024 // copied over we'll artificially fail the comparision.
1025 if (m_target_sp
&& !m_target_sp
->IsDummyTarget() &&
1026 m_target_sp
!= sc
.target_sp
)
1029 if (m_type
& eModuleSpecified
) {
1031 if (m_module_sp
.get() != nullptr) {
1032 if (m_module_sp
.get() != sc
.module_sp
.get())
1035 FileSpec
module_file_spec(m_module_spec
);
1036 if (!FileSpec::Match(module_file_spec
, sc
.module_sp
->GetFileSpec()))
1041 if (m_type
& eFileSpecified
) {
1042 if (m_file_spec_up
) {
1043 // If we don't have a block or a comp_unit, then we aren't going to match
1045 if (sc
.block
== nullptr && sc
.comp_unit
== nullptr)
1048 // Check if the block is present, and if so is it inlined:
1049 bool was_inlined
= false;
1050 if (sc
.block
!= nullptr) {
1051 const InlineFunctionInfo
*inline_info
=
1052 sc
.block
->GetInlinedFunctionInfo();
1053 if (inline_info
!= nullptr) {
1055 if (!FileSpec::Match(*m_file_spec_up
,
1056 inline_info
->GetDeclaration().GetFile()))
1061 // Next check the comp unit, but only if the SymbolContext was not
1063 if (!was_inlined
&& sc
.comp_unit
!= nullptr) {
1064 if (!FileSpec::Match(*m_file_spec_up
, sc
.comp_unit
->GetPrimaryFile()))
1069 if (m_type
& eLineStartSpecified
|| m_type
& eLineEndSpecified
) {
1070 if (sc
.line_entry
.line
< m_start_line
|| sc
.line_entry
.line
> m_end_line
)
1074 if (m_type
& eFunctionSpecified
) {
1075 // First check the current block, and if it is inlined, get the inlined
1077 bool was_inlined
= false;
1078 ConstString
func_name(m_function_spec
.c_str());
1080 if (sc
.block
!= nullptr) {
1081 const InlineFunctionInfo
*inline_info
=
1082 sc
.block
->GetInlinedFunctionInfo();
1083 if (inline_info
!= nullptr) {
1085 const Mangled
&name
= inline_info
->GetMangled();
1086 if (!name
.NameMatches(func_name
))
1090 // If it wasn't inlined, check the name in the function or symbol:
1092 if (sc
.function
!= nullptr) {
1093 if (!sc
.function
->GetMangled().NameMatches(func_name
))
1095 } else if (sc
.symbol
!= nullptr) {
1096 if (!sc
.symbol
->GetMangled().NameMatches(func_name
))
1105 bool SymbolContextSpecifier::AddressMatches(lldb::addr_t addr
) {
1106 if (m_type
& eAddressRangeSpecified
) {
1109 Address
match_address(addr
, nullptr);
1111 m_target_sp
->GetImages().ResolveSymbolContextForAddress(
1112 match_address
, eSymbolContextEverything
, sc
);
1113 return SymbolContextMatches(sc
);
1118 void SymbolContextSpecifier::GetDescription(
1119 Stream
*s
, lldb::DescriptionLevel level
) const {
1120 char path_str
[PATH_MAX
+ 1];
1122 if (m_type
== eNothingSpecified
) {
1123 s
->Printf("Nothing specified.\n");
1126 if (m_type
== eModuleSpecified
) {
1129 m_module_sp
->GetFileSpec().GetPath(path_str
, PATH_MAX
);
1130 s
->Printf("Module: %s\n", path_str
);
1132 s
->Printf("Module: %s\n", m_module_spec
.c_str());
1135 if (m_type
== eFileSpecified
&& m_file_spec_up
!= nullptr) {
1136 m_file_spec_up
->GetPath(path_str
, PATH_MAX
);
1138 s
->Printf("File: %s", path_str
);
1139 if (m_type
== eLineStartSpecified
) {
1140 s
->Printf(" from line %" PRIu64
"", (uint64_t)m_start_line
);
1141 if (m_type
== eLineEndSpecified
)
1142 s
->Printf("to line %" PRIu64
"", (uint64_t)m_end_line
);
1144 s
->Printf("to end");
1145 } else if (m_type
== eLineEndSpecified
) {
1146 s
->Printf(" from start to line %" PRIu64
"", (uint64_t)m_end_line
);
1151 if (m_type
== eLineStartSpecified
) {
1153 s
->Printf("From line %" PRIu64
"", (uint64_t)m_start_line
);
1154 if (m_type
== eLineEndSpecified
)
1155 s
->Printf("to line %" PRIu64
"", (uint64_t)m_end_line
);
1157 s
->Printf("to end");
1159 } else if (m_type
== eLineEndSpecified
) {
1160 s
->Printf("From start to line %" PRIu64
".\n", (uint64_t)m_end_line
);
1163 if (m_type
== eFunctionSpecified
) {
1165 s
->Printf("Function: %s.\n", m_function_spec
.c_str());
1168 if (m_type
== eClassOrNamespaceSpecified
) {
1170 s
->Printf("Class name: %s.\n", m_class_name
.c_str());
1173 if (m_type
== eAddressRangeSpecified
&& m_address_range_up
!= nullptr) {
1175 s
->PutCString("Address range: ");
1176 m_address_range_up
->Dump(s
, m_target_sp
.get(),
1177 Address::DumpStyleLoadAddress
,
1178 Address::DumpStyleFileAddress
);
1179 s
->PutCString("\n");
1184 // SymbolContextList
1187 SymbolContextList::SymbolContextList() : m_symbol_contexts() {}
1189 SymbolContextList::~SymbolContextList() = default;
1191 void SymbolContextList::Append(const SymbolContext
&sc
) {
1192 m_symbol_contexts
.push_back(sc
);
1195 void SymbolContextList::Append(const SymbolContextList
&sc_list
) {
1196 collection::const_iterator pos
, end
= sc_list
.m_symbol_contexts
.end();
1197 for (pos
= sc_list
.m_symbol_contexts
.begin(); pos
!= end
; ++pos
)
1198 m_symbol_contexts
.push_back(*pos
);
1201 uint32_t SymbolContextList::AppendIfUnique(const SymbolContextList
&sc_list
,
1202 bool merge_symbol_into_function
) {
1203 uint32_t unique_sc_add_count
= 0;
1204 collection::const_iterator pos
, end
= sc_list
.m_symbol_contexts
.end();
1205 for (pos
= sc_list
.m_symbol_contexts
.begin(); pos
!= end
; ++pos
) {
1206 if (AppendIfUnique(*pos
, merge_symbol_into_function
))
1207 ++unique_sc_add_count
;
1209 return unique_sc_add_count
;
1212 bool SymbolContextList::AppendIfUnique(const SymbolContext
&sc
,
1213 bool merge_symbol_into_function
) {
1214 collection::iterator pos
, end
= m_symbol_contexts
.end();
1215 for (pos
= m_symbol_contexts
.begin(); pos
!= end
; ++pos
) {
1219 if (merge_symbol_into_function
&& sc
.symbol
!= nullptr &&
1220 sc
.comp_unit
== nullptr && sc
.function
== nullptr &&
1221 sc
.block
== nullptr && !sc
.line_entry
.IsValid()) {
1222 if (sc
.symbol
->ValueIsAddress()) {
1223 for (pos
= m_symbol_contexts
.begin(); pos
!= end
; ++pos
) {
1224 // Don't merge symbols into inlined function symbol contexts
1225 if (pos
->block
&& pos
->block
->GetContainingInlinedBlock())
1228 if (pos
->function
) {
1229 if (pos
->function
->GetAddressRange().GetBaseAddress() ==
1230 sc
.symbol
->GetAddressRef()) {
1231 // Do we already have a function with this symbol?
1232 if (pos
->symbol
== sc
.symbol
)
1234 if (pos
->symbol
== nullptr) {
1235 pos
->symbol
= sc
.symbol
;
1243 m_symbol_contexts
.push_back(sc
);
1247 void SymbolContextList::Clear() { m_symbol_contexts
.clear(); }
1249 void SymbolContextList::Dump(Stream
*s
, Target
*target
) const {
1253 s
->PutCString("SymbolContextList");
1257 collection::const_iterator pos
, end
= m_symbol_contexts
.end();
1258 for (pos
= m_symbol_contexts
.begin(); pos
!= end
; ++pos
) {
1259 // pos->Dump(s, target);
1260 pos
->GetDescription(s
, eDescriptionLevelVerbose
, target
);
1265 bool SymbolContextList::GetContextAtIndex(size_t idx
, SymbolContext
&sc
) const {
1266 if (idx
< m_symbol_contexts
.size()) {
1267 sc
= m_symbol_contexts
[idx
];
1273 bool SymbolContextList::RemoveContextAtIndex(size_t idx
) {
1274 if (idx
< m_symbol_contexts
.size()) {
1275 m_symbol_contexts
.erase(m_symbol_contexts
.begin() + idx
);
1281 uint32_t SymbolContextList::GetSize() const { return m_symbol_contexts
.size(); }
1283 bool SymbolContextList::IsEmpty() const { return m_symbol_contexts
.empty(); }
1285 uint32_t SymbolContextList::NumLineEntriesWithLine(uint32_t line
) const {
1286 uint32_t match_count
= 0;
1287 const size_t size
= m_symbol_contexts
.size();
1288 for (size_t idx
= 0; idx
< size
; ++idx
) {
1289 if (m_symbol_contexts
[idx
].line_entry
.line
== line
)
1295 void SymbolContextList::GetDescription(Stream
*s
, lldb::DescriptionLevel level
,
1296 Target
*target
) const {
1297 const size_t size
= m_symbol_contexts
.size();
1298 for (size_t idx
= 0; idx
< size
; ++idx
)
1299 m_symbol_contexts
[idx
].GetDescription(s
, level
, target
);
1302 bool lldb_private::operator==(const SymbolContextList
&lhs
,
1303 const SymbolContextList
&rhs
) {
1304 const uint32_t size
= lhs
.GetSize();
1305 if (size
!= rhs
.GetSize())
1308 SymbolContext lhs_sc
;
1309 SymbolContext rhs_sc
;
1310 for (uint32_t i
= 0; i
< size
; ++i
) {
1311 lhs
.GetContextAtIndex(i
, lhs_sc
);
1312 rhs
.GetContextAtIndex(i
, rhs_sc
);
1313 if (lhs_sc
!= rhs_sc
)
1319 bool lldb_private::operator!=(const SymbolContextList
&lhs
,
1320 const SymbolContextList
&rhs
) {
1321 return !(lhs
== rhs
);