xref: /openbsd-src/gnu/llvm/lldb/source/Symbol/Variable.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1dda28197Spatrick //===-- Variable.cpp ------------------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "lldb/Symbol/Variable.h"
10061da546Spatrick 
11061da546Spatrick #include "lldb/Core/Module.h"
12061da546Spatrick #include "lldb/Core/ValueObject.h"
13061da546Spatrick #include "lldb/Core/ValueObjectVariable.h"
14061da546Spatrick #include "lldb/Symbol/Block.h"
15061da546Spatrick #include "lldb/Symbol/CompileUnit.h"
16061da546Spatrick #include "lldb/Symbol/CompilerDecl.h"
17061da546Spatrick #include "lldb/Symbol/CompilerDeclContext.h"
18061da546Spatrick #include "lldb/Symbol/Function.h"
19061da546Spatrick #include "lldb/Symbol/SymbolContext.h"
20061da546Spatrick #include "lldb/Symbol/SymbolFile.h"
21061da546Spatrick #include "lldb/Symbol/Type.h"
22061da546Spatrick #include "lldb/Symbol/TypeSystem.h"
23061da546Spatrick #include "lldb/Symbol/VariableList.h"
24061da546Spatrick #include "lldb/Target/ABI.h"
25061da546Spatrick #include "lldb/Target/Process.h"
26061da546Spatrick #include "lldb/Target/RegisterContext.h"
27061da546Spatrick #include "lldb/Target/StackFrame.h"
28061da546Spatrick #include "lldb/Target/Target.h"
29061da546Spatrick #include "lldb/Target/Thread.h"
30061da546Spatrick #include "lldb/Utility/RegularExpression.h"
31061da546Spatrick #include "lldb/Utility/Stream.h"
32061da546Spatrick 
33061da546Spatrick #include "llvm/ADT/Twine.h"
34061da546Spatrick 
35061da546Spatrick using namespace lldb;
36061da546Spatrick using namespace lldb_private;
37061da546Spatrick 
Variable(lldb::user_id_t uid,const char * name,const char * mangled,const lldb::SymbolFileTypeSP & symfile_type_sp,ValueType scope,SymbolContextScope * context,const RangeList & scope_range,Declaration * decl_ptr,const DWARFExpressionList & location_list,bool external,bool artificial,bool location_is_constant_data,bool static_member)38061da546Spatrick Variable::Variable(lldb::user_id_t uid, const char *name, const char *mangled,
39061da546Spatrick                    const lldb::SymbolFileTypeSP &symfile_type_sp,
40061da546Spatrick                    ValueType scope, SymbolContextScope *context,
41061da546Spatrick                    const RangeList &scope_range, Declaration *decl_ptr,
42*f6aab3d8Srobert                    const DWARFExpressionList &location_list, bool external,
43be691f3bSpatrick                    bool artificial, bool location_is_constant_data,
44be691f3bSpatrick                    bool static_member)
45061da546Spatrick     : UserID(uid), m_name(name), m_mangled(ConstString(mangled)),
46061da546Spatrick       m_symfile_type_sp(symfile_type_sp), m_scope(scope),
47061da546Spatrick       m_owner_scope(context), m_scope_range(scope_range),
48*f6aab3d8Srobert       m_declaration(decl_ptr), m_location_list(location_list), m_external(external),
49be691f3bSpatrick       m_artificial(artificial), m_loc_is_const_data(location_is_constant_data),
50061da546Spatrick       m_static_member(static_member) {}
51061da546Spatrick 
52be691f3bSpatrick Variable::~Variable() = default;
53061da546Spatrick 
GetLanguage() const54061da546Spatrick lldb::LanguageType Variable::GetLanguage() const {
55061da546Spatrick   lldb::LanguageType lang = m_mangled.GuessLanguage();
56061da546Spatrick   if (lang != lldb::eLanguageTypeUnknown)
57061da546Spatrick     return lang;
58061da546Spatrick 
59061da546Spatrick   if (auto *func = m_owner_scope->CalculateSymbolContextFunction()) {
60061da546Spatrick     if ((lang = func->GetLanguage()) != lldb::eLanguageTypeUnknown)
61061da546Spatrick       return lang;
62061da546Spatrick   } else if (auto *comp_unit =
63061da546Spatrick                  m_owner_scope->CalculateSymbolContextCompileUnit()) {
64061da546Spatrick     if ((lang = comp_unit->GetLanguage()) != lldb::eLanguageTypeUnknown)
65061da546Spatrick       return lang;
66061da546Spatrick   }
67061da546Spatrick 
68061da546Spatrick   return lldb::eLanguageTypeUnknown;
69061da546Spatrick }
70061da546Spatrick 
GetName() const71061da546Spatrick ConstString Variable::GetName() const {
72dda28197Spatrick   ConstString name = m_mangled.GetName();
73061da546Spatrick   if (name)
74061da546Spatrick     return name;
75061da546Spatrick   return m_name;
76061da546Spatrick }
77061da546Spatrick 
GetUnqualifiedName() const78061da546Spatrick ConstString Variable::GetUnqualifiedName() const { return m_name; }
79061da546Spatrick 
NameMatches(ConstString name) const80061da546Spatrick bool Variable::NameMatches(ConstString name) const {
81061da546Spatrick   if (m_name == name)
82061da546Spatrick     return true;
83061da546Spatrick   SymbolContext variable_sc;
84061da546Spatrick   m_owner_scope->CalculateSymbolContext(&variable_sc);
85061da546Spatrick 
86dda28197Spatrick   return m_mangled.NameMatches(name);
87061da546Spatrick }
NameMatches(const RegularExpression & regex) const88061da546Spatrick bool Variable::NameMatches(const RegularExpression &regex) const {
89061da546Spatrick   if (regex.Execute(m_name.AsCString()))
90061da546Spatrick     return true;
91061da546Spatrick   if (m_mangled)
92dda28197Spatrick     return m_mangled.NameMatches(regex);
93061da546Spatrick   return false;
94061da546Spatrick }
95061da546Spatrick 
GetType()96061da546Spatrick Type *Variable::GetType() {
97061da546Spatrick   if (m_symfile_type_sp)
98061da546Spatrick     return m_symfile_type_sp->GetType();
99061da546Spatrick   return nullptr;
100061da546Spatrick }
101061da546Spatrick 
Dump(Stream * s,bool show_context) const102061da546Spatrick void Variable::Dump(Stream *s, bool show_context) const {
103061da546Spatrick   s->Printf("%p: ", static_cast<const void *>(this));
104061da546Spatrick   s->Indent();
105061da546Spatrick   *s << "Variable" << (const UserID &)*this;
106061da546Spatrick 
107061da546Spatrick   if (m_name)
108061da546Spatrick     *s << ", name = \"" << m_name << "\"";
109061da546Spatrick 
110061da546Spatrick   if (m_symfile_type_sp) {
111061da546Spatrick     Type *type = m_symfile_type_sp->GetType();
112061da546Spatrick     if (type) {
113061da546Spatrick       s->Format(", type = {{{0:x-16}} {1} (", type->GetID(), type);
114061da546Spatrick       type->DumpTypeName(s);
115061da546Spatrick       s->PutChar(')');
116061da546Spatrick     }
117061da546Spatrick   }
118061da546Spatrick 
119061da546Spatrick   if (m_scope != eValueTypeInvalid) {
120061da546Spatrick     s->PutCString(", scope = ");
121061da546Spatrick     switch (m_scope) {
122061da546Spatrick     case eValueTypeVariableGlobal:
123061da546Spatrick       s->PutCString(m_external ? "global" : "static");
124061da546Spatrick       break;
125061da546Spatrick     case eValueTypeVariableArgument:
126061da546Spatrick       s->PutCString("parameter");
127061da546Spatrick       break;
128061da546Spatrick     case eValueTypeVariableLocal:
129061da546Spatrick       s->PutCString("local");
130061da546Spatrick       break;
131061da546Spatrick     case eValueTypeVariableThreadLocal:
132061da546Spatrick       s->PutCString("thread local");
133061da546Spatrick       break;
134061da546Spatrick     default:
135061da546Spatrick       s->AsRawOstream() << "??? (" << m_scope << ')';
136061da546Spatrick     }
137061da546Spatrick   }
138061da546Spatrick 
139061da546Spatrick   if (show_context && m_owner_scope != nullptr) {
140061da546Spatrick     s->PutCString(", context = ( ");
141061da546Spatrick     m_owner_scope->DumpSymbolContext(s);
142061da546Spatrick     s->PutCString(" )");
143061da546Spatrick   }
144061da546Spatrick 
145061da546Spatrick   bool show_fullpaths = false;
146061da546Spatrick   m_declaration.Dump(s, show_fullpaths);
147061da546Spatrick 
148*f6aab3d8Srobert   if (m_location_list.IsValid()) {
149061da546Spatrick     s->PutCString(", location = ");
150061da546Spatrick     ABISP abi;
151061da546Spatrick     if (m_owner_scope) {
152061da546Spatrick       ModuleSP module_sp(m_owner_scope->CalculateSymbolContextModule());
153061da546Spatrick       if (module_sp)
154061da546Spatrick         abi = ABI::FindPlugin(ProcessSP(), module_sp->GetArchitecture());
155061da546Spatrick     }
156*f6aab3d8Srobert     m_location_list.GetDescription(s, lldb::eDescriptionLevelBrief, abi.get());
157061da546Spatrick   }
158061da546Spatrick 
159061da546Spatrick   if (m_external)
160061da546Spatrick     s->PutCString(", external");
161061da546Spatrick 
162061da546Spatrick   if (m_artificial)
163061da546Spatrick     s->PutCString(", artificial");
164061da546Spatrick 
165061da546Spatrick   s->EOL();
166061da546Spatrick }
167061da546Spatrick 
DumpDeclaration(Stream * s,bool show_fullpaths,bool show_module)168061da546Spatrick bool Variable::DumpDeclaration(Stream *s, bool show_fullpaths,
169061da546Spatrick                                bool show_module) {
170061da546Spatrick   bool dumped_declaration_info = false;
171061da546Spatrick   if (m_owner_scope) {
172061da546Spatrick     SymbolContext sc;
173061da546Spatrick     m_owner_scope->CalculateSymbolContext(&sc);
174061da546Spatrick     sc.block = nullptr;
175061da546Spatrick     sc.line_entry.Clear();
176061da546Spatrick     bool show_inlined_frames = false;
177061da546Spatrick     const bool show_function_arguments = true;
178061da546Spatrick     const bool show_function_name = true;
179061da546Spatrick 
180061da546Spatrick     dumped_declaration_info = sc.DumpStopContext(
181061da546Spatrick         s, nullptr, Address(), show_fullpaths, show_module, show_inlined_frames,
182061da546Spatrick         show_function_arguments, show_function_name);
183061da546Spatrick 
184061da546Spatrick     if (sc.function)
185061da546Spatrick       s->PutChar(':');
186061da546Spatrick   }
187061da546Spatrick   if (m_declaration.DumpStopContext(s, false))
188061da546Spatrick     dumped_declaration_info = true;
189061da546Spatrick   return dumped_declaration_info;
190061da546Spatrick }
191061da546Spatrick 
MemorySize() const192061da546Spatrick size_t Variable::MemorySize() const { return sizeof(Variable); }
193061da546Spatrick 
GetDeclContext()194061da546Spatrick CompilerDeclContext Variable::GetDeclContext() {
195061da546Spatrick   Type *type = GetType();
196061da546Spatrick   if (type)
197061da546Spatrick     return type->GetSymbolFile()->GetDeclContextContainingUID(GetID());
198061da546Spatrick   return CompilerDeclContext();
199061da546Spatrick }
200061da546Spatrick 
GetDecl()201061da546Spatrick CompilerDecl Variable::GetDecl() {
202061da546Spatrick   Type *type = GetType();
203061da546Spatrick   return type ? type->GetSymbolFile()->GetDeclForUID(GetID()) : CompilerDecl();
204061da546Spatrick }
205061da546Spatrick 
CalculateSymbolContext(SymbolContext * sc)206061da546Spatrick void Variable::CalculateSymbolContext(SymbolContext *sc) {
207061da546Spatrick   if (m_owner_scope) {
208061da546Spatrick     m_owner_scope->CalculateSymbolContext(sc);
209061da546Spatrick     sc->variable = this;
210061da546Spatrick   } else
211061da546Spatrick     sc->Clear(false);
212061da546Spatrick }
213061da546Spatrick 
LocationIsValidForFrame(StackFrame * frame)214061da546Spatrick bool Variable::LocationIsValidForFrame(StackFrame *frame) {
215061da546Spatrick   if (frame) {
216061da546Spatrick     Function *function =
217061da546Spatrick         frame->GetSymbolContext(eSymbolContextFunction).function;
218061da546Spatrick     if (function) {
219061da546Spatrick       TargetSP target_sp(frame->CalculateTarget());
220061da546Spatrick 
221061da546Spatrick       addr_t loclist_base_load_addr =
222061da546Spatrick           function->GetAddressRange().GetBaseAddress().GetLoadAddress(
223061da546Spatrick               target_sp.get());
224061da546Spatrick       if (loclist_base_load_addr == LLDB_INVALID_ADDRESS)
225061da546Spatrick         return false;
226061da546Spatrick       // It is a location list. We just need to tell if the location list
227061da546Spatrick       // contains the current address when converted to a load address
228*f6aab3d8Srobert       return m_location_list.ContainsAddress(
229061da546Spatrick           loclist_base_load_addr,
230061da546Spatrick           frame->GetFrameCodeAddress().GetLoadAddress(target_sp.get()));
231061da546Spatrick     }
232061da546Spatrick   }
233061da546Spatrick   return false;
234061da546Spatrick }
235061da546Spatrick 
LocationIsValidForAddress(const Address & address)236061da546Spatrick bool Variable::LocationIsValidForAddress(const Address &address) {
237061da546Spatrick   // Be sure to resolve the address to section offset prior to calling this
238061da546Spatrick   // function.
239061da546Spatrick   if (address.IsSectionOffset()) {
240*f6aab3d8Srobert     // We need to check if the address is valid for both scope range and value
241*f6aab3d8Srobert     // range.
242*f6aab3d8Srobert     // Empty scope range means block range.
243*f6aab3d8Srobert     bool valid_in_scope_range =
244*f6aab3d8Srobert         GetScopeRange().IsEmpty() || GetScopeRange().FindEntryThatContains(
245*f6aab3d8Srobert                                          address.GetFileAddress()) != nullptr;
246*f6aab3d8Srobert     if (!valid_in_scope_range)
247*f6aab3d8Srobert       return false;
248061da546Spatrick     SymbolContext sc;
249061da546Spatrick     CalculateSymbolContext(&sc);
250061da546Spatrick     if (sc.module_sp == address.GetModule()) {
251061da546Spatrick       // Is the variable is described by a single location?
252*f6aab3d8Srobert       if (m_location_list.IsAlwaysValidSingleExpr()) {
253061da546Spatrick         // Yes it is, the location is valid.
254061da546Spatrick         return true;
255061da546Spatrick       }
256061da546Spatrick 
257061da546Spatrick       if (sc.function) {
258061da546Spatrick         addr_t loclist_base_file_addr =
259061da546Spatrick             sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
260061da546Spatrick         if (loclist_base_file_addr == LLDB_INVALID_ADDRESS)
261061da546Spatrick           return false;
262061da546Spatrick         // It is a location list. We just need to tell if the location list
263061da546Spatrick         // contains the current address when converted to a load address
264*f6aab3d8Srobert         return m_location_list.ContainsAddress(loclist_base_file_addr,
265061da546Spatrick                                                address.GetFileAddress());
266061da546Spatrick       }
267061da546Spatrick     }
268061da546Spatrick   }
269061da546Spatrick   return false;
270061da546Spatrick }
271061da546Spatrick 
IsInScope(StackFrame * frame)272061da546Spatrick bool Variable::IsInScope(StackFrame *frame) {
273061da546Spatrick   switch (m_scope) {
274061da546Spatrick   case eValueTypeRegister:
275061da546Spatrick   case eValueTypeRegisterSet:
276061da546Spatrick     return frame != nullptr;
277061da546Spatrick 
278061da546Spatrick   case eValueTypeConstResult:
279061da546Spatrick   case eValueTypeVariableGlobal:
280061da546Spatrick   case eValueTypeVariableStatic:
281061da546Spatrick   case eValueTypeVariableThreadLocal:
282061da546Spatrick     return true;
283061da546Spatrick 
284061da546Spatrick   case eValueTypeVariableArgument:
285061da546Spatrick   case eValueTypeVariableLocal:
286061da546Spatrick     if (frame) {
287061da546Spatrick       // We don't have a location list, we just need to see if the block that
288061da546Spatrick       // this variable was defined in is currently
289061da546Spatrick       Block *deepest_frame_block =
290061da546Spatrick           frame->GetSymbolContext(eSymbolContextBlock).block;
291061da546Spatrick       if (deepest_frame_block) {
292061da546Spatrick         SymbolContext variable_sc;
293061da546Spatrick         CalculateSymbolContext(&variable_sc);
294061da546Spatrick 
295061da546Spatrick         // Check for static or global variable defined at the compile unit
296061da546Spatrick         // level that wasn't defined in a block
297061da546Spatrick         if (variable_sc.block == nullptr)
298061da546Spatrick           return true;
299061da546Spatrick 
300061da546Spatrick         // Check if the variable is valid in the current block
301061da546Spatrick         if (variable_sc.block != deepest_frame_block &&
302061da546Spatrick             !variable_sc.block->Contains(deepest_frame_block))
303061da546Spatrick           return false;
304061da546Spatrick 
305061da546Spatrick         // If no scope range is specified then it means that the scope is the
306061da546Spatrick         // same as the scope of the enclosing lexical block.
307061da546Spatrick         if (m_scope_range.IsEmpty())
308061da546Spatrick           return true;
309061da546Spatrick 
310061da546Spatrick         addr_t file_address = frame->GetFrameCodeAddress().GetFileAddress();
311061da546Spatrick         return m_scope_range.FindEntryThatContains(file_address) != nullptr;
312061da546Spatrick       }
313061da546Spatrick     }
314061da546Spatrick     break;
315061da546Spatrick 
316061da546Spatrick   default:
317061da546Spatrick     break;
318061da546Spatrick   }
319061da546Spatrick   return false;
320061da546Spatrick }
321061da546Spatrick 
GetValuesForVariableExpressionPath(llvm::StringRef variable_expr_path,ExecutionContextScope * scope,GetVariableCallback callback,void * baton,VariableList & variable_list,ValueObjectList & valobj_list)322061da546Spatrick Status Variable::GetValuesForVariableExpressionPath(
323061da546Spatrick     llvm::StringRef variable_expr_path, ExecutionContextScope *scope,
324061da546Spatrick     GetVariableCallback callback, void *baton, VariableList &variable_list,
325061da546Spatrick     ValueObjectList &valobj_list) {
326061da546Spatrick   Status error;
327061da546Spatrick   if (!callback || variable_expr_path.empty()) {
328061da546Spatrick     error.SetErrorString("unknown error");
329061da546Spatrick     return error;
330061da546Spatrick   }
331061da546Spatrick 
332061da546Spatrick   switch (variable_expr_path.front()) {
333061da546Spatrick   case '*':
334061da546Spatrick     error = Variable::GetValuesForVariableExpressionPath(
335061da546Spatrick         variable_expr_path.drop_front(), scope, callback, baton, variable_list,
336061da546Spatrick         valobj_list);
337061da546Spatrick     if (error.Fail()) {
338061da546Spatrick       error.SetErrorString("unknown error");
339061da546Spatrick       return error;
340061da546Spatrick     }
341061da546Spatrick     for (uint32_t i = 0; i < valobj_list.GetSize();) {
342061da546Spatrick       Status tmp_error;
343061da546Spatrick       ValueObjectSP valobj_sp(
344061da546Spatrick           valobj_list.GetValueObjectAtIndex(i)->Dereference(tmp_error));
345061da546Spatrick       if (tmp_error.Fail()) {
346061da546Spatrick         variable_list.RemoveVariableAtIndex(i);
347061da546Spatrick         valobj_list.RemoveValueObjectAtIndex(i);
348061da546Spatrick       } else {
349061da546Spatrick         valobj_list.SetValueObjectAtIndex(i, valobj_sp);
350061da546Spatrick         ++i;
351061da546Spatrick       }
352061da546Spatrick     }
353061da546Spatrick     return error;
354061da546Spatrick   case '&': {
355061da546Spatrick     error = Variable::GetValuesForVariableExpressionPath(
356061da546Spatrick         variable_expr_path.drop_front(), scope, callback, baton, variable_list,
357061da546Spatrick         valobj_list);
358061da546Spatrick     if (error.Success()) {
359061da546Spatrick       for (uint32_t i = 0; i < valobj_list.GetSize();) {
360061da546Spatrick         Status tmp_error;
361061da546Spatrick         ValueObjectSP valobj_sp(
362061da546Spatrick             valobj_list.GetValueObjectAtIndex(i)->AddressOf(tmp_error));
363061da546Spatrick         if (tmp_error.Fail()) {
364061da546Spatrick           variable_list.RemoveVariableAtIndex(i);
365061da546Spatrick           valobj_list.RemoveValueObjectAtIndex(i);
366061da546Spatrick         } else {
367061da546Spatrick           valobj_list.SetValueObjectAtIndex(i, valobj_sp);
368061da546Spatrick           ++i;
369061da546Spatrick         }
370061da546Spatrick       }
371061da546Spatrick     } else {
372061da546Spatrick       error.SetErrorString("unknown error");
373061da546Spatrick     }
374061da546Spatrick     return error;
375061da546Spatrick   } break;
376061da546Spatrick 
377061da546Spatrick   default: {
378061da546Spatrick     static RegularExpression g_regex(
379061da546Spatrick         llvm::StringRef("^([A-Za-z_:][A-Za-z_0-9:]*)(.*)"));
380061da546Spatrick     llvm::SmallVector<llvm::StringRef, 2> matches;
381061da546Spatrick     variable_list.Clear();
382061da546Spatrick     if (!g_regex.Execute(variable_expr_path, &matches)) {
383061da546Spatrick       error.SetErrorStringWithFormat(
384061da546Spatrick           "unable to extract a variable name from '%s'",
385061da546Spatrick           variable_expr_path.str().c_str());
386061da546Spatrick       return error;
387061da546Spatrick     }
388061da546Spatrick     std::string variable_name = matches[1].str();
389061da546Spatrick     if (!callback(baton, variable_name.c_str(), variable_list)) {
390061da546Spatrick       error.SetErrorString("unknown error");
391061da546Spatrick       return error;
392061da546Spatrick     }
393061da546Spatrick     uint32_t i = 0;
394061da546Spatrick     while (i < variable_list.GetSize()) {
395061da546Spatrick       VariableSP var_sp(variable_list.GetVariableAtIndex(i));
396061da546Spatrick       ValueObjectSP valobj_sp;
397061da546Spatrick       if (!var_sp) {
398061da546Spatrick         variable_list.RemoveVariableAtIndex(i);
399061da546Spatrick         continue;
400061da546Spatrick       }
401061da546Spatrick       ValueObjectSP variable_valobj_sp(
402061da546Spatrick           ValueObjectVariable::Create(scope, var_sp));
403061da546Spatrick       if (!variable_valobj_sp) {
404061da546Spatrick         variable_list.RemoveVariableAtIndex(i);
405061da546Spatrick         continue;
406061da546Spatrick       }
407061da546Spatrick 
408061da546Spatrick       llvm::StringRef variable_sub_expr_path =
409061da546Spatrick           variable_expr_path.drop_front(variable_name.size());
410061da546Spatrick       if (!variable_sub_expr_path.empty()) {
411061da546Spatrick         valobj_sp = variable_valobj_sp->GetValueForExpressionPath(
412061da546Spatrick             variable_sub_expr_path);
413061da546Spatrick         if (!valobj_sp) {
414061da546Spatrick           error.SetErrorStringWithFormat(
415061da546Spatrick               "invalid expression path '%s' for variable '%s'",
416061da546Spatrick               variable_sub_expr_path.str().c_str(),
417061da546Spatrick               var_sp->GetName().GetCString());
418061da546Spatrick           variable_list.RemoveVariableAtIndex(i);
419061da546Spatrick           continue;
420061da546Spatrick         }
421061da546Spatrick       } else {
422061da546Spatrick         // Just the name of a variable with no extras
423061da546Spatrick         valobj_sp = variable_valobj_sp;
424061da546Spatrick       }
425061da546Spatrick 
426061da546Spatrick       valobj_list.Append(valobj_sp);
427061da546Spatrick       ++i;
428061da546Spatrick     }
429061da546Spatrick 
430061da546Spatrick     if (variable_list.GetSize() > 0) {
431061da546Spatrick       error.Clear();
432061da546Spatrick       return error;
433061da546Spatrick     }
434061da546Spatrick   } break;
435061da546Spatrick   }
436061da546Spatrick   error.SetErrorString("unknown error");
437061da546Spatrick   return error;
438061da546Spatrick }
439061da546Spatrick 
DumpLocations(Stream * s,const Address & address)440*f6aab3d8Srobert bool Variable::DumpLocations(Stream *s, const Address &address) {
441061da546Spatrick   SymbolContext sc;
442061da546Spatrick   CalculateSymbolContext(&sc);
443061da546Spatrick   ABISP abi;
444061da546Spatrick   if (m_owner_scope) {
445061da546Spatrick     ModuleSP module_sp(m_owner_scope->CalculateSymbolContextModule());
446061da546Spatrick     if (module_sp)
447061da546Spatrick       abi = ABI::FindPlugin(ProcessSP(), module_sp->GetArchitecture());
448061da546Spatrick   }
449061da546Spatrick 
450061da546Spatrick   const addr_t file_addr = address.GetFileAddress();
451061da546Spatrick   if (sc.function) {
452061da546Spatrick     addr_t loclist_base_file_addr =
453061da546Spatrick         sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
454061da546Spatrick     if (loclist_base_file_addr == LLDB_INVALID_ADDRESS)
455061da546Spatrick       return false;
456*f6aab3d8Srobert     return m_location_list.DumpLocations(s, eDescriptionLevelBrief,
457*f6aab3d8Srobert                                          loclist_base_file_addr, file_addr,
458061da546Spatrick                                          abi.get());
459061da546Spatrick   }
460061da546Spatrick   return false;
461061da546Spatrick }
462061da546Spatrick 
463061da546Spatrick static void PrivateAutoComplete(
464061da546Spatrick     StackFrame *frame, llvm::StringRef partial_path,
465061da546Spatrick     const llvm::Twine
466061da546Spatrick         &prefix_path, // Anything that has been resolved already will be in here
467061da546Spatrick     const CompilerType &compiler_type, CompletionRequest &request);
468061da546Spatrick 
PrivateAutoCompleteMembers(StackFrame * frame,const std::string & partial_member_name,llvm::StringRef partial_path,const llvm::Twine & prefix_path,const CompilerType & compiler_type,CompletionRequest & request)469061da546Spatrick static void PrivateAutoCompleteMembers(
470061da546Spatrick     StackFrame *frame, const std::string &partial_member_name,
471061da546Spatrick     llvm::StringRef partial_path,
472061da546Spatrick     const llvm::Twine
473061da546Spatrick         &prefix_path, // Anything that has been resolved already will be in here
474061da546Spatrick     const CompilerType &compiler_type, CompletionRequest &request) {
475061da546Spatrick 
476061da546Spatrick   // We are in a type parsing child members
477061da546Spatrick   const uint32_t num_bases = compiler_type.GetNumDirectBaseClasses();
478061da546Spatrick 
479061da546Spatrick   if (num_bases > 0) {
480061da546Spatrick     for (uint32_t i = 0; i < num_bases; ++i) {
481061da546Spatrick       CompilerType base_class_type =
482061da546Spatrick           compiler_type.GetDirectBaseClassAtIndex(i, nullptr);
483061da546Spatrick 
484061da546Spatrick       PrivateAutoCompleteMembers(frame, partial_member_name, partial_path,
485061da546Spatrick                                  prefix_path,
486061da546Spatrick                                  base_class_type.GetCanonicalType(), request);
487061da546Spatrick     }
488061da546Spatrick   }
489061da546Spatrick 
490061da546Spatrick   const uint32_t num_vbases = compiler_type.GetNumVirtualBaseClasses();
491061da546Spatrick 
492061da546Spatrick   if (num_vbases > 0) {
493061da546Spatrick     for (uint32_t i = 0; i < num_vbases; ++i) {
494061da546Spatrick       CompilerType vbase_class_type =
495061da546Spatrick           compiler_type.GetVirtualBaseClassAtIndex(i, nullptr);
496061da546Spatrick 
497061da546Spatrick       PrivateAutoCompleteMembers(frame, partial_member_name, partial_path,
498061da546Spatrick                                  prefix_path,
499061da546Spatrick                                  vbase_class_type.GetCanonicalType(), request);
500061da546Spatrick     }
501061da546Spatrick   }
502061da546Spatrick 
503061da546Spatrick   // We are in a type parsing child members
504061da546Spatrick   const uint32_t num_fields = compiler_type.GetNumFields();
505061da546Spatrick 
506061da546Spatrick   if (num_fields > 0) {
507061da546Spatrick     for (uint32_t i = 0; i < num_fields; ++i) {
508061da546Spatrick       std::string member_name;
509061da546Spatrick 
510061da546Spatrick       CompilerType member_compiler_type = compiler_type.GetFieldAtIndex(
511061da546Spatrick           i, member_name, nullptr, nullptr, nullptr);
512061da546Spatrick 
513061da546Spatrick       if (partial_member_name.empty() ||
514dda28197Spatrick           llvm::StringRef(member_name).startswith(partial_member_name)) {
515061da546Spatrick         if (member_name == partial_member_name) {
516061da546Spatrick           PrivateAutoComplete(
517061da546Spatrick               frame, partial_path,
518061da546Spatrick               prefix_path + member_name, // Anything that has been resolved
519061da546Spatrick                                          // already will be in here
520061da546Spatrick               member_compiler_type.GetCanonicalType(), request);
521061da546Spatrick         } else {
522061da546Spatrick           request.AddCompletion((prefix_path + member_name).str());
523061da546Spatrick         }
524061da546Spatrick       }
525061da546Spatrick     }
526061da546Spatrick   }
527061da546Spatrick }
528061da546Spatrick 
PrivateAutoComplete(StackFrame * frame,llvm::StringRef partial_path,const llvm::Twine & prefix_path,const CompilerType & compiler_type,CompletionRequest & request)529061da546Spatrick static void PrivateAutoComplete(
530061da546Spatrick     StackFrame *frame, llvm::StringRef partial_path,
531061da546Spatrick     const llvm::Twine
532061da546Spatrick         &prefix_path, // Anything that has been resolved already will be in here
533061da546Spatrick     const CompilerType &compiler_type, CompletionRequest &request) {
534061da546Spatrick   //    printf ("\nPrivateAutoComplete()\n\tprefix_path = '%s'\n\tpartial_path =
535061da546Spatrick   //    '%s'\n", prefix_path.c_str(), partial_path.c_str());
536061da546Spatrick   std::string remaining_partial_path;
537061da546Spatrick 
538061da546Spatrick   const lldb::TypeClass type_class = compiler_type.GetTypeClass();
539061da546Spatrick   if (partial_path.empty()) {
540061da546Spatrick     if (compiler_type.IsValid()) {
541061da546Spatrick       switch (type_class) {
542061da546Spatrick       default:
543061da546Spatrick       case eTypeClassArray:
544061da546Spatrick       case eTypeClassBlockPointer:
545061da546Spatrick       case eTypeClassBuiltin:
546061da546Spatrick       case eTypeClassComplexFloat:
547061da546Spatrick       case eTypeClassComplexInteger:
548061da546Spatrick       case eTypeClassEnumeration:
549061da546Spatrick       case eTypeClassFunction:
550061da546Spatrick       case eTypeClassMemberPointer:
551061da546Spatrick       case eTypeClassReference:
552061da546Spatrick       case eTypeClassTypedef:
553061da546Spatrick       case eTypeClassVector: {
554061da546Spatrick         request.AddCompletion(prefix_path.str());
555061da546Spatrick       } break;
556061da546Spatrick 
557061da546Spatrick       case eTypeClassClass:
558061da546Spatrick       case eTypeClassStruct:
559061da546Spatrick       case eTypeClassUnion:
560061da546Spatrick         if (prefix_path.str().back() != '.')
561061da546Spatrick           request.AddCompletion((prefix_path + ".").str());
562061da546Spatrick         break;
563061da546Spatrick 
564061da546Spatrick       case eTypeClassObjCObject:
565061da546Spatrick       case eTypeClassObjCInterface:
566061da546Spatrick         break;
567061da546Spatrick       case eTypeClassObjCObjectPointer:
568061da546Spatrick       case eTypeClassPointer: {
569061da546Spatrick         bool omit_empty_base_classes = true;
570061da546Spatrick         if (compiler_type.GetNumChildren(omit_empty_base_classes, nullptr) > 0)
571061da546Spatrick           request.AddCompletion((prefix_path + "->").str());
572061da546Spatrick         else {
573061da546Spatrick           request.AddCompletion(prefix_path.str());
574061da546Spatrick         }
575061da546Spatrick       } break;
576061da546Spatrick       }
577061da546Spatrick     } else {
578061da546Spatrick       if (frame) {
579061da546Spatrick         const bool get_file_globals = true;
580061da546Spatrick 
581*f6aab3d8Srobert         VariableList *variable_list = frame->GetVariableList(get_file_globals,
582*f6aab3d8Srobert                                                              nullptr);
583061da546Spatrick 
584061da546Spatrick         if (variable_list) {
585061da546Spatrick           for (const VariableSP &var_sp : *variable_list)
586061da546Spatrick             request.AddCompletion(var_sp->GetName().AsCString());
587061da546Spatrick         }
588061da546Spatrick       }
589061da546Spatrick     }
590061da546Spatrick   } else {
591061da546Spatrick     const char ch = partial_path[0];
592061da546Spatrick     switch (ch) {
593061da546Spatrick     case '*':
594061da546Spatrick       if (prefix_path.str().empty()) {
595061da546Spatrick         PrivateAutoComplete(frame, partial_path.substr(1), "*", compiler_type,
596061da546Spatrick                             request);
597061da546Spatrick       }
598061da546Spatrick       break;
599061da546Spatrick 
600061da546Spatrick     case '&':
601061da546Spatrick       if (prefix_path.isTriviallyEmpty()) {
602061da546Spatrick         PrivateAutoComplete(frame, partial_path.substr(1), std::string("&"),
603061da546Spatrick                             compiler_type, request);
604061da546Spatrick       }
605061da546Spatrick       break;
606061da546Spatrick 
607061da546Spatrick     case '-':
608061da546Spatrick       if (partial_path.size() > 1 && partial_path[1] == '>' &&
609061da546Spatrick           !prefix_path.str().empty()) {
610061da546Spatrick         switch (type_class) {
611061da546Spatrick         case lldb::eTypeClassPointer: {
612061da546Spatrick           CompilerType pointee_type(compiler_type.GetPointeeType());
613061da546Spatrick           if (partial_path.size() > 2 && partial_path[2]) {
614061da546Spatrick             // If there is more after the "->", then search deeper
615061da546Spatrick             PrivateAutoComplete(frame, partial_path.substr(2),
616061da546Spatrick                                 prefix_path + "->",
617061da546Spatrick                                 pointee_type.GetCanonicalType(), request);
618061da546Spatrick           } else {
619061da546Spatrick             // Nothing after the "->", so list all members
620061da546Spatrick             PrivateAutoCompleteMembers(
621061da546Spatrick                 frame, std::string(), std::string(), prefix_path + "->",
622061da546Spatrick                 pointee_type.GetCanonicalType(), request);
623061da546Spatrick           }
624061da546Spatrick         } break;
625061da546Spatrick         default:
626061da546Spatrick           break;
627061da546Spatrick         }
628061da546Spatrick       }
629061da546Spatrick       break;
630061da546Spatrick 
631061da546Spatrick     case '.':
632061da546Spatrick       if (compiler_type.IsValid()) {
633061da546Spatrick         switch (type_class) {
634061da546Spatrick         case lldb::eTypeClassUnion:
635061da546Spatrick         case lldb::eTypeClassStruct:
636061da546Spatrick         case lldb::eTypeClassClass:
637061da546Spatrick           if (partial_path.size() > 1 && partial_path[1]) {
638061da546Spatrick             // If there is more after the ".", then search deeper
639061da546Spatrick             PrivateAutoComplete(frame, partial_path.substr(1),
640061da546Spatrick                                 prefix_path + ".", compiler_type, request);
641061da546Spatrick 
642061da546Spatrick           } else {
643061da546Spatrick             // Nothing after the ".", so list all members
644061da546Spatrick             PrivateAutoCompleteMembers(frame, std::string(), partial_path,
645061da546Spatrick                                        prefix_path + ".", compiler_type,
646061da546Spatrick                                        request);
647061da546Spatrick           }
648061da546Spatrick           break;
649061da546Spatrick         default:
650061da546Spatrick           break;
651061da546Spatrick         }
652061da546Spatrick       }
653061da546Spatrick       break;
654061da546Spatrick     default:
655061da546Spatrick       if (isalpha(ch) || ch == '_' || ch == '$') {
656061da546Spatrick         const size_t partial_path_len = partial_path.size();
657061da546Spatrick         size_t pos = 1;
658061da546Spatrick         while (pos < partial_path_len) {
659061da546Spatrick           const char curr_ch = partial_path[pos];
660061da546Spatrick           if (isalnum(curr_ch) || curr_ch == '_' || curr_ch == '$') {
661061da546Spatrick             ++pos;
662061da546Spatrick             continue;
663061da546Spatrick           }
664061da546Spatrick           break;
665061da546Spatrick         }
666061da546Spatrick 
667dda28197Spatrick         std::string token(std::string(partial_path), 0, pos);
668dda28197Spatrick         remaining_partial_path = std::string(partial_path.substr(pos));
669061da546Spatrick 
670061da546Spatrick         if (compiler_type.IsValid()) {
671061da546Spatrick           PrivateAutoCompleteMembers(frame, token, remaining_partial_path,
672061da546Spatrick                                      prefix_path, compiler_type, request);
673061da546Spatrick         } else if (frame) {
674061da546Spatrick           // We haven't found our variable yet
675061da546Spatrick           const bool get_file_globals = true;
676061da546Spatrick 
677061da546Spatrick           VariableList *variable_list =
678*f6aab3d8Srobert               frame->GetVariableList(get_file_globals, nullptr);
679061da546Spatrick 
680061da546Spatrick           if (!variable_list)
681061da546Spatrick             break;
682061da546Spatrick 
683061da546Spatrick           for (VariableSP var_sp : *variable_list) {
684061da546Spatrick 
685061da546Spatrick             if (!var_sp)
686061da546Spatrick               continue;
687061da546Spatrick 
688061da546Spatrick             llvm::StringRef variable_name = var_sp->GetName().GetStringRef();
689061da546Spatrick             if (variable_name.startswith(token)) {
690061da546Spatrick               if (variable_name == token) {
691061da546Spatrick                 Type *variable_type = var_sp->GetType();
692061da546Spatrick                 if (variable_type) {
693061da546Spatrick                   CompilerType variable_compiler_type(
694061da546Spatrick                       variable_type->GetForwardCompilerType());
695061da546Spatrick                   PrivateAutoComplete(
696061da546Spatrick                       frame, remaining_partial_path,
697061da546Spatrick                       prefix_path + token, // Anything that has been resolved
698061da546Spatrick                                            // already will be in here
699061da546Spatrick                       variable_compiler_type.GetCanonicalType(), request);
700061da546Spatrick                 } else {
701061da546Spatrick                   request.AddCompletion((prefix_path + variable_name).str());
702061da546Spatrick                 }
703061da546Spatrick               } else if (remaining_partial_path.empty()) {
704061da546Spatrick                 request.AddCompletion((prefix_path + variable_name).str());
705061da546Spatrick               }
706061da546Spatrick             }
707061da546Spatrick           }
708061da546Spatrick         }
709061da546Spatrick       }
710061da546Spatrick       break;
711061da546Spatrick     }
712061da546Spatrick   }
713061da546Spatrick }
714061da546Spatrick 
AutoComplete(const ExecutionContext & exe_ctx,CompletionRequest & request)715061da546Spatrick void Variable::AutoComplete(const ExecutionContext &exe_ctx,
716061da546Spatrick                             CompletionRequest &request) {
717061da546Spatrick   CompilerType compiler_type;
718061da546Spatrick 
719061da546Spatrick   PrivateAutoComplete(exe_ctx.GetFramePtr(), request.GetCursorArgumentPrefix(),
720061da546Spatrick                       "", compiler_type, request);
721061da546Spatrick }
722