Last active
February 5, 2019 16:49
-
-
Save oliora/dc895d01389205b20a45c1f9045f26da to your computer and use it in GitHub Desktop.
Extra LLVM formatters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Extra LLDB Formatters | |
Contains formatters for: | |
- `llvm::SmallVector` - https://llvm.org/doxygen/classllvm_1_1SmallVector.html | |
- `boost::container::flat_map` - https://www.boost.org/doc/libs/1_69_0/doc/html/boost/container/flat_map.html | |
- `boost::optional` - https://www.boost.org/doc/libs/1_69_0/libs/optional/doc/html/index.html | |
- `mpark::variant` - https://github.com/mpark/variant | |
Load into LLDB with `command script import /path/to/extra-formatters.py` | |
or add this command to `~/.lldbinit` | |
Links: | |
- https://lldb.llvm.org/varformats.html | |
- https://github.com/llvm/llvm-project/tree/master/lldb/examples | |
- https://github.com/llvm/llvm-project/blob/master/llvm/utils/lldbDataFormatters.py | |
""" | |
def __lldb_init_module(debugger, internal_dict): | |
debugger.HandleCommand('type category define -e oliora -l c++') | |
debugger.HandleCommand('type synthetic add -w oliora -l extra_formatters.LlvmSmallVectorSynthProvider -x "^llvm::SmallVectorImpl<.+>$"') | |
debugger.HandleCommand('type summary add --expand -x "^llvm::SmallVectorImpl<.+>$" --summary-string "${svar%#} items') | |
debugger.HandleCommand('type synthetic add -w oliora -l extra_formatters.LlvmSmallVectorSynthProvider -x "^llvm::SmallVector<.+,.+>$"') | |
debugger.HandleCommand('type summary add --expand -x "^llvm::SmallVector<.+,.+>$" --summary-string "${svar%#} items') | |
debugger.HandleCommand('type synthetic add -w oliora -l extra_formatters.BoostFlatMapSynthProvider -x "^boost::container::flat_map<.+>$"') | |
debugger.HandleCommand('type summary add --expand -x "^boost::container::flat_map<.+>$" --summary-string "${svar%#} items') | |
debugger.HandleCommand('type synthetic add -w oliora -l extra_formatters.BoostOptionalSynthProvider -x "^boost::optional<.+>$"') | |
debugger.HandleCommand('type summary add --inline-children -w oliora -x "^boost::optional<.+>$"') | |
debugger.HandleCommand('type synthetic add -w oliora -l extra_formatters.MparkVariantSynthProvider -x "^mpark::variant<.+>$"') | |
debugger.HandleCommand('type summary add --inline-children -w oliora -x "^mpark::variant<.+>$"') | |
class LlvmSmallVectorSynthProvider: | |
def __init__(self, valobj, dict): | |
self.valobj = valobj; | |
self.update() | |
def num_children(self): | |
begin = self.begin.GetValueAsUnsigned(0) | |
end = self.end.GetValueAsUnsigned(0) | |
if (begin >= end) or not begin or not end or not self.type_size: | |
return 0; | |
distance = end - begin | |
if distance % self.type_size: | |
return 0 | |
return distance / self.type_size | |
def get_child_index(self, name): | |
try: | |
return int(name.lstrip('[').rstrip(']')) | |
except: | |
return -1; | |
def get_child_at_index(self, index): | |
if index < 0 or index >= self.num_children(): | |
return None; | |
offset = index * self.type_size | |
return self.begin.CreateChildAtOffset('['+str(index)+']', offset, self.value_type) | |
def update(self): | |
self.begin = self.valobj.GetChildMemberWithName('BeginX') | |
self.end = self.valobj.GetChildMemberWithName('EndX') | |
the_type = self.valobj.GetType() | |
if the_type.IsReferenceType(): | |
the_type = the_type.GetDereferencedType() | |
self.value_type = the_type.GetTemplateArgumentType(0) | |
self.type_size = self.value_type.GetByteSize() | |
# TODO: also show comparator | |
class BoostFlatMapSynthProvider: | |
def __init__(self, valobj, dict): | |
self.valobj = valobj; | |
self.update() | |
def num_children(self): | |
if self.size < 0: | |
return 0 | |
return self.size.GetValueAsUnsigned(0) | |
def get_child_index(self, name): | |
try: | |
return int(name.lstrip('[').rstrip(']')) | |
except: | |
return -1; | |
def get_child_at_index(self, index): | |
if index < 0 or index >= self.num_children(): | |
return None; | |
offset = index * self.type_size | |
return self.data.CreateChildAtOffset('['+str(index)+']', offset, self.value_type) | |
def update(self): | |
boost_vector = self.valobj.GetChildMemberWithName('m_flat_tree').GetChildMemberWithName('m_data').GetChildMemberWithName('m_seq') | |
holder = boost_vector.GetChildMemberWithName('m_holder') | |
self.data = holder.GetChildMemberWithName('m_start') | |
self.size = holder.GetChildMemberWithName('m_size') | |
the_type = boost_vector.GetType() | |
if the_type.IsReferenceType(): | |
the_type = the_type.GetDereferencedType() | |
self.value_type = the_type.GetTemplateArgumentType(0) | |
self.type_size = self.value_type.GetByteSize() | |
class BoostOptionalSynthProvider: | |
def __init__(self, valobj, dict): | |
self.valobj = valobj; | |
self.update() | |
def num_children(self): | |
return 1 | |
def get_child_index(self, name): | |
try: | |
return int(name.lstrip('[').rstrip(']')) | |
except: | |
return -1; | |
def get_child_at_index(self, index): | |
num_children = 1 if self.initialized.GetValueAsUnsigned() == 1 else 0 | |
if index < 0 or index >= num_children: | |
return None; | |
return self.storage.CreateChildAtOffset('value_', 0, self.value_type) | |
def update(self): | |
self.initialized = self.valobj.GetChildMemberWithName('m_initialized') | |
the_type = self.valobj.GetType() | |
if the_type.IsReferenceType(): | |
the_type = self.the_type.GetDereferencedType() | |
self.value_type = the_type.GetTemplateArgumentType(0) | |
self.storage = self.valobj.GetChildMemberWithName('m_storage').GetChildMemberWithName('dummy_') | |
def get_recursive_union_types(union_type): | |
while True: | |
head = union_type.GetChildMemberWithName('head_') | |
if not head.IsValid(): | |
return | |
yield head.GetType().GetTemplateArgumentType(1) | |
union_type = union_type.GetChildMemberWithName('tail_') | |
class MparkVariantSynthProvider: | |
def __init__(self, valobj, dict): | |
self.valobj = valobj; | |
self.update() | |
def num_children(self): | |
return 2 | |
def get_child_index(self, name): | |
try: | |
return int(name.lstrip('[').rstrip(']')) | |
except: | |
return -1; | |
def get_child_at_index(self, index): | |
if index == 0: | |
return self.index | |
elif index == 1: | |
index = self.index.GetValueAsSigned() | |
if index < 0: | |
return None | |
value_type = self.types[index] | |
return self.storage.Cast(value_type) | |
else: | |
return None | |
def update(self): | |
impl = self.valobj.GetChildMemberWithName('impl_') | |
self.index = impl.GetChildMemberWithName('index_') | |
self.storage = impl.GetChildMemberWithName('data_') | |
self.types = list(t for t in get_recursive_union_types(self.storage)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment