1 //===-- Variable.cpp --------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "lldb/Symbol/Variable.h"
11 
12 #include "lldb/Core/Stream.h"
13 #include "lldb/Core/RegularExpression.h"
14 #include "lldb/Core/ValueObject.h"
15 #include "lldb/Core/ValueObjectVariable.h"
16 #include "lldb/Symbol/Block.h"
17 #include "lldb/Symbol/Function.h"
18 #include "lldb/Symbol/SymbolContext.h"
19 #include "lldb/Symbol/Type.h"
20 #include "lldb/Symbol/VariableList.h"
21 #include "lldb/Target/ABI.h"
22 #include "lldb/Target/Process.h"
23 #include "lldb/Target/RegisterContext.h"
24 #include "lldb/Target/StackFrame.h"
25 #include "lldb/Target/Thread.h"
26 #include "lldb/Target/Target.h"
27 
28 using namespace lldb;
29 using namespace lldb_private;
30 
31 //----------------------------------------------------------------------
32 // Variable constructor
33 //----------------------------------------------------------------------
34 Variable::Variable
35 (
36     lldb::user_id_t uid,
37     const char *name,
38     const char *mangled,   // The mangled variable name for variables in namespaces
39     const lldb::SymbolFileTypeSP &symfile_type_sp,
40     ValueType scope,
41     SymbolContextScope *context,
42     Declaration* decl_ptr,
43     const DWARFExpression& location,
44     bool external,
45     bool artificial
46 ) :
47     UserID(uid),
48     m_name(name),
49     m_mangled (ConstString(mangled), true),
50     m_symfile_type_sp(symfile_type_sp),
51     m_scope(scope),
52     m_owner_scope(context),
53     m_declaration(decl_ptr),
54     m_location(location),
55     m_external(external),
56     m_artificial(artificial)
57 {
58 }
59 
60 //----------------------------------------------------------------------
61 // Destructor
62 //----------------------------------------------------------------------
63 Variable::~Variable()
64 {
65 }
66 
67 
68 const ConstString&
69 Variable::GetName() const
70 {
71     if (m_mangled)
72         return m_mangled.GetName();
73     return m_name;
74 }
75 
76 bool
77 Variable::NameMatches (const RegularExpression& regex) const
78 {
79     if (regex.Execute (m_name.AsCString()))
80         return true;
81     return m_mangled.NameMatches (regex);
82 }
83 
84 Type *
85 Variable::GetType()
86 {
87     if (m_symfile_type_sp)
88         return m_symfile_type_sp->GetType();
89     return NULL;
90 }
91 
92 void
93 Variable::Dump(Stream *s, bool show_context) const
94 {
95     s->Printf("%p: ", this);
96     s->Indent();
97     *s << "Variable" << (const UserID&)*this;
98 
99     if (m_name)
100         *s << ", name = \"" << m_name << "\"";
101 
102     if (m_symfile_type_sp)
103     {
104         Type *type = m_symfile_type_sp->GetType();
105         if (type)
106         {
107             *s << ", type = {" << type->GetID() << "} " << (void*)type << " (";
108             type->DumpTypeName(s);
109             s->PutChar(')');
110         }
111     }
112 
113     if (m_scope != eValueTypeInvalid)
114     {
115         s->PutCString(", scope = ");
116         switch (m_scope)
117         {
118         case eValueTypeVariableGlobal:       s->PutCString(m_external ? "global" : "static"); break;
119         case eValueTypeVariableArgument:    s->PutCString("parameter"); break;
120         case eValueTypeVariableLocal:        s->PutCString("local"); break;
121         default:            *s << "??? (" << m_scope << ')';
122         }
123     }
124 
125     if (show_context && m_owner_scope != NULL)
126     {
127         s->PutCString(", context = ( ");
128         m_owner_scope->DumpSymbolContext(s);
129         s->PutCString(" )");
130     }
131 
132     bool show_fullpaths = false;
133     m_declaration.Dump(s, show_fullpaths);
134 
135     if (m_location.IsValid())
136     {
137         s->PutCString(", location = ");
138         lldb::addr_t loclist_base_addr = LLDB_INVALID_ADDRESS;
139         if (m_location.IsLocationList())
140         {
141             SymbolContext variable_sc;
142             m_owner_scope->CalculateSymbolContext(&variable_sc);
143             if (variable_sc.function)
144                 loclist_base_addr = variable_sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
145         }
146         ABI *abi = NULL;
147         if (m_owner_scope)
148         {
149             ModuleSP module_sp (m_owner_scope->CalculateSymbolContextModule());
150             if (module_sp)
151                 abi = ABI::FindPlugin (module_sp->GetArchitecture()).get();
152         }
153         m_location.GetDescription(s, lldb::eDescriptionLevelBrief, loclist_base_addr, abi);
154     }
155 
156     if (m_external)
157         s->PutCString(", external");
158 
159     if (m_artificial)
160         s->PutCString(", artificial");
161 
162     s->EOL();
163 }
164 
165 bool
166 Variable::DumpDeclaration (Stream *s, bool show_fullpaths, bool show_module)
167 {
168     bool dumped_declaration_info = false;
169     if (m_owner_scope)
170     {
171         SymbolContext sc;
172         m_owner_scope->CalculateSymbolContext(&sc);
173         sc.block = NULL;
174         sc.line_entry.Clear();
175         bool show_inlined_frames = false;
176 
177         dumped_declaration_info = sc.DumpStopContext (s,
178                                                       NULL,
179                                                       Address(),
180                                                       show_fullpaths,
181                                                       show_module,
182                                                       show_inlined_frames);
183 
184         if (sc.function)
185             s->PutChar(':');
186     }
187     if (m_declaration.DumpStopContext (s, false))
188         dumped_declaration_info = true;
189     return dumped_declaration_info;
190 }
191 
192 size_t
193 Variable::MemorySize() const
194 {
195     return sizeof(Variable);
196 }
197 
198 
199 void
200 Variable::CalculateSymbolContext (SymbolContext *sc)
201 {
202     if (m_owner_scope)
203         m_owner_scope->CalculateSymbolContext(sc);
204     else
205         sc->Clear();
206 }
207 
208 bool
209 Variable::LocationIsValidForFrame (StackFrame *frame)
210 {
211     // Is the variable is described by a single location?
212     if (!m_location.IsLocationList())
213     {
214         // Yes it is, the location is valid.
215         return true;
216     }
217 
218     if (frame)
219     {
220         Function *function = frame->GetSymbolContext(eSymbolContextFunction).function;
221         if (function)
222         {
223             TargetSP target_sp (frame->CalculateTarget());
224 
225             addr_t loclist_base_load_addr = function->GetAddressRange().GetBaseAddress().GetLoadAddress (target_sp.get());
226             if (loclist_base_load_addr == LLDB_INVALID_ADDRESS)
227                 return false;
228             // It is a location list. We just need to tell if the location
229             // list contains the current address when converted to a load
230             // address
231             return m_location.LocationListContainsAddress (loclist_base_load_addr,
232                                                            frame->GetFrameCodeAddress().GetLoadAddress (target_sp.get()));
233         }
234     }
235     return false;
236 }
237 
238 bool
239 Variable::LocationIsValidForAddress (const Address &address)
240 {
241     // Be sure to resolve the address to section offset prior to
242     // calling this function.
243     if (address.IsSectionOffset())
244     {
245         SymbolContext sc;
246         CalculateSymbolContext(&sc);
247         if (sc.module_sp == address.GetModule())
248         {
249             // Is the variable is described by a single location?
250             if (!m_location.IsLocationList())
251             {
252                 // Yes it is, the location is valid.
253                 return true;
254             }
255 
256             if (sc.function)
257             {
258                 addr_t loclist_base_file_addr = sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
259                 if (loclist_base_file_addr == LLDB_INVALID_ADDRESS)
260                     return false;
261                 // It is a location list. We just need to tell if the location
262                 // list contains the current address when converted to a load
263                 // address
264                 return m_location.LocationListContainsAddress (loclist_base_file_addr,
265                                                                address.GetFileAddress());
266             }
267         }
268     }
269     return false;
270 }
271 
272 bool
273 Variable::IsInScope (StackFrame *frame)
274 {
275     switch (m_scope)
276     {
277     case eValueTypeRegister:
278     case eValueTypeRegisterSet:
279         return frame != NULL;
280 
281     case eValueTypeConstResult:
282     case eValueTypeVariableGlobal:
283     case eValueTypeVariableStatic:
284         return true;
285 
286     case eValueTypeVariableArgument:
287     case eValueTypeVariableLocal:
288         if (frame)
289         {
290             // We don't have a location list, we just need to see if the block
291             // that this variable was defined in is currently
292             Block *deepest_frame_block = frame->GetSymbolContext(eSymbolContextBlock).block;
293             if (deepest_frame_block)
294             {
295                 SymbolContext variable_sc;
296                 CalculateSymbolContext (&variable_sc);
297                 // Check for static or global variable defined at the compile unit
298                 // level that wasn't defined in a block
299                 if (variable_sc.block == NULL)
300                     return true;
301 
302                 if (variable_sc.block == deepest_frame_block)
303                     return true;
304                 return variable_sc.block->Contains (deepest_frame_block);
305             }
306         }
307         break;
308 
309     default:
310         break;
311     }
312     return false;
313 }
314 
315 Error
316 Variable::GetValuesForVariableExpressionPath (const char *variable_expr_path,
317                                               ExecutionContextScope *scope,
318                                               GetVariableCallback callback,
319                                               void *baton,
320                                               VariableList &variable_list,
321                                               ValueObjectList &valobj_list)
322 {
323     Error error;
324     if (variable_expr_path && callback)
325     {
326         switch (variable_expr_path[0])
327         {
328         case '*':
329             {
330                 error = Variable::GetValuesForVariableExpressionPath (variable_expr_path + 1,
331                                                                       scope,
332                                                                       callback,
333                                                                       baton,
334                                                                       variable_list,
335                                                                       valobj_list);
336                 if (error.Success())
337                 {
338                     for (uint32_t i=0; i<valobj_list.GetSize(); )
339                     {
340                         Error tmp_error;
341                         ValueObjectSP valobj_sp (valobj_list.GetValueObjectAtIndex(i)->Dereference(tmp_error));
342                         if (tmp_error.Fail())
343                         {
344                             variable_list.RemoveVariableAtIndex (i);
345                             valobj_list.RemoveValueObjectAtIndex (i);
346                         }
347                         else
348                         {
349                             valobj_list.SetValueObjectAtIndex (i, valobj_sp);
350                             ++i;
351                         }
352                     }
353                 }
354                 else
355                 {
356                     error.SetErrorString ("unknown error");
357                 }
358                 return error;
359             }
360             break;
361 
362         case '&':
363             {
364                 error = Variable::GetValuesForVariableExpressionPath (variable_expr_path + 1,
365                                                                       scope,
366                                                                       callback,
367                                                                       baton,
368                                                                       variable_list,
369                                                                       valobj_list);
370                 if (error.Success())
371                 {
372                     for (uint32_t i=0; i<valobj_list.GetSize(); )
373                     {
374                         Error tmp_error;
375                         ValueObjectSP valobj_sp (valobj_list.GetValueObjectAtIndex(i)->AddressOf(tmp_error));
376                         if (tmp_error.Fail())
377                         {
378                             variable_list.RemoveVariableAtIndex (i);
379                             valobj_list.RemoveValueObjectAtIndex (i);
380                         }
381                         else
382                         {
383                             valobj_list.SetValueObjectAtIndex (i, valobj_sp);
384                             ++i;
385                         }
386                     }
387                 }
388                 else
389                 {
390                     error.SetErrorString ("unknown error");
391                 }
392                 return error;
393             }
394             break;
395 
396         default:
397             {
398                 RegularExpression regex ("^([A-Za-z_:][A-Za-z_0-9:]*)(.*)");
399                 if (regex.Execute(variable_expr_path, 1))
400                 {
401                     std::string variable_name;
402                     if (regex.GetMatchAtIndex(variable_expr_path, 1, variable_name))
403                     {
404                         variable_list.Clear();
405                         if (callback (baton, variable_name.c_str(), variable_list))
406                         {
407                             uint32_t i=0;
408                             while (i < variable_list.GetSize())
409                             {
410                                 VariableSP var_sp (variable_list.GetVariableAtIndex (i));
411                                 ValueObjectSP valobj_sp;
412                                 if (var_sp)
413                                 {
414                                     ValueObjectSP variable_valobj_sp(ValueObjectVariable::Create (scope, var_sp));
415                                     if (variable_valobj_sp)
416                                     {
417                                         variable_expr_path += variable_name.size();
418                                         if (*variable_expr_path)
419                                         {
420                                             const char* first_unparsed = NULL;
421                                             ValueObject::ExpressionPathScanEndReason reason_to_stop;
422                                             ValueObject::ExpressionPathEndResultType final_value_type;
423                                             ValueObject::GetValueForExpressionPathOptions options;
424                                             ValueObject::ExpressionPathAftermath final_task_on_target;
425 
426                                             valobj_sp = variable_valobj_sp->GetValueForExpressionPath (variable_expr_path,
427                                                                                                        &first_unparsed,
428                                                                                                        &reason_to_stop,
429                                                                                                        &final_value_type,
430                                                                                                        options,
431                                                                                                        &final_task_on_target);
432                                             if (!valobj_sp)
433                                             {
434                                                 error.SetErrorStringWithFormat ("invalid expression path '%s' for variable '%s'",
435                                                                                 variable_expr_path,
436                                                                                 var_sp->GetName().GetCString());
437                                             }
438                                         }
439                                         else
440                                         {
441                                             // Just the name of a variable with no extras
442                                             valobj_sp = variable_valobj_sp;
443                                         }
444                                     }
445                                 }
446 
447                                 if (!var_sp || !valobj_sp)
448                                 {
449                                     variable_list.RemoveVariableAtIndex (i);
450                                 }
451                                 else
452                                 {
453                                     valobj_list.Append(valobj_sp);
454                                     ++i;
455                                 }
456                             }
457 
458                             if (variable_list.GetSize() > 0)
459                             {
460                                 error.Clear();
461                                 return error;
462                             }
463                         }
464                     }
465                 }
466                 error.SetErrorStringWithFormat ("unable to extracta variable name from '%s'", variable_expr_path);
467             }
468             break;
469         }
470     }
471     error.SetErrorString ("unknown error");
472     return error;
473 }
474 
475 bool
476 Variable::DumpLocationForAddress (Stream *s, const Address &address)
477 {
478     // Be sure to resolve the address to section offset prior to
479     // calling this function.
480     if (address.IsSectionOffset())
481     {
482         SymbolContext sc;
483         CalculateSymbolContext(&sc);
484         if (sc.module_sp == address.GetModule())
485         {
486             ABI *abi = NULL;
487             if (m_owner_scope)
488             {
489                 ModuleSP module_sp (m_owner_scope->CalculateSymbolContextModule());
490                 if (module_sp)
491                     abi = ABI::FindPlugin (module_sp->GetArchitecture()).get();
492             }
493 
494             const addr_t file_addr = address.GetFileAddress();
495             if (sc.function)
496             {
497                 if (sc.function->GetAddressRange().ContainsFileAddress(address))
498                 {
499                     addr_t loclist_base_file_addr = sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
500                     if (loclist_base_file_addr == LLDB_INVALID_ADDRESS)
501                         return false;
502                     return m_location.DumpLocationForAddress (s,
503                                                               eDescriptionLevelBrief,
504                                                               loclist_base_file_addr,
505                                                               file_addr,
506                                                               abi);
507                 }
508             }
509             return m_location.DumpLocationForAddress (s,
510                                                       eDescriptionLevelBrief,
511                                                       LLDB_INVALID_ADDRESS,
512                                                       file_addr,
513                                                       abi);
514         }
515     }
516     return false;
517 
518 }
519 
520