blob: 6c4dabb24a363420781cc41a77434a164f028f8e [file] [log] [blame]
Greg Clayton994ba642014-09-22 22:06:41 +00001#!/usr/bin/python
2
3import lldb
4import shlex
5import sys
6from Tkinter import *
7import ttk
8
9def get_item_dictionary_for_sbvalue(v, include_typename):
10 '''Given an lldb.SBValue, create an item dictionary for that value and return it
11
12 The dictionary must have the following key/value pairs:
13 'values' - must be a list of string values for each column defined in self.get_column_definitions()
14 'children' - a boolean value that indicates if an item has children or not
15 '''
16 name = v.name
17 if name is None:
18 name = ''
19 if include_typename:
20 typename = v.type
21 if typename is None:
22 typename = ''
23 value = v.value
24 if value is None:
25 value = ''
26 summary = v.summary
27 if summary is None:
28 summary = ''
29 if include_typename:
30 return { 'values' : [name, typename, value, summary],
31 'children' : v.MightHaveChildren(),
32 'type' : 'SBValue',
33 'object' : v }
34 else:
35 return { 'values' : [name, value, summary],
36 'children' : v.MightHaveChildren(),
37 'type' : 'SBValue',
38 'object' : v }
39
40
41def get_item_dictionary_for_process(process):
42 id = process.GetProcessID()
43 num_threads = process.GetNumThreads()
44 value = str(process.GetProcessID())
45 summary = process.target.executable.fullpath
46 return { 'values' : ['process', value, summary],
47 'children' : num_threads > 0,
48 'type' : 'SBProcess',
49 'object' : process }
50
51def get_item_dictionary_for_thread(thread):
52 num_frames = thread.GetNumFrames()
53 value = '0x%x' % (thread.GetThreadID())
54 summary = '%u frames' % (num_frames)
55 return { 'values' : ['thread #%u' % (thread.GetIndexID()), value, summary],
56 'children' : num_frames > 0,
57 'type' : 'SBThread',
58 'object' : thread }
59
60def get_item_dictionary_for_frame(frame):
61 id = frame.GetFrameID()
62 value = '0x%16.16x' % (frame.GetPC())
63 stream = lldb.SBStream()
64 frame.GetDescription(stream)
65 summary = stream.GetData().split("`")[1]
66 return { 'values' : ['frame #%u' % (id), value, summary],
67 'children' : frame.GetVariables(True, True, True, True).GetSize() > 0,
68 'type' : 'SBFrame',
69 'object' : frame }
70
71class ProcessTreeDelegate(object):
72 def __init__(self, process):
73 self.process = process
74
75 def get_column_definitions(self):
76 '''Return an array of column definition dictionaries'''
77 return [{ 'id' : '#0' , 'text' : 'Name' , 'anchor' : W , 'stretch' : 0 },
78 { 'id' : 'value' , 'text' : 'Value' , 'anchor' : W , 'stretch' : 0 },
79 { 'id' : 'summary', 'text' : 'Summary', 'anchor' : W , 'stretch' : 1 }]
80
81 def get_item_dictionary(self, sbvalue):
82 '''Given an lldb.SBValue, create an item dictionary for that value and return it
83
84 The dictionary must have the following key/value pairs:
85 'values' - must be a list of string values for each column defined in self.get_column_definitions()
86 'children' - a boolean value that indicates if an item has children or not
87 '''
88
89 def get_child_item_dictionaries(self, parent_item_dict):
90 '''Given an lldb.SBValue, create an item dictionary for that value and return it'''
91 item_dicts = list()
92 if parent_item_dict is None:
93 # Create root items if parent_item_dict is None
94 item_dicts.append(get_item_dictionary_for_process(self.process))
95 else:
96 # Get children for a specified item given its item dictionary
97 item_type = parent_item_dict['type']
98 if item_type == 'SBProcess':
99 for thread in parent_item_dict['object']:
100 item_dicts.append(get_item_dictionary_for_thread(thread))
101 elif item_type == 'SBThread':
102 for frame in parent_item_dict['object']:
103 item_dicts.append(get_item_dictionary_for_frame(frame))
104 elif item_type == 'SBFrame':
105 frame = parent_item_dict['object']
106 variables = frame.GetVariables(True, True, True, True)
107 n = variables.GetSize()
108 for i in range(n):
109 item_dicts.append(get_item_dictionary_for_sbvalue(variables[i], False))
110 elif item_type == 'SBValue':
111 sbvalue = parent_item_dict['object']
112 if sbvalue.IsValid():
113 for i in range(sbvalue.num_children):
114 item_dicts.append(get_item_dictionary_for_sbvalue(sbvalue.GetChildAtIndex(i), False))
115 return item_dicts
116
117class VariableTreeDelegate(object):
118 def __init__(self, frame):
119 self.frame = frame
120
121 def get_column_definitions(self):
122 '''Return an array of column definition dictionaries'''
123 return [{ 'id' : '#0' , 'text' : 'Name' , 'anchor' : W , 'stretch' : 0 },
124 { 'id' : 'type' , 'text' : 'Type' , 'anchor' : W , 'stretch' : 0 },
125 { 'id' : 'value' , 'text' : 'Value' , 'anchor' : W , 'stretch' : 0 },
126 { 'id' : 'summary', 'text' : 'Summary', 'anchor' : W , 'stretch' : 1 }]
127
128 def get_child_item_dictionaries(self, parent_item_dict):
129 '''Given an lldb.SBValue, create an item dictionary for that value and return it'''
130 item_dicts = list()
131 if parent_item_dict is None:
132 # Create root items if parent_item_dict is None
133 variables = self.frame.GetVariables(True, True, True, True)
134 n = variables.GetSize()
135 for i in range(n):
136 item_dicts.append(get_item_dictionary_for_sbvalue(variables[i], True))
137 else:
138 # Get children for a specified item given its item dictionary
139 sbvalue = parent_item_dict['object']
140 if sbvalue.IsValid():
141 for i in range(sbvalue.num_children):
142 item_dicts.append(get_item_dictionary_for_sbvalue(sbvalue.GetChildAtIndex(i), True))
143 return item_dicts
144
145class DelegateTree(ttk.Frame):
146
147 def __init__(self, delegate, title, name):
148 ttk.Frame.__init__(self, name=name)
149 self.pack(expand=Y, fill=BOTH)
150 self.master.title(title)
151 self.delegate = delegate
152 self.item_id_to_item_dict = dict()
153 frame = Frame(self)
154 frame.pack(side=TOP, fill=BOTH, expand=Y)
155 self._create_treeview(frame)
156 self._populate_root()
157
158 def _create_treeview(self, parent):
159 frame = ttk.Frame(parent)
160 frame.pack(side=TOP, fill=BOTH, expand=Y)
161
162 columns_dicts = self.delegate.get_column_definitions()
163 column_ids = list()
164 for i in range(1,len(columns_dicts)):
165 column_ids.append(columns_dicts[i]['id'])
166 # create the tree and scrollbars
167 self.tree = ttk.Treeview(columns=column_ids)
168
169 scroll_bar_v = ttk.Scrollbar(orient=VERTICAL, command= self.tree.yview)
170 scroll_bar_h = ttk.Scrollbar(orient=HORIZONTAL, command= self.tree.xview)
171 self.tree['yscroll'] = scroll_bar_v.set
172 self.tree['xscroll'] = scroll_bar_h.set
173
174 # setup column headings and columns properties
175 for columns_dict in columns_dicts:
176 self.tree.heading(columns_dict['id'], text=columns_dict['text'], anchor=columns_dict['anchor'])
177 self.tree.column(columns_dict['id'], stretch=columns_dict['stretch'])
178
179 # add tree and scrollbars to frame
180 self.tree.grid(in_=frame, row=0, column=0, sticky=NSEW)
181 scroll_bar_v.grid(in_=frame, row=0, column=1, sticky=NS)
182 scroll_bar_h.grid(in_=frame, row=1, column=0, sticky=EW)
183
184 # set frame resizing priorities
185 frame.rowconfigure(0, weight=1)
186 frame.columnconfigure(0, weight=1)
187
188 # action to perform when a node is expanded
189 self.tree.bind('<<TreeviewOpen>>', self._update_tree)
190
191 def insert_items(self, parent_id, item_dicts):
192 for item_dict in item_dicts:
193 values = item_dict['values']
194 item_id = self.tree.insert (parent_id, # root item has an empty name
195 END,
196 text=values[0],
197 values=values[1:])
198 self.item_id_to_item_dict[item_id] = item_dict
199 if item_dict['children']:
200 self.tree.insert(item_id, END, text='dummy')
201
202 def _populate_root(self):
203 # use current directory as root node
204 self.insert_items('', self.delegate.get_child_item_dictionaries(None))
205
206 def _update_tree(self, event):
207 # user expanded a node - build the related directory
208 item_id = self.tree.focus() # the id of the expanded node
209 children = self.tree.get_children (item_id)
210 if len(children):
211 first_child = children[0]
212 # if the node only has a 'dummy' child, remove it and
213 # build new directory; skip if the node is already
214 # populated
215 if self.tree.item(first_child, option='text') == 'dummy':
216 self.tree.delete(first_child)
217 item_dicts = self.delegate.get_child_item_dictionaries(self.item_id_to_item_dict[item_id])
218 self.insert_items(item_id, item_dicts)
219
220@lldb.command("tk-variables")
221def tk_variable_display(debugger, command, result, dict):
222 sys.argv = ['tk-variables'] # needed for tree creation in TK library as it uses sys.argv...
223 target = debugger.GetSelectedTarget()
224 if not target:
225 print >>result, "invalid target"
226 return
227 process = target.GetProcess()
228 if not process:
229 print >>result, "invalid process"
230 return
231 thread = process.GetSelectedThread()
232 if not thread:
233 print >>result, "invalid thread"
234 return
235 frame = thread.GetSelectedFrame()
236 if not frame:
237 print >>result, "invalid frame"
238 return
239 # Parse command line args
240 command_args = shlex.split(command)
241
242 tree = DelegateTree(VariableTreeDelegate(frame), 'Variables', 'lldb-tk-variables')
243 tree.mainloop()
244
245@lldb.command("tk-process")
246def tk_process_display(debugger, command, result, dict):
247 sys.argv = ['tk-process'] # needed for tree creation in TK library as it uses sys.argv...
248 target = debugger.GetSelectedTarget()
249 if not target:
250 print >>result, "invalid target"
251 return
252 process = target.GetProcess()
253 if not process:
254 print >>result, "invalid process"
255 return
256 # Parse command line args
257 command_args = shlex.split(command)
258 tree = DelegateTree(ProcessTreeDelegate(process), 'Process', 'lldb-tk-process')
259 tree.mainloop()
260