[RFC PATCH] scripts/gdb: add data window feature

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add data window feature to show current kernel status
on separate consoles, including: 1) registers, 2) back
trace and 3) watch data windows.

The data window would help kernel developer to understand
current hardware/ kernel status, and on single-stepping, the
modified fields in the data window would be highlighted.

Signed-off-by: Houcheng Lin <houcheng@xxxxxxxxx>
---
 Documentation/gdb-kernel-debugging.txt |   9 ++
 scripts/gdb/linux/dw.py                | 234 +++++++++++++++++++++++++++++++++
 scripts/gdb/linux/lx-dw.py             |  53 ++++++++
 scripts/gdb/vmlinux-gdb.py             |   1 +
 scripts/lx-dw.sh                       |   4 +
 5 files changed, 301 insertions(+)
 create mode 100644 scripts/gdb/linux/dw.py
 create mode 100644 scripts/gdb/linux/lx-dw.py
 create mode 100755 scripts/lx-dw.sh

diff --git a/Documentation/gdb-kernel-debugging.txt b/Documentation/gdb-kernel-debugging.txt
index 7050ce8..b74ecff 100644
--- a/Documentation/gdb-kernel-debugging.txt
+++ b/Documentation/gdb-kernel-debugging.txt
@@ -139,6 +139,14 @@ Examples of using the Linux-provided gdb helpers
       start_comm = "swapper/2\000\000\000\000\000\000"
     }
 
+ o Enable the debugging data window feature in GDB, then run lx-dw.sh script
+   to create three xterm console on desktop to display the CPU registers,
+   back trace and variables.
+    (gdb) lx-dw
+    (gdb) lx-add p $lx_current().comm
+    (gdb) lx-add x/8x $rsp
+    (gdb) lx-add x/8i $rip
+
 
 List of commands and functions
 ------------------------------
@@ -153,6 +161,7 @@ this is just a snapshot of the initial version:
  function lx_task_by_pid -- Find Linux task by PID and return the task_struct variable
  function lx_thread_info -- Calculate Linux thread_info from task variable
  lx-dmesg -- Print Linux kernel log buffer
+ lx-dw -- Enable GDB data window feature
  lx-lsmod -- List currently loaded modules
  lx-symbols -- (Re-)load symbols of Linux kernel and currently loaded modules
 
diff --git a/scripts/gdb/linux/dw.py b/scripts/gdb/linux/dw.py
new file mode 100644
index 0000000..9d78bb3
--- /dev/null
+++ b/scripts/gdb/linux/dw.py
@@ -0,0 +1,234 @@
+#
+# gdb data window feature for Linux kernel debugging
+#
+#
+# Authors:
+#  Houcheng Lin <houcheng@xxxxxxxxx>
+#
+# This work is licensed under the terms of the GNU GPL version 2.
+#
+
+from __future__ import with_statement
+from __future__ import print_function
+
+import gdb
+
+
+class CmdWindow:
+    def __init__(self, file, cmd, DecoClass):
+        self.cmd = cmd
+        self.file = file
+        self.decowin = DecoClass(file)
+    def refresh(self, events):
+        try:
+            regstr = gdb.execute(self.cmd, False, True)
+        except:
+            regstr = 'Exception on instruction:%s' % cmd
+        v = self.decowin.parse(regstr)
+        self.decowin.update(v)
+        self.decowin.refresh()
+
+class DecoWindow:
+    def __init__(self, filename):
+        self.filename = filename
+        self.file = None
+        self.pre = {}
+        self.pre2 = {}
+    def insertLine(self, i, v, prev):
+        if self.file == None:
+            self.file = open(self.filename, 'w')
+        if v == prev:
+            print(v , file=self.file)
+        else:
+            print('@@' + v, file=self.file)
+        self.file.flush()
+    def update(self, valuelist):
+        for (i, v) in valuelist:
+            try:
+                prevalue = self.pre[i]
+            except:
+                prevalue = None
+            self.insertLine(i, v, prevalue)
+            self.pre2[i] = v
+    def parse(self, regstr):
+        vlist = []
+        for line in regstr.split('\n'):
+            if len(line.strip()) == 0:
+                continue
+            vlist.append((line.split()[0], line))
+        return vlist
+    def refresh(self):
+        if self.file == None:
+            self.file = open(self.filename, 'w')
+        self.file.close()
+        self.file = None
+        self.pre = self.pre2
+        self.pre2 = {}
+
+
+def findRegAnnotate(regstr):
+    b = regstr.find('<')
+    if b > 0:
+        return regstr[b:regstr.find('>') + 1]
+    b = regstr.find('[')
+    if b > 0:
+        return regstr[b:regstr.find(']') + 1]
+
+
+class RegDecoWindow(DecoWindow):
+    def __init__(self, filename):
+        DecoWindow.__init__(self, filename)
+    def insertLine(self, i, v, prev):
+        if self.file == None:
+            self.file = open(self.filename, 'w')
+        ann = findRegAnnotate(v)
+        if v == prev:
+            prefix = '\r'
+        else:
+            prefix = '\r@@'
+        if ann != None:
+            output = prefix + i + '\t' + v.split()[1] + '///\t' + ann
+        else:
+            output = prefix + i + '\t' + v.split()[1]
+        print(output, file=self.file)
+        self.file.flush()
+
+'''
+  decorate bt output string
+'''
+class BtDecoWindow(DecoWindow):
+    def __init__(self, filename):
+        DecoWindow.__init__(self, filename)
+    def parse(self, regstr):
+        vlist = []
+        lines = regstr.strip().split('\n')
+        # reverse the index order
+        index = len(lines)
+        for line in lines:
+            if len(line.strip()) == 0:
+                continue
+            if line.split()[0] == 'Exception':
+                pass
+            else:
+                # remove first token
+                line = line.replace(line.split()[0], '').lstrip()
+                line = ('#%-3d' % index ) + line
+            vlist.append((str(index), line))
+            index = index -1
+        return vlist
+
+
+'''
+  store watch variables
+'''
+global LxWatch
+LxWatch = {}
+LxWatch[1] = "p $lx_current().comm"
+LxWatch[2] = "x/32x $rsp"
+LxWatch[3] = "x/8i $rip"
+
+'''
+  Watch data window's decorator
+'''
+class WatchDecoWindow(DecoWindow):
+    def __init__(self, filename):
+        DecoWindow.__init__(self, filename)
+    def parse(self, index, cmd, regstr):
+        vlist = []
+        vlist.append(('[%d]'%index, '[%d] '%index + cmd))
+        cmd0 = cmd.split()[0]
+        lineno = 0
+        for line in regstr.split('\n'):
+            if len(line.strip()) == 0:
+                continue
+            istr = '[%d](%d)' % (index, lineno)
+            if cmd0 == 'p' and line.find('=') > 0:
+                line = line[line.find('=')+1:]
+                vlist.append((istr, line))
+            else:
+                vlist.append((istr, line))
+            lineno = lineno + 1
+        return vlist
+
+class WatchWindow(CmdWindow):
+    def __init__(self, file, cmd, DecoClass):
+        CmdWindow.__init__(self, file, cmd, DecoClass)
+    def refresh(self, events):
+        for index in LxWatch:
+            cmd = LxWatch[index]
+            try:
+                regstr = gdb.execute(cmd, False, True)
+            except:
+                regstr = 'Exception on instruction:%s' % cmd
+            v = self.decowin.parse(index, cmd, regstr)
+            self.decowin.update(v)
+        self.decowin.refresh()
+    def parse(self, index, regstr):
+        vlist = []
+        for line in regstr.split('\n'):
+            if len(line.strip()) == 0:
+                continue
+            vlist.append(('[%d]' % index + line.split()[0], line))
+        return vlist
+
+class LxGuiFUnction(gdb.Command):
+    """Enable GDB data window feature.
+
+lx-dw: to enable the data window feature, including reg/ bt and watch data windows.
+    """
+    def __init__ (self):
+        gdb.Command.__init__(self, "lx-dw", gdb.COMMAND_DATA, gdb.COMPLETE_SYMBOL, True)
+    def invoke (self, arg, from_tty):
+        if arg == "off":
+            try:
+                gdb.events.stop.disconnect(self.regw.refresh)
+                gdb.events.stop.disconnect(self.btw.refresh)
+                gdb.events.stop.disconnect(self.watchw.refresh)
+            except:
+                pass
+        else:
+            self.regw = CmdWindow('/tmp/reg-dw', 'info reg', RegDecoWindow)
+            self.btw = CmdWindow('/tmp/bt-dw', 'bt', BtDecoWindow)
+            self.watchw = WatchWindow('/tmp/watch-dw', '', WatchDecoWindow)
+            gdb.events.stop.connect(self.regw.refresh)
+            gdb.events.stop.connect(self.btw.refresh)
+            gdb.events.stop.connect(self.watchw.refresh)
+
+LxGuiFUnction()
+
+def findLxWatchSlot():
+    i = 1
+    while True:
+        if not i in LxWatch:
+            return i
+        i = i +1
+
+class LxAddFunction(gdb.Command):
+    """Add gdb command into watch data window.
+
+lx-add <gdb-command>: add gdb command into watch data window; the command would be
+executed on every step or execution break and command results would be updated on
+to watch data window."""
+
+    def __init__ (self):
+        gdb.Command.__init__(self, "lx-add", gdb.COMMAND_DATA, gdb.COMPLETE_SYMBOL, True)
+    def invoke (self, arg, from_tty):
+        index = findLxWatchSlot()
+        LxWatch[index] = arg
+        print(LxWatch)
+
+LxAddFunction()
+
+class LxDelFunction(gdb.Command):
+    """Remove one expression into watch data window.
+
+lx-del <id>: remove the gdb command from watch data window."""
+
+    def __init__ (self):
+        gdb.Command.__init__(self, "lx-del", gdb.COMMAND_DATA, gdb.COMPLETE_SYMBOL, True)
+    def invoke (self, arg, from_tty):
+        index = int(arg)
+        del LxWatch[index]
+        print(LxWatch)
+
+LxDelFunction()
diff --git a/scripts/gdb/linux/lx-dw.py b/scripts/gdb/linux/lx-dw.py
new file mode 100644
index 0000000..26a8c2c
--- /dev/null
+++ b/scripts/gdb/linux/lx-dw.py
@@ -0,0 +1,53 @@
+#
+# gdb data window feature for Linux kernel debugging
+#
+#
+# Authors:
+#  Houcheng Lin <houcheng@xxxxxxxxx>
+#
+# This work is licensed under the terms of the GNU GPL version 2.
+#
+
+import os, time, sys
+import curses
+
+''' for curses control '''
+global stdscr
+stdscr = curses.initscr()
+prevlen = 0
+
+def update(filename):
+    global prevlen
+    fd = open(filename, 'r')
+    count = 0
+    stdscr.erase()
+    try:
+      for line in fd.readlines():
+        if line.find('@@') >= 0:
+            line = line.replace('@@', '')
+            for oline in line.split('///'):
+                stdscr.addstr(count, 0, oline, curses.A_REVERSE)
+                count = count +1
+        else:
+            for oline in line.split('///'):
+                stdscr.addstr(count, 0, oline)
+                count = count +1
+        stdscr.refresh()
+      while count < prevlen:
+        stdscr.addstr(count, 0, "")
+        stdscr.refresh()
+        count = count + 1
+    except:
+      pass
+    prevlen = count
+    fd.close()
+
+''' main display loop '''
+file = '/tmp/' + sys.argv[1]
+pretime = None
+while True:
+    nowtime = os.path.getmtime(file)
+    if pretime != nowtime:
+        update(file)
+        pretime = nowtime
+    time.sleep(0.1)
diff --git a/scripts/gdb/vmlinux-gdb.py b/scripts/gdb/vmlinux-gdb.py
index 4848928..7ca6f7b 100644
--- a/scripts/gdb/vmlinux-gdb.py
+++ b/scripts/gdb/vmlinux-gdb.py
@@ -28,3 +28,4 @@ else:
     import linux.dmesg
     import linux.tasks
     import linux.cpus
+    import linux.dw
\ No newline at end of file
diff --git a/scripts/lx-dw.sh b/scripts/lx-dw.sh
new file mode 100755
index 0000000..831b36c
--- /dev/null
+++ b/scripts/lx-dw.sh
@@ -0,0 +1,4 @@
+xterm -fa 'Monospace' -fs 12 -e "python gdb/linux/lx-dw.py bt-dw" &
+xterm -fa 'Monospace' -fs 12 -e "python gdb/linux/lx-dw.py reg-dw" &
+xterm -fa 'Monospace' -fs 12 -e "python gdb/linux/lx-dw.py watch-dw" &
+
-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-doc" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux FS]     [Yosemite Forum]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux