1#!/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 261