From: Masami Hiramatsu <masami.hiramatsu@gmail.com>
To: linux-kernel@vger.kernel.org
Cc: Huang Ying <ying.huang@intel.com>,
Ananth N Mavinakayanahalli <ananth@in.ibm.com>,
Frederic Weisbecker <fweisbec@gmail.com>,
"H. Peter Anvin" <hpa@zytor.com>, Ingo Molnar <mingo@redhat.com>,
Jason Wessel <jason.wessel@windriver.com>,
Thomas Gleixner <tglx@linutronix.de>,
Peter Zijlstra <a.p.zijlstra@chello.nl>
Subject: [RFC PATCH -tip 09/16] x86: kernel function disassembly interface
Date: Mon, 02 Apr 2012 01:03:50 +0900 [thread overview]
Message-ID: <20120401160350.4502.57559.stgit@shimauta> (raw)
In-Reply-To: <20120401160229.4502.2541.stgit@shimauta>
Add a debugfs interface for disassembling kernel functions
as /sys/kernel/debug/x86/disassembly.
To disassemble a kernel function, at first write a symbol
name into above file, as below;
# echo sys_symlink > /sys/kernel/debug/x86/disassembly
And then, it shows the assembly code of that function.
# cat /sys/kernel/debug/x86/disassembly
<sys_symlink>:
ffffffff81169f90: 55 push %rbp
ffffffff81169f91: 48 89 e5 mov %rsp,%rbp
ffffffff81169f94: 66 66 66 66 90 nop
ffffffff81169f99: 48 89 f2 mov %rsi,%rdx
ffffffff81169f9c: be 9c ff ff ff mov $0xffffff9c,%esi
...
Signed-off-by: Masami Hiramatsu <masami.hiramatsu@gmail.com>
---
arch/x86/Kconfig.debug | 7 ++
arch/x86/include/asm/kprobes.h | 2 +
arch/x86/kernel/kdebugfs.c | 140 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 149 insertions(+), 0 deletions(-)
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index ae64888..5f51e05 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -181,6 +181,13 @@ config X86_DISASSEMBLER
kernel panic.
If unsure, say "Y" here, since this will help you to report bugs.
+config DEBUG_X86_DISASSEMBLY
+ bool "x86 instruction disassembly interface on debugfs"
+ depends on X86_DISASSEMBLER && DEBUG_FS
+ ---help---
+ This option adds /sys/kernel/debug/x86/disassembly interface
+ for disassembling a kernel function.
+
#
# IO delay types:
#
diff --git a/arch/x86/include/asm/kprobes.h b/arch/x86/include/asm/kprobes.h
index 5478825..9fc372b 100644
--- a/arch/x86/include/asm/kprobes.h
+++ b/arch/x86/include/asm/kprobes.h
@@ -114,4 +114,6 @@ struct kprobe_ctlblk {
extern int kprobe_fault_handler(struct pt_regs *regs, int trapnr);
extern int kprobe_exceptions_notify(struct notifier_block *self,
unsigned long val, void *data);
+extern unsigned long recover_probed_instruction(kprobe_opcode_t *buf,
+ unsigned long addr);
#endif /* _ASM_X86_KPROBES_H */
diff --git a/arch/x86/kernel/kdebugfs.c b/arch/x86/kernel/kdebugfs.c
index 90fcf62..5da917d 100644
--- a/arch/x86/kernel/kdebugfs.c
+++ b/arch/x86/kernel/kdebugfs.c
@@ -14,8 +14,12 @@
#include <linux/stat.h>
#include <linux/io.h>
#include <linux/mm.h>
+#include <linux/kallsyms.h>
+#include <linux/kprobes.h>
+#include <linux/ctype.h>
#include <asm/setup.h>
+#include <asm/disasm.h>
struct dentry *arch_debugfs_dir;
EXPORT_SYMBOL(arch_debugfs_dir);
@@ -202,6 +206,137 @@ err_dir:
}
#endif /* CONFIG_DEBUG_BOOT_PARAMS */
+#ifdef CONFIG_DEBUG_X86_DISASSEMBLY
+static DEFINE_MUTEX(disasm_lock);
+static char disasm_funcname[KSYM_NAME_LEN];
+static unsigned long disasm_addr;
+static unsigned long disasm_size;
+static void *disasm_pos;
+
+static ssize_t disasm_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ ssize_t ret = count;
+ char *c;
+
+ if (count >= KSYM_NAME_LEN)
+ return -E2BIG;
+
+ mutex_lock(&disasm_lock);
+ if (copy_from_user(disasm_funcname, buffer, count)) {
+ ret = -EFAULT;
+ goto end;
+ }
+
+ disasm_funcname[count] = '\0';
+ c = strchr(disasm_funcname, '\n');
+ if (c)
+ *c = '\0';
+
+ disasm_addr = (unsigned long)kallsyms_lookup_name(disasm_funcname);
+ if (!disasm_addr)
+ ret = -EINVAL;
+end:
+ mutex_unlock(&disasm_lock);
+
+ return ret;
+}
+
+static void *disasm_seq_next(struct seq_file *m, void *v, loff_t *pos)
+{
+ struct insn insn;
+ char kbuf[MAX_INSN_SIZE];
+ void *p;
+
+ if (!v)
+ return NULL;
+
+ p = (void *)recover_probed_instruction(kbuf, (unsigned long)v);
+ kernel_insn_init(&insn, p);
+ insn_get_length(&insn);
+ v += insn.length;
+
+ if ((unsigned long)v >= disasm_addr + disasm_size)
+ return NULL;
+ return v;
+}
+
+static void *disasm_seq_start(struct seq_file *m, loff_t *pos)
+{
+ unsigned long offs;
+ const char *name;
+
+ mutex_lock(&disasm_lock);
+ if (!disasm_addr)
+ return NULL;
+
+ if (*pos == 0) {
+ name = kallsyms_lookup(disasm_addr, &disasm_size, &offs, NULL,
+ disasm_funcname);
+ if (!name || offs != 0)
+ return NULL;
+
+ seq_printf(m, "<%s>:\n", name);
+ return (void *)disasm_addr;
+ } else
+ return disasm_seq_next(m, disasm_pos, pos);
+}
+
+static void disasm_seq_stop(struct seq_file *m, void *v)
+{
+ disasm_pos = v;
+ mutex_unlock(&disasm_lock);
+}
+
+#define DISASM_BUF_LEN 150
+
+static int disasm_seq_show(struct seq_file *m, void *v)
+{
+ char buf[DISASM_BUF_LEN];
+ u8 kbuf[MAX_INSN_SIZE];
+ struct insn insn;
+ void *p;
+
+ p = (void *)recover_probed_instruction(kbuf, (unsigned long)v);
+ kernel_insn_init(&insn, p);
+ insn_get_length(&insn);
+ insn.kaddr = v;
+ snprint_assembly(buf, DISASM_BUF_LEN, &insn, DISASM_PR_ALL);
+ seq_printf(m, "%s", buf);
+
+ return 0;
+}
+
+static const struct seq_operations disasm_seq_ops = {
+ .start = disasm_seq_start,
+ .next = disasm_seq_next,
+ .stop = disasm_seq_stop,
+ .show = disasm_seq_show,
+};
+
+static int disasm_open(struct inode *inode, struct file *file)
+{
+ /* Currently we just ignore O_APPEND */
+ return seq_open(file, &disasm_seq_ops);
+}
+
+static const struct file_operations disasm_fops = {
+ .open = disasm_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+ .write = disasm_write,
+};
+
+static int __init disassembly_kdebugfs_init(void)
+{
+ debugfs_create_file("disassembly", S_IRUSR | S_IWUSR,
+ arch_debugfs_dir, NULL, &disasm_fops);
+ return 0;
+}
+
+#endif /* CONFIG_DEBUG_X86_DISASSEMBLY */
+
static int __init arch_kdebugfs_init(void)
{
int error = 0;
@@ -210,6 +345,11 @@ static int __init arch_kdebugfs_init(void)
if (!arch_debugfs_dir)
return -ENOMEM;
+#ifdef CONFIG_DEBUG_X86_DISASSEMBLY
+ error = disassembly_kdebugfs_init();
+ if (error)
+ return error;
+#endif
#ifdef CONFIG_DEBUG_BOOT_PARAMS
error = boot_params_kdebugfs_init();
#endif
next prev parent reply other threads:[~2012-04-01 16:03 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-04-01 16:02 [RFC PATCH -tip 00/16] in-kernel x86 disassember Masami Hiramatsu
2012-04-01 16:02 ` [RFC PATCH -tip 01/16] x86: Split default64 flag from force64 flag Masami Hiramatsu
2012-04-01 16:02 ` [RFC PATCH -tip 02/16] x86: Change the order of segment prefix macro Masami Hiramatsu
2012-04-01 16:02 ` [RFC PATCH -tip 03/16] x86: Add bogus disassembler support Masami Hiramatsu
2012-04-01 16:03 ` [RFC PATCH -tip 04/16] x86: Show kernel symbol in disassembler Masami Hiramatsu
2012-04-01 16:03 ` [RFC PATCH -tip 05/16] x86: Disassemble x86-64 only instructions Masami Hiramatsu
2012-04-01 16:03 ` [RFC PATCH -tip 06/16] x86: Change asm syntax to AT&T-like one Masami Hiramatsu
2012-04-01 16:03 ` [RFC PATCH -tip 07/16] kdb: Provide original instruction modified by sw breakpoint Masami Hiramatsu
2012-04-01 16:03 ` [RFC PATCH -tip 08/16] x86/kprobes: Recover breakpoint instruction if KGDB knows Masami Hiramatsu
2012-04-01 16:03 ` Masami Hiramatsu [this message]
2012-04-01 16:03 ` [RFC PATCH -tip 10/16] x86/disasm: Indicate modified instructions Masami Hiramatsu
2012-04-01 16:04 ` [RFC PATCH -tip 11/16] tracing/docs: add explanation about disassembler interface Masami Hiramatsu
2012-04-01 16:04 ` [RFC PATCH -tip 12/16] x86: Merge code dump in show_registers Masami Hiramatsu
2012-04-01 16:04 ` [RFC PATCH -tip 13/16] x86: Disassemble support in register dump Masami Hiramatsu
2012-04-01 16:04 ` [RFC PATCH -tip 14/16] x86: Indicate trapped address and probed address Masami Hiramatsu
2012-04-01 16:04 ` [RFC PATCH -tip 15/16] x86/kdb: Add x86 disassembe command Masami Hiramatsu
2012-04-01 16:05 ` [RFC PATCH -tip 16/16] tools/bogodis: Add bogus disassembler tool in userspace Masami Hiramatsu
2012-04-01 19:58 ` [RFC PATCH -tip 00/16] in-kernel x86 disassember H. Peter Anvin
2012-04-02 7:04 ` Ingo Molnar
2012-04-02 22:17 ` H. Peter Anvin
2012-04-03 7:55 ` Masami Hiramatsu
2012-04-02 22:01 ` H. Peter Anvin
2012-04-03 7:31 ` Ingo Molnar
2012-04-03 8:39 ` Masami Hiramatsu
2012-04-03 16:10 ` H. Peter Anvin
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=20120401160350.4502.57559.stgit@shimauta \
--to=masami.hiramatsu@gmail.com \
--cc=a.p.zijlstra@chello.nl \
--cc=ananth@in.ibm.com \
--cc=fweisbec@gmail.com \
--cc=hpa@zytor.com \
--cc=jason.wessel@windriver.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=tglx@linutronix.de \
--cc=ying.huang@intel.com \
/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.