[Lldb-commits] [lldb] r218279 - Played around with TK UI a bit this weekend.

Todd Fiala tfiala at google.com
Tue Sep 23 11:02:09 PDT 2014


> Basic tk-frames and tk-variables
tk-process and tk-variables, rather...

On Tue, Sep 23, 2014 at 11:01 AM, Todd Fiala <tfiala at google.com> wrote:

> Basic tk-frames and tk-variables functionality seems to be working fine on
> Linux FWIW in a couple simple cases I tried.
>
> -Todd
>
> On Mon, Sep 22, 2014 at 3:06 PM, Greg Clayton <gclayton at apple.com> wrote:
>
>> 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()
>> +
>>
>>
>> _______________________________________________
>> lldb-commits mailing list
>> lldb-commits at cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits
>>
>
>
>
> --
> Todd Fiala | Software Engineer | tfiala at google.com | 650-943-3180
>



-- 
Todd Fiala | Software Engineer | tfiala at google.com | 650-943-3180
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/lldb-commits/attachments/20140923/6a7ad2ea/attachment.html>


More information about the lldb-commits mailing list