From: Jan Kiszka <jan.kiszka@web.de>
To: Ray Lee <ray-lk@madrabbit.org>, Ingo Molnar <mingo@elte.hu>
Cc: Sam Ravnborg <sam@ravnborg.org>,
linux-kernel@vger.kernel.org,
Linus Torvalds <torvalds@linux-foundation.org>,
Andrew Morton <akpm@zip.com.au>,
Thomas Gleixner <tglx@linutronix.de>,
Jason Wessel <jason.wessel@windriver.com>
Subject: Re: [git pull] kgdb light, v5
Date: Sun, 10 Feb 2008 19:53:50 +0100 [thread overview]
Message-ID: <47AF483E.10905@web.de> (raw)
In-Reply-To: <2c0942db0802100930y5338e545k808d996f9a19bac@mail.gmail.com>
[This still runs fine here, but sharp eyes are always welcome!]
Cleanup of the way kgdb
- accesses unsafe memory via probe_kernel_*
- converts to/from hex representation
- passes errors due to such accesses around
At this chance I also fix kgdb_ebin2mem, which was broken /wrt escape
sequence handling.
Signed-off-by: Jan Kiszka <jan.kiszka@web.de>
---
include/linux/kgdb.h | 4
kernel/kgdb.c | 349 +++++++++++++++------------------------------------
2 files changed, 109 insertions(+), 244 deletions(-)
diff --git a/include/linux/kgdb.h b/include/linux/kgdb.h
index 7f4ee55..0359280 100644
--- a/include/linux/kgdb.h
+++ b/include/linux/kgdb.h
@@ -313,8 +313,8 @@ extern int kgdb_register_io_module(struct kgdb_io *local_kgdb_io_ops);
extern void kgdb_unregister_io_module(struct kgdb_io *local_kgdb_io_ops);
extern int kgdb_hex2long(char **ptr, long *long_val);
-extern char *kgdb_mem2hex(char *mem, char *buf, int count);
-extern char *kgdb_hex2mem(char *buf, char *mem, int count);
+extern int kgdb_mem2hex(char *mem, char *buf, int count);
+extern int kgdb_hex2mem(char *buf, char *mem, int count);
extern int kgdb_isremovedbreak(unsigned long addr);
diff --git a/kernel/kgdb.c b/kernel/kgdb.c
index d55fdd1..ac9d196 100644
--- a/kernel/kgdb.c
+++ b/kernel/kgdb.c
@@ -145,38 +145,20 @@ static struct notifier_block kgdb_reboot_notifier = {
* Finally, some KGDB code :-)
*/
-static char *kgdb_get_mem(char *addr, unsigned char *buf, int count)
+static int kgdb_get_mem(char *addr, unsigned char *buf, int count)
{
- while (count) {
- if ((unsigned long)addr < TASK_SIZE)
- return ERR_PTR(-EINVAL);
+ if ((unsigned long)addr < TASK_SIZE)
+ return -EFAULT;
- if (probe_kernel_address(addr, *buf))
- return ERR_PTR(-EINVAL);
-
- buf++;
- addr++;
- count--;
- }
-
- return NULL;
+ return probe_kernel_read(buf, addr, count);
}
-static char *kgdb_set_mem(char *addr, unsigned char *buf, int count)
+static int kgdb_set_mem(char *addr, unsigned char *buf, int count)
{
- while (count) {
- if ((unsigned long)addr < TASK_SIZE)
- return ERR_PTR(-EINVAL);
-
- if (probe_kernel_write(addr, *buf))
- return ERR_PTR(-EINVAL);
+ if ((unsigned long)addr < TASK_SIZE)
+ return -EINVAL;
- buf++;
- addr++;
- count--;
- }
-
- return NULL;
+ return probe_kernel_write(addr, buf, count);
}
@@ -188,27 +170,24 @@ int __weak kgdb_validate_break_address(unsigned long addr)
{
char tmp_variable[BREAK_INSTR_SIZE];
- if (!kgdb_get_mem((char *)addr, tmp_variable, BREAK_INSTR_SIZE))
- return 0;
- return -1;
+ return kgdb_get_mem((char *)addr, tmp_variable, BREAK_INSTR_SIZE);
}
int __weak kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr)
{
- if (kgdb_get_mem((char *)addr, saved_instr, BREAK_INSTR_SIZE))
- return -1;
+ int err;
- if (kgdb_set_mem((char *)addr, arch_kgdb_ops.gdb_bpt_instr,
- BREAK_INSTR_SIZE))
- return -1;
- return 0;
+ err = kgdb_get_mem((char *)addr, saved_instr, BREAK_INSTR_SIZE);
+ if (err)
+ return err;
+
+ return kgdb_set_mem((char *)addr, arch_kgdb_ops.gdb_bpt_instr,
+ BREAK_INSTR_SIZE);
}
int __weak kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle)
{
- if (kgdb_set_mem((char *)addr, (char *)bundle, BREAK_INSTR_SIZE))
- return -1;
- return 0;
+ return kgdb_set_mem((char *)addr, (char *)bundle, BREAK_INSTR_SIZE);
}
unsigned long __weak kgdb_arch_pc(int exception, struct pt_regs *regs)
@@ -339,125 +318,47 @@ static void put_packet(char *buffer)
}
}
-/*
- * Fault-tolerant memory accessor wrappers. Performance is a secondary
- * concern, the primary concern is not to crash the debugger (or the
- * debuggee):
- */
+static char *pack_hex_byte(char *pkt, u8 byte)
+{
+ *pkt++ = hexchars[byte >> 4];
+ *pkt++ = hexchars[byte & 0xf];
+
+ return pkt;
+}
/*
* Convert the memory pointed to by mem into hex, placing result in buf.
* Return a pointer to the last char put in buf (null). May return an error.
*/
-char *kgdb_mem2hex(char *mem, char *buf, int count)
+int kgdb_mem2hex(char *mem, char *buf, int count)
{
+ char *tmp;
+ int err;
+
/*
- * Accessing some registers in a single load instruction is
- * required to avoid bad side effects for some I/O registers.
+ * We use the upper half of buf as an intermediate buffer for the
+ * raw memory copy. Hex conversion will work against this one.
*/
- if ((count == 2) && (((long)mem & 1) == 0)) {
- u16 tmp_s;
-
- if (probe_kernel_address(mem, tmp_s))
- return ERR_PTR(-EINVAL);
-
- mem += 2;
-#ifdef __BIG_ENDIAN
- *buf++ = hexchars[(tmp_s >> 12) & 0xf];
- *buf++ = hexchars[(tmp_s >> 8) & 0xf];
- *buf++ = hexchars[(tmp_s >> 4) & 0xf];
- *buf++ = hexchars[tmp_s & 0xf];
-#else
- *buf++ = hexchars[(tmp_s >> 4) & 0xf];
- *buf++ = hexchars[tmp_s & 0xf];
- *buf++ = hexchars[(tmp_s >> 12) & 0xf];
- *buf++ = hexchars[(tmp_s >> 8) & 0xf];
-#endif
- } else if ((count == 4) && (((long)mem & 3) == 0)) {
- u32 tmp_l;
- if (probe_kernel_address(mem, tmp_l))
- return ERR_PTR(-EINVAL);
-
-
- mem += 4;
-#ifdef __BIG_ENDIAN
- *buf++ = hexchars[(tmp_l >> 28) & 0xf];
- *buf++ = hexchars[(tmp_l >> 24) & 0xf];
- *buf++ = hexchars[(tmp_l >> 20) & 0xf];
- *buf++ = hexchars[(tmp_l >> 16) & 0xf];
- *buf++ = hexchars[(tmp_l >> 12) & 0xf];
- *buf++ = hexchars[(tmp_l >> 8) & 0xf];
- *buf++ = hexchars[(tmp_l >> 4) & 0xf];
- *buf++ = hexchars[tmp_l & 0xf];
-#else
- *buf++ = hexchars[(tmp_l >> 4) & 0xf];
- *buf++ = hexchars[tmp_l & 0xf];
- *buf++ = hexchars[(tmp_l >> 12) & 0xf];
- *buf++ = hexchars[(tmp_l >> 8) & 0xf];
- *buf++ = hexchars[(tmp_l >> 20) & 0xf];
- *buf++ = hexchars[(tmp_l >> 16) & 0xf];
- *buf++ = hexchars[(tmp_l >> 28) & 0xf];
- *buf++ = hexchars[(tmp_l >> 24) & 0xf];
-#endif
-#ifdef CONFIG_64BIT
- } else if ((count == 8) && (((long)mem & 7) == 0)) {
- u64 tmp_ll;
- if (probe_kernel_address(mem, tmp_ll))
- return ERR_PTR(-EINVAL);
-
- mem += 8;
-#ifdef __BIG_ENDIAN
- *buf++ = hexchars[(tmp_ll >> 60) & 0xf];
- *buf++ = hexchars[(tmp_ll >> 56) & 0xf];
- *buf++ = hexchars[(tmp_ll >> 52) & 0xf];
- *buf++ = hexchars[(tmp_ll >> 48) & 0xf];
- *buf++ = hexchars[(tmp_ll >> 44) & 0xf];
- *buf++ = hexchars[(tmp_ll >> 40) & 0xf];
- *buf++ = hexchars[(tmp_ll >> 36) & 0xf];
- *buf++ = hexchars[(tmp_ll >> 32) & 0xf];
- *buf++ = hexchars[(tmp_ll >> 28) & 0xf];
- *buf++ = hexchars[(tmp_ll >> 24) & 0xf];
- *buf++ = hexchars[(tmp_ll >> 20) & 0xf];
- *buf++ = hexchars[(tmp_ll >> 16) & 0xf];
- *buf++ = hexchars[(tmp_ll >> 12) & 0xf];
- *buf++ = hexchars[(tmp_ll >> 8) & 0xf];
- *buf++ = hexchars[(tmp_ll >> 4) & 0xf];
- *buf++ = hexchars[tmp_ll & 0xf];
-#else
- *buf++ = hexchars[(tmp_ll >> 4) & 0xf];
- *buf++ = hexchars[tmp_ll & 0xf];
- *buf++ = hexchars[(tmp_ll >> 12) & 0xf];
- *buf++ = hexchars[(tmp_ll >> 8) & 0xf];
- *buf++ = hexchars[(tmp_ll >> 20) & 0xf];
- *buf++ = hexchars[(tmp_ll >> 16) & 0xf];
- *buf++ = hexchars[(tmp_ll >> 28) & 0xf];
- *buf++ = hexchars[(tmp_ll >> 24) & 0xf];
- *buf++ = hexchars[(tmp_ll >> 36) & 0xf];
- *buf++ = hexchars[(tmp_ll >> 32) & 0xf];
- *buf++ = hexchars[(tmp_ll >> 44) & 0xf];
- *buf++ = hexchars[(tmp_ll >> 40) & 0xf];
- *buf++ = hexchars[(tmp_ll >> 52) & 0xf];
- *buf++ = hexchars[(tmp_ll >> 48) & 0xf];
- *buf++ = hexchars[(tmp_ll >> 60) & 0xf];
- *buf++ = hexchars[(tmp_ll >> 56) & 0xf];
-#endif
-#endif
- } else {
- while (count-- > 0) {
- unsigned char ch;
+ tmp = buf + count;
+
+ if (count == 2 && ((long)mem & 1) == 0)
+ err = probe_kernel_read(tmp, mem, 2);
+ else if (count == 4 && ((long)mem & 3) == 0)
+ err = probe_kernel_read(tmp, mem, 4);
+ else if (count == 8 && ((long)mem & 7) == 0)
+ err = probe_kernel_read(tmp, mem, 8);
+ else
+ err = probe_kernel_read(tmp, mem, count);
- if (probe_kernel_address(mem, ch))
- return ERR_PTR(-EINVAL);
+ if (err)
+ return err;
- mem++;
- *buf++ = hexchars[ch >> 4];
- *buf++ = hexchars[ch & 0xf];
- }
- }
+ while (count-- > 0)
+ buf = pack_hex_byte(buf, *tmp++);
*buf = 0;
- return buf;
+ return 0;
}
/*
@@ -465,21 +366,24 @@ char *kgdb_mem2hex(char *mem, char *buf, int count)
* 0x7d escaped with 0x7d. Return a pointer to the character after
* the last byte written.
*/
-static char *kgdb_ebin2mem(char *buf, char *mem, int count)
+static int kgdb_ebin2mem(char *buf, char *mem, int count)
{
- for (; count > 0; count--, buf++) {
- if (*buf == 0x7d) {
- if (probe_kernel_write(mem, (char)(*buf ^ 0x20)))
- return ERR_PTR(-EINVAL);
- buf++;
- } else {
- if (probe_kernel_write(mem, *buf))
- return ERR_PTR(-EINVAL);
- }
+ int err = 0;
+ char c;
+
+ while (count-- > 0) {
+ c = *buf++;
+ if (c == 0x7d)
+ c = *buf++ ^ 0x20;
+
+ err = probe_kernel_write(mem, &c, 1);
+ if (err)
+ break;
+
mem++;
}
- return mem;
+ return err;
}
/*
@@ -487,65 +391,35 @@ static char *kgdb_ebin2mem(char *buf, char *mem, int count)
* Return a pointer to the character AFTER the last byte written.
* May return an error.
*/
-char *kgdb_hex2mem(char *buf, char *mem, int count)
+int kgdb_hex2mem(char *buf, char *mem, int count)
{
- if ((count == 2) && (((long)mem & 1) == 0)) {
- u16 tmp_s = 0;
-
-#ifdef __BIG_ENDIAN
- tmp_s |= hex(*buf++) << 12;
- tmp_s |= hex(*buf++) << 8;
- tmp_s |= hex(*buf++) << 4;
- tmp_s |= hex(*buf++);
-#else
- tmp_s |= hex(*buf++) << 4;
- tmp_s |= hex(*buf++);
- tmp_s |= hex(*buf++) << 12;
- tmp_s |= hex(*buf++) << 8;
-#endif
- if (probe_kernel_write(mem, tmp_s))
- return ERR_PTR(-EINVAL);
-
- mem += 2;
- } else if ((count == 4) && (((long)mem & 3) == 0)) {
- u32 tmp_l = 0;
-
-#ifdef __BIG_ENDIAN
- tmp_l |= hex(*buf++) << 28;
- tmp_l |= hex(*buf++) << 24;
- tmp_l |= hex(*buf++) << 20;
- tmp_l |= hex(*buf++) << 16;
- tmp_l |= hex(*buf++) << 12;
- tmp_l |= hex(*buf++) << 8;
- tmp_l |= hex(*buf++) << 4;
- tmp_l |= hex(*buf++);
-#else
- tmp_l |= hex(*buf++) << 4;
- tmp_l |= hex(*buf++);
- tmp_l |= hex(*buf++) << 12;
- tmp_l |= hex(*buf++) << 8;
- tmp_l |= hex(*buf++) << 20;
- tmp_l |= hex(*buf++) << 16;
- tmp_l |= hex(*buf++) << 28;
- tmp_l |= hex(*buf++) << 24;
-#endif
- if (probe_kernel_write(mem, tmp_l))
- return ERR_PTR(-EINVAL);
- mem += 4;
- } else {
- int i;
+ char *tmp_raw;
+ char *tmp_hex;
+ int err;
- for (i = 0; i < count; i++) {
- unsigned char ch = hex(*buf++) << 4;
+ /*
+ * We use the upper half of buf as an intermediate buffer for the
+ * raw memory that is converted from hex.
+ */
+ tmp_raw = buf + count * 2;
- ch |= hex(*buf++);
- if (probe_kernel_write(mem, ch))
- return ERR_PTR(-EINVAL);
- mem++;
- }
+ tmp_hex = tmp_raw - 1;
+ while (tmp_hex >= buf) {
+ tmp_raw--;
+ *tmp_raw = hex(*tmp_hex--);
+ *tmp_raw |= hex(*tmp_hex--) << 4;
}
- return mem;
+ if (count == 2 && ((long)mem & 1) == 0)
+ err = probe_kernel_write(mem, tmp_raw, 2);
+ else if (count == 4 && ((long)mem & 3) == 0)
+ err = probe_kernel_write(mem, tmp_raw, 4);
+ else if (count == 8 && ((long)mem & 7) == 0)
+ err = probe_kernel_write(mem, tmp_raw, 8);
+ else
+ err = probe_kernel_write(mem, tmp_raw, count);
+
+ return err;
}
/*
@@ -573,37 +447,30 @@ int kgdb_hex2long(char **ptr, long *long_val)
}
/* Write memory due to an 'M' or 'X' packet. */
-static char *write_mem_msg(int binary)
+static int write_mem_msg(int binary)
{
char *ptr = &remcom_in_buffer[1];
unsigned long addr;
unsigned long length;
+ int err;
if (kgdb_hex2long(&ptr, &addr) > 0 && *(ptr++) == ',' &&
kgdb_hex2long(&ptr, &length) > 0 && *(ptr++) == ':') {
if (binary)
- ptr = kgdb_ebin2mem(ptr, (char *)addr, length);
+ err = kgdb_ebin2mem(ptr, (char *)addr, length);
else
- ptr = kgdb_hex2mem(ptr, (char *)addr, length);
- if (IS_ERR(ptr))
- return ptr;
+ err = kgdb_hex2mem(ptr, (char *)addr, length);
+ if (err)
+ return err;
if (CACHE_FLUSH_IS_SAFE)
flush_icache_range(addr, addr + length + 1);
- return NULL;
+ return 0;
}
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
}
-static inline char *pack_hex_byte(char *pkt, int byte)
-{
- *pkt++ = hexchars[(byte >> 4) & 0xf];
- *pkt++ = hexchars[(byte & 0xf)];
-
- return pkt;
-}
-
-static inline void error_packet(char *pkt, int error)
+static void error_packet(char *pkt, int error)
{
error = -error;
pkt[0] = 'E';
@@ -753,12 +620,12 @@ static int kgdb_activate_sw_breakpoints(void)
static int kgdb_set_sw_break(unsigned long addr)
{
- int error = kgdb_validate_break_address(addr);
+ int err = kgdb_validate_break_address(addr);
int breakno = -1;
int i;
- if (error < 0)
- return error;
+ if (err)
+ return err;
for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) {
if ((kgdb_break[i].state == BP_SET) &&
@@ -961,8 +828,7 @@ static void gdb_cmd_status(struct kgdb_state *ks)
kgdb_msg_write("Not all CPUs have been synced for KGDB\n", 39);
remcom_out_buffer[0] = 'S';
- remcom_out_buffer[1] = hexchars[ks->signo >> 4];
- remcom_out_buffer[2] = hexchars[ks->signo & 0xf];
+ pack_hex_byte(&remcom_out_buffer[1], ks->signo);
}
/* Handle the 'g' get registers request */
@@ -1044,13 +910,13 @@ static void gdb_cmd_memread(struct kgdb_state *ks)
char *ptr = &remcom_in_buffer[1];
unsigned long length;
unsigned long addr;
+ int err;
if (kgdb_hex2long(&ptr, &addr) > 0 && *ptr++ == ',' &&
kgdb_hex2long(&ptr, &length) > 0) {
-
- ptr = kgdb_mem2hex((char *)addr, remcom_out_buffer, length);
- if (IS_ERR(ptr))
- error_packet(remcom_out_buffer, PTR_ERR(ptr));
+ err = kgdb_mem2hex((char *)addr, remcom_out_buffer, length);
+ if (err)
+ error_packet(remcom_out_buffer, err);
} else {
error_packet(remcom_out_buffer, -EINVAL);
}
@@ -1059,10 +925,10 @@ static void gdb_cmd_memread(struct kgdb_state *ks)
/* Handle the 'M' memory write bytes */
static void gdb_cmd_memwrite(struct kgdb_state *ks)
{
- char *ptr = write_mem_msg(0);
+ int err = write_mem_msg(0);
- if (IS_ERR(ptr))
- error_packet(remcom_out_buffer, PTR_ERR(ptr));
+ if (err)
+ error_packet(remcom_out_buffer, err);
else
strcpy(remcom_out_buffer, "OK");
}
@@ -1070,10 +936,10 @@ static void gdb_cmd_memwrite(struct kgdb_state *ks)
/* Handle the 'X' memory binary write bytes */
static void gdb_cmd_binwrite(struct kgdb_state *ks)
{
- char *ptr = write_mem_msg(1);
+ int err = write_mem_msg(1);
- if (IS_ERR(ptr))
- error_packet(remcom_out_buffer, PTR_ERR(ptr));
+ if (err)
+ error_packet(remcom_out_buffer, err);
else
strcpy(remcom_out_buffer, "OK");
}
@@ -1382,8 +1248,7 @@ static int gdb_serial_stub(struct kgdb_state *ks)
/* Reply to host that an exception has occurred */
ptr = remcom_out_buffer;
*ptr++ = 'T';
- *ptr++ = hexchars[(ks->signo >> 4) & 0xf];
- *ptr++ = hexchars[ks->signo & 0xf];
+ ptr = pack_hex_byte(ptr, ks->signo);
ptr += strlen(strcpy(ptr, "thread:"));
int_to_threadref(thref, shadow_pid(current->pid));
ptr = pack_threadid(ptr, thref);
next prev parent reply other threads:[~2008-02-10 18:54 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-02-10 7:13 [0/6] kgdb light Ingo Molnar
2008-02-10 7:37 ` David Miller
2008-02-10 10:47 ` Sam Ravnborg
2008-02-10 13:25 ` Jan Kiszka
2008-02-10 19:31 ` Sam Ravnborg
2008-02-10 20:23 ` Jan Kiszka
2008-02-10 21:16 ` Ingo Molnar
2008-02-10 21:30 ` Sam Ravnborg
2008-02-10 21:34 ` Ingo Molnar
2008-02-10 16:36 ` [git pull] kgdb light, v5 Ingo Molnar
2008-02-10 17:30 ` Ray Lee
2008-02-10 17:39 ` Jan Kiszka
2008-02-10 18:59 ` Ray Lee
2008-02-10 18:53 ` Jan Kiszka [this message]
2008-02-10 19:34 ` Ingo Molnar
2008-02-10 19:44 ` Linus Torvalds
2008-02-10 20:19 ` Ingo Molnar
2008-02-10 20:22 ` Jan Kiszka
2008-02-10 21:13 ` Ingo Molnar
2008-02-10 20:29 ` Ingo Molnar
2008-02-10 20:41 ` Ingo Molnar
2008-02-10 19:34 ` Sam Ravnborg
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=47AF483E.10905@web.de \
--to=jan.kiszka@web.de \
--cc=akpm@zip.com.au \
--cc=jason.wessel@windriver.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@elte.hu \
--cc=ray-lk@madrabbit.org \
--cc=sam@ravnborg.org \
--cc=tglx@linutronix.de \
--cc=torvalds@linux-foundation.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.