1 //===-- Variable.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/Variable.h"
11 #include "lldb/Core/Module.h"
12 #include "lldb/Symbol/Block.h"
13 #include "lldb/Symbol/CompileUnit.h"
14 #include "lldb/Symbol/CompilerDecl.h"
15 #include "lldb/Symbol/CompilerDeclContext.h"
16 #include "lldb/Symbol/Function.h"
17 #include "lldb/Symbol/SymbolContext.h"
18 #include "lldb/Symbol/SymbolFile.h"
19 #include "lldb/Symbol/Type.h"
20 #include "lldb/Symbol/TypeSystem.h"
21 #include "lldb/Symbol/VariableList.h"
22 #include "lldb/Target/ABI.h"
23 #include "lldb/Target/Process.h"
24 #include "lldb/Target/RegisterContext.h"
25 #include "lldb/Target/StackFrame.h"
26 #include "lldb/Target/Target.h"
27 #include "lldb/Target/Thread.h"
28 #include "lldb/Utility/LLDBLog.h"
29 #include "lldb/Utility/Log.h"
30 #include "lldb/Utility/RegularExpression.h"
31 #include "lldb/Utility/Stream.h"
32 #include "lldb/ValueObject/ValueObject.h"
33 #include "lldb/ValueObject/ValueObjectVariable.h"
35 #include "llvm/ADT/Twine.h"
38 using namespace lldb_private
;
40 Variable::Variable(lldb::user_id_t uid
, const char *name
, const char *mangled
,
41 const lldb::SymbolFileTypeSP
&symfile_type_sp
,
42 ValueType scope
, SymbolContextScope
*context
,
43 const RangeList
&scope_range
, Declaration
*decl_ptr
,
44 const DWARFExpressionList
&location_list
, bool external
,
45 bool artificial
, bool location_is_constant_data
,
47 : UserID(uid
), m_name(name
), m_mangled(ConstString(mangled
)),
48 m_symfile_type_sp(symfile_type_sp
), m_scope(scope
),
49 m_owner_scope(context
), m_scope_range(scope_range
),
50 m_declaration(decl_ptr
), m_location_list(location_list
), m_external(external
),
51 m_artificial(artificial
), m_loc_is_const_data(location_is_constant_data
),
52 m_static_member(static_member
) {}
54 Variable::~Variable() = default;
56 lldb::LanguageType
Variable::GetLanguage() const {
57 lldb::LanguageType lang
= m_mangled
.GuessLanguage();
58 if (lang
!= lldb::eLanguageTypeUnknown
)
61 if (auto *func
= m_owner_scope
->CalculateSymbolContextFunction()) {
62 if ((lang
= func
->GetLanguage()) != lldb::eLanguageTypeUnknown
)
64 } else if (auto *comp_unit
=
65 m_owner_scope
->CalculateSymbolContextCompileUnit()) {
66 if ((lang
= comp_unit
->GetLanguage()) != lldb::eLanguageTypeUnknown
)
70 return lldb::eLanguageTypeUnknown
;
73 ConstString
Variable::GetName() const {
74 ConstString name
= m_mangled
.GetName();
80 ConstString
Variable::GetUnqualifiedName() const { return m_name
; }
82 bool Variable::NameMatches(ConstString name
) const {
85 SymbolContext variable_sc
;
86 m_owner_scope
->CalculateSymbolContext(&variable_sc
);
88 return m_mangled
.NameMatches(name
);
90 bool Variable::NameMatches(const RegularExpression
®ex
) const {
91 if (regex
.Execute(m_name
.AsCString()))
94 return m_mangled
.NameMatches(regex
);
98 Type
*Variable::GetType() {
99 if (m_symfile_type_sp
)
100 return m_symfile_type_sp
->GetType();
104 void Variable::Dump(Stream
*s
, bool show_context
) const {
105 s
->Printf("%p: ", static_cast<const void *>(this));
107 *s
<< "Variable" << (const UserID
&)*this;
110 *s
<< ", name = \"" << m_name
<< "\"";
112 if (m_symfile_type_sp
) {
113 Type
*type
= m_symfile_type_sp
->GetType();
115 s
->Format(", type = {{{0:x-16}} {1} (", type
->GetID(), type
);
116 type
->DumpTypeName(s
);
121 if (m_scope
!= eValueTypeInvalid
) {
122 s
->PutCString(", scope = ");
124 case eValueTypeVariableGlobal
:
125 s
->PutCString(m_external
? "global" : "static");
127 case eValueTypeVariableArgument
:
128 s
->PutCString("parameter");
130 case eValueTypeVariableLocal
:
131 s
->PutCString("local");
133 case eValueTypeVariableThreadLocal
:
134 s
->PutCString("thread local");
137 s
->AsRawOstream() << "??? (" << m_scope
<< ')';
141 if (show_context
&& m_owner_scope
!= nullptr) {
142 s
->PutCString(", context = ( ");
143 m_owner_scope
->DumpSymbolContext(s
);
147 bool show_fullpaths
= false;
148 m_declaration
.Dump(s
, show_fullpaths
);
150 if (m_location_list
.IsValid()) {
151 s
->PutCString(", location = ");
154 ModuleSP
module_sp(m_owner_scope
->CalculateSymbolContextModule());
156 abi
= ABI::FindPlugin(ProcessSP(), module_sp
->GetArchitecture());
158 m_location_list
.GetDescription(s
, lldb::eDescriptionLevelBrief
, abi
.get());
162 s
->PutCString(", external");
165 s
->PutCString(", artificial");
170 bool Variable::DumpDeclaration(Stream
*s
, bool show_fullpaths
,
172 bool dumped_declaration_info
= false;
175 m_owner_scope
->CalculateSymbolContext(&sc
);
177 sc
.line_entry
.Clear();
178 bool show_inlined_frames
= false;
179 const bool show_function_arguments
= true;
180 const bool show_function_name
= true;
182 dumped_declaration_info
= sc
.DumpStopContext(
183 s
, nullptr, Address(), show_fullpaths
, show_module
, show_inlined_frames
,
184 show_function_arguments
, show_function_name
);
189 if (m_declaration
.DumpStopContext(s
, false))
190 dumped_declaration_info
= true;
191 return dumped_declaration_info
;
194 size_t Variable::MemorySize() const { return sizeof(Variable
); }
196 CompilerDeclContext
Variable::GetDeclContext() {
197 Type
*type
= GetType();
199 return type
->GetSymbolFile()->GetDeclContextContainingUID(GetID());
200 return CompilerDeclContext();
203 CompilerDecl
Variable::GetDecl() {
204 Type
*type
= GetType();
205 return type
? type
->GetSymbolFile()->GetDeclForUID(GetID()) : CompilerDecl();
208 void Variable::CalculateSymbolContext(SymbolContext
*sc
) {
210 m_owner_scope
->CalculateSymbolContext(sc
);
216 bool Variable::LocationIsValidForFrame(StackFrame
*frame
) {
219 frame
->GetSymbolContext(eSymbolContextFunction
).function
;
221 TargetSP
target_sp(frame
->CalculateTarget());
223 addr_t loclist_base_load_addr
=
224 function
->GetAddressRange().GetBaseAddress().GetLoadAddress(
226 if (loclist_base_load_addr
== LLDB_INVALID_ADDRESS
)
228 // It is a location list. We just need to tell if the location list
229 // contains the current address when converted to a load address
230 return m_location_list
.ContainsAddress(
231 loclist_base_load_addr
,
232 frame
->GetFrameCodeAddressForSymbolication().GetLoadAddress(
239 bool Variable::LocationIsValidForAddress(const Address
&address
) {
240 // Be sure to resolve the address to section offset prior to calling this
242 if (address
.IsSectionOffset()) {
243 // We need to check if the address is valid for both scope range and value
245 // Empty scope range means block range.
246 bool valid_in_scope_range
=
247 GetScopeRange().IsEmpty() || GetScopeRange().FindEntryThatContains(
248 address
.GetFileAddress()) != nullptr;
249 if (!valid_in_scope_range
)
252 CalculateSymbolContext(&sc
);
253 if (sc
.module_sp
== address
.GetModule()) {
254 // Is the variable is described by a single location?
255 if (m_location_list
.IsAlwaysValidSingleExpr()) {
256 // Yes it is, the location is valid.
261 addr_t loclist_base_file_addr
=
262 sc
.function
->GetAddressRange().GetBaseAddress().GetFileAddress();
263 if (loclist_base_file_addr
== LLDB_INVALID_ADDRESS
)
265 // It is a location list. We just need to tell if the location list
266 // contains the current address when converted to a load address
267 return m_location_list
.ContainsAddress(loclist_base_file_addr
,
268 address
.GetFileAddress());
275 bool Variable::IsInScope(StackFrame
*frame
) {
277 case eValueTypeRegister
:
278 case eValueTypeRegisterSet
:
279 return frame
!= nullptr;
281 case eValueTypeConstResult
:
282 case eValueTypeVariableGlobal
:
283 case eValueTypeVariableStatic
:
284 case eValueTypeVariableThreadLocal
:
287 case eValueTypeVariableArgument
:
288 case eValueTypeVariableLocal
:
290 // We don't have a location list, we just need to see if the block that
291 // this variable was defined in is currently
292 Block
*deepest_frame_block
=
293 frame
->GetSymbolContext(eSymbolContextBlock
).block
;
294 if (deepest_frame_block
) {
295 SymbolContext variable_sc
;
296 CalculateSymbolContext(&variable_sc
);
298 // Check for static or global variable defined at the compile unit
299 // level that wasn't defined in a block
300 if (variable_sc
.block
== nullptr)
303 // Check if the variable is valid in the current block
304 if (variable_sc
.block
!= deepest_frame_block
&&
305 !variable_sc
.block
->Contains(deepest_frame_block
))
308 // If no scope range is specified then it means that the scope is the
309 // same as the scope of the enclosing lexical block.
310 if (m_scope_range
.IsEmpty())
313 addr_t file_address
= frame
->GetFrameCodeAddress().GetFileAddress();
314 return m_scope_range
.FindEntryThatContains(file_address
) != nullptr;
325 Status
Variable::GetValuesForVariableExpressionPath(
326 llvm::StringRef variable_expr_path
, ExecutionContextScope
*scope
,
327 GetVariableCallback callback
, void *baton
, VariableList
&variable_list
,
328 ValueObjectList
&valobj_list
) {
330 if (!callback
|| variable_expr_path
.empty()) {
331 error
= Status::FromErrorString("unknown error");
335 switch (variable_expr_path
.front()) {
337 error
= Variable::GetValuesForVariableExpressionPath(
338 variable_expr_path
.drop_front(), scope
, callback
, baton
, variable_list
,
341 error
= Status::FromErrorString("unknown error");
344 for (uint32_t i
= 0; i
< valobj_list
.GetSize();) {
346 ValueObjectSP
valobj_sp(
347 valobj_list
.GetValueObjectAtIndex(i
)->Dereference(tmp_error
));
348 if (tmp_error
.Fail()) {
349 variable_list
.RemoveVariableAtIndex(i
);
350 valobj_list
.RemoveValueObjectAtIndex(i
);
352 valobj_list
.SetValueObjectAtIndex(i
, valobj_sp
);
358 error
= Variable::GetValuesForVariableExpressionPath(
359 variable_expr_path
.drop_front(), scope
, callback
, baton
, variable_list
,
361 if (error
.Success()) {
362 for (uint32_t i
= 0; i
< valobj_list
.GetSize();) {
364 ValueObjectSP
valobj_sp(
365 valobj_list
.GetValueObjectAtIndex(i
)->AddressOf(tmp_error
));
366 if (tmp_error
.Fail()) {
367 variable_list
.RemoveVariableAtIndex(i
);
368 valobj_list
.RemoveValueObjectAtIndex(i
);
370 valobj_list
.SetValueObjectAtIndex(i
, valobj_sp
);
375 error
= Status::FromErrorString("unknown error");
381 static RegularExpression
g_regex(
382 llvm::StringRef("^([A-Za-z_:][A-Za-z_0-9:]*)(.*)"));
383 llvm::SmallVector
<llvm::StringRef
, 2> matches
;
384 variable_list
.Clear();
385 if (!g_regex
.Execute(variable_expr_path
, &matches
)) {
386 error
= Status::FromErrorStringWithFormatv(
387 "unable to extract a variable name from '{0}'", variable_expr_path
);
390 std::string variable_name
= matches
[1].str();
391 if (!callback(baton
, variable_name
.c_str(), variable_list
)) {
392 error
= Status::FromErrorString("unknown error");
396 while (i
< variable_list
.GetSize()) {
397 VariableSP
var_sp(variable_list
.GetVariableAtIndex(i
));
398 ValueObjectSP valobj_sp
;
400 variable_list
.RemoveVariableAtIndex(i
);
403 ValueObjectSP
variable_valobj_sp(
404 ValueObjectVariable::Create(scope
, var_sp
));
405 if (!variable_valobj_sp
) {
406 variable_list
.RemoveVariableAtIndex(i
);
410 llvm::StringRef variable_sub_expr_path
=
411 variable_expr_path
.drop_front(variable_name
.size());
412 if (!variable_sub_expr_path
.empty()) {
413 valobj_sp
= variable_valobj_sp
->GetValueForExpressionPath(
414 variable_sub_expr_path
);
416 error
= Status::FromErrorStringWithFormatv(
417 "invalid expression path '{0}' for variable '{1}'",
418 variable_sub_expr_path
, var_sp
->GetName().GetCString());
419 variable_list
.RemoveVariableAtIndex(i
);
423 // Just the name of a variable with no extras
424 valobj_sp
= variable_valobj_sp
;
427 valobj_list
.Append(valobj_sp
);
431 if (variable_list
.GetSize() > 0) {
437 error
= Status::FromErrorString("unknown error");
441 bool Variable::DumpLocations(Stream
*s
, const Address
&address
) {
443 CalculateSymbolContext(&sc
);
446 ModuleSP
module_sp(m_owner_scope
->CalculateSymbolContextModule());
448 abi
= ABI::FindPlugin(ProcessSP(), module_sp
->GetArchitecture());
451 const addr_t file_addr
= address
.GetFileAddress();
453 addr_t loclist_base_file_addr
=
454 sc
.function
->GetAddressRange().GetBaseAddress().GetFileAddress();
455 if (loclist_base_file_addr
== LLDB_INVALID_ADDRESS
)
457 return m_location_list
.DumpLocations(s
, eDescriptionLevelBrief
,
458 loclist_base_file_addr
, file_addr
,
464 static void PrivateAutoComplete(
465 StackFrame
*frame
, llvm::StringRef partial_path
,
467 &prefix_path
, // Anything that has been resolved already will be in here
468 const CompilerType
&compiler_type
, CompletionRequest
&request
);
470 static void PrivateAutoCompleteMembers(
471 StackFrame
*frame
, const std::string
&partial_member_name
,
472 llvm::StringRef partial_path
,
474 &prefix_path
, // Anything that has been resolved already will be in here
475 const CompilerType
&compiler_type
, CompletionRequest
&request
) {
477 // We are in a type parsing child members
478 const uint32_t num_bases
= compiler_type
.GetNumDirectBaseClasses();
481 for (uint32_t i
= 0; i
< num_bases
; ++i
) {
482 CompilerType base_class_type
=
483 compiler_type
.GetDirectBaseClassAtIndex(i
, nullptr);
485 PrivateAutoCompleteMembers(frame
, partial_member_name
, partial_path
,
487 base_class_type
.GetCanonicalType(), request
);
491 const uint32_t num_vbases
= compiler_type
.GetNumVirtualBaseClasses();
493 if (num_vbases
> 0) {
494 for (uint32_t i
= 0; i
< num_vbases
; ++i
) {
495 CompilerType vbase_class_type
=
496 compiler_type
.GetVirtualBaseClassAtIndex(i
, nullptr);
498 PrivateAutoCompleteMembers(frame
, partial_member_name
, partial_path
,
500 vbase_class_type
.GetCanonicalType(), request
);
504 // We are in a type parsing child members
505 const uint32_t num_fields
= compiler_type
.GetNumFields();
507 if (num_fields
> 0) {
508 for (uint32_t i
= 0; i
< num_fields
; ++i
) {
509 std::string member_name
;
511 CompilerType member_compiler_type
= compiler_type
.GetFieldAtIndex(
512 i
, member_name
, nullptr, nullptr, nullptr);
514 if (partial_member_name
.empty()) {
515 request
.AddCompletion((prefix_path
+ member_name
).str());
516 } else if (llvm::StringRef(member_name
)
517 .starts_with(partial_member_name
)) {
518 if (member_name
== partial_member_name
) {
521 prefix_path
+ member_name
, // Anything that has been resolved
522 // already will be in here
523 member_compiler_type
.GetCanonicalType(), request
);
524 } else if (partial_path
.empty()) {
525 request
.AddCompletion((prefix_path
+ member_name
).str());
532 static void PrivateAutoComplete(
533 StackFrame
*frame
, llvm::StringRef partial_path
,
535 &prefix_path
, // Anything that has been resolved already will be in here
536 const CompilerType
&compiler_type
, CompletionRequest
&request
) {
537 // printf ("\nPrivateAutoComplete()\n\tprefix_path = '%s'\n\tpartial_path =
538 // '%s'\n", prefix_path.c_str(), partial_path.c_str());
539 std::string remaining_partial_path
;
541 const lldb::TypeClass type_class
= compiler_type
.GetTypeClass();
542 if (partial_path
.empty()) {
543 if (compiler_type
.IsValid()) {
544 switch (type_class
) {
546 case eTypeClassArray
:
547 case eTypeClassBlockPointer
:
548 case eTypeClassBuiltin
:
549 case eTypeClassComplexFloat
:
550 case eTypeClassComplexInteger
:
551 case eTypeClassEnumeration
:
552 case eTypeClassFunction
:
553 case eTypeClassMemberPointer
:
554 case eTypeClassReference
:
555 case eTypeClassTypedef
:
556 case eTypeClassVector
: {
557 request
.AddCompletion(prefix_path
.str());
560 case eTypeClassClass
:
561 case eTypeClassStruct
:
562 case eTypeClassUnion
:
563 if (prefix_path
.str().back() != '.')
564 request
.AddCompletion((prefix_path
+ ".").str());
567 case eTypeClassObjCObject
:
568 case eTypeClassObjCInterface
:
570 case eTypeClassObjCObjectPointer
:
571 case eTypeClassPointer
: {
572 bool omit_empty_base_classes
= true;
573 if (llvm::expectedToStdOptional(
574 compiler_type
.GetNumChildren(omit_empty_base_classes
, nullptr))
576 request
.AddCompletion((prefix_path
+ "->").str());
578 request
.AddCompletion(prefix_path
.str());
584 const bool get_file_globals
= true;
586 VariableList
*variable_list
= frame
->GetVariableList(get_file_globals
,
590 for (const VariableSP
&var_sp
: *variable_list
)
591 request
.AddCompletion(var_sp
->GetName().AsCString());
596 const char ch
= partial_path
[0];
599 if (prefix_path
.str().empty()) {
600 PrivateAutoComplete(frame
, partial_path
.substr(1), "*", compiler_type
,
606 if (prefix_path
.isTriviallyEmpty()) {
607 PrivateAutoComplete(frame
, partial_path
.substr(1), std::string("&"),
608 compiler_type
, request
);
613 if (partial_path
.size() > 1 && partial_path
[1] == '>' &&
614 !prefix_path
.str().empty()) {
615 switch (type_class
) {
616 case lldb::eTypeClassPointer
: {
617 CompilerType
pointee_type(compiler_type
.GetPointeeType());
618 if (partial_path
.size() > 2 && partial_path
[2]) {
619 // If there is more after the "->", then search deeper
620 PrivateAutoComplete(frame
, partial_path
.substr(2),
622 pointee_type
.GetCanonicalType(), request
);
624 // Nothing after the "->", so list all members
625 PrivateAutoCompleteMembers(
626 frame
, std::string(), std::string(), prefix_path
+ "->",
627 pointee_type
.GetCanonicalType(), request
);
637 if (compiler_type
.IsValid()) {
638 switch (type_class
) {
639 case lldb::eTypeClassUnion
:
640 case lldb::eTypeClassStruct
:
641 case lldb::eTypeClassClass
:
642 if (partial_path
.size() > 1 && partial_path
[1]) {
643 // If there is more after the ".", then search deeper
644 PrivateAutoComplete(frame
, partial_path
.substr(1),
645 prefix_path
+ ".", compiler_type
, request
);
648 // Nothing after the ".", so list all members
649 PrivateAutoCompleteMembers(frame
, std::string(), partial_path
,
650 prefix_path
+ ".", compiler_type
,
660 if (isalpha(ch
) || ch
== '_' || ch
== '$') {
661 const size_t partial_path_len
= partial_path
.size();
663 while (pos
< partial_path_len
) {
664 const char curr_ch
= partial_path
[pos
];
665 if (isalnum(curr_ch
) || curr_ch
== '_' || curr_ch
== '$') {
672 std::string
token(std::string(partial_path
), 0, pos
);
673 remaining_partial_path
= std::string(partial_path
.substr(pos
));
675 if (compiler_type
.IsValid()) {
676 PrivateAutoCompleteMembers(frame
, token
, remaining_partial_path
,
677 prefix_path
, compiler_type
, request
);
679 // We haven't found our variable yet
680 const bool get_file_globals
= true;
682 VariableList
*variable_list
=
683 frame
->GetVariableList(get_file_globals
, nullptr);
688 for (VariableSP var_sp
: *variable_list
) {
693 llvm::StringRef variable_name
= var_sp
->GetName().GetStringRef();
694 if (variable_name
.starts_with(token
)) {
695 if (variable_name
== token
) {
696 Type
*variable_type
= var_sp
->GetType();
698 CompilerType
variable_compiler_type(
699 variable_type
->GetForwardCompilerType());
701 frame
, remaining_partial_path
,
702 prefix_path
+ token
, // Anything that has been resolved
703 // already will be in here
704 variable_compiler_type
.GetCanonicalType(), request
);
706 request
.AddCompletion((prefix_path
+ variable_name
).str());
708 } else if (remaining_partial_path
.empty()) {
709 request
.AddCompletion((prefix_path
+ variable_name
).str());
720 void Variable::AutoComplete(const ExecutionContext
&exe_ctx
,
721 CompletionRequest
&request
) {
722 CompilerType compiler_type
;
724 PrivateAutoComplete(exe_ctx
.GetFramePtr(), request
.GetCursorArgumentPrefix(),
725 "", compiler_type
, request
);