From: Houcheng Lin <houcheng@gmail.com>
To: jan.kiszka@siemens.com, corbet@lwn.net, houcheng@gmail.com
Cc: linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [RFC PATCH] scripts/gdb: add data window feature
Date: Thu, 16 Jul 2015 23:58:58 +0800 [thread overview]
Message-ID: <1437062338-21971-1-git-send-email-houcheng@gmail.com> (raw)
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@gmail.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@gmail.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@gmail.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
next reply other threads:[~2015-07-16 15:59 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-07-16 15:58 Houcheng Lin [this message]
2015-07-21 21:04 ` [RFC PATCH] scripts/gdb: add data window feature Jan Kiszka
2015-07-22 1:55 ` Houcheng Lin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1437062338-21971-1-git-send-email-houcheng@gmail.com \
--to=houcheng@gmail.com \
--cc=corbet@lwn.net \
--cc=jan.kiszka@siemens.com \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.