1 | """lldb data formatters for clang classes. |
2 | |
3 | Usage |
4 | -- |
5 | import this file in your ~/.lldbinit by adding this line: |
6 | |
7 | command script import /path/to/ClangDataFormat.py |
8 | |
9 | After that, instead of getting this: |
10 | |
11 | (lldb) p Tok.Loc |
12 | (clang::SourceLocation) $0 = { |
13 | (unsigned int) ID = 123582 |
14 | } |
15 | |
16 | you'll get: |
17 | |
18 | (lldb) p Tok.Loc |
19 | (clang::SourceLocation) $4 = "/usr/include/i386/_types.h:37:1" (offset: 123582, file, local) |
20 | """ |
21 | |
22 | import lldb |
23 | |
24 | def __lldb_init_module(debugger, internal_dict): |
25 | debugger.HandleCommand("type summary add -F ClangDataFormat.SourceLocation_summary clang::SourceLocation") |
26 | debugger.HandleCommand("type summary add -F ClangDataFormat.QualType_summary clang::QualType") |
27 | debugger.HandleCommand("type summary add -F ClangDataFormat.StringRef_summary llvm::StringRef") |
28 | |
29 | def SourceLocation_summary(srcloc, internal_dict): |
30 | return SourceLocation(srcloc).summary() |
31 | |
32 | def QualType_summary(qualty, internal_dict): |
33 | return QualType(qualty).summary() |
34 | |
35 | def StringRef_summary(strref, internal_dict): |
36 | return StringRef(strref).summary() |
37 | |
38 | class SourceLocation(object): |
39 | def __init__(self, srcloc): |
40 | self.srcloc = srcloc |
41 | self.ID = srcloc.GetChildAtIndex(0).GetValueAsUnsigned() |
42 | self.frame = srcloc.GetFrame() |
43 | |
44 | def offset(self): |
45 | return getValueFromExpression(self.srcloc, ".getOffset()").GetValueAsUnsigned() |
46 | |
47 | def isInvalid(self): |
48 | return self.ID == 0 |
49 | |
50 | def isMacro(self): |
51 | return getValueFromExpression(self.srcloc, ".isMacroID()").GetValueAsUnsigned() |
52 | |
53 | def isLocal(self, srcmgr_path): |
54 | return self.frame.EvaluateExpression("(%s).isLocalSourceLocation(%s)" % (srcmgr_path, getExpressionPath(self.srcloc))).GetValueAsUnsigned() |
55 | |
56 | def getPrint(self, srcmgr_path): |
57 | print_str = getValueFromExpression(self.srcloc, ".printToString(%s)" % srcmgr_path) |
58 | return print_str.GetSummary() |
59 | |
60 | def summary(self): |
61 | if self.isInvalid(): |
62 | return "<invalid loc>" |
63 | srcmgr_path = findObjectExpressionPath("clang::SourceManager", self.frame) |
64 | if srcmgr_path: |
65 | return "%s (offset: %d, %s, %s)" % (self.getPrint(srcmgr_path), self.offset(), "macro" if self.isMacro() else "file", "local" if self.isLocal(srcmgr_path) else "loaded") |
66 | return "(offset: %d, %s)" % (self.offset(), "macro" if self.isMacro() else "file") |
67 | |
68 | class QualType(object): |
69 | def __init__(self, qualty): |
70 | self.qualty = qualty |
71 | |
72 | def getAsString(self): |
73 | std_str = getValueFromExpression(self.qualty, ".getAsString()") |
74 | return std_str.GetSummary() |
75 | |
76 | def summary(self): |
77 | desc = self.getAsString() |
78 | if desc == '"NULL TYPE"': |
79 | return "<NULL TYPE>" |
80 | return desc |
81 | |
82 | class StringRef(object): |
83 | def __init__(self, strref): |
84 | self.strref = strref |
85 | self.Data_value = strref.GetChildAtIndex(0) |
86 | self.Length = strref.GetChildAtIndex(1).GetValueAsUnsigned() |
87 | |
88 | def summary(self): |
89 | if self.Length == 0: |
90 | return '""' |
91 | data = self.Data_value.GetPointeeData(0, self.Length) |
92 | error = lldb.SBError() |
93 | string = data.ReadRawData(error, 0, data.GetByteSize()) |
94 | if error.Fail(): |
95 | return None |
96 | return '"%s"' % string |
97 | |
98 | |
99 | # Key is a (function address, type name) tuple, value is the expression path for |
100 | # an object with such a type name from inside that function. |
101 | FramePathMapCache = {} |
102 | |
103 | def findObjectExpressionPath(typename, frame): |
104 | func_addr = frame.GetFunction().GetStartAddress().GetFileAddress() |
105 | key = (func_addr, typename) |
106 | try: |
107 | return FramePathMapCache[key] |
108 | except KeyError: |
109 | #print "CACHE MISS" |
110 | path = None |
111 | obj = findObject(typename, frame) |
112 | if obj: |
113 | path = getExpressionPath(obj) |
114 | FramePathMapCache[key] = path |
115 | return path |
116 | |
117 | def findObject(typename, frame): |
118 | def getTypename(value): |
119 | # FIXME: lldb should provide something like getBaseType |
120 | ty = value.GetType() |
121 | if ty.IsPointerType() or ty.IsReferenceType(): |
122 | return ty.GetPointeeType().GetName() |
123 | return ty.GetName() |
124 | |
125 | def searchForType(value, searched): |
126 | tyname = getTypename(value) |
127 | #print "SEARCH:", getExpressionPath(value), value.GetType().GetName() |
128 | if tyname == typename: |
129 | return value |
130 | ty = value.GetType() |
131 | if not (ty.IsPointerType() or |
132 | ty.IsReferenceType() or |
133 | # FIXME: lldb should provide something like getCanonicalType |
134 | tyname.startswith("llvm::IntrusiveRefCntPtr<") or |
135 | tyname.startswith("llvm::OwningPtr<")): |
136 | return None |
137 | # FIXME: Hashing for SBTypes does not seem to work correctly, uses the typename instead, |
138 | # and not the canonical one unfortunately. |
139 | if tyname in searched: |
140 | return None |
141 | searched.add(tyname) |
142 | for i in range(value.GetNumChildren()): |
143 | child = value.GetChildAtIndex(i, 0, False) |
144 | found = searchForType(child, searched) |
145 | if found: |
146 | return found |
147 | |
148 | searched = set() |
149 | value_list = frame.GetVariables(True, True, True, True) |
150 | for val in value_list: |
151 | found = searchForType(val, searched) |
152 | if found: |
153 | return found if not found.TypeIsPointerType() else found.Dereference() |
154 | |
155 | def getValueFromExpression(val, expr): |
156 | return val.GetFrame().EvaluateExpression(getExpressionPath(val) + expr) |
157 | |
158 | def getExpressionPath(val): |
159 | stream = lldb.SBStream() |
160 | val.GetExpressionPath(stream) |
161 | return stream.GetData() |
162 | |