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/Module.h"
12 #include "lldb/Core/ModuleSpec.h"
13 #include "lldb/Host/Host.h"
14 #include "lldb/Symbol/Block.h"
15 #include "lldb/Symbol/CompileUnit.h"
16 #include "lldb/Symbol/ObjectFile.h"
17 #include "lldb/Symbol/Symbol.h"
18 #include "lldb/Symbol/SymbolFile.h"
19 #include "lldb/Symbol/SymbolVendor.h"
20 #include "lldb/Symbol/Variable.h"
21 #include "lldb/Target/Target.h"
22 #include "lldb/Utility/Log.h"
23 #include "lldb/Utility/StreamString.h"
26 using namespace lldb_private
;
28 SymbolContext::SymbolContext() : target_sp(), module_sp(), line_entry() {}
30 SymbolContext::SymbolContext(const ModuleSP
&m
, CompileUnit
*cu
, Function
*f
,
31 Block
*b
, LineEntry
*le
, Symbol
*s
)
32 : target_sp(), module_sp(m
), comp_unit(cu
), function(f
), block(b
),
33 line_entry(), symbol(s
), variable(nullptr) {
38 SymbolContext::SymbolContext(const TargetSP
&t
, const ModuleSP
&m
,
39 CompileUnit
*cu
, Function
*f
, Block
*b
,
40 LineEntry
*le
, Symbol
*s
)
41 : target_sp(t
), module_sp(m
), comp_unit(cu
), function(f
), block(b
),
42 line_entry(), symbol(s
), variable(nullptr) {
47 SymbolContext::SymbolContext(SymbolContextScope
*sc_scope
)
48 : target_sp(), module_sp(), comp_unit(nullptr), function(nullptr),
49 block(nullptr), line_entry(), symbol(nullptr), variable(nullptr) {
50 sc_scope
->CalculateSymbolContext(this);
53 SymbolContext::~SymbolContext() = default;
55 void SymbolContext::Clear(bool clear_target
) {
67 bool SymbolContext::DumpStopContext(Stream
*s
, ExecutionContextScope
*exe_scope
,
68 const Address
&addr
, bool show_fullpaths
,
69 bool show_module
, bool show_inlined_frames
,
70 bool show_function_arguments
,
71 bool show_function_name
) const {
72 bool dumped_something
= false;
73 if (show_module
&& module_sp
) {
75 *s
<< module_sp
->GetFileSpec();
77 *s
<< module_sp
->GetFileSpec().GetFilename();
79 dumped_something
= true;
82 if (function
!= nullptr) {
83 SymbolContext inline_parent_sc
;
84 Address inline_parent_addr
;
85 if (!show_function_name
) {
87 dumped_something
= true;
90 if (!show_function_arguments
)
91 name
= function
->GetNameNoArguments();
93 name
= function
->GetName();
99 const addr_t function_offset
=
101 function
->GetAddressRange().GetBaseAddress().GetOffset();
102 if (!show_function_name
) {
103 // Print +offset even if offset is 0
104 dumped_something
= true;
105 s
->Printf("+%" PRIu64
">", function_offset
);
106 } else if (function_offset
) {
107 dumped_something
= true;
108 s
->Printf(" + %" PRIu64
, function_offset
);
112 if (GetParentOfInlinedScope(addr
, inline_parent_sc
, inline_parent_addr
)) {
113 dumped_something
= true;
114 Block
*inlined_block
= block
->GetContainingInlinedBlock();
115 const InlineFunctionInfo
*inlined_block_info
=
116 inlined_block
->GetInlinedFunctionInfo();
117 s
->Printf(" [inlined] %s", inlined_block_info
->GetName().GetCString());
119 lldb_private::AddressRange block_range
;
120 if (inlined_block
->GetRangeContainingAddress(addr
, block_range
)) {
121 const addr_t inlined_function_offset
=
122 addr
.GetOffset() - block_range
.GetBaseAddress().GetOffset();
123 if (inlined_function_offset
) {
124 s
->Printf(" + %" PRIu64
, inlined_function_offset
);
127 // "line_entry" will always be valid as GetParentOfInlinedScope(...) will
128 // fill it in correctly with the calling file and line. Previous code
129 // was extracting the calling file and line from inlined_block_info and
130 // using it right away which is not correct. On the first call to this
131 // function "line_entry" will contain the actual line table entry. On
132 // susequent calls "line_entry" will contain the calling file and line
133 // from the previous inline info.
134 if (line_entry
.IsValid()) {
135 s
->PutCString(" at ");
136 line_entry
.DumpStopContext(s
, show_fullpaths
);
139 if (show_inlined_frames
) {
142 const bool show_function_name
= true;
143 return inline_parent_sc
.DumpStopContext(
144 s
, exe_scope
, inline_parent_addr
, show_fullpaths
, show_module
,
145 show_inlined_frames
, show_function_arguments
, show_function_name
);
148 if (line_entry
.IsValid()) {
149 dumped_something
= true;
150 s
->PutCString(" at ");
151 if (line_entry
.DumpStopContext(s
, show_fullpaths
))
152 dumped_something
= true;
155 } else if (symbol
!= nullptr) {
156 if (!show_function_name
) {
158 dumped_something
= true;
159 } else if (symbol
->GetName()) {
160 dumped_something
= true;
161 if (symbol
->GetType() == eSymbolTypeTrampoline
)
162 s
->PutCString("symbol stub for: ");
163 symbol
->GetName().Dump(s
);
166 if (addr
.IsValid() && symbol
->ValueIsAddress()) {
167 const addr_t symbol_offset
=
168 addr
.GetOffset() - symbol
->GetAddressRef().GetOffset();
169 if (!show_function_name
) {
170 // Print +offset even if offset is 0
171 dumped_something
= true;
172 s
->Printf("+%" PRIu64
">", symbol_offset
);
173 } else if (symbol_offset
) {
174 dumped_something
= true;
175 s
->Printf(" + %" PRIu64
, symbol_offset
);
178 } else if (addr
.IsValid()) {
179 addr
.Dump(s
, exe_scope
, Address::DumpStyleModuleWithFileAddress
);
180 dumped_something
= true;
182 return dumped_something
;
185 void SymbolContext::GetDescription(Stream
*s
, lldb::DescriptionLevel level
,
186 Target
*target
) const {
188 s
->Indent(" Module: file = \"");
189 module_sp
->GetFileSpec().Dump(s
->AsRawOstream());
191 if (module_sp
->GetArchitecture().IsValid())
192 s
->Printf(", arch = \"%s\"",
193 module_sp
->GetArchitecture().GetArchitectureName());
197 if (comp_unit
!= nullptr) {
198 s
->Indent("CompileUnit: ");
199 comp_unit
->GetDescription(s
, level
);
203 if (function
!= nullptr) {
204 s
->Indent(" Function: ");
205 function
->GetDescription(s
, level
, target
);
208 Type
*func_type
= function
->GetType();
210 s
->Indent(" FuncType: ");
211 func_type
->GetDescription(s
, level
, false, target
);
216 if (block
!= nullptr) {
217 std::vector
<Block
*> blocks
;
218 blocks
.push_back(block
);
219 Block
*parent_block
= block
->GetParent();
221 while (parent_block
) {
222 blocks
.push_back(parent_block
);
223 parent_block
= parent_block
->GetParent();
225 std::vector
<Block
*>::reverse_iterator pos
;
226 std::vector
<Block
*>::reverse_iterator begin
= blocks
.rbegin();
227 std::vector
<Block
*>::reverse_iterator end
= blocks
.rend();
228 for (pos
= begin
; pos
!= end
; ++pos
) {
230 s
->Indent(" Blocks: ");
233 (*pos
)->GetDescription(s
, function
, level
, target
);
238 if (line_entry
.IsValid()) {
239 s
->Indent(" LineEntry: ");
240 line_entry
.GetDescription(s
, level
, comp_unit
, target
, false);
244 if (symbol
!= nullptr) {
245 s
->Indent(" Symbol: ");
246 symbol
->GetDescription(s
, level
, target
);
250 if (variable
!= nullptr) {
251 s
->Indent(" Variable: ");
253 s
->Printf("id = {0x%8.8" PRIx64
"}, ", variable
->GetID());
255 switch (variable
->GetScope()) {
256 case eValueTypeVariableGlobal
:
257 s
->PutCString("kind = global, ");
260 case eValueTypeVariableStatic
:
261 s
->PutCString("kind = static, ");
264 case eValueTypeVariableArgument
:
265 s
->PutCString("kind = argument, ");
268 case eValueTypeVariableLocal
:
269 s
->PutCString("kind = local, ");
272 case eValueTypeVariableThreadLocal
:
273 s
->PutCString("kind = thread local, ");
280 s
->Printf("name = \"%s\"\n", variable
->GetName().GetCString());
284 uint32_t SymbolContext::GetResolvedMask() const {
285 uint32_t resolved_mask
= 0;
287 resolved_mask
|= eSymbolContextTarget
;
289 resolved_mask
|= eSymbolContextModule
;
291 resolved_mask
|= eSymbolContextCompUnit
;
293 resolved_mask
|= eSymbolContextFunction
;
295 resolved_mask
|= eSymbolContextBlock
;
296 if (line_entry
.IsValid())
297 resolved_mask
|= eSymbolContextLineEntry
;
299 resolved_mask
|= eSymbolContextSymbol
;
301 resolved_mask
|= eSymbolContextVariable
;
302 return resolved_mask
;
305 void SymbolContext::Dump(Stream
*s
, Target
*target
) const {
308 s
->PutCString("SymbolContext");
313 *s
<< "Module = " << module_sp
.get() << ' ';
315 module_sp
->GetFileSpec().Dump(s
->AsRawOstream());
318 *s
<< "CompileUnit = " << comp_unit
;
319 if (comp_unit
!= nullptr)
320 s
->Format(" {{{0:x-16}} {1}", comp_unit
->GetID(),
321 comp_unit
->GetPrimaryFile());
324 *s
<< "Function = " << function
;
325 if (function
!= nullptr) {
326 s
->Format(" {{{0:x-16}} {1}, address-range = ", function
->GetID(),
327 function
->GetType()->GetName());
328 function
->GetAddressRange().Dump(s
, target
, Address::DumpStyleLoadAddress
,
329 Address::DumpStyleModuleWithFileAddress
);
332 Type
*func_type
= function
->GetType();
335 func_type
->Dump(s
, false);
340 *s
<< "Block = " << block
;
341 if (block
!= nullptr)
342 s
->Format(" {{{0:x-16}}", block
->GetID());
345 *s
<< "LineEntry = ";
346 line_entry
.Dump(s
, target
, true, Address::DumpStyleLoadAddress
,
347 Address::DumpStyleModuleWithFileAddress
, true);
350 *s
<< "Symbol = " << symbol
;
351 if (symbol
!= nullptr && symbol
->GetMangled())
352 *s
<< ' ' << symbol
->GetName().AsCString();
354 *s
<< "Variable = " << variable
;
355 if (variable
!= nullptr) {
356 s
->Format(" {{{0:x-16}} {1}", variable
->GetID(),
357 variable
->GetType()->GetName());
364 bool lldb_private::operator==(const SymbolContext
&lhs
,
365 const SymbolContext
&rhs
) {
366 return lhs
.function
== rhs
.function
&& lhs
.symbol
== rhs
.symbol
&&
367 lhs
.module_sp
.get() == rhs
.module_sp
.get() &&
368 lhs
.comp_unit
== rhs
.comp_unit
&&
369 lhs
.target_sp
.get() == rhs
.target_sp
.get() &&
370 LineEntry::Compare(lhs
.line_entry
, rhs
.line_entry
) == 0 &&
371 lhs
.variable
== rhs
.variable
;
374 bool lldb_private::operator!=(const SymbolContext
&lhs
,
375 const SymbolContext
&rhs
) {
376 return !(lhs
== rhs
);
379 bool SymbolContext::GetAddressRange(uint32_t scope
, uint32_t range_idx
,
380 bool use_inline_block_range
,
381 AddressRange
&range
) const {
382 if ((scope
& eSymbolContextLineEntry
) && line_entry
.IsValid()) {
383 range
= line_entry
.range
;
387 if ((scope
& eSymbolContextBlock
) && (block
!= nullptr)) {
388 if (use_inline_block_range
) {
389 Block
*inline_block
= block
->GetContainingInlinedBlock();
391 return inline_block
->GetRangeAtIndex(range_idx
, range
);
393 return block
->GetRangeAtIndex(range_idx
, range
);
397 if ((scope
& eSymbolContextFunction
) && (function
!= nullptr)) {
398 if (range_idx
== 0) {
399 range
= function
->GetAddressRange();
404 if ((scope
& eSymbolContextSymbol
) && (symbol
!= nullptr)) {
405 if (range_idx
== 0) {
406 if (symbol
->ValueIsAddress()) {
407 range
.GetBaseAddress() = symbol
->GetAddressRef();
408 range
.SetByteSize(symbol
->GetByteSize());
417 LanguageType
SymbolContext::GetLanguage() const {
419 if (function
&& (lang
= function
->GetLanguage()) != eLanguageTypeUnknown
) {
421 } else if (variable
&&
422 (lang
= variable
->GetLanguage()) != eLanguageTypeUnknown
) {
424 } else if (symbol
&& (lang
= symbol
->GetLanguage()) != eLanguageTypeUnknown
) {
426 } else if (comp_unit
&&
427 (lang
= comp_unit
->GetLanguage()) != eLanguageTypeUnknown
) {
430 // If all else fails, try to guess the language from the name.
431 return symbol
->GetMangled().GuessLanguage();
433 return eLanguageTypeUnknown
;
436 bool SymbolContext::GetParentOfInlinedScope(const Address
&curr_frame_pc
,
437 SymbolContext
&next_frame_sc
,
438 Address
&next_frame_pc
) const {
439 next_frame_sc
.Clear(false);
440 next_frame_pc
.Clear();
443 // const addr_t curr_frame_file_addr = curr_frame_pc.GetFileAddress();
445 // In order to get the parent of an inlined function we first need to see
446 // if we are in an inlined block as "this->block" could be an inlined
447 // block, or a parent of "block" could be. So lets check if this block or
448 // one of this blocks parents is an inlined function.
449 Block
*curr_inlined_block
= block
->GetContainingInlinedBlock();
450 if (curr_inlined_block
) {
451 // "this->block" is contained in an inline function block, so to get the
452 // scope above the inlined block, we get the parent of the inlined block
454 Block
*next_frame_block
= curr_inlined_block
->GetParent();
455 // Now calculate the symbol context of the containing block
456 next_frame_block
->CalculateSymbolContext(&next_frame_sc
);
458 // If we get here we weren't able to find the return line entry using the
459 // nesting of the blocks and the line table. So just use the call site
460 // info from our inlined block.
463 if (curr_inlined_block
->GetRangeContainingAddress(curr_frame_pc
, range
)) {
464 // To see there this new frame block it, we need to look at the call
465 // site information from
466 const InlineFunctionInfo
*curr_inlined_block_inlined_info
=
467 curr_inlined_block
->GetInlinedFunctionInfo();
468 next_frame_pc
= range
.GetBaseAddress();
469 next_frame_sc
.line_entry
.range
.GetBaseAddress() = next_frame_pc
;
470 next_frame_sc
.line_entry
.file
=
471 curr_inlined_block_inlined_info
->GetCallSite().GetFile();
472 next_frame_sc
.line_entry
.original_file
=
473 curr_inlined_block_inlined_info
->GetCallSite().GetFile();
474 next_frame_sc
.line_entry
.line
=
475 curr_inlined_block_inlined_info
->GetCallSite().GetLine();
476 next_frame_sc
.line_entry
.column
=
477 curr_inlined_block_inlined_info
->GetCallSite().GetColumn();
480 Log
*log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS
));
485 "warning: inlined block 0x%8.8" PRIx64
486 " doesn't have a range that contains file address 0x%" PRIx64
,
487 curr_inlined_block
->GetID(), curr_frame_pc
.GetFileAddress());
489 #ifdef LLDB_CONFIGURATION_DEBUG
491 ObjectFile
*objfile
= nullptr;
493 if (SymbolFile
*symbol_file
= module_sp
->GetSymbolFile())
494 objfile
= symbol_file
->GetObjectFile();
498 Host::eSystemLogWarning
,
499 "warning: inlined block 0x%8.8" PRIx64
500 " doesn't have a range that contains file address 0x%" PRIx64
502 curr_inlined_block
->GetID(), curr_frame_pc
.GetFileAddress(),
503 objfile
->GetFileSpec().GetPath().c_str());
506 Host::eSystemLogWarning
,
507 "warning: inlined block 0x%8.8" PRIx64
508 " doesn't have a range that contains file address 0x%" PRIx64
510 curr_inlined_block
->GetID(), curr_frame_pc
.GetFileAddress());
521 Block
*SymbolContext::GetFunctionBlock() {
524 // If this symbol context has a block, check to see if this block is
525 // itself, or is contained within a block with inlined function
526 // information. If so, then the inlined block is the block that defines
528 Block
*inlined_block
= block
->GetContainingInlinedBlock();
530 return inlined_block
;
532 // The block in this symbol context is not inside an inlined block, so
533 // the block that defines the function is the function's top level block,
534 // which is returned below.
537 // There is no block information in this symbol context, so we must assume
538 // that the block that is desired is the top level block of the function
540 return &function
->GetBlock(true);
545 bool SymbolContext::GetFunctionMethodInfo(lldb::LanguageType
&language
,
546 bool &is_instance_method
,
547 ConstString
&language_object_name
)
550 Block
*function_block
= GetFunctionBlock();
551 if (function_block
) {
552 CompilerDeclContext decl_ctx
= function_block
->GetDeclContext();
554 return decl_ctx
.IsClassMethod(&language
, &is_instance_method
,
555 &language_object_name
);
560 void SymbolContext::SortTypeList(TypeMap
&type_map
, TypeList
&type_list
) const {
561 Block
*curr_block
= block
;
562 bool isInlinedblock
= false;
563 if (curr_block
!= nullptr &&
564 curr_block
->GetContainingInlinedBlock() != nullptr)
565 isInlinedblock
= true;
567 // Find all types that match the current block if we have one and put them
568 // first in the list. Keep iterating up through all blocks.
569 while (curr_block
!= nullptr && !isInlinedblock
) {
571 [curr_block
, &type_list
](const lldb::TypeSP
&type_sp
) -> bool {
572 SymbolContextScope
*scs
= type_sp
->GetSymbolContextScope();
573 if (scs
&& curr_block
== scs
->CalculateSymbolContextBlock())
574 type_list
.Insert(type_sp
);
575 return true; // Keep iterating
578 // Remove any entries that are now in "type_list" from "type_map" since we
579 // can't remove from type_map while iterating
580 type_list
.ForEach([&type_map
](const lldb::TypeSP
&type_sp
) -> bool {
581 type_map
.Remove(type_sp
);
582 return true; // Keep iterating
584 curr_block
= curr_block
->GetParent();
586 // Find all types that match the current function, if we have onem, and put
587 // them next in the list.
588 if (function
!= nullptr && !type_map
.Empty()) {
589 const size_t old_type_list_size
= type_list
.GetSize();
590 type_map
.ForEach([this, &type_list
](const lldb::TypeSP
&type_sp
) -> bool {
591 SymbolContextScope
*scs
= type_sp
->GetSymbolContextScope();
592 if (scs
&& function
== scs
->CalculateSymbolContextFunction())
593 type_list
.Insert(type_sp
);
594 return true; // Keep iterating
597 // Remove any entries that are now in "type_list" from "type_map" since we
598 // can't remove from type_map while iterating
599 const size_t new_type_list_size
= type_list
.GetSize();
600 if (new_type_list_size
> old_type_list_size
) {
601 for (size_t i
= old_type_list_size
; i
< new_type_list_size
; ++i
)
602 type_map
.Remove(type_list
.GetTypeAtIndex(i
));
605 // Find all types that match the current compile unit, if we have one, and
606 // put them next in the list.
607 if (comp_unit
!= nullptr && !type_map
.Empty()) {
608 const size_t old_type_list_size
= type_list
.GetSize();
610 type_map
.ForEach([this, &type_list
](const lldb::TypeSP
&type_sp
) -> bool {
611 SymbolContextScope
*scs
= type_sp
->GetSymbolContextScope();
612 if (scs
&& comp_unit
== scs
->CalculateSymbolContextCompileUnit())
613 type_list
.Insert(type_sp
);
614 return true; // Keep iterating
617 // Remove any entries that are now in "type_list" from "type_map" since we
618 // can't remove from type_map while iterating
619 const size_t new_type_list_size
= type_list
.GetSize();
620 if (new_type_list_size
> old_type_list_size
) {
621 for (size_t i
= old_type_list_size
; i
< new_type_list_size
; ++i
)
622 type_map
.Remove(type_list
.GetTypeAtIndex(i
));
625 // Find all types that match the current module, if we have one, and put them
627 if (module_sp
&& !type_map
.Empty()) {
628 const size_t old_type_list_size
= type_list
.GetSize();
629 type_map
.ForEach([this, &type_list
](const lldb::TypeSP
&type_sp
) -> bool {
630 SymbolContextScope
*scs
= type_sp
->GetSymbolContextScope();
631 if (scs
&& module_sp
== scs
->CalculateSymbolContextModule())
632 type_list
.Insert(type_sp
);
633 return true; // Keep iterating
635 // Remove any entries that are now in "type_list" from "type_map" since we
636 // can't remove from type_map while iterating
637 const size_t new_type_list_size
= type_list
.GetSize();
638 if (new_type_list_size
> old_type_list_size
) {
639 for (size_t i
= old_type_list_size
; i
< new_type_list_size
; ++i
)
640 type_map
.Remove(type_list
.GetTypeAtIndex(i
));
643 // Any types that are left get copied into the list an any order.
644 if (!type_map
.Empty()) {
645 type_map
.ForEach([&type_list
](const lldb::TypeSP
&type_sp
) -> bool {
646 type_list
.Insert(type_sp
);
647 return true; // Keep iterating
653 SymbolContext::GetFunctionName(Mangled::NamePreference preference
) const {
656 Block
*inlined_block
= block
->GetContainingInlinedBlock();
659 const InlineFunctionInfo
*inline_info
=
660 inlined_block
->GetInlinedFunctionInfo();
662 return inline_info
->GetName();
665 return function
->GetMangled().GetName(preference
);
666 } else if (symbol
&& symbol
->ValueIsAddress()) {
667 return symbol
->GetMangled().GetName(preference
);
669 // No function, return an empty string.
670 return ConstString();
674 LineEntry
SymbolContext::GetFunctionStartLineEntry() const {
675 LineEntry line_entry
;
678 Block
*inlined_block
= block
->GetContainingInlinedBlock();
680 if (inlined_block
->GetStartAddress(start_addr
)) {
681 if (start_addr
.CalculateSymbolContextLineEntry(line_entry
))
689 if (function
->GetAddressRange()
691 .CalculateSymbolContextLineEntry(line_entry
))
697 bool SymbolContext::GetAddressRangeFromHereToEndLine(uint32_t end_line
,
700 if (!line_entry
.IsValid()) {
701 error
.SetErrorString("Symbol context has no line table.");
705 range
= line_entry
.range
;
706 if (line_entry
.line
> end_line
) {
707 error
.SetErrorStringWithFormat(
708 "end line option %d must be after the current line: %d", end_line
,
713 uint32_t line_index
= 0;
717 line_index
= comp_unit
->FindLineEntry(line_index
, line_entry
.line
, nullptr,
719 if (line_index
== UINT32_MAX
)
721 if (LineEntry::Compare(this_line
, line_entry
) == 0) {
729 // Can't find the index of the SymbolContext's line entry in the
730 // SymbolContext's CompUnit.
731 error
.SetErrorString(
732 "Can't find the current line entry in the CompUnit - can't process "
733 "the end-line option");
737 line_index
= comp_unit
->FindLineEntry(line_index
, end_line
, nullptr, false,
739 if (line_index
== UINT32_MAX
) {
740 error
.SetErrorStringWithFormat(
741 "could not find a line table entry corresponding "
742 "to end line number %d",
747 Block
*func_block
= GetFunctionBlock();
748 if (func_block
&& func_block
->GetRangeIndexContainingAddress(
749 end_entry
.range
.GetBaseAddress()) == UINT32_MAX
) {
750 error
.SetErrorStringWithFormat(
751 "end line number %d is not contained within the current function.",
756 lldb::addr_t range_size
= end_entry
.range
.GetBaseAddress().GetFileAddress() -
757 range
.GetBaseAddress().GetFileAddress();
758 range
.SetByteSize(range_size
);
762 const Symbol
*SymbolContext::FindBestGlobalDataSymbol(ConstString name
,
770 Target
&target
= *target_sp
;
771 Module
*module
= module_sp
.get();
773 auto ProcessMatches
= [this, &name
, &target
,
774 module
](SymbolContextList
&sc_list
,
775 Status
&error
) -> const Symbol
* {
776 llvm::SmallVector
<const Symbol
*, 1> external_symbols
;
777 llvm::SmallVector
<const Symbol
*, 1> internal_symbols
;
778 const uint32_t matches
= sc_list
.GetSize();
779 for (uint32_t i
= 0; i
< matches
; ++i
) {
780 SymbolContext sym_ctx
;
781 sc_list
.GetContextAtIndex(i
, sym_ctx
);
782 if (sym_ctx
.symbol
) {
783 const Symbol
*symbol
= sym_ctx
.symbol
;
784 const Address sym_address
= symbol
->GetAddress();
786 if (sym_address
.IsValid()) {
787 switch (symbol
->GetType()) {
788 case eSymbolTypeData
:
789 case eSymbolTypeRuntime
:
790 case eSymbolTypeAbsolute
:
791 case eSymbolTypeObjCClass
:
792 case eSymbolTypeObjCMetaClass
:
793 case eSymbolTypeObjCIVar
:
794 if (symbol
->GetDemangledNameIsSynthesized()) {
795 // If the demangled name was synthesized, then don't use it for
796 // expressions. Only let the symbol match if the mangled named
797 // matches for these symbols.
798 if (symbol
->GetMangled().GetMangledName() != name
)
801 if (symbol
->IsExternal()) {
802 external_symbols
.push_back(symbol
);
804 internal_symbols
.push_back(symbol
);
807 case eSymbolTypeReExported
: {
808 ConstString reexport_name
= symbol
->GetReExportedSymbolName();
810 ModuleSP reexport_module_sp
;
811 ModuleSpec reexport_module_spec
;
812 reexport_module_spec
.GetPlatformFileSpec() =
813 symbol
->GetReExportedSymbolSharedLibrary();
814 if (reexport_module_spec
.GetPlatformFileSpec()) {
816 target
.GetImages().FindFirstModule(reexport_module_spec
);
817 if (!reexport_module_sp
) {
818 reexport_module_spec
.GetPlatformFileSpec()
822 target
.GetImages().FindFirstModule(reexport_module_spec
);
825 // Don't allow us to try and resolve a re-exported symbol if it
826 // is the same as the current symbol
827 if (name
== symbol
->GetReExportedSymbolName() &&
828 module
== reexport_module_sp
.get())
831 return FindBestGlobalDataSymbol(symbol
->GetReExportedSymbolName(),
836 case eSymbolTypeCode
: // We already lookup functions elsewhere
837 case eSymbolTypeVariable
:
838 case eSymbolTypeLocal
:
839 case eSymbolTypeParam
:
840 case eSymbolTypeTrampoline
:
841 case eSymbolTypeInvalid
:
842 case eSymbolTypeException
:
843 case eSymbolTypeSourceFile
:
844 case eSymbolTypeHeaderFile
:
845 case eSymbolTypeObjectFile
:
846 case eSymbolTypeCommonBlock
:
847 case eSymbolTypeBlock
:
848 case eSymbolTypeVariableType
:
849 case eSymbolTypeLineEntry
:
850 case eSymbolTypeLineHeader
:
851 case eSymbolTypeScopeBegin
:
852 case eSymbolTypeScopeEnd
:
853 case eSymbolTypeAdditional
:
854 case eSymbolTypeCompiler
:
855 case eSymbolTypeInstrumentation
:
856 case eSymbolTypeUndefined
:
857 case eSymbolTypeResolver
:
864 if (external_symbols
.size() > 1) {
866 ss
.Printf("Multiple external symbols found for '%s'\n", name
.AsCString());
867 for (const Symbol
*symbol
: external_symbols
) {
868 symbol
->GetDescription(&ss
, eDescriptionLevelFull
, &target
);
871 error
.SetErrorString(ss
.GetData());
873 } else if (external_symbols
.size()) {
874 return external_symbols
[0];
875 } else if (internal_symbols
.size() > 1) {
877 ss
.Printf("Multiple internal symbols found for '%s'\n", name
.AsCString());
878 for (const Symbol
*symbol
: internal_symbols
) {
879 symbol
->GetDescription(&ss
, eDescriptionLevelVerbose
, &target
);
882 error
.SetErrorString(ss
.GetData());
884 } else if (internal_symbols
.size()) {
885 return internal_symbols
[0];
892 SymbolContextList sc_list
;
893 module
->FindSymbolsWithNameAndType(name
, eSymbolTypeAny
, sc_list
);
894 const Symbol
*const module_symbol
= ProcessMatches(sc_list
, error
);
896 if (!error
.Success()) {
898 } else if (module_symbol
) {
899 return module_symbol
;
904 SymbolContextList sc_list
;
905 target
.GetImages().FindSymbolsWithNameAndType(name
, eSymbolTypeAny
,
907 const Symbol
*const target_symbol
= ProcessMatches(sc_list
, error
);
909 if (!error
.Success()) {
911 } else if (target_symbol
) {
912 return target_symbol
;
916 return nullptr; // no error; we just didn't find anything
920 // SymbolContextSpecifier
923 SymbolContextSpecifier::SymbolContextSpecifier(const TargetSP
&target_sp
)
924 : m_target_sp(target_sp
), m_module_spec(), m_module_sp(), m_file_spec_up(),
925 m_start_line(0), m_end_line(0), m_function_spec(), m_class_name(),
926 m_address_range_up(), m_type(eNothingSpecified
) {}
928 SymbolContextSpecifier::~SymbolContextSpecifier() = default;
930 bool SymbolContextSpecifier::AddLineSpecification(uint32_t line_no
,
931 SpecificationType type
) {
932 bool return_value
= true;
934 case eNothingSpecified
:
937 case eLineStartSpecified
:
938 m_start_line
= line_no
;
939 m_type
|= eLineStartSpecified
;
941 case eLineEndSpecified
:
942 m_end_line
= line_no
;
943 m_type
|= eLineEndSpecified
;
946 return_value
= false;
952 bool SymbolContextSpecifier::AddSpecification(const char *spec_string
,
953 SpecificationType type
) {
954 bool return_value
= true;
956 case eNothingSpecified
:
959 case eModuleSpecified
: {
960 // See if we can find the Module, if so stick it in the SymbolContext.
961 FileSpec
module_file_spec(spec_string
);
962 ModuleSpec
module_spec(module_file_spec
);
963 lldb::ModuleSP
module_sp(
964 m_target_sp
->GetImages().FindFirstModule(module_spec
));
965 m_type
|= eModuleSpecified
;
967 m_module_sp
= module_sp
;
969 m_module_spec
.assign(spec_string
);
972 // CompUnits can't necessarily be resolved here, since an inlined function
973 // might show up in a number of CompUnits. Instead we just convert to a
974 // FileSpec and store it away.
975 m_file_spec_up
= std::make_unique
<FileSpec
>(spec_string
);
976 m_type
|= eFileSpecified
;
978 case eLineStartSpecified
:
979 if ((return_value
= llvm::to_integer(spec_string
, m_start_line
)))
980 m_type
|= eLineStartSpecified
;
982 case eLineEndSpecified
:
983 if ((return_value
= llvm::to_integer(spec_string
, m_end_line
)))
984 m_type
|= eLineEndSpecified
;
986 case eFunctionSpecified
:
987 m_function_spec
.assign(spec_string
);
988 m_type
|= eFunctionSpecified
;
990 case eClassOrNamespaceSpecified
:
992 m_class_name
.assign(spec_string
);
993 m_type
= eClassOrNamespaceSpecified
;
995 case eAddressRangeSpecified
:
996 // Not specified yet...
1000 return return_value
;
1003 void SymbolContextSpecifier::Clear() {
1004 m_module_spec
.clear();
1005 m_file_spec_up
.reset();
1006 m_function_spec
.clear();
1007 m_class_name
.clear();
1010 m_address_range_up
.reset();
1012 m_type
= eNothingSpecified
;
1015 bool SymbolContextSpecifier::SymbolContextMatches(const SymbolContext
&sc
) {
1016 if (m_type
== eNothingSpecified
)
1019 // Only compare targets if this specifier has one and it's not the Dummy
1020 // target. Otherwise if a specifier gets made in the dummy target and
1021 // copied over we'll artificially fail the comparision.
1022 if (m_target_sp
&& !m_target_sp
->IsDummyTarget() &&
1023 m_target_sp
!= sc
.target_sp
)
1026 if (m_type
& eModuleSpecified
) {
1028 if (m_module_sp
.get() != nullptr) {
1029 if (m_module_sp
.get() != sc
.module_sp
.get())
1032 FileSpec
module_file_spec(m_module_spec
);
1033 if (!FileSpec::Match(module_file_spec
, sc
.module_sp
->GetFileSpec()))
1038 if (m_type
& eFileSpecified
) {
1039 if (m_file_spec_up
) {
1040 // If we don't have a block or a comp_unit, then we aren't going to match
1042 if (sc
.block
== nullptr && sc
.comp_unit
== nullptr)
1045 // Check if the block is present, and if so is it inlined:
1046 bool was_inlined
= false;
1047 if (sc
.block
!= nullptr) {
1048 const InlineFunctionInfo
*inline_info
=
1049 sc
.block
->GetInlinedFunctionInfo();
1050 if (inline_info
!= nullptr) {
1052 if (!FileSpec::Match(*m_file_spec_up
,
1053 inline_info
->GetDeclaration().GetFile()))
1058 // Next check the comp unit, but only if the SymbolContext was not
1060 if (!was_inlined
&& sc
.comp_unit
!= nullptr) {
1061 if (!FileSpec::Match(*m_file_spec_up
, sc
.comp_unit
->GetPrimaryFile()))
1066 if (m_type
& eLineStartSpecified
|| m_type
& eLineEndSpecified
) {
1067 if (sc
.line_entry
.line
< m_start_line
|| sc
.line_entry
.line
> m_end_line
)
1071 if (m_type
& eFunctionSpecified
) {
1072 // First check the current block, and if it is inlined, get the inlined
1074 bool was_inlined
= false;
1075 ConstString
func_name(m_function_spec
.c_str());
1077 if (sc
.block
!= nullptr) {
1078 const InlineFunctionInfo
*inline_info
=
1079 sc
.block
->GetInlinedFunctionInfo();
1080 if (inline_info
!= nullptr) {
1082 const Mangled
&name
= inline_info
->GetMangled();
1083 if (!name
.NameMatches(func_name
))
1087 // If it wasn't inlined, check the name in the function or symbol:
1089 if (sc
.function
!= nullptr) {
1090 if (!sc
.function
->GetMangled().NameMatches(func_name
))
1092 } else if (sc
.symbol
!= nullptr) {
1093 if (!sc
.symbol
->GetMangled().NameMatches(func_name
))
1102 bool SymbolContextSpecifier::AddressMatches(lldb::addr_t addr
) {
1103 if (m_type
& eAddressRangeSpecified
) {
1106 Address
match_address(addr
, nullptr);
1108 m_target_sp
->GetImages().ResolveSymbolContextForAddress(
1109 match_address
, eSymbolContextEverything
, sc
);
1110 return SymbolContextMatches(sc
);
1115 void SymbolContextSpecifier::GetDescription(
1116 Stream
*s
, lldb::DescriptionLevel level
) const {
1117 char path_str
[PATH_MAX
+ 1];
1119 if (m_type
== eNothingSpecified
) {
1120 s
->Printf("Nothing specified.\n");
1123 if (m_type
== eModuleSpecified
) {
1126 m_module_sp
->GetFileSpec().GetPath(path_str
, PATH_MAX
);
1127 s
->Printf("Module: %s\n", path_str
);
1129 s
->Printf("Module: %s\n", m_module_spec
.c_str());
1132 if (m_type
== eFileSpecified
&& m_file_spec_up
!= nullptr) {
1133 m_file_spec_up
->GetPath(path_str
, PATH_MAX
);
1135 s
->Printf("File: %s", path_str
);
1136 if (m_type
== eLineStartSpecified
) {
1137 s
->Printf(" from line %" PRIu64
"", (uint64_t)m_start_line
);
1138 if (m_type
== eLineEndSpecified
)
1139 s
->Printf("to line %" PRIu64
"", (uint64_t)m_end_line
);
1141 s
->Printf("to end");
1142 } else if (m_type
== eLineEndSpecified
) {
1143 s
->Printf(" from start to line %" PRIu64
"", (uint64_t)m_end_line
);
1148 if (m_type
== eLineStartSpecified
) {
1150 s
->Printf("From line %" PRIu64
"", (uint64_t)m_start_line
);
1151 if (m_type
== eLineEndSpecified
)
1152 s
->Printf("to line %" PRIu64
"", (uint64_t)m_end_line
);
1154 s
->Printf("to end");
1156 } else if (m_type
== eLineEndSpecified
) {
1157 s
->Printf("From start to line %" PRIu64
".\n", (uint64_t)m_end_line
);
1160 if (m_type
== eFunctionSpecified
) {
1162 s
->Printf("Function: %s.\n", m_function_spec
.c_str());
1165 if (m_type
== eClassOrNamespaceSpecified
) {
1167 s
->Printf("Class name: %s.\n", m_class_name
.c_str());
1170 if (m_type
== eAddressRangeSpecified
&& m_address_range_up
!= nullptr) {
1172 s
->PutCString("Address range: ");
1173 m_address_range_up
->Dump(s
, m_target_sp
.get(),
1174 Address::DumpStyleLoadAddress
,
1175 Address::DumpStyleFileAddress
);
1176 s
->PutCString("\n");
1181 // SymbolContextList
1184 SymbolContextList::SymbolContextList() : m_symbol_contexts() {}
1186 SymbolContextList::~SymbolContextList() = default;
1188 void SymbolContextList::Append(const SymbolContext
&sc
) {
1189 m_symbol_contexts
.push_back(sc
);
1192 void SymbolContextList::Append(const SymbolContextList
&sc_list
) {
1193 collection::const_iterator pos
, end
= sc_list
.m_symbol_contexts
.end();
1194 for (pos
= sc_list
.m_symbol_contexts
.begin(); pos
!= end
; ++pos
)
1195 m_symbol_contexts
.push_back(*pos
);
1198 uint32_t SymbolContextList::AppendIfUnique(const SymbolContextList
&sc_list
,
1199 bool merge_symbol_into_function
) {
1200 uint32_t unique_sc_add_count
= 0;
1201 collection::const_iterator pos
, end
= sc_list
.m_symbol_contexts
.end();
1202 for (pos
= sc_list
.m_symbol_contexts
.begin(); pos
!= end
; ++pos
) {
1203 if (AppendIfUnique(*pos
, merge_symbol_into_function
))
1204 ++unique_sc_add_count
;
1206 return unique_sc_add_count
;
1209 bool SymbolContextList::AppendIfUnique(const SymbolContext
&sc
,
1210 bool merge_symbol_into_function
) {
1211 collection::iterator pos
, end
= m_symbol_contexts
.end();
1212 for (pos
= m_symbol_contexts
.begin(); pos
!= end
; ++pos
) {
1216 if (merge_symbol_into_function
&& sc
.symbol
!= nullptr &&
1217 sc
.comp_unit
== nullptr && sc
.function
== nullptr &&
1218 sc
.block
== nullptr && !sc
.line_entry
.IsValid()) {
1219 if (sc
.symbol
->ValueIsAddress()) {
1220 for (pos
= m_symbol_contexts
.begin(); pos
!= end
; ++pos
) {
1221 // Don't merge symbols into inlined function symbol contexts
1222 if (pos
->block
&& pos
->block
->GetContainingInlinedBlock())
1225 if (pos
->function
) {
1226 if (pos
->function
->GetAddressRange().GetBaseAddress() ==
1227 sc
.symbol
->GetAddressRef()) {
1228 // Do we already have a function with this symbol?
1229 if (pos
->symbol
== sc
.symbol
)
1231 if (pos
->symbol
== nullptr) {
1232 pos
->symbol
= sc
.symbol
;
1240 m_symbol_contexts
.push_back(sc
);
1244 void SymbolContextList::Clear() { m_symbol_contexts
.clear(); }
1246 void SymbolContextList::Dump(Stream
*s
, Target
*target
) const {
1250 s
->PutCString("SymbolContextList");
1254 collection::const_iterator pos
, end
= m_symbol_contexts
.end();
1255 for (pos
= m_symbol_contexts
.begin(); pos
!= end
; ++pos
) {
1256 // pos->Dump(s, target);
1257 pos
->GetDescription(s
, eDescriptionLevelVerbose
, target
);
1262 bool SymbolContextList::GetContextAtIndex(size_t idx
, SymbolContext
&sc
) const {
1263 if (idx
< m_symbol_contexts
.size()) {
1264 sc
= m_symbol_contexts
[idx
];
1270 bool SymbolContextList::RemoveContextAtIndex(size_t idx
) {
1271 if (idx
< m_symbol_contexts
.size()) {
1272 m_symbol_contexts
.erase(m_symbol_contexts
.begin() + idx
);
1278 uint32_t SymbolContextList::GetSize() const { return m_symbol_contexts
.size(); }
1280 bool SymbolContextList::IsEmpty() const { return m_symbol_contexts
.empty(); }
1282 uint32_t SymbolContextList::NumLineEntriesWithLine(uint32_t line
) const {
1283 uint32_t match_count
= 0;
1284 const size_t size
= m_symbol_contexts
.size();
1285 for (size_t idx
= 0; idx
< size
; ++idx
) {
1286 if (m_symbol_contexts
[idx
].line_entry
.line
== line
)
1292 void SymbolContextList::GetDescription(Stream
*s
, lldb::DescriptionLevel level
,
1293 Target
*target
) const {
1294 const size_t size
= m_symbol_contexts
.size();
1295 for (size_t idx
= 0; idx
< size
; ++idx
)
1296 m_symbol_contexts
[idx
].GetDescription(s
, level
, target
);
1299 bool lldb_private::operator==(const SymbolContextList
&lhs
,
1300 const SymbolContextList
&rhs
) {
1301 const uint32_t size
= lhs
.GetSize();
1302 if (size
!= rhs
.GetSize())
1305 SymbolContext lhs_sc
;
1306 SymbolContext rhs_sc
;
1307 for (uint32_t i
= 0; i
< size
; ++i
) {
1308 lhs
.GetContextAtIndex(i
, lhs_sc
);
1309 rhs
.GetContextAtIndex(i
, rhs_sc
);
1310 if (lhs_sc
!= rhs_sc
)
1316 bool lldb_private::operator!=(const SymbolContextList
&lhs
,
1317 const SymbolContextList
&rhs
) {
1318 return !(lhs
== rhs
);