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