[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <1437062338-21971-1-git-send-email-houcheng@gmail.com>
Date: Thu, 16 Jul 2015 23:58:58 +0800
From: Houcheng Lin <houcheng@...il.com>
To: jan.kiszka@...mens.com, corbet@....net, houcheng@...il.com
Cc: linux-doc@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: [RFC PATCH] scripts/gdb: add data window feature
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@...il.com>
---
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@...il.com>
+#
+# 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@...il.com>
+#
+# 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-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists