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