aboutsummaryrefslogtreecommitdiff
path: root/examples/synthetic/libcxx.py
diff options
context:
space:
mode:
Diffstat (limited to 'examples/synthetic/libcxx.py')
-rw-r--r--examples/synthetic/libcxx.py1240
1 files changed, 661 insertions, 579 deletions
diff --git a/examples/synthetic/libcxx.py b/examples/synthetic/libcxx.py
index 6623fea097c4..e6f8223e2dad 100644
--- a/examples/synthetic/libcxx.py
+++ b/examples/synthetic/libcxx.py
@@ -4,583 +4,633 @@ import lldb.formatters.Logger
# libcxx STL formatters for LLDB
# These formatters are based upon the implementation of libc++ that
# ships with current releases of OS X - They will not work for other implementations
-# of the standard C++ library - and they are bound to use the libc++-specific namespace
+# of the standard C++ library - and they are bound to use the
+# libc++-specific namespace
# the std::string summary is just an example for your convenience
# the actual summary that LLDB uses is C++ code inside the debugger's own core
# this could probably be made more efficient but since it only reads a handful of bytes at a time
# we probably don't need to worry too much about this for the time being
-def make_string(F,L):
- strval = ''
- G = F.GetData().uint8
- for X in range(L):
- V = G[X]
- if V == 0:
- break
- strval = strval + chr(V % 256)
- return '"' + strval + '"'
+
+
+def make_string(F, L):
+ strval = ''
+ G = F.GetData().uint8
+ for X in range(L):
+ V = G[X]
+ if V == 0:
+ break
+ strval = strval + chr(V % 256)
+ return '"' + strval + '"'
# if we ever care about big-endian, these two functions might need to change
+
+
def is_short_string(value):
- return True if (value & 1) == 0 else False
+ return True if (value & 1) == 0 else False
+
+
def extract_short_size(value):
- return ((value >> 1) % 256)
+ return ((value >> 1) % 256)
# some of the members of libc++ std::string are anonymous or have internal names that convey
# no external significance - we access them by index since this saves a name lookup that would add
-# no information for readers of the code, but when possible try to use meaningful variable names
-def stdstring_SummaryProvider(valobj,dict):
- logger = lldb.formatters.Logger.Logger()
- r = valobj.GetChildAtIndex(0)
- B = r.GetChildAtIndex(0)
- first = B.GetChildAtIndex(0)
- D = first.GetChildAtIndex(0)
- l = D.GetChildAtIndex(0)
- s = D.GetChildAtIndex(1)
- D20 = s.GetChildAtIndex(0)
- size_mode = D20.GetChildAtIndex(0).GetValueAsUnsigned(0)
- if is_short_string(size_mode):
- size = extract_short_size(size_mode)
- return make_string(s.GetChildAtIndex(1),size)
- else:
- data_ptr = l.GetChildAtIndex(2)
- size_vo = l.GetChildAtIndex(1)
- size = size_vo.GetValueAsUnsigned(0)+1 # the NULL terminator must be accounted for
- if size <= 1 or size == None: # should never be the case
- return '""'
- try:
- data = data_ptr.GetPointeeData(0,size)
- except:
- return '""'
- error = lldb.SBError()
- strval = data.GetString(error,0)
- if error.Fail():
- return '<error:' + error.GetCString() + '>'
- else:
- return '"' + strval + '"'
+# no information for readers of the code, but when possible try to use
+# meaningful variable names
+
+
+def stdstring_SummaryProvider(valobj, dict):
+ logger = lldb.formatters.Logger.Logger()
+ r = valobj.GetChildAtIndex(0)
+ B = r.GetChildAtIndex(0)
+ first = B.GetChildAtIndex(0)
+ D = first.GetChildAtIndex(0)
+ l = D.GetChildAtIndex(0)
+ s = D.GetChildAtIndex(1)
+ D20 = s.GetChildAtIndex(0)
+ size_mode = D20.GetChildAtIndex(0).GetValueAsUnsigned(0)
+ if is_short_string(size_mode):
+ size = extract_short_size(size_mode)
+ return make_string(s.GetChildAtIndex(1), size)
+ else:
+ data_ptr = l.GetChildAtIndex(2)
+ size_vo = l.GetChildAtIndex(1)
+ # the NULL terminator must be accounted for
+ size = size_vo.GetValueAsUnsigned(0) + 1
+ if size <= 1 or size is None: # should never be the case
+ return '""'
+ try:
+ data = data_ptr.GetPointeeData(0, size)
+ except:
+ return '""'
+ error = lldb.SBError()
+ strval = data.GetString(error, 0)
+ if error.Fail():
+ return '<error:' + error.GetCString() + '>'
+ else:
+ return '"' + strval + '"'
+
class stdvector_SynthProvider:
- def __init__(self, valobj, dict):
- logger = lldb.formatters.Logger.Logger()
- self.valobj = valobj;
-
- def num_children(self):
- logger = lldb.formatters.Logger.Logger()
- try:
- start_val = self.start.GetValueAsUnsigned(0)
- finish_val = self.finish.GetValueAsUnsigned(0)
- # Before a vector has been constructed, it will contain bad values
- # so we really need to be careful about the length we return since
- # uninitialized data can cause us to return a huge number. We need
- # to also check for any of the start, finish or end of storage values
- # being zero (NULL). If any are, then this vector has not been
- # initialized yet and we should return zero
-
- # Make sure nothing is NULL
- if start_val == 0 or finish_val == 0:
- return 0
- # Make sure start is less than finish
- if start_val >= finish_val:
- return 0
-
- num_children = (finish_val-start_val)
- if (num_children % self.data_size) != 0:
- return 0
- else:
- num_children = num_children/self.data_size
- return num_children
- except:
- return 0;
-
- def get_child_index(self,name):
- logger = lldb.formatters.Logger.Logger()
- try:
- return int(name.lstrip('[').rstrip(']'))
- except:
- return -1
-
- def get_child_at_index(self,index):
- logger = lldb.formatters.Logger.Logger()
- logger >> "Retrieving child " + str(index)
- if index < 0:
- return None;
- if index >= self.num_children():
- return None;
- try:
- offset = index * self.data_size
- return self.start.CreateChildAtOffset('['+str(index)+']',offset,self.data_type)
- except:
- return None
-
- def update(self):
- logger = lldb.formatters.Logger.Logger()
- try:
- self.start = self.valobj.GetChildMemberWithName('__begin_')
- self.finish = self.valobj.GetChildMemberWithName('__end_')
- # the purpose of this field is unclear, but it is the only field whose type is clearly T* for a vector<T>
- # if this ends up not being correct, we can use the APIs to get at template arguments
- data_type_finder = self.valobj.GetChildMemberWithName('__end_cap_').GetChildMemberWithName('__first_')
- self.data_type = data_type_finder.GetType().GetPointeeType()
- self.data_size = self.data_type.GetByteSize()
- except:
- pass
-
- def has_children(self):
- return True
-
-# Just an example: the actual summary is produced by a summary string: size=${svar%#}
-def stdvector_SummaryProvider(valobj,dict):
- prov = stdvector_SynthProvider(valobj,None)
- return 'size=' + str(prov.num_children())
+ def __init__(self, valobj, dict):
+ logger = lldb.formatters.Logger.Logger()
+ self.valobj = valobj
+
+ def num_children(self):
+ logger = lldb.formatters.Logger.Logger()
+ try:
+ start_val = self.start.GetValueAsUnsigned(0)
+ finish_val = self.finish.GetValueAsUnsigned(0)
+ # Before a vector has been constructed, it will contain bad values
+ # so we really need to be careful about the length we return since
+ # uninitialized data can cause us to return a huge number. We need
+ # to also check for any of the start, finish or end of storage values
+ # being zero (NULL). If any are, then this vector has not been
+ # initialized yet and we should return zero
+
+ # Make sure nothing is NULL
+ if start_val == 0 or finish_val == 0:
+ return 0
+ # Make sure start is less than finish
+ if start_val >= finish_val:
+ return 0
+
+ num_children = (finish_val - start_val)
+ if (num_children % self.data_size) != 0:
+ return 0
+ else:
+ num_children = num_children / self.data_size
+ return num_children
+ except:
+ return 0
+
+ def get_child_index(self, name):
+ logger = lldb.formatters.Logger.Logger()
+ try:
+ return int(name.lstrip('[').rstrip(']'))
+ except:
+ return -1
+
+ def get_child_at_index(self, index):
+ logger = lldb.formatters.Logger.Logger()
+ logger >> "Retrieving child " + str(index)
+ if index < 0:
+ return None
+ if index >= self.num_children():
+ return None
+ try:
+ offset = index * self.data_size
+ return self.start.CreateChildAtOffset(
+ '[' + str(index) + ']', offset, self.data_type)
+ except:
+ return None
+
+ def update(self):
+ logger = lldb.formatters.Logger.Logger()
+ try:
+ self.start = self.valobj.GetChildMemberWithName('__begin_')
+ self.finish = self.valobj.GetChildMemberWithName('__end_')
+ # the purpose of this field is unclear, but it is the only field whose type is clearly T* for a vector<T>
+ # if this ends up not being correct, we can use the APIs to get at
+ # template arguments
+ data_type_finder = self.valobj.GetChildMemberWithName(
+ '__end_cap_').GetChildMemberWithName('__first_')
+ self.data_type = data_type_finder.GetType().GetPointeeType()
+ self.data_size = self.data_type.GetByteSize()
+ except:
+ pass
+
+ def has_children(self):
+ return True
+
+# Just an example: the actual summary is produced by a summary string:
+# size=${svar%#}
+
+
+def stdvector_SummaryProvider(valobj, dict):
+ prov = stdvector_SynthProvider(valobj, None)
+ return 'size=' + str(prov.num_children())
+
class stdlist_entry:
- def __init__(self,entry):
- logger = lldb.formatters.Logger.Logger()
- self.entry = entry
+ def __init__(self, entry):
+ logger = lldb.formatters.Logger.Logger()
+ self.entry = entry
+
+ def _next_impl(self):
+ logger = lldb.formatters.Logger.Logger()
+ return stdlist_entry(self.entry.GetChildMemberWithName('__next_'))
- def _next_impl(self):
- logger = lldb.formatters.Logger.Logger()
- return stdlist_entry(self.entry.GetChildMemberWithName('__next_'))
+ def _prev_impl(self):
+ logger = lldb.formatters.Logger.Logger()
+ return stdlist_entry(self.entry.GetChildMemberWithName('__prev_'))
- def _prev_impl(self):
- logger = lldb.formatters.Logger.Logger()
- return stdlist_entry(self.entry.GetChildMemberWithName('__prev_'))
+ def _value_impl(self):
+ logger = lldb.formatters.Logger.Logger()
+ return self.entry.GetValueAsUnsigned(0)
- def _value_impl(self):
- logger = lldb.formatters.Logger.Logger()
- return self.entry.GetValueAsUnsigned(0)
+ def _isnull_impl(self):
+ logger = lldb.formatters.Logger.Logger()
+ return self._value_impl() == 0
- def _isnull_impl(self):
- logger = lldb.formatters.Logger.Logger()
- return self._value_impl() == 0
+ def _sbvalue_impl(self):
+ logger = lldb.formatters.Logger.Logger()
+ return self.entry
- def _sbvalue_impl(self):
- logger = lldb.formatters.Logger.Logger()
- return self.entry
+ next = property(_next_impl, None)
+ value = property(_value_impl, None)
+ is_null = property(_isnull_impl, None)
+ sbvalue = property(_sbvalue_impl, None)
- next = property(_next_impl,None)
- value = property(_value_impl,None)
- is_null = property(_isnull_impl,None)
- sbvalue = property(_sbvalue_impl,None)
class stdlist_iterator:
- def increment_node(self,node):
- logger = lldb.formatters.Logger.Logger()
- if node.is_null:
- return None
- return node.next
-
- def __init__(self,node):
- logger = lldb.formatters.Logger.Logger()
- self.node = stdlist_entry(node) # we convert the SBValue to an internal node object on entry
-
- def value(self):
- logger = lldb.formatters.Logger.Logger()
- return self.node.sbvalue # and return the SBValue back on exit
-
- def next(self):
- logger = lldb.formatters.Logger.Logger()
- node = self.increment_node(self.node)
- if node != None and node.sbvalue.IsValid() and not(node.is_null):
- self.node = node
- return self.value()
- else:
- return None
-
- def advance(self,N):
- logger = lldb.formatters.Logger.Logger()
- if N < 0:
- return None
- if N == 0:
- return self.value()
- if N == 1:
- return self.next()
- while N > 0:
- self.next()
- N = N - 1
- return self.value()
+ def increment_node(self, node):
+ logger = lldb.formatters.Logger.Logger()
+ if node.is_null:
+ return None
+ return node.next
+
+ def __init__(self, node):
+ logger = lldb.formatters.Logger.Logger()
+ # we convert the SBValue to an internal node object on entry
+ self.node = stdlist_entry(node)
+
+ def value(self):
+ logger = lldb.formatters.Logger.Logger()
+ return self.node.sbvalue # and return the SBValue back on exit
+
+ def next(self):
+ logger = lldb.formatters.Logger.Logger()
+ node = self.increment_node(self.node)
+ if node is not None and node.sbvalue.IsValid() and not(node.is_null):
+ self.node = node
+ return self.value()
+ else:
+ return None
+
+ def advance(self, N):
+ logger = lldb.formatters.Logger.Logger()
+ if N < 0:
+ return None
+ if N == 0:
+ return self.value()
+ if N == 1:
+ return self.next()
+ while N > 0:
+ self.next()
+ N = N - 1
+ return self.value()
class stdlist_SynthProvider:
- def __init__(self, valobj, dict):
- logger = lldb.formatters.Logger.Logger()
- self.valobj = valobj
- self.count = None
-
- def next_node(self,node):
- logger = lldb.formatters.Logger.Logger()
- return node.GetChildMemberWithName('__next_')
-
- def value(self,node):
- logger = lldb.formatters.Logger.Logger()
- return node.GetValueAsUnsigned()
-
- # Floyd's cycle-finding algorithm
- # try to detect if this list has a loop
- def has_loop(self):
- global _list_uses_loop_detector
- logger = lldb.formatters.Logger.Logger()
- if _list_uses_loop_detector == False:
- logger >> "Asked not to use loop detection"
- return False
- slow = stdlist_entry(self.head)
- fast1 = stdlist_entry(self.head)
- fast2 = stdlist_entry(self.head)
- while slow.next.value != self.node_address:
- slow_value = slow.value
- fast1 = fast2.next
- fast2 = fast1.next
- if fast1.value == slow_value or fast2.value == slow_value:
- return True
- slow = slow.next
- return False
-
- def num_children(self):
- global _list_capping_size
- logger = lldb.formatters.Logger.Logger()
- if self.count == None:
- self.count = self.num_children_impl()
- if self.count > _list_capping_size:
- self.count = _list_capping_size
- return self.count
-
- def num_children_impl(self):
- global _list_capping_size
- logger = lldb.formatters.Logger.Logger()
- try:
- next_val = self.head.GetValueAsUnsigned(0)
- prev_val = self.tail.GetValueAsUnsigned(0)
- # After a std::list has been initialized, both next and prev will be non-NULL
- if next_val == 0 or prev_val == 0:
- return 0
- if next_val == self.node_address:
- return 0
- if next_val == prev_val:
- return 1
- if self.has_loop():
- return 0
- size = 2
- current = stdlist_entry(self.head)
- while current.next.value != self.node_address:
- size = size + 1
- current = current.next
- if size > _list_capping_size:
- return _list_capping_size
- return (size - 1)
- except:
- return 0;
-
- def get_child_index(self,name):
- logger = lldb.formatters.Logger.Logger()
- try:
- return int(name.lstrip('[').rstrip(']'))
- except:
- return -1
-
- def get_child_at_index(self,index):
- logger = lldb.formatters.Logger.Logger()
- logger >> "Fetching child " + str(index)
- if index < 0:
- return None;
- if index >= self.num_children():
- return None;
- try:
- current = stdlist_iterator(self.head)
- current = current.advance(index)
- # we do not return __value_ because then all our children would be named __value_
- # we need to make a copy of __value__ with the right name - unfortunate
- obj = current.GetChildMemberWithName('__value_')
- obj_data = obj.GetData()
- return self.valobj.CreateValueFromData('[' + str(index) + ']',obj_data,self.data_type)
- except:
- return None
-
- def extract_type(self):
- logger = lldb.formatters.Logger.Logger()
- list_type = self.valobj.GetType().GetUnqualifiedType()
- if list_type.IsReferenceType():
- list_type = list_type.GetDereferencedType()
- if list_type.GetNumberOfTemplateArguments() > 0:
- data_type = list_type.GetTemplateArgumentType(0)
- else:
- data_type = None
- return data_type
-
- def update(self):
- logger = lldb.formatters.Logger.Logger()
- self.count = None
- try:
- impl = self.valobj.GetChildMemberWithName('__end_')
- self.node_address = self.valobj.AddressOf().GetValueAsUnsigned(0)
- self.head = impl.GetChildMemberWithName('__next_')
- self.tail = impl.GetChildMemberWithName('__prev_')
- self.data_type = self.extract_type()
- self.data_size = self.data_type.GetByteSize()
- except:
- pass
-
- def has_children(self):
- return True
-
-
-# Just an example: the actual summary is produced by a summary string: size=${svar%#}
-def stdlist_SummaryProvider(valobj,dict):
- prov = stdlist_SynthProvider(valobj,None)
- return 'size=' + str(prov.num_children())
-
-# a tree node - this class makes the syntax in the actual iterator nicer to read and maintain
+
+ def __init__(self, valobj, dict):
+ logger = lldb.formatters.Logger.Logger()
+ self.valobj = valobj
+ self.count = None
+
+ def next_node(self, node):
+ logger = lldb.formatters.Logger.Logger()
+ return node.GetChildMemberWithName('__next_')
+
+ def value(self, node):
+ logger = lldb.formatters.Logger.Logger()
+ return node.GetValueAsUnsigned()
+
+ # Floyd's cycle-finding algorithm
+ # try to detect if this list has a loop
+ def has_loop(self):
+ global _list_uses_loop_detector
+ logger = lldb.formatters.Logger.Logger()
+ if not _list_uses_loop_detector:
+ logger >> "Asked not to use loop detection"
+ return False
+ slow = stdlist_entry(self.head)
+ fast1 = stdlist_entry(self.head)
+ fast2 = stdlist_entry(self.head)
+ while slow.next.value != self.node_address:
+ slow_value = slow.value
+ fast1 = fast2.next
+ fast2 = fast1.next
+ if fast1.value == slow_value or fast2.value == slow_value:
+ return True
+ slow = slow.next
+ return False
+
+ def num_children(self):
+ global _list_capping_size
+ logger = lldb.formatters.Logger.Logger()
+ if self.count is None:
+ self.count = self.num_children_impl()
+ if self.count > _list_capping_size:
+ self.count = _list_capping_size
+ return self.count
+
+ def num_children_impl(self):
+ global _list_capping_size
+ logger = lldb.formatters.Logger.Logger()
+ try:
+ next_val = self.head.GetValueAsUnsigned(0)
+ prev_val = self.tail.GetValueAsUnsigned(0)
+ # After a std::list has been initialized, both next and prev will
+ # be non-NULL
+ if next_val == 0 or prev_val == 0:
+ return 0
+ if next_val == self.node_address:
+ return 0
+ if next_val == prev_val:
+ return 1
+ if self.has_loop():
+ return 0
+ size = 2
+ current = stdlist_entry(self.head)
+ while current.next.value != self.node_address:
+ size = size + 1
+ current = current.next
+ if size > _list_capping_size:
+ return _list_capping_size
+ return (size - 1)
+ except:
+ return 0
+
+ def get_child_index(self, name):
+ logger = lldb.formatters.Logger.Logger()
+ try:
+ return int(name.lstrip('[').rstrip(']'))
+ except:
+ return -1
+
+ def get_child_at_index(self, index):
+ logger = lldb.formatters.Logger.Logger()
+ logger >> "Fetching child " + str(index)
+ if index < 0:
+ return None
+ if index >= self.num_children():
+ return None
+ try:
+ current = stdlist_iterator(self.head)
+ current = current.advance(index)
+ # we do not return __value_ because then all our children would be named __value_
+ # we need to make a copy of __value__ with the right name -
+ # unfortunate
+ obj = current.GetChildMemberWithName('__value_')
+ obj_data = obj.GetData()
+ return self.valobj.CreateValueFromData(
+ '[' + str(index) + ']', obj_data, self.data_type)
+ except:
+ return None
+
+ def extract_type(self):
+ logger = lldb.formatters.Logger.Logger()
+ list_type = self.valobj.GetType().GetUnqualifiedType()
+ if list_type.IsReferenceType():
+ list_type = list_type.GetDereferencedType()
+ if list_type.GetNumberOfTemplateArguments() > 0:
+ data_type = list_type.GetTemplateArgumentType(0)
+ else:
+ data_type = None
+ return data_type
+
+ def update(self):
+ logger = lldb.formatters.Logger.Logger()
+ self.count = None
+ try:
+ impl = self.valobj.GetChildMemberWithName('__end_')
+ self.node_address = self.valobj.AddressOf().GetValueAsUnsigned(0)
+ self.head = impl.GetChildMemberWithName('__next_')
+ self.tail = impl.GetChildMemberWithName('__prev_')
+ self.data_type = self.extract_type()
+ self.data_size = self.data_type.GetByteSize()
+ except:
+ pass
+
+ def has_children(self):
+ return True
+
+
+# Just an example: the actual summary is produced by a summary string:
+# size=${svar%#}
+def stdlist_SummaryProvider(valobj, dict):
+ prov = stdlist_SynthProvider(valobj, None)
+ return 'size=' + str(prov.num_children())
+
+# a tree node - this class makes the syntax in the actual iterator nicer
+# to read and maintain
+
+
class stdmap_iterator_node:
- def _left_impl(self):
- logger = lldb.formatters.Logger.Logger()
- return stdmap_iterator_node(self.node.GetChildMemberWithName("__left_"))
- def _right_impl(self):
- logger = lldb.formatters.Logger.Logger()
- return stdmap_iterator_node(self.node.GetChildMemberWithName("__right_"))
+ def _left_impl(self):
+ logger = lldb.formatters.Logger.Logger()
+ return stdmap_iterator_node(
+ self.node.GetChildMemberWithName("__left_"))
+
+ def _right_impl(self):
+ logger = lldb.formatters.Logger.Logger()
+ return stdmap_iterator_node(
+ self.node.GetChildMemberWithName("__right_"))
- def _parent_impl(self):
- logger = lldb.formatters.Logger.Logger()
- return stdmap_iterator_node(self.node.GetChildMemberWithName("__parent_"))
+ def _parent_impl(self):
+ logger = lldb.formatters.Logger.Logger()
+ return stdmap_iterator_node(
+ self.node.GetChildMemberWithName("__parent_"))
- def _value_impl(self):
- logger = lldb.formatters.Logger.Logger()
- return self.node.GetValueAsUnsigned(0)
+ def _value_impl(self):
+ logger = lldb.formatters.Logger.Logger()
+ return self.node.GetValueAsUnsigned(0)
- def _sbvalue_impl(self):
- logger = lldb.formatters.Logger.Logger()
- return self.node
+ def _sbvalue_impl(self):
+ logger = lldb.formatters.Logger.Logger()
+ return self.node
- def _null_impl(self):
- logger = lldb.formatters.Logger.Logger()
- return self.value == 0
+ def _null_impl(self):
+ logger = lldb.formatters.Logger.Logger()
+ return self.value == 0
- def __init__(self,node):
- logger = lldb.formatters.Logger.Logger()
- self.node = node
+ def __init__(self, node):
+ logger = lldb.formatters.Logger.Logger()
+ self.node = node
- left = property(_left_impl,None)
- right = property(_right_impl,None)
- parent = property(_parent_impl,None)
- value = property(_value_impl,None)
- is_null = property(_null_impl,None)
- sbvalue = property(_sbvalue_impl,None)
+ left = property(_left_impl, None)
+ right = property(_right_impl, None)
+ parent = property(_parent_impl, None)
+ value = property(_value_impl, None)
+ is_null = property(_null_impl, None)
+ sbvalue = property(_sbvalue_impl, None)
# a Python implementation of the tree iterator used by libc++
+
+
class stdmap_iterator:
- def tree_min(self,x):
- logger = lldb.formatters.Logger.Logger()
- steps = 0
- if x.is_null:
- return None
- while (not x.left.is_null):
- x = x.left
- steps += 1
- if steps > self.max_count:
- logger >> "Returning None - we overflowed"
- return None
- return x
-
- def tree_max(self,x):
- logger = lldb.formatters.Logger.Logger()
- if x.is_null:
- return None
- while (not x.right.is_null):
- x = x.right
- return x
-
- def tree_is_left_child(self,x):
- logger = lldb.formatters.Logger.Logger()
- if x.is_null:
- return None
- return True if x.value == x.parent.left.value else False
-
- def increment_node(self,node):
- logger = lldb.formatters.Logger.Logger()
- if node.is_null:
- return None
- if not node.right.is_null:
- return self.tree_min(node.right)
- steps = 0
- while (not self.tree_is_left_child(node)):
- steps += 1
- if steps > self.max_count:
- logger >> "Returning None - we overflowed"
- return None
- node = node.parent
- return node.parent
-
- def __init__(self,node,max_count=0):
- logger = lldb.formatters.Logger.Logger()
- self.node = stdmap_iterator_node(node) # we convert the SBValue to an internal node object on entry
- self.max_count = max_count
-
- def value(self):
- logger = lldb.formatters.Logger.Logger()
- return self.node.sbvalue # and return the SBValue back on exit
-
- def next(self):
- logger = lldb.formatters.Logger.Logger()
- node = self.increment_node(self.node)
- if node != None and node.sbvalue.IsValid() and not(node.is_null):
- self.node = node
- return self.value()
- else:
- return None
-
- def advance(self,N):
- logger = lldb.formatters.Logger.Logger()
- if N < 0:
- return None
- if N == 0:
- return self.value()
- if N == 1:
- return self.next()
- while N > 0:
- if self.next() == None:
- return None
- N = N - 1
- return self.value()
+ def tree_min(self, x):
+ logger = lldb.formatters.Logger.Logger()
+ steps = 0
+ if x.is_null:
+ return None
+ while (not x.left.is_null):
+ x = x.left
+ steps += 1
+ if steps > self.max_count:
+ logger >> "Returning None - we overflowed"
+ return None
+ return x
+
+ def tree_max(self, x):
+ logger = lldb.formatters.Logger.Logger()
+ if x.is_null:
+ return None
+ while (not x.right.is_null):
+ x = x.right
+ return x
+
+ def tree_is_left_child(self, x):
+ logger = lldb.formatters.Logger.Logger()
+ if x.is_null:
+ return None
+ return True if x.value == x.parent.left.value else False
+
+ def increment_node(self, node):
+ logger = lldb.formatters.Logger.Logger()
+ if node.is_null:
+ return None
+ if not node.right.is_null:
+ return self.tree_min(node.right)
+ steps = 0
+ while (not self.tree_is_left_child(node)):
+ steps += 1
+ if steps > self.max_count:
+ logger >> "Returning None - we overflowed"
+ return None
+ node = node.parent
+ return node.parent
+
+ def __init__(self, node, max_count=0):
+ logger = lldb.formatters.Logger.Logger()
+ # we convert the SBValue to an internal node object on entry
+ self.node = stdmap_iterator_node(node)
+ self.max_count = max_count
+
+ def value(self):
+ logger = lldb.formatters.Logger.Logger()
+ return self.node.sbvalue # and return the SBValue back on exit
+
+ def next(self):
+ logger = lldb.formatters.Logger.Logger()
+ node = self.increment_node(self.node)
+ if node is not None and node.sbvalue.IsValid() and not(node.is_null):
+ self.node = node
+ return self.value()
+ else:
+ return None
+
+ def advance(self, N):
+ logger = lldb.formatters.Logger.Logger()
+ if N < 0:
+ return None
+ if N == 0:
+ return self.value()
+ if N == 1:
+ return self.next()
+ while N > 0:
+ if self.next() is None:
+ return None
+ N = N - 1
+ return self.value()
+
class stdmap_SynthProvider:
- def __init__(self, valobj, dict):
- logger = lldb.formatters.Logger.Logger()
- self.valobj = valobj;
- self.pointer_size = self.valobj.GetProcess().GetAddressByteSize()
- self.count = None
-
- def update(self):
- logger = lldb.formatters.Logger.Logger()
- self.count = None
- try:
- # we will set this to True if we find out that discovering a node in the map takes more steps than the overall size of the RB tree
- # if this gets set to True, then we will merrily return None for any child from that moment on
- self.garbage = False
- self.tree = self.valobj.GetChildMemberWithName('__tree_')
- self.root_node = self.tree.GetChildMemberWithName('__begin_node_')
- # this data is either lazily-calculated, or cannot be inferred at this moment
- # we still need to mark it as None, meaning "please set me ASAP"
- self.data_type = None
- self.data_size = None
- self.skip_size = None
- except:
- pass
-
- def num_children(self):
- global _map_capping_size
- logger = lldb.formatters.Logger.Logger()
- if self.count == None:
- self.count = self.num_children_impl()
- if self.count > _map_capping_size:
- self.count = _map_capping_size
- return self.count
-
- def num_children_impl(self):
- logger = lldb.formatters.Logger.Logger()
- try:
- return self.valobj.GetChildMemberWithName('__tree_').GetChildMemberWithName('__pair3_').GetChildMemberWithName('__first_').GetValueAsUnsigned()
- except:
- return 0;
-
- def has_children(self):
- return True
-
- def get_data_type(self):
- logger = lldb.formatters.Logger.Logger()
- if self.data_type == None or self.data_size == None:
- if self.num_children() == 0:
- return False
- deref = self.root_node.Dereference()
- if not(deref.IsValid()):
- return False
- value = deref.GetChildMemberWithName('__value_')
- if not(value.IsValid()):
- return False
- self.data_type = value.GetType()
- self.data_size = self.data_type.GetByteSize()
- self.skip_size = None
- return True
- else:
- return True
-
- def get_value_offset(self,node):
- logger = lldb.formatters.Logger.Logger()
- if self.skip_size == None:
- node_type = node.GetType()
- fields_count = node_type.GetNumberOfFields()
- for i in range(fields_count):
- field = node_type.GetFieldAtIndex(i)
- if field.GetName() == '__value_':
- self.skip_size = field.GetOffsetInBytes()
- break
- return (self.skip_size != None)
-
- def get_child_index(self,name):
- logger = lldb.formatters.Logger.Logger()
- try:
- return int(name.lstrip('[').rstrip(']'))
- except:
- return -1
-
- def get_child_at_index(self,index):
- logger = lldb.formatters.Logger.Logger()
- logger >> "Retrieving child " + str(index)
- if index < 0:
- return None
- if index >= self.num_children():
- return None;
- if self.garbage:
- logger >> "Returning None since this tree is garbage"
- return None
- try:
- iterator = stdmap_iterator(self.root_node,max_count=self.num_children())
- # the debug info for libc++ std::map is such that __begin_node_ has a very nice and useful type
- # out of which we can grab the information we need - every other node has a less informative
- # type which omits all value information and only contains housekeeping information for the RB tree
- # hence, we need to know if we are at a node != 0, so that we can still get at the data
- need_to_skip = (index > 0)
- current = iterator.advance(index)
- if current == None:
- logger >> "Tree is garbage - returning None"
- self.garbage = True
- return None
- if self.get_data_type():
- if not(need_to_skip):
- current = current.Dereference()
- obj = current.GetChildMemberWithName('__value_')
- obj_data = obj.GetData()
- self.get_value_offset(current) # make sure we have a valid offset for the next items
- # we do not return __value_ because then we would end up with a child named
- # __value_ instead of [0]
- return self.valobj.CreateValueFromData('[' + str(index) + ']',obj_data,self.data_type)
- else:
- # FIXME we need to have accessed item 0 before accessing any other item!
- if self.skip_size == None:
- logger >> "You asked for item > 0 before asking for item == 0, I will fetch 0 now then retry"
- if self.get_child_at_index(0):
- return self.get_child_at_index(index)
- else:
- logger >> "item == 0 could not be found. sorry, nothing can be done here."
- return None
- return current.CreateChildAtOffset('[' + str(index) + ']',self.skip_size,self.data_type)
- else:
- logger >> "Unable to infer data-type - returning None (should mark tree as garbage here?)"
- return None
- except Exception as err:
- logger >> "Hit an exception: " + str(err)
- return None
-
-# Just an example: the actual summary is produced by a summary string: size=${svar%#}
-def stdmap_SummaryProvider(valobj,dict):
- prov = stdmap_SynthProvider(valobj,None)
- return 'size=' + str(prov.num_children())
+ def __init__(self, valobj, dict):
+ logger = lldb.formatters.Logger.Logger()
+ self.valobj = valobj
+ self.pointer_size = self.valobj.GetProcess().GetAddressByteSize()
+ self.count = None
+
+ def update(self):
+ logger = lldb.formatters.Logger.Logger()
+ self.count = None
+ try:
+ # we will set this to True if we find out that discovering a node in the map takes more steps than the overall size of the RB tree
+ # if this gets set to True, then we will merrily return None for
+ # any child from that moment on
+ self.garbage = False
+ self.tree = self.valobj.GetChildMemberWithName('__tree_')
+ self.root_node = self.tree.GetChildMemberWithName('__begin_node_')
+ # this data is either lazily-calculated, or cannot be inferred at this moment
+ # we still need to mark it as None, meaning "please set me ASAP"
+ self.data_type = None
+ self.data_size = None
+ self.skip_size = None
+ except:
+ pass
+
+ def num_children(self):
+ global _map_capping_size
+ logger = lldb.formatters.Logger.Logger()
+ if self.count is None:
+ self.count = self.num_children_impl()
+ if self.count > _map_capping_size:
+ self.count = _map_capping_size
+ return self.count
+
+ def num_children_impl(self):
+ logger = lldb.formatters.Logger.Logger()
+ try:
+ return self.valobj.GetChildMemberWithName('__tree_').GetChildMemberWithName(
+ '__pair3_').GetChildMemberWithName('__first_').GetValueAsUnsigned()
+ except:
+ return 0
+
+ def has_children(self):
+ return True
+
+ def get_data_type(self):
+ logger = lldb.formatters.Logger.Logger()
+ if self.data_type is None or self.data_size is None:
+ if self.num_children() == 0:
+ return False
+ deref = self.root_node.Dereference()
+ if not(deref.IsValid()):
+ return False
+ value = deref.GetChildMemberWithName('__value_')
+ if not(value.IsValid()):
+ return False
+ self.data_type = value.GetType()
+ self.data_size = self.data_type.GetByteSize()
+ self.skip_size = None
+ return True
+ else:
+ return True
+
+ def get_value_offset(self, node):
+ logger = lldb.formatters.Logger.Logger()
+ if self.skip_size is None:
+ node_type = node.GetType()
+ fields_count = node_type.GetNumberOfFields()
+ for i in range(fields_count):
+ field = node_type.GetFieldAtIndex(i)
+ if field.GetName() == '__value_':
+ self.skip_size = field.GetOffsetInBytes()
+ break
+ return (self.skip_size is not None)
+
+ def get_child_index(self, name):
+ logger = lldb.formatters.Logger.Logger()
+ try:
+ return int(name.lstrip('[').rstrip(']'))
+ except:
+ return -1
+
+ def get_child_at_index(self, index):
+ logger = lldb.formatters.Logger.Logger()
+ logger >> "Retrieving child " + str(index)
+ if index < 0:
+ return None
+ if index >= self.num_children():
+ return None
+ if self.garbage:
+ logger >> "Returning None since this tree is garbage"
+ return None
+ try:
+ iterator = stdmap_iterator(
+ self.root_node, max_count=self.num_children())
+ # the debug info for libc++ std::map is such that __begin_node_ has a very nice and useful type
+ # out of which we can grab the information we need - every other node has a less informative
+ # type which omits all value information and only contains housekeeping information for the RB tree
+ # hence, we need to know if we are at a node != 0, so that we can
+ # still get at the data
+ need_to_skip = (index > 0)
+ current = iterator.advance(index)
+ if current is None:
+ logger >> "Tree is garbage - returning None"
+ self.garbage = True
+ return None
+ if self.get_data_type():
+ if not(need_to_skip):
+ current = current.Dereference()
+ obj = current.GetChildMemberWithName('__value_')
+ obj_data = obj.GetData()
+ # make sure we have a valid offset for the next items
+ self.get_value_offset(current)
+ # we do not return __value_ because then we would end up with a child named
+ # __value_ instead of [0]
+ return self.valobj.CreateValueFromData(
+ '[' + str(index) + ']', obj_data, self.data_type)
+ else:
+ # FIXME we need to have accessed item 0 before accessing
+ # any other item!
+ if self.skip_size is None:
+ logger >> "You asked for item > 0 before asking for item == 0, I will fetch 0 now then retry"
+ if self.get_child_at_index(0):
+ return self.get_child_at_index(index)
+ else:
+ logger >> "item == 0 could not be found. sorry, nothing can be done here."
+ return None
+ return current.CreateChildAtOffset(
+ '[' + str(index) + ']', self.skip_size, self.data_type)
+ else:
+ logger >> "Unable to infer data-type - returning None (should mark tree as garbage here?)"
+ return None
+ except Exception as err:
+ logger >> "Hit an exception: " + str(err)
+ return None
+
+# Just an example: the actual summary is produced by a summary string:
+# size=${svar%#}
+
+
+def stdmap_SummaryProvider(valobj, dict):
+ prov = stdmap_SynthProvider(valobj, None)
+ return 'size=' + str(prov.num_children())
+
class stddeque_SynthProvider:
+
def __init__(self, valobj, d):
logger = lldb.formatters.Logger.Logger()
logger.write("init")
@@ -592,7 +642,9 @@ class stddeque_SynthProvider:
except:
self.block_size = -1
self.element_size = -1
- logger.write("block_size=%d, element_size=%d" % (self.block_size, self.element_size))
+ logger.write(
+ "block_size=%d, element_size=%d" %
+ (self.block_size, self.element_size))
def find_block_size(self):
# in order to use the deque we must have the block size, or else
@@ -605,7 +657,7 @@ class stddeque_SynthProvider:
# static const difference_type __block_size = sizeof(value_type) < 256 ? 4096 / sizeof(value_type) : 16;
# }
if self.element_size < 256:
- self.block_size = 4096 / self.element_size
+ self.block_size = 4096 / self.element_size
else:
self.block_size = 16
@@ -619,24 +671,25 @@ class stddeque_SynthProvider:
def has_children(self):
return True
- def get_child_index(self,name):
+ def get_child_index(self, name):
logger = lldb.formatters.Logger.Logger()
try:
return int(name.lstrip('[').rstrip(']'))
except:
return -1
- def get_child_at_index(self,index):
+ def get_child_at_index(self, index):
logger = lldb.formatters.Logger.Logger()
logger.write("Fetching child " + str(index))
if index < 0 or self.count is None:
- return None;
+ return None
if index >= self.num_children():
- return None;
+ return None
try:
- i, j = divmod(self.start+index, self.block_size)
- return self.first.CreateValueFromExpression('[' + str(index) + ']',
- '*(*(%s + %d) + %d)' % (self.first.get_expr_path(), i, j))
+ i, j = divmod(self.start + index, self.block_size)
+ return self.first.CreateValueFromExpression(
+ '[' + str(index) + ']', '*(*(%s + %d) + %d)' %
+ (self.first.get_expr_path(), i, j))
except:
return None
@@ -656,23 +709,29 @@ class stddeque_SynthProvider:
# variable tells which element in this NxM array is the 0th
# one, and the 'size' element gives the number of elements
# in the deque.
- count = self.valobj.GetChildMemberWithName('__size_').GetChildMemberWithName('__first_').GetValueAsUnsigned(0)
+ count = self.valobj.GetChildMemberWithName(
+ '__size_').GetChildMemberWithName('__first_').GetValueAsUnsigned(0)
# give up now if we cant access memory reliably
if self.block_size < 0:
logger.write("block_size < 0")
return
map_ = self.valobj.GetChildMemberWithName('__map_')
- start = self.valobj.GetChildMemberWithName('__start_').GetValueAsUnsigned(0)
+ start = self.valobj.GetChildMemberWithName(
+ '__start_').GetValueAsUnsigned(0)
first = map_.GetChildMemberWithName('__first_')
map_first = first.GetValueAsUnsigned(0)
- map_begin = map_.GetChildMemberWithName('__begin_').GetValueAsUnsigned(0)
- map_end = map_.GetChildMemberWithName('__end_').GetValueAsUnsigned(0)
- map_endcap= map_.GetChildMemberWithName('__end_cap_').GetChildMemberWithName('__first_').GetValueAsUnsigned(0)
+ map_begin = map_.GetChildMemberWithName(
+ '__begin_').GetValueAsUnsigned(0)
+ map_end = map_.GetChildMemberWithName(
+ '__end_').GetValueAsUnsigned(0)
+ map_endcap = map_.GetChildMemberWithName(
+ '__end_cap_').GetChildMemberWithName('__first_').GetValueAsUnsigned(0)
# check consistency
if not map_first <= map_begin <= map_end <= map_endcap:
logger.write("map pointers are not monotonic")
return
- total_rows, junk = divmod(map_endcap - map_first, self.pointer_size)
+ total_rows, junk = divmod(
+ map_endcap - map_first, self.pointer_size)
if junk:
logger.write("endcap-first doesnt align correctly")
return
@@ -684,18 +743,21 @@ class stddeque_SynthProvider:
if junk:
logger.write("begin-first doesnt align correctly")
return
- if not start_row*self.block_size <= start < (start_row+1)*self.block_size:
+ if not start_row * \
+ self.block_size <= start < (start_row + 1) * self.block_size:
logger.write("0th element must be in the 'begin' row")
return
end_row = start_row + active_rows
if not count:
if active_rows:
logger.write("empty deque but begin!=end")
- return
- elif not (end_row-1)*self.block_size <= start+count < end_row*self.block_size:
+ return
+ elif not (end_row - 1) * self.block_size <= start + count < end_row * self.block_size:
logger.write("nth element must be before the 'end' row")
return
- logger.write("update success: count=%r, start=%r, first=%r" % (count,start,first))
+ logger.write(
+ "update success: count=%r, start=%r, first=%r" %
+ (count, start, first))
# if consistent, save all we really need:
self.count = count
self.start = start
@@ -706,7 +768,9 @@ class stddeque_SynthProvider:
self.map_first = None
self.map_begin = None
+
class stdsharedptr_SynthProvider:
+
def __init__(self, valobj, d):
logger = lldb.formatters.Logger.Logger()
logger.write("init")
@@ -725,39 +789,42 @@ class stdsharedptr_SynthProvider:
def has_children(self):
return True
- def get_child_index(self,name):
- if name=="__ptr_":
+ def get_child_index(self, name):
+ if name == "__ptr_":
return 0
- if name=="count":
+ if name == "count":
return 1
- if name=="weak_count":
+ if name == "weak_count":
return 2
return -1
- def get_child_at_index(self,index):
+ def get_child_at_index(self, index):
if index == 0:
return self.ptr
if index == 1:
- if self.cntrl == None:
+ if self.cntrl is None:
count = 0
else:
- count = 1 + self.cntrl.GetChildMemberWithName('__shared_owners_').GetValueAsSigned()
- return self.valobj.CreateValueFromData("count",
- lldb.SBData.CreateDataFromUInt64Array(self.endianness, self.pointer_size, [count]),
- self.count_type)
+ count = 1 + \
+ self.cntrl.GetChildMemberWithName('__shared_owners_').GetValueAsSigned()
+ return self.valobj.CreateValueFromData(
+ "count", lldb.SBData.CreateDataFromUInt64Array(
+ self.endianness, self.pointer_size, [count]), self.count_type)
if index == 2:
- if self.cntrl == None:
+ if self.cntrl is None:
count = 0
else:
- count = 1 + self.cntrl.GetChildMemberWithName('__shared_weak_owners_').GetValueAsSigned()
- return self.valobj.CreateValueFromData("weak_count",
- lldb.SBData.CreateDataFromUInt64Array(self.endianness, self.pointer_size, [count]),
- self.count_type)
+ count = 1 + \
+ self.cntrl.GetChildMemberWithName('__shared_weak_owners_').GetValueAsSigned()
+ return self.valobj.CreateValueFromData(
+ "weak_count", lldb.SBData.CreateDataFromUInt64Array(
+ self.endianness, self.pointer_size, [count]), self.count_type)
return None
def update(self):
logger = lldb.formatters.Logger.Logger()
- self.ptr = self.valobj.GetChildMemberWithName('__ptr_')#.Cast(self.element_ptr_type)
+ self.ptr = self.valobj.GetChildMemberWithName(
+ '__ptr_') # .Cast(self.element_ptr_type)
cntrl = self.valobj.GetChildMemberWithName('__cntrl_')
if cntrl.GetValueAsUnsigned(0):
self.cntrl = cntrl.Dereference()
@@ -765,21 +832,36 @@ class stdsharedptr_SynthProvider:
self.cntrl = None
# we can use two different categories for old and new formatters - type names are different enough that we should make no confusion
-# talking with libc++ developer: "std::__1::class_name is set in stone until we decide to change the ABI. That shouldn't happen within a 5 year time frame"
-def __lldb_init_module(debugger,dict):
- debugger.HandleCommand('type summary add -F libcxx.stdstring_SummaryProvider "std::__1::string" -w libcxx')
- debugger.HandleCommand('type summary add -F libcxx.stdstring_SummaryProvider "std::__1::basic_string<char, class std::__1::char_traits<char>, class std::__1::allocator<char> >" -w libcxx')
- debugger.HandleCommand('type synthetic add -l libcxx.stdvector_SynthProvider -x "^(std::__1::)vector<.+>$" -w libcxx')
- debugger.HandleCommand('type summary add -F libcxx.stdvector_SummaryProvider -e -x "^(std::__1::)vector<.+>$" -w libcxx')
- debugger.HandleCommand('type synthetic add -l libcxx.stdlist_SynthProvider -x "^(std::__1::)list<.+>$" -w libcxx')
- debugger.HandleCommand('type summary add -F libcxx.stdlist_SummaryProvider -e -x "^(std::__1::)list<.+>$" -w libcxx')
- debugger.HandleCommand('type synthetic add -l libcxx.stdmap_SynthProvider -x "^(std::__1::)map<.+> >$" -w libcxx')
- debugger.HandleCommand('type summary add -F libcxx.stdmap_SummaryProvider -e -x "^(std::__1::)map<.+> >$" -w libcxx')
- debugger.HandleCommand("type category enable libcxx")
- debugger.HandleCommand('type synthetic add -l libcxx.stddeque_SynthProvider -x "^(std::__1::)deque<.+>$" -w libcxx')
- debugger.HandleCommand('type synthetic add -l libcxx.stdsharedptr_SynthProvider -x "^(std::__1::)shared_ptr<.+>$" -w libcxx')
- # turns out the structs look the same, so weak_ptr can be handled the same!
- debugger.HandleCommand('type synthetic add -l libcxx.stdsharedptr_SynthProvider -x "^(std::__1::)weak_ptr<.+>$" -w libcxx')
+# talking with libc++ developer: "std::__1::class_name is set in stone
+# until we decide to change the ABI. That shouldn't happen within a 5 year
+# time frame"
+
+
+def __lldb_init_module(debugger, dict):
+ debugger.HandleCommand(
+ 'type summary add -F libcxx.stdstring_SummaryProvider "std::__1::string" -w libcxx')
+ debugger.HandleCommand(
+ 'type summary add -F libcxx.stdstring_SummaryProvider "std::__1::basic_string<char, class std::__1::char_traits<char>, class std::__1::allocator<char> >" -w libcxx')
+ debugger.HandleCommand(
+ 'type synthetic add -l libcxx.stdvector_SynthProvider -x "^(std::__1::)vector<.+>$" -w libcxx')
+ debugger.HandleCommand(
+ 'type summary add -F libcxx.stdvector_SummaryProvider -e -x "^(std::__1::)vector<.+>$" -w libcxx')
+ debugger.HandleCommand(
+ 'type synthetic add -l libcxx.stdlist_SynthProvider -x "^(std::__1::)list<.+>$" -w libcxx')
+ debugger.HandleCommand(
+ 'type summary add -F libcxx.stdlist_SummaryProvider -e -x "^(std::__1::)list<.+>$" -w libcxx')
+ debugger.HandleCommand(
+ 'type synthetic add -l libcxx.stdmap_SynthProvider -x "^(std::__1::)map<.+> >$" -w libcxx')
+ debugger.HandleCommand(
+ 'type summary add -F libcxx.stdmap_SummaryProvider -e -x "^(std::__1::)map<.+> >$" -w libcxx')
+ debugger.HandleCommand("type category enable libcxx")
+ debugger.HandleCommand(
+ 'type synthetic add -l libcxx.stddeque_SynthProvider -x "^(std::__1::)deque<.+>$" -w libcxx')
+ debugger.HandleCommand(
+ 'type synthetic add -l libcxx.stdsharedptr_SynthProvider -x "^(std::__1::)shared_ptr<.+>$" -w libcxx')
+ # turns out the structs look the same, so weak_ptr can be handled the same!
+ debugger.HandleCommand(
+ 'type synthetic add -l libcxx.stdsharedptr_SynthProvider -x "^(std::__1::)weak_ptr<.+>$" -w libcxx')
_map_capping_size = 255
_list_capping_size = 255