[Lldb-commits] [lldb] r218279 - Played around with TK UI a bit this weekend.
Greg Clayton
gclayton at apple.com
Mon Sep 22 15:06:42 PDT 2014
Author: gclayton
Date: Mon Sep 22 17:06:41 2014
New Revision: 218279
URL: http://llvm.org/viewvc/llvm-project?rev=218279&view=rev
Log:
Played around with TK UI a bit this weekend.
If you "command script import" this file, then you will have two new commands:
(lldb) tk-variables
(lldb) tk-process
Not sure how this will work on all other systems, but on MacOSX, you will get a window with a tree view that allows you to inspect your local variables by expanding variables to see the child values.
The "tk-process" allows you to inspect the currently selected process by expanding the process to see the threads, the threads to see the frames, and the frames to see the variables. Very handy if you want to view variables for all frames simultaneously.
Added:
lldb/trunk/examples/python/lldbtk.py
Added: lldb/trunk/examples/python/lldbtk.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/examples/python/lldbtk.py?rev=218279&view=auto
==============================================================================
--- lldb/trunk/examples/python/lldbtk.py (added)
+++ lldb/trunk/examples/python/lldbtk.py Mon Sep 22 17:06:41 2014
@@ -0,0 +1,260 @@
+#!/usr/bin/python
+
+import lldb
+import shlex
+import sys
+from Tkinter import *
+import ttk
+
+def get_item_dictionary_for_sbvalue(v, include_typename):
+ '''Given an lldb.SBValue, create an item dictionary for that value and return it
+
+ The dictionary must have the following key/value pairs:
+ 'values' - must be a list of string values for each column defined in self.get_column_definitions()
+ 'children' - a boolean value that indicates if an item has children or not
+ '''
+ name = v.name
+ if name is None:
+ name = ''
+ if include_typename:
+ typename = v.type
+ if typename is None:
+ typename = ''
+ value = v.value
+ if value is None:
+ value = ''
+ summary = v.summary
+ if summary is None:
+ summary = ''
+ if include_typename:
+ return { 'values' : [name, typename, value, summary],
+ 'children' : v.MightHaveChildren(),
+ 'type' : 'SBValue',
+ 'object' : v }
+ else:
+ return { 'values' : [name, value, summary],
+ 'children' : v.MightHaveChildren(),
+ 'type' : 'SBValue',
+ 'object' : v }
+
+
+def get_item_dictionary_for_process(process):
+ id = process.GetProcessID()
+ num_threads = process.GetNumThreads()
+ value = str(process.GetProcessID())
+ summary = process.target.executable.fullpath
+ return { 'values' : ['process', value, summary],
+ 'children' : num_threads > 0,
+ 'type' : 'SBProcess',
+ 'object' : process }
+
+def get_item_dictionary_for_thread(thread):
+ num_frames = thread.GetNumFrames()
+ value = '0x%x' % (thread.GetThreadID())
+ summary = '%u frames' % (num_frames)
+ return { 'values' : ['thread #%u' % (thread.GetIndexID()), value, summary],
+ 'children' : num_frames > 0,
+ 'type' : 'SBThread',
+ 'object' : thread }
+
+def get_item_dictionary_for_frame(frame):
+ id = frame.GetFrameID()
+ value = '0x%16.16x' % (frame.GetPC())
+ stream = lldb.SBStream()
+ frame.GetDescription(stream)
+ summary = stream.GetData().split("`")[1]
+ return { 'values' : ['frame #%u' % (id), value, summary],
+ 'children' : frame.GetVariables(True, True, True, True).GetSize() > 0,
+ 'type' : 'SBFrame',
+ 'object' : frame }
+
+class ProcessTreeDelegate(object):
+ def __init__(self, process):
+ self.process = process
+
+ def get_column_definitions(self):
+ '''Return an array of column definition dictionaries'''
+ return [{ 'id' : '#0' , 'text' : 'Name' , 'anchor' : W , 'stretch' : 0 },
+ { 'id' : 'value' , 'text' : 'Value' , 'anchor' : W , 'stretch' : 0 },
+ { 'id' : 'summary', 'text' : 'Summary', 'anchor' : W , 'stretch' : 1 }]
+
+ def get_item_dictionary(self, sbvalue):
+ '''Given an lldb.SBValue, create an item dictionary for that value and return it
+
+ The dictionary must have the following key/value pairs:
+ 'values' - must be a list of string values for each column defined in self.get_column_definitions()
+ 'children' - a boolean value that indicates if an item has children or not
+ '''
+
+ def get_child_item_dictionaries(self, parent_item_dict):
+ '''Given an lldb.SBValue, create an item dictionary for that value and return it'''
+ item_dicts = list()
+ if parent_item_dict is None:
+ # Create root items if parent_item_dict is None
+ item_dicts.append(get_item_dictionary_for_process(self.process))
+ else:
+ # Get children for a specified item given its item dictionary
+ item_type = parent_item_dict['type']
+ if item_type == 'SBProcess':
+ for thread in parent_item_dict['object']:
+ item_dicts.append(get_item_dictionary_for_thread(thread))
+ elif item_type == 'SBThread':
+ for frame in parent_item_dict['object']:
+ item_dicts.append(get_item_dictionary_for_frame(frame))
+ elif item_type == 'SBFrame':
+ frame = parent_item_dict['object']
+ variables = frame.GetVariables(True, True, True, True)
+ n = variables.GetSize()
+ for i in range(n):
+ item_dicts.append(get_item_dictionary_for_sbvalue(variables[i], False))
+ elif item_type == 'SBValue':
+ sbvalue = parent_item_dict['object']
+ if sbvalue.IsValid():
+ for i in range(sbvalue.num_children):
+ item_dicts.append(get_item_dictionary_for_sbvalue(sbvalue.GetChildAtIndex(i), False))
+ return item_dicts
+
+class VariableTreeDelegate(object):
+ def __init__(self, frame):
+ self.frame = frame
+
+ def get_column_definitions(self):
+ '''Return an array of column definition dictionaries'''
+ return [{ 'id' : '#0' , 'text' : 'Name' , 'anchor' : W , 'stretch' : 0 },
+ { 'id' : 'type' , 'text' : 'Type' , 'anchor' : W , 'stretch' : 0 },
+ { 'id' : 'value' , 'text' : 'Value' , 'anchor' : W , 'stretch' : 0 },
+ { 'id' : 'summary', 'text' : 'Summary', 'anchor' : W , 'stretch' : 1 }]
+
+ def get_child_item_dictionaries(self, parent_item_dict):
+ '''Given an lldb.SBValue, create an item dictionary for that value and return it'''
+ item_dicts = list()
+ if parent_item_dict is None:
+ # Create root items if parent_item_dict is None
+ variables = self.frame.GetVariables(True, True, True, True)
+ n = variables.GetSize()
+ for i in range(n):
+ item_dicts.append(get_item_dictionary_for_sbvalue(variables[i], True))
+ else:
+ # Get children for a specified item given its item dictionary
+ sbvalue = parent_item_dict['object']
+ if sbvalue.IsValid():
+ for i in range(sbvalue.num_children):
+ item_dicts.append(get_item_dictionary_for_sbvalue(sbvalue.GetChildAtIndex(i), True))
+ return item_dicts
+
+class DelegateTree(ttk.Frame):
+
+ def __init__(self, delegate, title, name):
+ ttk.Frame.__init__(self, name=name)
+ self.pack(expand=Y, fill=BOTH)
+ self.master.title(title)
+ self.delegate = delegate
+ self.item_id_to_item_dict = dict()
+ frame = Frame(self)
+ frame.pack(side=TOP, fill=BOTH, expand=Y)
+ self._create_treeview(frame)
+ self._populate_root()
+
+ def _create_treeview(self, parent):
+ frame = ttk.Frame(parent)
+ frame.pack(side=TOP, fill=BOTH, expand=Y)
+
+ columns_dicts = self.delegate.get_column_definitions()
+ column_ids = list()
+ for i in range(1,len(columns_dicts)):
+ column_ids.append(columns_dicts[i]['id'])
+ # create the tree and scrollbars
+ self.tree = ttk.Treeview(columns=column_ids)
+
+ scroll_bar_v = ttk.Scrollbar(orient=VERTICAL, command= self.tree.yview)
+ scroll_bar_h = ttk.Scrollbar(orient=HORIZONTAL, command= self.tree.xview)
+ self.tree['yscroll'] = scroll_bar_v.set
+ self.tree['xscroll'] = scroll_bar_h.set
+
+ # setup column headings and columns properties
+ for columns_dict in columns_dicts:
+ self.tree.heading(columns_dict['id'], text=columns_dict['text'], anchor=columns_dict['anchor'])
+ self.tree.column(columns_dict['id'], stretch=columns_dict['stretch'])
+
+ # add tree and scrollbars to frame
+ self.tree.grid(in_=frame, row=0, column=0, sticky=NSEW)
+ scroll_bar_v.grid(in_=frame, row=0, column=1, sticky=NS)
+ scroll_bar_h.grid(in_=frame, row=1, column=0, sticky=EW)
+
+ # set frame resizing priorities
+ frame.rowconfigure(0, weight=1)
+ frame.columnconfigure(0, weight=1)
+
+ # action to perform when a node is expanded
+ self.tree.bind('<<TreeviewOpen>>', self._update_tree)
+
+ def insert_items(self, parent_id, item_dicts):
+ for item_dict in item_dicts:
+ values = item_dict['values']
+ item_id = self.tree.insert (parent_id, # root item has an empty name
+ END,
+ text=values[0],
+ values=values[1:])
+ self.item_id_to_item_dict[item_id] = item_dict
+ if item_dict['children']:
+ self.tree.insert(item_id, END, text='dummy')
+
+ def _populate_root(self):
+ # use current directory as root node
+ self.insert_items('', self.delegate.get_child_item_dictionaries(None))
+
+ def _update_tree(self, event):
+ # user expanded a node - build the related directory
+ item_id = self.tree.focus() # the id of the expanded node
+ children = self.tree.get_children (item_id)
+ if len(children):
+ first_child = children[0]
+ # if the node only has a 'dummy' child, remove it and
+ # build new directory; skip if the node is already
+ # populated
+ if self.tree.item(first_child, option='text') == 'dummy':
+ self.tree.delete(first_child)
+ item_dicts = self.delegate.get_child_item_dictionaries(self.item_id_to_item_dict[item_id])
+ self.insert_items(item_id, item_dicts)
+
+ at lldb.command("tk-variables")
+def tk_variable_display(debugger, command, result, dict):
+ sys.argv = ['tk-variables'] # needed for tree creation in TK library as it uses sys.argv...
+ target = debugger.GetSelectedTarget()
+ if not target:
+ print >>result, "invalid target"
+ return
+ process = target.GetProcess()
+ if not process:
+ print >>result, "invalid process"
+ return
+ thread = process.GetSelectedThread()
+ if not thread:
+ print >>result, "invalid thread"
+ return
+ frame = thread.GetSelectedFrame()
+ if not frame:
+ print >>result, "invalid frame"
+ return
+ # Parse command line args
+ command_args = shlex.split(command)
+
+ tree = DelegateTree(VariableTreeDelegate(frame), 'Variables', 'lldb-tk-variables')
+ tree.mainloop()
+
+ at lldb.command("tk-process")
+def tk_process_display(debugger, command, result, dict):
+ sys.argv = ['tk-process'] # needed for tree creation in TK library as it uses sys.argv...
+ target = debugger.GetSelectedTarget()
+ if not target:
+ print >>result, "invalid target"
+ return
+ process = target.GetProcess()
+ if not process:
+ print >>result, "invalid process"
+ return
+ # Parse command line args
+ command_args = shlex.split(command)
+ tree = DelegateTree(ProcessTreeDelegate(process), 'Process', 'lldb-tk-process')
+ tree.mainloop()
+
More information about the lldb-commits
mailing list