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_t file_addr
= addr
.GetFileAddress();
106 file_addr
!= LLDB_INVALID_ADDRESS
) {
107 const addr_t function_offset
=
109 function
->GetAddressRange().GetBaseAddress().GetFileAddress();
110 if (!show_function_name
) {
111 // Print +offset even if offset is 0
112 dumped_something
= true;
113 s
->Printf("+%" PRIu64
">", function_offset
);
114 } else if (function_offset
) {
115 dumped_something
= true;
116 s
->Printf(" + %" PRIu64
, function_offset
);
120 if (GetParentOfInlinedScope(addr
, inline_parent_sc
, inline_parent_addr
)) {
121 dumped_something
= true;
122 Block
*inlined_block
= block
->GetContainingInlinedBlock();
123 const InlineFunctionInfo
*inlined_block_info
=
124 inlined_block
->GetInlinedFunctionInfo();
125 s
->Printf(" [inlined] %s", inlined_block_info
->GetName().GetCString());
127 lldb_private::AddressRange block_range
;
128 if (inlined_block
->GetRangeContainingAddress(addr
, block_range
)) {
129 const addr_t inlined_function_offset
=
130 addr
.GetFileAddress() -
131 block_range
.GetBaseAddress().GetFileAddress();
132 if (inlined_function_offset
) {
133 s
->Printf(" + %" PRIu64
, inlined_function_offset
);
136 // "line_entry" will always be valid as GetParentOfInlinedScope(...) will
137 // fill it in correctly with the calling file and line. Previous code
138 // was extracting the calling file and line from inlined_block_info and
139 // using it right away which is not correct. On the first call to this
140 // function "line_entry" will contain the actual line table entry. On
141 // susequent calls "line_entry" will contain the calling file and line
142 // from the previous inline info.
143 if (line_entry
.IsValid()) {
144 s
->PutCString(" at ");
145 line_entry
.DumpStopContext(s
, show_fullpaths
);
148 if (show_inlined_frames
) {
151 const bool show_function_name
= true;
152 return inline_parent_sc
.DumpStopContext(
153 s
, exe_scope
, inline_parent_addr
, show_fullpaths
, show_module
,
154 show_inlined_frames
, show_function_arguments
, show_function_name
,
155 show_function_display_name
);
158 if (line_entry
.IsValid()) {
159 dumped_something
= true;
160 s
->PutCString(" at ");
161 if (line_entry
.DumpStopContext(s
, show_fullpaths
))
162 dumped_something
= true;
165 } else if (symbol
!= nullptr) {
166 if (!show_function_name
) {
168 dumped_something
= true;
169 } else if (symbol
->GetName()) {
170 dumped_something
= true;
171 if (symbol
->GetType() == eSymbolTypeTrampoline
)
172 s
->PutCString("symbol stub for: ");
174 if (show_function_display_name
)
175 name
= symbol
->GetDisplayName();
177 name
= symbol
->GetName();
178 s
->PutCStringColorHighlighted(name
.GetStringRef(), settings
);
181 if (addr
.IsValid() && symbol
->ValueIsAddress()) {
182 const addr_t symbol_offset
=
183 addr
.GetOffset() - symbol
->GetAddressRef().GetOffset();
184 if (!show_function_name
) {
185 // Print +offset even if offset is 0
186 dumped_something
= true;
187 s
->Printf("+%" PRIu64
">", symbol_offset
);
188 } else if (symbol_offset
) {
189 dumped_something
= true;
190 s
->Printf(" + %" PRIu64
, symbol_offset
);
193 } else if (addr
.IsValid()) {
194 addr
.Dump(s
, exe_scope
, Address::DumpStyleModuleWithFileAddress
);
195 dumped_something
= true;
197 return dumped_something
;
200 void SymbolContext::GetDescription(
201 Stream
*s
, lldb::DescriptionLevel level
, Target
*target
,
202 std::optional
<Stream::HighlightSettings
> settings
) const {
204 s
->Indent(" Module: file = \"");
205 module_sp
->GetFileSpec().Dump(s
->AsRawOstream());
207 if (module_sp
->GetArchitecture().IsValid())
208 s
->Printf(", arch = \"%s\"",
209 module_sp
->GetArchitecture().GetArchitectureName());
213 if (comp_unit
!= nullptr) {
214 s
->Indent("CompileUnit: ");
215 comp_unit
->GetDescription(s
, level
);
219 if (function
!= nullptr) {
220 s
->Indent(" Function: ");
221 function
->GetDescription(s
, level
, target
);
224 Type
*func_type
= function
->GetType();
226 s
->Indent(" FuncType: ");
227 func_type
->GetDescription(s
, level
, false, target
);
232 if (block
!= nullptr) {
233 std::vector
<Block
*> blocks
;
234 blocks
.push_back(block
);
235 Block
*parent_block
= block
->GetParent();
237 while (parent_block
) {
238 blocks
.push_back(parent_block
);
239 parent_block
= parent_block
->GetParent();
241 std::vector
<Block
*>::reverse_iterator pos
;
242 std::vector
<Block
*>::reverse_iterator begin
= blocks
.rbegin();
243 std::vector
<Block
*>::reverse_iterator end
= blocks
.rend();
244 for (pos
= begin
; pos
!= end
; ++pos
) {
246 s
->Indent(" Blocks: ");
249 (*pos
)->GetDescription(s
, function
, level
, target
);
254 if (line_entry
.IsValid()) {
255 s
->Indent(" LineEntry: ");
256 line_entry
.GetDescription(s
, level
, comp_unit
, target
, false);
260 if (symbol
!= nullptr) {
261 s
->Indent(" Symbol: ");
262 symbol
->GetDescription(s
, level
, target
, settings
);
266 if (variable
!= nullptr) {
267 s
->Indent(" Variable: ");
269 s
->Printf("id = {0x%8.8" PRIx64
"}, ", variable
->GetID());
271 switch (variable
->GetScope()) {
272 case eValueTypeVariableGlobal
:
273 s
->PutCString("kind = global, ");
276 case eValueTypeVariableStatic
:
277 s
->PutCString("kind = static, ");
280 case eValueTypeVariableArgument
:
281 s
->PutCString("kind = argument, ");
284 case eValueTypeVariableLocal
:
285 s
->PutCString("kind = local, ");
288 case eValueTypeVariableThreadLocal
:
289 s
->PutCString("kind = thread local, ");
296 s
->Printf("name = \"%s\"\n", variable
->GetName().GetCString());
300 uint32_t SymbolContext::GetResolvedMask() const {
301 uint32_t resolved_mask
= 0;
303 resolved_mask
|= eSymbolContextTarget
;
305 resolved_mask
|= eSymbolContextModule
;
307 resolved_mask
|= eSymbolContextCompUnit
;
309 resolved_mask
|= eSymbolContextFunction
;
311 resolved_mask
|= eSymbolContextBlock
;
312 if (line_entry
.IsValid())
313 resolved_mask
|= eSymbolContextLineEntry
;
315 resolved_mask
|= eSymbolContextSymbol
;
317 resolved_mask
|= eSymbolContextVariable
;
318 return resolved_mask
;
321 void SymbolContext::Dump(Stream
*s
, Target
*target
) const {
324 s
->PutCString("SymbolContext");
329 *s
<< "Module = " << module_sp
.get() << ' ';
331 module_sp
->GetFileSpec().Dump(s
->AsRawOstream());
334 *s
<< "CompileUnit = " << comp_unit
;
335 if (comp_unit
!= nullptr)
336 s
->Format(" {{{0:x-16}} {1}", comp_unit
->GetID(),
337 comp_unit
->GetPrimaryFile());
340 *s
<< "Function = " << function
;
341 if (function
!= nullptr) {
342 s
->Format(" {{{0:x-16}} {1}, address-range = ", function
->GetID(),
343 function
->GetType()->GetName());
344 function
->GetAddressRange().Dump(s
, target
, Address::DumpStyleLoadAddress
,
345 Address::DumpStyleModuleWithFileAddress
);
348 Type
*func_type
= function
->GetType();
351 func_type
->Dump(s
, false);
356 *s
<< "Block = " << block
;
357 if (block
!= nullptr)
358 s
->Format(" {{{0:x-16}}", block
->GetID());
361 *s
<< "LineEntry = ";
362 line_entry
.Dump(s
, target
, true, Address::DumpStyleLoadAddress
,
363 Address::DumpStyleModuleWithFileAddress
, true);
366 *s
<< "Symbol = " << symbol
;
367 if (symbol
!= nullptr && symbol
->GetMangled())
368 *s
<< ' ' << symbol
->GetName().AsCString();
370 *s
<< "Variable = " << variable
;
371 if (variable
!= nullptr) {
372 s
->Format(" {{{0:x-16}} {1}", variable
->GetID(),
373 variable
->GetType()->GetName());
380 bool lldb_private::operator==(const SymbolContext
&lhs
,
381 const SymbolContext
&rhs
) {
382 return lhs
.function
== rhs
.function
&& lhs
.symbol
== rhs
.symbol
&&
383 lhs
.module_sp
.get() == rhs
.module_sp
.get() &&
384 lhs
.comp_unit
== rhs
.comp_unit
&&
385 lhs
.target_sp
.get() == rhs
.target_sp
.get() &&
386 LineEntry::Compare(lhs
.line_entry
, rhs
.line_entry
) == 0 &&
387 lhs
.variable
== rhs
.variable
;
390 bool lldb_private::operator!=(const SymbolContext
&lhs
,
391 const SymbolContext
&rhs
) {
392 return !(lhs
== rhs
);
395 bool SymbolContext::GetAddressRange(uint32_t scope
, uint32_t range_idx
,
396 bool use_inline_block_range
,
397 AddressRange
&range
) const {
398 if ((scope
& eSymbolContextLineEntry
) && line_entry
.IsValid()) {
399 range
= line_entry
.range
;
403 if ((scope
& eSymbolContextBlock
) && (block
!= nullptr)) {
404 if (use_inline_block_range
) {
405 Block
*inline_block
= block
->GetContainingInlinedBlock();
407 return inline_block
->GetRangeAtIndex(range_idx
, range
);
409 return block
->GetRangeAtIndex(range_idx
, range
);
413 if ((scope
& eSymbolContextFunction
) && (function
!= nullptr)) {
414 if (range_idx
== 0) {
415 range
= function
->GetAddressRange();
420 if ((scope
& eSymbolContextSymbol
) && (symbol
!= nullptr)) {
421 if (range_idx
== 0) {
422 if (symbol
->ValueIsAddress()) {
423 range
.GetBaseAddress() = symbol
->GetAddressRef();
424 range
.SetByteSize(symbol
->GetByteSize());
433 LanguageType
SymbolContext::GetLanguage() const {
435 if (function
&& (lang
= function
->GetLanguage()) != eLanguageTypeUnknown
) {
437 } else if (variable
&&
438 (lang
= variable
->GetLanguage()) != eLanguageTypeUnknown
) {
440 } else if (symbol
&& (lang
= symbol
->GetLanguage()) != eLanguageTypeUnknown
) {
442 } else if (comp_unit
&&
443 (lang
= comp_unit
->GetLanguage()) != eLanguageTypeUnknown
) {
446 // If all else fails, try to guess the language from the name.
447 return symbol
->GetMangled().GuessLanguage();
449 return eLanguageTypeUnknown
;
452 bool SymbolContext::GetParentOfInlinedScope(const Address
&curr_frame_pc
,
453 SymbolContext
&next_frame_sc
,
454 Address
&next_frame_pc
) const {
455 next_frame_sc
.Clear(false);
456 next_frame_pc
.Clear();
459 // const addr_t curr_frame_file_addr = curr_frame_pc.GetFileAddress();
461 // In order to get the parent of an inlined function we first need to see
462 // if we are in an inlined block as "this->block" could be an inlined
463 // block, or a parent of "block" could be. So lets check if this block or
464 // one of this blocks parents is an inlined function.
465 Block
*curr_inlined_block
= block
->GetContainingInlinedBlock();
466 if (curr_inlined_block
) {
467 // "this->block" is contained in an inline function block, so to get the
468 // scope above the inlined block, we get the parent of the inlined block
470 Block
*next_frame_block
= curr_inlined_block
->GetParent();
471 // Now calculate the symbol context of the containing block
472 next_frame_block
->CalculateSymbolContext(&next_frame_sc
);
474 // If we get here we weren't able to find the return line entry using the
475 // nesting of the blocks and the line table. So just use the call site
476 // info from our inlined block.
479 if (curr_inlined_block
->GetRangeContainingAddress(curr_frame_pc
, range
)) {
480 // To see there this new frame block it, we need to look at the call
481 // site information from
482 const InlineFunctionInfo
*curr_inlined_block_inlined_info
=
483 curr_inlined_block
->GetInlinedFunctionInfo();
484 next_frame_pc
= range
.GetBaseAddress();
485 next_frame_sc
.line_entry
.range
.GetBaseAddress() = next_frame_pc
;
486 next_frame_sc
.line_entry
.file_sp
= std::make_shared
<SupportFile
>(
487 curr_inlined_block_inlined_info
->GetCallSite().GetFile());
488 next_frame_sc
.line_entry
.original_file_sp
=
489 std::make_shared
<SupportFile
>(
490 curr_inlined_block_inlined_info
->GetCallSite().GetFile());
491 next_frame_sc
.line_entry
.line
=
492 curr_inlined_block_inlined_info
->GetCallSite().GetLine();
493 next_frame_sc
.line_entry
.column
=
494 curr_inlined_block_inlined_info
->GetCallSite().GetColumn();
497 Log
*log
= GetLog(LLDBLog::Symbols
);
502 "warning: inlined block 0x%8.8" PRIx64
503 " doesn't have a range that contains file address 0x%" PRIx64
,
504 curr_inlined_block
->GetID(), curr_frame_pc
.GetFileAddress());
506 #ifdef LLDB_CONFIGURATION_DEBUG
508 ObjectFile
*objfile
= nullptr;
510 if (SymbolFile
*symbol_file
= module_sp
->GetSymbolFile())
511 objfile
= symbol_file
->GetObjectFile();
514 Debugger::ReportWarning(llvm::formatv(
515 "inlined block {0:x} doesn't have a range that contains file "
516 "address {1:x} in {2}",
517 curr_inlined_block
->GetID(), curr_frame_pc
.GetFileAddress(),
518 objfile
->GetFileSpec().GetPath()));
520 Debugger::ReportWarning(llvm::formatv(
521 "inlined block {0:x} doesn't have a range that contains file "
523 curr_inlined_block
->GetID(), curr_frame_pc
.GetFileAddress()));
534 Block
*SymbolContext::GetFunctionBlock() {
537 // If this symbol context has a block, check to see if this block is
538 // itself, or is contained within a block with inlined function
539 // information. If so, then the inlined block is the block that defines
541 Block
*inlined_block
= block
->GetContainingInlinedBlock();
543 return inlined_block
;
545 // The block in this symbol context is not inside an inlined block, so
546 // the block that defines the function is the function's top level block,
547 // which is returned below.
550 // There is no block information in this symbol context, so we must assume
551 // that the block that is desired is the top level block of the function
553 return &function
->GetBlock(true);
558 llvm::StringRef
SymbolContext::GetInstanceVariableName() {
559 LanguageType lang_type
= eLanguageTypeUnknown
;
561 if (Block
*function_block
= GetFunctionBlock())
562 if (CompilerDeclContext decl_ctx
= function_block
->GetDeclContext())
563 lang_type
= decl_ctx
.GetLanguage();
565 if (lang_type
== eLanguageTypeUnknown
)
566 lang_type
= GetLanguage();
568 if (auto *lang
= Language::FindPlugin(lang_type
))
569 return lang
->GetInstanceVariableName();
574 void SymbolContext::SortTypeList(TypeMap
&type_map
, TypeList
&type_list
) const {
575 Block
*curr_block
= block
;
576 bool isInlinedblock
= false;
577 if (curr_block
!= nullptr &&
578 curr_block
->GetContainingInlinedBlock() != nullptr)
579 isInlinedblock
= true;
581 // Find all types that match the current block if we have one and put them
582 // first in the list. Keep iterating up through all blocks.
583 while (curr_block
!= nullptr && !isInlinedblock
) {
585 [curr_block
, &type_list
](const lldb::TypeSP
&type_sp
) -> bool {
586 SymbolContextScope
*scs
= type_sp
->GetSymbolContextScope();
587 if (scs
&& curr_block
== scs
->CalculateSymbolContextBlock())
588 type_list
.Insert(type_sp
);
589 return true; // Keep iterating
592 // Remove any entries that are now in "type_list" from "type_map" since we
593 // can't remove from type_map while iterating
594 type_list
.ForEach([&type_map
](const lldb::TypeSP
&type_sp
) -> bool {
595 type_map
.Remove(type_sp
);
596 return true; // Keep iterating
598 curr_block
= curr_block
->GetParent();
600 // Find all types that match the current function, if we have onem, and put
601 // them next in the list.
602 if (function
!= nullptr && !type_map
.Empty()) {
603 const size_t old_type_list_size
= type_list
.GetSize();
604 type_map
.ForEach([this, &type_list
](const lldb::TypeSP
&type_sp
) -> bool {
605 SymbolContextScope
*scs
= type_sp
->GetSymbolContextScope();
606 if (scs
&& function
== scs
->CalculateSymbolContextFunction())
607 type_list
.Insert(type_sp
);
608 return true; // Keep iterating
611 // Remove any entries that are now in "type_list" from "type_map" since we
612 // can't remove from type_map while iterating
613 const size_t new_type_list_size
= type_list
.GetSize();
614 if (new_type_list_size
> old_type_list_size
) {
615 for (size_t i
= old_type_list_size
; i
< new_type_list_size
; ++i
)
616 type_map
.Remove(type_list
.GetTypeAtIndex(i
));
619 // Find all types that match the current compile unit, if we have one, and
620 // put them next in the list.
621 if (comp_unit
!= nullptr && !type_map
.Empty()) {
622 const size_t old_type_list_size
= type_list
.GetSize();
624 type_map
.ForEach([this, &type_list
](const lldb::TypeSP
&type_sp
) -> bool {
625 SymbolContextScope
*scs
= type_sp
->GetSymbolContextScope();
626 if (scs
&& comp_unit
== scs
->CalculateSymbolContextCompileUnit())
627 type_list
.Insert(type_sp
);
628 return true; // Keep iterating
631 // Remove any entries that are now in "type_list" from "type_map" since we
632 // can't remove from type_map while iterating
633 const size_t new_type_list_size
= type_list
.GetSize();
634 if (new_type_list_size
> old_type_list_size
) {
635 for (size_t i
= old_type_list_size
; i
< new_type_list_size
; ++i
)
636 type_map
.Remove(type_list
.GetTypeAtIndex(i
));
639 // Find all types that match the current module, if we have one, and put them
641 if (module_sp
&& !type_map
.Empty()) {
642 const size_t old_type_list_size
= type_list
.GetSize();
643 type_map
.ForEach([this, &type_list
](const lldb::TypeSP
&type_sp
) -> bool {
644 SymbolContextScope
*scs
= type_sp
->GetSymbolContextScope();
645 if (scs
&& module_sp
== scs
->CalculateSymbolContextModule())
646 type_list
.Insert(type_sp
);
647 return true; // Keep iterating
649 // Remove any entries that are now in "type_list" from "type_map" since we
650 // can't remove from type_map while iterating
651 const size_t new_type_list_size
= type_list
.GetSize();
652 if (new_type_list_size
> old_type_list_size
) {
653 for (size_t i
= old_type_list_size
; i
< new_type_list_size
; ++i
)
654 type_map
.Remove(type_list
.GetTypeAtIndex(i
));
657 // Any types that are left get copied into the list an any order.
658 if (!type_map
.Empty()) {
659 type_map
.ForEach([&type_list
](const lldb::TypeSP
&type_sp
) -> bool {
660 type_list
.Insert(type_sp
);
661 return true; // Keep iterating
667 SymbolContext::GetFunctionName(Mangled::NamePreference preference
) const {
670 Block
*inlined_block
= block
->GetContainingInlinedBlock();
673 const InlineFunctionInfo
*inline_info
=
674 inlined_block
->GetInlinedFunctionInfo();
676 return inline_info
->GetName();
679 return function
->GetMangled().GetName(preference
);
680 } else if (symbol
&& symbol
->ValueIsAddress()) {
681 return symbol
->GetMangled().GetName(preference
);
683 // No function, return an empty string.
684 return ConstString();
688 LineEntry
SymbolContext::GetFunctionStartLineEntry() const {
689 LineEntry line_entry
;
692 Block
*inlined_block
= block
->GetContainingInlinedBlock();
694 if (inlined_block
->GetStartAddress(start_addr
)) {
695 if (start_addr
.CalculateSymbolContextLineEntry(line_entry
))
703 if (function
->GetAddressRange()
705 .CalculateSymbolContextLineEntry(line_entry
))
712 SymbolContext::GetAddressRangeFromHereToEndLine(uint32_t end_line
,
713 AddressRange
&range
) {
714 if (!line_entry
.IsValid()) {
715 return llvm::createStringError("Symbol context has no line table.");
718 range
= line_entry
.range
;
719 if (line_entry
.line
> end_line
) {
720 return llvm::createStringError(
721 "end line option %d must be after the current line: %d", end_line
,
725 uint32_t line_index
= 0;
729 line_index
= comp_unit
->FindLineEntry(line_index
, line_entry
.line
, nullptr,
731 if (line_index
== UINT32_MAX
)
733 if (LineEntry::Compare(this_line
, line_entry
) == 0) {
741 // Can't find the index of the SymbolContext's line entry in the
742 // SymbolContext's CompUnit.
743 return llvm::createStringError(
744 "Can't find the current line entry in the CompUnit - can't process "
745 "the end-line option");
748 line_index
= comp_unit
->FindLineEntry(line_index
, end_line
, nullptr, false,
750 if (line_index
== UINT32_MAX
) {
751 return llvm::createStringError(
752 "could not find a line table entry corresponding "
753 "to end line number %d",
757 Block
*func_block
= GetFunctionBlock();
758 if (func_block
&& func_block
->GetRangeIndexContainingAddress(
759 end_entry
.range
.GetBaseAddress()) == UINT32_MAX
) {
760 return llvm::createStringError(
761 "end line number %d is not contained within the current function.",
765 lldb::addr_t range_size
= end_entry
.range
.GetBaseAddress().GetFileAddress() -
766 range
.GetBaseAddress().GetFileAddress();
767 range
.SetByteSize(range_size
);
768 return llvm::Error::success();
771 const Symbol
*SymbolContext::FindBestGlobalDataSymbol(ConstString name
,
779 Target
&target
= *target_sp
;
780 Module
*module
= module_sp
.get();
782 auto ProcessMatches
= [this, &name
, &target
,
783 module
](const SymbolContextList
&sc_list
,
784 Status
&error
) -> const Symbol
* {
785 llvm::SmallVector
<const Symbol
*, 1> external_symbols
;
786 llvm::SmallVector
<const Symbol
*, 1> internal_symbols
;
787 for (const SymbolContext
&sym_ctx
: sc_list
) {
788 if (sym_ctx
.symbol
) {
789 const Symbol
*symbol
= sym_ctx
.symbol
;
790 const Address sym_address
= symbol
->GetAddress();
792 if (sym_address
.IsValid()) {
793 switch (symbol
->GetType()) {
794 case eSymbolTypeData
:
795 case eSymbolTypeRuntime
:
796 case eSymbolTypeAbsolute
:
797 case eSymbolTypeObjCClass
:
798 case eSymbolTypeObjCMetaClass
:
799 case eSymbolTypeObjCIVar
:
800 if (symbol
->GetDemangledNameIsSynthesized()) {
801 // If the demangled name was synthesized, then don't use it for
802 // expressions. Only let the symbol match if the mangled named
803 // matches for these symbols.
804 if (symbol
->GetMangled().GetMangledName() != name
)
807 if (symbol
->IsExternal()) {
808 external_symbols
.push_back(symbol
);
810 internal_symbols
.push_back(symbol
);
813 case eSymbolTypeReExported
: {
814 ConstString reexport_name
= symbol
->GetReExportedSymbolName();
816 ModuleSP reexport_module_sp
;
817 ModuleSpec reexport_module_spec
;
818 reexport_module_spec
.GetPlatformFileSpec() =
819 symbol
->GetReExportedSymbolSharedLibrary();
820 if (reexport_module_spec
.GetPlatformFileSpec()) {
822 target
.GetImages().FindFirstModule(reexport_module_spec
);
823 if (!reexport_module_sp
) {
824 reexport_module_spec
.GetPlatformFileSpec().ClearDirectory();
826 target
.GetImages().FindFirstModule(reexport_module_spec
);
829 // Don't allow us to try and resolve a re-exported symbol if it
830 // is the same as the current symbol
831 if (name
== symbol
->GetReExportedSymbolName() &&
832 module
== reexport_module_sp
.get())
835 return FindBestGlobalDataSymbol(symbol
->GetReExportedSymbolName(),
840 case eSymbolTypeCode
: // We already lookup functions elsewhere
841 case eSymbolTypeVariable
:
842 case eSymbolTypeLocal
:
843 case eSymbolTypeParam
:
844 case eSymbolTypeTrampoline
:
845 case eSymbolTypeInvalid
:
846 case eSymbolTypeException
:
847 case eSymbolTypeSourceFile
:
848 case eSymbolTypeHeaderFile
:
849 case eSymbolTypeObjectFile
:
850 case eSymbolTypeCommonBlock
:
851 case eSymbolTypeBlock
:
852 case eSymbolTypeVariableType
:
853 case eSymbolTypeLineEntry
:
854 case eSymbolTypeLineHeader
:
855 case eSymbolTypeScopeBegin
:
856 case eSymbolTypeScopeEnd
:
857 case eSymbolTypeAdditional
:
858 case eSymbolTypeCompiler
:
859 case eSymbolTypeInstrumentation
:
860 case eSymbolTypeUndefined
:
861 case eSymbolTypeResolver
:
868 if (external_symbols
.size() > 1) {
870 ss
.Printf("Multiple external symbols found for '%s'\n", name
.AsCString());
871 for (const Symbol
*symbol
: external_symbols
) {
872 symbol
->GetDescription(&ss
, eDescriptionLevelFull
, &target
);
875 error
= Status::FromErrorString(ss
.GetData());
877 } else if (external_symbols
.size()) {
878 return external_symbols
[0];
879 } else if (internal_symbols
.size() > 1) {
881 ss
.Printf("Multiple internal symbols found for '%s'\n", name
.AsCString());
882 for (const Symbol
*symbol
: internal_symbols
) {
883 symbol
->GetDescription(&ss
, eDescriptionLevelVerbose
, &target
);
886 error
= Status::FromErrorString(ss
.GetData());
888 } else if (internal_symbols
.size()) {
889 return internal_symbols
[0];
896 SymbolContextList sc_list
;
897 module
->FindSymbolsWithNameAndType(name
, eSymbolTypeAny
, sc_list
);
898 const Symbol
*const module_symbol
= ProcessMatches(sc_list
, error
);
900 if (!error
.Success()) {
902 } else if (module_symbol
) {
903 return module_symbol
;
908 SymbolContextList sc_list
;
909 target
.GetImages().FindSymbolsWithNameAndType(name
, eSymbolTypeAny
,
911 const Symbol
*const target_symbol
= ProcessMatches(sc_list
, error
);
913 if (!error
.Success()) {
915 } else if (target_symbol
) {
916 return target_symbol
;
920 return nullptr; // no error; we just didn't find anything
924 // SymbolContextSpecifier
927 SymbolContextSpecifier::SymbolContextSpecifier(const TargetSP
&target_sp
)
928 : m_target_sp(target_sp
), m_module_spec(), m_module_sp(), m_file_spec_up(),
929 m_start_line(0), m_end_line(0), m_function_spec(), m_class_name(),
930 m_address_range_up(), m_type(eNothingSpecified
) {}
932 SymbolContextSpecifier::~SymbolContextSpecifier() = default;
934 bool SymbolContextSpecifier::AddLineSpecification(uint32_t line_no
,
935 SpecificationType type
) {
936 bool return_value
= true;
938 case eNothingSpecified
:
941 case eLineStartSpecified
:
942 m_start_line
= line_no
;
943 m_type
|= eLineStartSpecified
;
945 case eLineEndSpecified
:
946 m_end_line
= line_no
;
947 m_type
|= eLineEndSpecified
;
950 return_value
= false;
956 bool SymbolContextSpecifier::AddSpecification(const char *spec_string
,
957 SpecificationType type
) {
958 bool return_value
= true;
960 case eNothingSpecified
:
963 case eModuleSpecified
: {
964 // See if we can find the Module, if so stick it in the SymbolContext.
965 FileSpec
module_file_spec(spec_string
);
966 ModuleSpec
module_spec(module_file_spec
);
967 lldb::ModuleSP module_sp
=
968 m_target_sp
? m_target_sp
->GetImages().FindFirstModule(module_spec
)
970 m_type
|= eModuleSpecified
;
972 m_module_sp
= module_sp
;
974 m_module_spec
.assign(spec_string
);
977 // CompUnits can't necessarily be resolved here, since an inlined function
978 // might show up in a number of CompUnits. Instead we just convert to a
979 // FileSpec and store it away.
980 m_file_spec_up
= std::make_unique
<FileSpec
>(spec_string
);
981 m_type
|= eFileSpecified
;
983 case eLineStartSpecified
:
984 if ((return_value
= llvm::to_integer(spec_string
, m_start_line
)))
985 m_type
|= eLineStartSpecified
;
987 case eLineEndSpecified
:
988 if ((return_value
= llvm::to_integer(spec_string
, m_end_line
)))
989 m_type
|= eLineEndSpecified
;
991 case eFunctionSpecified
:
992 m_function_spec
.assign(spec_string
);
993 m_type
|= eFunctionSpecified
;
995 case eClassOrNamespaceSpecified
:
997 m_class_name
.assign(spec_string
);
998 m_type
= eClassOrNamespaceSpecified
;
1000 case eAddressRangeSpecified
:
1001 // Not specified yet...
1005 return return_value
;
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();
1015 m_address_range_up
.reset();
1017 m_type
= eNothingSpecified
;
1020 bool SymbolContextSpecifier::SymbolContextMatches(const SymbolContext
&sc
) {
1021 if (m_type
== eNothingSpecified
)
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
)
1031 if (m_type
& eModuleSpecified
) {
1033 if (m_module_sp
.get() != nullptr) {
1034 if (m_module_sp
.get() != sc
.module_sp
.get())
1037 FileSpec
module_file_spec(m_module_spec
);
1038 if (!FileSpec::Match(module_file_spec
, sc
.module_sp
->GetFileSpec()))
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
1047 if (sc
.block
== nullptr && sc
.comp_unit
== nullptr)
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) {
1057 if (!FileSpec::Match(*m_file_spec_up
,
1058 inline_info
->GetDeclaration().GetFile()))
1063 // Next check the comp unit, but only if the SymbolContext was not
1065 if (!was_inlined
&& sc
.comp_unit
!= nullptr) {
1066 if (!FileSpec::Match(*m_file_spec_up
, sc
.comp_unit
->GetPrimaryFile()))
1071 if (m_type
& eLineStartSpecified
|| m_type
& eLineEndSpecified
) {
1072 if (sc
.line_entry
.line
< m_start_line
|| sc
.line_entry
.line
> m_end_line
)
1076 if (m_type
& eFunctionSpecified
) {
1077 // First check the current block, and if it is inlined, get the inlined
1079 bool was_inlined
= false;
1080 ConstString
func_name(m_function_spec
.c_str());
1082 if (sc
.block
!= nullptr) {
1083 const InlineFunctionInfo
*inline_info
=
1084 sc
.block
->GetInlinedFunctionInfo();
1085 if (inline_info
!= nullptr) {
1087 const Mangled
&name
= inline_info
->GetMangled();
1088 if (!name
.NameMatches(func_name
))
1092 // If it wasn't inlined, check the name in the function or symbol:
1094 if (sc
.function
!= nullptr) {
1095 if (!sc
.function
->GetMangled().NameMatches(func_name
))
1097 } else if (sc
.symbol
!= nullptr) {
1098 if (!sc
.symbol
->GetMangled().NameMatches(func_name
))
1107 bool SymbolContextSpecifier::AddressMatches(lldb::addr_t addr
) {
1108 if (m_type
& eAddressRangeSpecified
) {
1111 Address
match_address(addr
, nullptr);
1113 m_target_sp
->GetImages().ResolveSymbolContextForAddress(
1114 match_address
, eSymbolContextEverything
, sc
);
1115 return SymbolContextMatches(sc
);
1120 void SymbolContextSpecifier::GetDescription(
1121 Stream
*s
, lldb::DescriptionLevel level
) const {
1122 char path_str
[PATH_MAX
+ 1];
1124 if (m_type
== eNothingSpecified
) {
1125 s
->Printf("Nothing specified.\n");
1128 if (m_type
== eModuleSpecified
) {
1131 m_module_sp
->GetFileSpec().GetPath(path_str
, PATH_MAX
);
1132 s
->Printf("Module: %s\n", path_str
);
1134 s
->Printf("Module: %s\n", m_module_spec
.c_str());
1137 if (m_type
== eFileSpecified
&& m_file_spec_up
!= nullptr) {
1138 m_file_spec_up
->GetPath(path_str
, PATH_MAX
);
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
);
1146 s
->Printf("to end");
1147 } else if (m_type
== eLineEndSpecified
) {
1148 s
->Printf(" from start to line %" PRIu64
"", (uint64_t)m_end_line
);
1153 if (m_type
== eLineStartSpecified
) {
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
);
1159 s
->Printf("to end");
1161 } else if (m_type
== eLineEndSpecified
) {
1162 s
->Printf("From start to line %" PRIu64
".\n", (uint64_t)m_end_line
);
1165 if (m_type
== eFunctionSpecified
) {
1167 s
->Printf("Function: %s.\n", m_function_spec
.c_str());
1170 if (m_type
== eClassOrNamespaceSpecified
) {
1172 s
->Printf("Class name: %s.\n", m_class_name
.c_str());
1175 if (m_type
== eAddressRangeSpecified
&& m_address_range_up
!= nullptr) {
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");
1186 // SymbolContextList
1189 SymbolContextList::SymbolContextList() : m_symbol_contexts() {}
1191 SymbolContextList::~SymbolContextList() = default;
1193 void SymbolContextList::Append(const SymbolContext
&sc
) {
1194 m_symbol_contexts
.push_back(sc
);
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
);
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
;
1211 return unique_sc_add_count
;
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
) {
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())
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
)
1236 if (pos
->symbol
== nullptr) {
1237 pos
->symbol
= sc
.symbol
;
1245 m_symbol_contexts
.push_back(sc
);
1249 void SymbolContextList::Clear() { m_symbol_contexts
.clear(); }
1251 void SymbolContextList::Dump(Stream
*s
, Target
*target
) const {
1255 s
->PutCString("SymbolContextList");
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
);
1267 bool SymbolContextList::GetContextAtIndex(size_t idx
, SymbolContext
&sc
) const {
1268 if (idx
< m_symbol_contexts
.size()) {
1269 sc
= m_symbol_contexts
[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
);
1283 uint32_t SymbolContextList::GetSize() const { return m_symbol_contexts
.size(); }
1285 bool SymbolContextList::IsEmpty() const { return m_symbol_contexts
.empty(); }
1287 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
)
1297 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
);
1304 bool lldb_private::operator==(const SymbolContextList
&lhs
,
1305 const SymbolContextList
&rhs
) {
1306 const uint32_t size
= lhs
.GetSize();
1307 if (size
!= rhs
.GetSize())
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
)
1321 bool lldb_private::operator!=(const SymbolContextList
&lhs
,
1322 const SymbolContextList
&rhs
) {
1323 return !(lhs
== rhs
);