1 //===-- FormatNavigator.h ----------------------------------------*- 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 #ifndef lldb_FormatNavigator_h_
11 #define lldb_FormatNavigator_h_
12
13 // C Includes
14 // C++ Includes
15
16 // Other libraries and framework includes
17 #include "clang/AST/DeclCXX.h"
18 #include "clang/AST/Type.h"
19 #include "clang/AST/DeclObjC.h"
20
21 // Project includes
22 #include "lldb/lldb-public.h"
23
24 #include "lldb/Core/Log.h"
25 #include "lldb/Core/RegularExpression.h"
26 #include "lldb/Core/ValueObject.h"
27
28 #include "lldb/DataFormatters/FormatClasses.h"
29
30 #include "lldb/Symbol/ClangASTContext.h"
31 #include "lldb/Symbol/ClangASTType.h"
32
33 #include "lldb/Target/ObjCLanguageRuntime.h"
34 #include "lldb/Target/Process.h"
35 #include "lldb/Target/StackFrame.h"
36 #include "lldb/Target/TargetList.h"
37
38 namespace lldb_private {
39
40 // this file (and its. cpp) contain the low-level implementation of LLDB Data Visualization
41 // class DataVisualization is the high-level front-end of this feature
42 // clients should refer to that class as the entry-point into the data formatters
43 // unless they have a good reason to bypass it and prefer to use this file's objects directly
44 class IFormatChangeListener
45 {
46 public:
47 virtual void
48 Changed () = 0;
49
50 virtual
~IFormatChangeListener()51 ~IFormatChangeListener () {}
52
53 virtual uint32_t
54 GetCurrentRevision () = 0;
55
56 };
57
58 static inline bool
IsWhitespace(char c)59 IsWhitespace (char c)
60 {
61 return ( (c == ' ') || (c == '\t') || (c == '\v') || (c == '\f') );
62 }
63
64 static inline bool
HasPrefix(const char * str1,const char * str2)65 HasPrefix (const char* str1, const char* str2)
66 {
67 return ( ::strstr(str1, str2) == str1 );
68 }
69
70 // if the user tries to add formatters for, say, "struct Foo"
71 // those will not match any type because of the way we strip qualifiers from typenames
72 // this method looks for the case where the user is adding a "class","struct","enum" or "union" Foo
73 // and strips the unnecessary qualifier
74 static inline ConstString
GetValidTypeName_Impl(const ConstString & type)75 GetValidTypeName_Impl (const ConstString& type)
76 {
77 int strip_len = 0;
78
79 if (type == false)
80 return type;
81
82 const char* type_cstr = type.AsCString();
83
84 if ( HasPrefix(type_cstr, "class ") )
85 strip_len = 6;
86 else if ( HasPrefix(type_cstr, "enum ") )
87 strip_len = 5;
88 else if ( HasPrefix(type_cstr, "struct ") )
89 strip_len = 7;
90 else if ( HasPrefix(type_cstr, "union ") )
91 strip_len = 6;
92
93 if (strip_len == 0)
94 return type;
95
96 type_cstr += strip_len;
97 while (IsWhitespace(*type_cstr) && ++type_cstr)
98 ;
99
100 return ConstString(type_cstr);
101 }
102
103 template<typename KeyType, typename ValueType>
104 class FormatNavigator;
105
106 template<typename KeyType, typename ValueType>
107 class FormatMap
108 {
109 public:
110
111 typedef typename ValueType::SharedPointer ValueSP;
112 typedef std::map<KeyType, ValueSP> MapType;
113 typedef typename MapType::iterator MapIterator;
114 typedef bool(*CallbackType)(void*, KeyType, const ValueSP&);
115
FormatMap(IFormatChangeListener * lst)116 FormatMap(IFormatChangeListener* lst) :
117 m_map(),
118 m_map_mutex(Mutex::eMutexTypeRecursive),
119 listener(lst)
120 {
121 }
122
123 void
Add(KeyType name,const ValueSP & entry)124 Add(KeyType name,
125 const ValueSP& entry)
126 {
127 if (listener)
128 entry->GetRevision() = listener->GetCurrentRevision();
129 else
130 entry->GetRevision() = 0;
131
132 Mutex::Locker locker(m_map_mutex);
133 m_map[name] = entry;
134 if (listener)
135 listener->Changed();
136 }
137
138 bool
Delete(KeyType name)139 Delete (KeyType name)
140 {
141 Mutex::Locker locker(m_map_mutex);
142 MapIterator iter = m_map.find(name);
143 if (iter == m_map.end())
144 return false;
145 m_map.erase(name);
146 if (listener)
147 listener->Changed();
148 return true;
149 }
150
151 void
Clear()152 Clear ()
153 {
154 Mutex::Locker locker(m_map_mutex);
155 m_map.clear();
156 if (listener)
157 listener->Changed();
158 }
159
160 bool
Get(KeyType name,ValueSP & entry)161 Get(KeyType name,
162 ValueSP& entry)
163 {
164 Mutex::Locker locker(m_map_mutex);
165 MapIterator iter = m_map.find(name);
166 if (iter == m_map.end())
167 return false;
168 entry = iter->second;
169 return true;
170 }
171
172 void
LoopThrough(CallbackType callback,void * param)173 LoopThrough (CallbackType callback, void* param)
174 {
175 if (callback)
176 {
177 Mutex::Locker locker(m_map_mutex);
178 MapIterator pos, end = m_map.end();
179 for (pos = m_map.begin(); pos != end; pos++)
180 {
181 KeyType type = pos->first;
182 if (!callback(param, type, pos->second))
183 break;
184 }
185 }
186 }
187
188 uint32_t
GetCount()189 GetCount ()
190 {
191 return m_map.size();
192 }
193
194 ValueSP
GetValueAtIndex(size_t index)195 GetValueAtIndex (size_t index)
196 {
197 Mutex::Locker locker(m_map_mutex);
198 MapIterator iter = m_map.begin();
199 MapIterator end = m_map.end();
200 while (index > 0)
201 {
202 iter++;
203 index--;
204 if (end == iter)
205 return ValueSP();
206 }
207 return iter->second;
208 }
209
210 KeyType
GetKeyAtIndex(size_t index)211 GetKeyAtIndex (size_t index)
212 {
213 Mutex::Locker locker(m_map_mutex);
214 MapIterator iter = m_map.begin();
215 MapIterator end = m_map.end();
216 while (index > 0)
217 {
218 iter++;
219 index--;
220 if (end == iter)
221 return KeyType();
222 }
223 return iter->first;
224 }
225
226 protected:
227 MapType m_map;
228 Mutex m_map_mutex;
229 IFormatChangeListener* listener;
230
231 MapType&
map()232 map ()
233 {
234 return m_map;
235 }
236
237 Mutex&
mutex()238 mutex ()
239 {
240 return m_map_mutex;
241 }
242
243 friend class FormatNavigator<KeyType, ValueType>;
244 friend class FormatManager;
245
246 };
247
248 template<typename KeyType, typename ValueType>
249 class FormatNavigator
250 {
251 protected:
252 typedef FormatMap<KeyType,ValueType> BackEndType;
253
254 public:
255 typedef typename BackEndType::MapType MapType;
256 typedef typename MapType::iterator MapIterator;
257 typedef typename MapType::key_type MapKeyType;
258 typedef typename MapType::mapped_type MapValueType;
259 typedef typename BackEndType::CallbackType CallbackType;
260 typedef typename std::shared_ptr<FormatNavigator<KeyType, ValueType> > SharedPointer;
261
262 friend class TypeCategoryImpl;
263
FormatNavigator(std::string name,IFormatChangeListener * lst)264 FormatNavigator(std::string name,
265 IFormatChangeListener* lst) :
266 m_format_map(lst),
267 m_name(name),
268 m_id_cs(ConstString("id"))
269 {
270 }
271
272 void
Add(const MapKeyType & type,const MapValueType & entry)273 Add (const MapKeyType &type, const MapValueType& entry)
274 {
275 Add_Impl(type, entry, (KeyType*)NULL);
276 }
277
278 bool
Delete(ConstString type)279 Delete (ConstString type)
280 {
281 return Delete_Impl(type, (KeyType*)NULL);
282 }
283
284 bool
285 Get(ValueObject& valobj,
286 MapValueType& entry,
287 lldb::DynamicValueType use_dynamic,
288 uint32_t* why = NULL)
289 {
290 uint32_t value = lldb_private::eFormatterChoiceCriterionDirectChoice;
291 ClangASTType ast_type(valobj.GetClangType());
292 bool ret = Get(valobj, ast_type, entry, use_dynamic, value);
293 if (ret)
294 entry = MapValueType(entry);
295 else
296 entry = MapValueType();
297 if (why)
298 *why = value;
299 return ret;
300 }
301
302 bool
Get(ConstString type,MapValueType & entry)303 Get (ConstString type, MapValueType& entry)
304 {
305 return Get_Impl(type, entry, (KeyType*)NULL);
306 }
307
308 bool
GetExact(ConstString type,MapValueType & entry)309 GetExact (ConstString type, MapValueType& entry)
310 {
311 return GetExact_Impl(type, entry, (KeyType*)NULL);
312 }
313
314 MapValueType
GetAtIndex(size_t index)315 GetAtIndex (size_t index)
316 {
317 return m_format_map.GetValueAtIndex(index);
318 }
319
320 lldb::TypeNameSpecifierImplSP
GetTypeNameSpecifierAtIndex(size_t index)321 GetTypeNameSpecifierAtIndex (size_t index)
322 {
323 return GetTypeNameSpecifierAtIndex_Impl(index, (KeyType*)NULL);
324 }
325
326 void
Clear()327 Clear ()
328 {
329 m_format_map.Clear();
330 }
331
332 void
LoopThrough(CallbackType callback,void * param)333 LoopThrough (CallbackType callback, void* param)
334 {
335 m_format_map.LoopThrough(callback,param);
336 }
337
338 uint32_t
GetCount()339 GetCount ()
340 {
341 return m_format_map.GetCount();
342 }
343
344 protected:
345
346 BackEndType m_format_map;
347
348 std::string m_name;
349
350 DISALLOW_COPY_AND_ASSIGN(FormatNavigator);
351
352 ConstString m_id_cs;
353
354 void
Add_Impl(const MapKeyType & type,const MapValueType & entry,lldb::RegularExpressionSP * dummy)355 Add_Impl (const MapKeyType &type, const MapValueType& entry, lldb::RegularExpressionSP *dummy)
356 {
357 m_format_map.Add(type,entry);
358 }
359
Add_Impl(const ConstString & type,const MapValueType & entry,ConstString * dummy)360 void Add_Impl (const ConstString &type, const MapValueType& entry, ConstString *dummy)
361 {
362 m_format_map.Add(GetValidTypeName_Impl(type), entry);
363 }
364
365 bool
Delete_Impl(ConstString type,ConstString * dummy)366 Delete_Impl (ConstString type, ConstString *dummy)
367 {
368 return m_format_map.Delete(type);
369 }
370
371 bool
Delete_Impl(ConstString type,lldb::RegularExpressionSP * dummy)372 Delete_Impl (ConstString type, lldb::RegularExpressionSP *dummy)
373 {
374 Mutex& x_mutex = m_format_map.mutex();
375 lldb_private::Mutex::Locker locker(x_mutex);
376 MapIterator pos, end = m_format_map.map().end();
377 for (pos = m_format_map.map().begin(); pos != end; pos++)
378 {
379 lldb::RegularExpressionSP regex = pos->first;
380 if ( ::strcmp(type.AsCString(),regex->GetText()) == 0)
381 {
382 m_format_map.map().erase(pos);
383 if (m_format_map.listener)
384 m_format_map.listener->Changed();
385 return true;
386 }
387 }
388 return false;
389 }
390
391 bool
Get_Impl(ConstString type,MapValueType & entry,ConstString * dummy)392 Get_Impl (ConstString type, MapValueType& entry, ConstString *dummy)
393 {
394 return m_format_map.Get(type, entry);
395 }
396
397 bool
GetExact_Impl(ConstString type,MapValueType & entry,ConstString * dummy)398 GetExact_Impl (ConstString type, MapValueType& entry, ConstString *dummy)
399 {
400 return Get_Impl(type,entry, (KeyType*)0);
401 }
402
403 lldb::TypeNameSpecifierImplSP
GetTypeNameSpecifierAtIndex_Impl(size_t index,ConstString * dummy)404 GetTypeNameSpecifierAtIndex_Impl (size_t index, ConstString *dummy)
405 {
406 ConstString key = m_format_map.GetKeyAtIndex(index);
407 if (key)
408 return lldb::TypeNameSpecifierImplSP(new TypeNameSpecifierImpl(key.AsCString(),
409 false));
410 else
411 return lldb::TypeNameSpecifierImplSP();
412 }
413
414 lldb::TypeNameSpecifierImplSP
GetTypeNameSpecifierAtIndex_Impl(size_t index,lldb::RegularExpressionSP * dummy)415 GetTypeNameSpecifierAtIndex_Impl (size_t index, lldb::RegularExpressionSP *dummy)
416 {
417 lldb::RegularExpressionSP regex = m_format_map.GetKeyAtIndex(index);
418 if (regex.get() == NULL)
419 return lldb::TypeNameSpecifierImplSP();
420 return lldb::TypeNameSpecifierImplSP(new TypeNameSpecifierImpl(regex->GetText(),
421 true));
422 }
423
424 bool
Get_Impl(ConstString key,MapValueType & value,lldb::RegularExpressionSP * dummy)425 Get_Impl (ConstString key, MapValueType& value, lldb::RegularExpressionSP *dummy)
426 {
427 const char* key_cstr = key.AsCString();
428 if (!key_cstr)
429 return false;
430 Mutex& x_mutex = m_format_map.mutex();
431 lldb_private::Mutex::Locker locker(x_mutex);
432 MapIterator pos, end = m_format_map.map().end();
433 for (pos = m_format_map.map().begin(); pos != end; pos++)
434 {
435 lldb::RegularExpressionSP regex = pos->first;
436 if (regex->Execute(key_cstr))
437 {
438 value = pos->second;
439 return true;
440 }
441 }
442 return false;
443 }
444
445 bool
GetExact_Impl(ConstString key,MapValueType & value,lldb::RegularExpressionSP * dummy)446 GetExact_Impl (ConstString key, MapValueType& value, lldb::RegularExpressionSP *dummy)
447 {
448 Mutex& x_mutex = m_format_map.mutex();
449 lldb_private::Mutex::Locker locker(x_mutex);
450 MapIterator pos, end = m_format_map.map().end();
451 for (pos = m_format_map.map().begin(); pos != end; pos++)
452 {
453 lldb::RegularExpressionSP regex = pos->first;
454 if (strcmp(regex->GetText(),key.AsCString()) == 0)
455 {
456 value = pos->second;
457 return true;
458 }
459 }
460 return false;
461 }
462
463 bool
Get_BitfieldMatch(ValueObject & valobj,ConstString typeName,MapValueType & entry,uint32_t & reason)464 Get_BitfieldMatch (ValueObject& valobj,
465 ConstString typeName,
466 MapValueType& entry,
467 uint32_t& reason)
468 {
469 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
470 // for bitfields, append size to the typename so one can custom format them
471 StreamString sstring;
472 sstring.Printf("%s:%d",typeName.AsCString(),valobj.GetBitfieldBitSize());
473 ConstString bitfieldname = ConstString(sstring.GetData());
474 if (log)
475 log->Printf("[Get_BitfieldMatch] appended bitfield info, final result is %s", bitfieldname.GetCString());
476 if (Get(bitfieldname, entry))
477 {
478 if (log)
479 log->Printf("[Get_BitfieldMatch] bitfield direct match found, returning");
480 return true;
481 }
482 else
483 {
484 reason |= lldb_private::eFormatterChoiceCriterionStrippedBitField;
485 if (log)
486 log->Printf("[Get_BitfieldMatch] no bitfield direct match");
487 return false;
488 }
489 }
490
Get_ObjC(ValueObject & valobj,MapValueType & entry)491 bool Get_ObjC (ValueObject& valobj,
492 MapValueType& entry)
493 {
494 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
495 lldb::ProcessSP process_sp = valobj.GetProcessSP();
496 ObjCLanguageRuntime* runtime = process_sp->GetObjCLanguageRuntime();
497 if (runtime == NULL)
498 {
499 if (log)
500 log->Printf("[Get_ObjC] no valid ObjC runtime, skipping dynamic");
501 return false;
502 }
503 ObjCLanguageRuntime::ClassDescriptorSP objc_class_sp (runtime->GetClassDescriptor(valobj));
504 if (!objc_class_sp)
505 {
506 if (log)
507 log->Printf("[Get_ObjC] invalid ISA, skipping dynamic");
508 return false;
509 }
510 ConstString name (objc_class_sp->GetClassName());
511 if (log)
512 log->Printf("[Get_ObjC] dynamic type inferred is %s - looking for direct dynamic match", name.GetCString());
513 if (Get(name, entry))
514 {
515 if (log)
516 log->Printf("[Get_ObjC] direct dynamic match found, returning");
517 return true;
518 }
519 if (log)
520 log->Printf("[Get_ObjC] no dynamic match");
521 return false;
522 }
523
524 bool
Get_Impl(ValueObject & valobj,ClangASTType clang_type,MapValueType & entry,lldb::DynamicValueType use_dynamic,uint32_t & reason)525 Get_Impl (ValueObject& valobj,
526 ClangASTType clang_type,
527 MapValueType& entry,
528 lldb::DynamicValueType use_dynamic,
529 uint32_t& reason)
530 {
531 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
532
533 if (!clang_type.IsValid())
534 {
535 if (log)
536 log->Printf("[Get_Impl] type is invalid, returning");
537 return false;
538 }
539
540 clang_type = clang_type.RemoveFastQualifiers();
541
542 ConstString typeName(clang_type.GetConstTypeName());
543
544 if (valobj.GetBitfieldBitSize() > 0)
545 {
546 if (Get_BitfieldMatch(valobj, typeName, entry, reason))
547 return true;
548 }
549
550 if (log)
551 log->Printf("[Get_Impl] trying to get %s for VO name %s of type %s",
552 m_name.c_str(),
553 valobj.GetName().AsCString(),
554 typeName.AsCString());
555
556 if (Get(typeName, entry))
557 {
558 if (log)
559 log->Printf("[Get] direct match found, returning");
560 return true;
561 }
562 if (log)
563 log->Printf("[Get_Impl] no direct match");
564
565 // strip pointers and references and see if that helps
566 if (clang_type.IsReferenceType())
567 {
568 if (log)
569 log->Printf("[Get_Impl] stripping reference");
570 if (Get_Impl(valobj, clang_type.GetNonReferenceType(), entry, use_dynamic, reason) && !entry->SkipsReferences())
571 {
572 reason |= lldb_private::eFormatterChoiceCriterionStrippedPointerReference;
573 return true;
574 }
575 }
576 else if (clang_type.IsPointerType())
577 {
578 if (log)
579 log->Printf("[Get_Impl] stripping pointer");
580 if (Get_Impl(valobj, clang_type.GetPointeeType(), entry, use_dynamic, reason) && !entry->SkipsPointers())
581 {
582 reason |= lldb_private::eFormatterChoiceCriterionStrippedPointerReference;
583 return true;
584 }
585 }
586
587 bool canBeObjCDynamic = valobj.GetClangType().IsPossibleDynamicType (NULL,
588 false, // no C++
589 true); // yes ObjC
590
591 if (canBeObjCDynamic)
592 {
593 if (use_dynamic != lldb::eNoDynamicValues)
594 {
595 if (log)
596 log->Printf("[Get_Impl] allowed to figure out dynamic ObjC type");
597 if (Get_ObjC(valobj,entry))
598 {
599 reason |= lldb_private::eFormatterChoiceCriterionDynamicObjCDiscovery;
600 return true;
601 }
602 }
603 if (log)
604 log->Printf("[Get_Impl] dynamic disabled or failed - stripping ObjC pointer");
605 if (Get_Impl(valobj, clang_type.GetPointeeType(), entry, use_dynamic, reason) && !entry->SkipsPointers())
606 {
607 reason |= lldb_private::eFormatterChoiceCriterionStrippedPointerReference;
608 return true;
609 }
610 }
611
612 // try to strip typedef chains
613 if (clang_type.IsTypedefType())
614 {
615 if (log)
616 log->Printf("[Get_Impl] stripping typedef");
617 if ((Get_Impl(valobj, clang_type.GetTypedefedType(), entry, use_dynamic, reason)) && entry->Cascades())
618 {
619 reason |= lldb_private::eFormatterChoiceCriterionNavigatedTypedefs;
620 return true;
621 }
622 }
623
624 // out of luck here
625 return false;
626 }
627
628 // we are separately passing in valobj and type because the valobj is fixed (and is used for ObjC discovery and bitfield size)
629 // but the type can change (e.g. stripping pointers, ...)
Get(ValueObject & valobj,ClangASTType clang_type,MapValueType & entry,lldb::DynamicValueType use_dynamic,uint32_t & reason)630 bool Get (ValueObject& valobj,
631 ClangASTType clang_type,
632 MapValueType& entry,
633 lldb::DynamicValueType use_dynamic,
634 uint32_t& reason)
635 {
636 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
637
638 if (Get_Impl (valobj, clang_type, entry, use_dynamic, reason))
639 return true;
640
641 // try going to the unqualified type
642 do {
643 if (log)
644 log->Printf("[Get] trying the unqualified type");
645 if (!clang_type.IsValid())
646 break;
647
648 ClangASTType unqual_clang_ast_type = clang_type.GetFullyUnqualifiedType();
649 if (!unqual_clang_ast_type.IsValid())
650 {
651 if (log)
652 log->Printf("[Get] could not get the unqual_clang_ast_type");
653 break;
654 }
655 if (unqual_clang_ast_type.GetOpaqueQualType() != clang_type.GetOpaqueQualType())
656 {
657 if (log)
658 log->Printf("[Get] unqualified type is there and is not the same, let's try");
659 if (Get_Impl (valobj, unqual_clang_ast_type,entry, use_dynamic, reason))
660 return true;
661 }
662 else if (log)
663 log->Printf("[Get] unqualified type same as original type");
664 } while(false);
665
666 // if all else fails, go to static type
667 if (valobj.IsDynamic())
668 {
669 if (log)
670 log->Printf("[Get] going to static value");
671 lldb::ValueObjectSP static_value_sp(valobj.GetStaticValue());
672 if (static_value_sp)
673 {
674 if (log)
675 log->Printf("[Get] has a static value - actually use it");
676 if (Get(*static_value_sp.get(), static_value_sp->GetClangType(), entry, use_dynamic, reason))
677 {
678 reason |= lldb_private::eFormatterChoiceCriterionWentToStaticValue;
679 return true;
680 }
681 }
682 }
683
684 return false;
685 }
686 };
687
688 } // namespace lldb_private
689
690 #endif // lldb_FormatNavigator_h_
691