1"""
2LLDB Formatters for LLVM data types.
3
4Load into LLDB with 'command script import /path/to/lldbDataFormatters.py'
5"""
6
7def __lldb_init_module(debugger, internal_dict):
8    debugger.HandleCommand('type category define -e llvm -l c++')
9    debugger.HandleCommand('type synthetic add -w llvm '
10                           '-l lldbDataFormatters.SmallVectorSynthProvider '
11                           '-x "^llvm::SmallVectorImpl<.+>$"')
12    debugger.HandleCommand('type synthetic add -w llvm '
13                           '-l lldbDataFormatters.SmallVectorSynthProvider '
14                           '-x "^llvm::SmallVector<.+,.+>$"')
15    debugger.HandleCommand('type synthetic add -w llvm '
16                           '-l lldbDataFormatters.ArrayRefSynthProvider '
17                           '-x "^llvm::ArrayRef<.+>$"')
18    debugger.HandleCommand('type summary add -w llvm '
19                           '-F lldbDataFormatters.OptionalSummaryProvider '
20                           '-x "^llvm::Optional<.+>$"')
21    debugger.HandleCommand('type summary add -w llvm '
22                           '-F lldbDataFormatters.SmallStringSummaryProvider '
23                           '-x "^llvm::SmallString<.+>$"')
24    debugger.HandleCommand('type summary add -w llvm '
25                           '-F lldbDataFormatters.StringRefSummaryProvider '
26                           '-x "^llvm::StringRef$"')
27    debugger.HandleCommand('type summary add -w llvm '
28                           '-F lldbDataFormatters.ConstStringSummaryProvider '
29                           '-x "^lldb_private::ConstString$"')
30
31# Pretty printer for llvm::SmallVector/llvm::SmallVectorImpl
32class SmallVectorSynthProvider:
33    def __init__(self, valobj, dict):
34        self.valobj = valobj;
35        self.update() # initialize this provider
36
37    def num_children(self):
38        return self.size.GetValueAsUnsigned(0)
39
40    def get_child_index(self, name):
41        try:
42            return int(name.lstrip('[').rstrip(']'))
43        except:
44            return -1;
45
46    def get_child_at_index(self, index):
47        # Do bounds checking.
48        if index < 0:
49            return None
50        if index >= self.num_children():
51            return None;
52
53        offset = index * self.type_size
54        return self.begin.CreateChildAtOffset('['+str(index)+']',
55                                              offset, self.data_type)
56
57    def update(self):
58        self.begin = self.valobj.GetChildMemberWithName('BeginX')
59        self.size = self.valobj.GetChildMemberWithName('Size')
60        the_type = self.valobj.GetType()
61        # If this is a reference type we have to dereference it to get to the
62        # template parameter.
63        if the_type.IsReferenceType():
64            the_type = the_type.GetDereferencedType()
65
66        self.data_type = the_type.GetTemplateArgumentType(0)
67        self.type_size = self.data_type.GetByteSize()
68        assert self.type_size != 0
69
70class ArrayRefSynthProvider:
71    """ Provider for llvm::ArrayRef """
72    def __init__(self, valobj, dict):
73        self.valobj = valobj;
74        self.update() # initialize this provider
75
76    def num_children(self):
77        return self.length
78
79    def get_child_index(self, name):
80        try:
81            return int(name.lstrip('[').rstrip(']'))
82        except:
83            return -1;
84
85    def get_child_at_index(self, index):
86        if index < 0 or index >= self.num_children():
87            return None;
88        offset = index * self.type_size
89        return self.data.CreateChildAtOffset('[' + str(index) + ']',
90                                             offset, self.data_type)
91
92    def update(self):
93        self.data = self.valobj.GetChildMemberWithName('Data')
94        length_obj = self.valobj.GetChildMemberWithName('Length')
95        self.length = length_obj.GetValueAsUnsigned(0)
96        self.data_type = self.data.GetType().GetPointeeType()
97        self.type_size = self.data_type.GetByteSize()
98        assert self.type_size != 0
99
100def OptionalSummaryProvider(valobj, internal_dict):
101    storage = valobj.GetChildMemberWithName('Storage')
102    if not storage:
103        storage = valobj
104
105    failure = 2
106    hasVal = storage.GetChildMemberWithName('hasVal').GetValueAsUnsigned(failure)
107    if hasVal == failure:
108        return '<could not read llvm::Optional>'
109
110    if hasVal == 0:
111        return 'None'
112
113    underlying_type = storage.GetType().GetTemplateArgumentType(0)
114    storage = storage.GetChildMemberWithName('storage')
115    return str(storage.Cast(underlying_type))
116
117def SmallStringSummaryProvider(valobj, internal_dict):
118    num_elements = valobj.GetNumChildren()
119    res = "\""
120    for i in range(0, num_elements):
121        c = valobj.GetChildAtIndex(i).GetValue()
122        if c:
123            res += c.strip("'")
124    res += "\""
125    return res
126
127def StringRefSummaryProvider(valobj, internal_dict):
128    if valobj.GetNumChildren() == 2:
129        # StringRef's are also used to point at binary blobs in memory,
130        # so filter out suspiciously long strings.
131        max_length = 256
132        length = valobj.GetChildAtIndex(1).GetValueAsUnsigned(max_length)
133        if length == 0:
134            return "NULL"
135        if length < max_length:
136            return valobj.GetChildAtIndex(0).GetSummary()
137    return ""
138
139def ConstStringSummaryProvider(valobj, internal_dict):
140    if valobj.GetNumChildren() == 1:
141        return valobj.GetChildAtIndex(0).GetSummary()
142    return ""
143