lkml.org 
[lkml]   [2012]   [Feb]   [26]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCHv3 3/3] KGDB: Allow registering multiple I/O ops.
    Date
    This allows multiple I/O ops, which is useful, if you want
    to be able to support debugging say both via console and
    via network (or 1394, dbgp, etc.)

    Tested with kgdboc and netkgdb.

    Signed-off-by: Andrei Warkentin <andrey.warkentin@gmail.com>
    ---
    drivers/usb/early/ehci-dbgp.c | 4 +-
    include/linux/kgdb.h | 6 ++-
    kernel/debug/debug_core.c | 130 +++++++++++++++++++++++++++--------------
    kernel/debug/gdbstub.c | 43 ++++++-------
    kernel/debug/kdb/kdb_io.c | 26 ++++-----
    5 files changed, 125 insertions(+), 84 deletions(-)

    diff --git a/drivers/usb/early/ehci-dbgp.c b/drivers/usb/early/ehci-dbgp.c
    index 1fc8f12..e5db14a 100644
    --- a/drivers/usb/early/ehci-dbgp.c
    +++ b/drivers/usb/early/ehci-dbgp.c
    @@ -97,7 +97,8 @@ static inline u32 dbgp_len_update(u32 x, u32 len)

    #ifdef CONFIG_KGDB
    static struct kgdb_io kgdbdbgp_io_ops;
    -#define dbgp_kgdb_mode (dbg_io_ops == &kgdbdbgp_io_ops)
    +static int kgdb_registered = 0;
    +#define dbgp_kgdb_mode (kgdb_registered)
    #else
    #define dbgp_kgdb_mode (0)
    #endif
    @@ -1051,6 +1052,7 @@ static int __init kgdbdbgp_parse_config(char *str)
    kgdbdbgp_wait_time = simple_strtoul(ptr, &ptr, 10);
    }
    kgdb_register_io_module(&kgdbdbgp_io_ops);
    + kgdb_registered = 1;
    kgdbdbgp_io_ops.is_console = early_dbgp_console.index != -1;

    return 0;
    diff --git a/include/linux/kgdb.h b/include/linux/kgdb.h
    index fa39183..c92cd30 100644
    --- a/include/linux/kgdb.h
    +++ b/include/linux/kgdb.h
    @@ -17,6 +17,7 @@
    #include <linux/linkage.h>
    #include <linux/init.h>
    #include <linux/atomic.h>
    +#include <linux/list.h>
    #ifdef CONFIG_HAVE_ARCH_KGDB
    #include <asm/kgdb.h>
    #endif
    @@ -276,6 +277,7 @@ struct kgdb_io {
    void (*pre_exception) (void);
    void (*post_exception) (void);
    int is_console;
    + struct list_head list;
    };

    extern struct kgdb_arch arch_kgdb_ops;
    @@ -284,7 +286,9 @@ extern unsigned long __weak kgdb_arch_pc(int exception, struct pt_regs *regs);

    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 struct kgdb_io *dbg_io_ops;
    +extern int dbg_io_get_char(void);
    +extern void dbg_io_put_char(u8, bool);
    +extern void dbg_io_flush(void);

    extern int kgdb_hex2long(char **ptr, unsigned long *long_val);
    extern char *kgdb_mem2hex(char *mem, char *buf, int count);
    diff --git a/kernel/debug/debug_core.c b/kernel/debug/debug_core.c
    index 0d7c087..bd29f92 100644
    --- a/kernel/debug/debug_core.c
    +++ b/kernel/debug/debug_core.c
    @@ -72,8 +72,8 @@ int kgdb_io_module_registered;
    /* Guard for recursive entry */
    static int exception_level;

    -struct kgdb_io *dbg_io_ops;
    -static DEFINE_SPINLOCK(kgdb_registration_lock);
    +static DEFINE_MUTEX(kgdb_registration_lock);
    +static LIST_HEAD(dbg_io_list);

    /* kgdb console driver is loaded */
    static int kgdb_con_registered;
    @@ -384,7 +384,7 @@ setundefined:
    */
    static int kgdb_io_ready(int print_wait)
    {
    - if (!dbg_io_ops)
    + if (list_empty(&dbg_io_list))
    return 0;
    if (kgdb_connected)
    return 1;
    @@ -455,6 +455,26 @@ static void dbg_touch_watchdogs(void)
    rcu_cpu_stall_reset();
    }

    +void dbg_io_run_pre(void)
    +{
    + struct kgdb_io *kio;
    +
    + list_for_each_entry(kio, &dbg_io_list, list) {
    + if (kio->pre_exception)
    + kio->pre_exception();
    + }
    +}
    +
    +void dbg_io_run_post(void)
    +{
    + struct kgdb_io *kio;
    +
    + list_for_each_entry_reverse(kio, &dbg_io_list, list) {
    + if (kio->post_exception)
    + kio->post_exception();
    + }
    +}
    +
    static int kgdb_cpu_enter(struct kgdb_state *ks, struct pt_regs *regs,
    int exception_state)
    {
    @@ -565,8 +585,7 @@ return_normal:
    goto kgdb_restore;

    /* Call the I/O driver's pre_exception routine */
    - if (dbg_io_ops->pre_exception)
    - dbg_io_ops->pre_exception();
    + dbg_io_run_pre();

    /*
    * Get the passive CPU lock which will hold all the non-primary
    @@ -625,8 +644,7 @@ cpu_master_loop:
    }

    /* Call the I/O driver's post_exception routine */
    - if (dbg_io_ops->post_exception)
    - dbg_io_ops->post_exception();
    + dbg_io_run_post();

    if (!kgdb_single_step) {
    raw_spin_unlock(&dbg_slave_lock);
    @@ -734,7 +752,7 @@ static struct console kgdbcons = {
    #ifdef CONFIG_MAGIC_SYSRQ
    static void sysrq_handle_dbg(int key)
    {
    - if (!dbg_io_ops) {
    + if (list_empty(&dbg_io_list)) {
    printk(KERN_CRIT "ERROR: No KGDB I/O module available\n");
    return;
    }
    @@ -867,38 +885,35 @@ static void kgdb_initial_breakpoint(void)
    int kgdb_register_io_module(struct kgdb_io *new_dbg_io_ops)
    {
    int err;
    + int first;

    - spin_lock(&kgdb_registration_lock);
    -
    - if (dbg_io_ops) {
    - spin_unlock(&kgdb_registration_lock);
    -
    - printk(KERN_ERR "kgdb: Another I/O driver is already "
    - "registered with KGDB.\n");
    - return -EBUSY;
    - }
    + BUG_ON(!new_dbg_io_ops->read_char);
    + BUG_ON(!new_dbg_io_ops->write_char);
    + mutex_lock(&kgdb_registration_lock);
    + first = list_empty(&dbg_io_list);

    if (new_dbg_io_ops->init) {
    err = new_dbg_io_ops->init();
    if (err) {
    - spin_unlock(&kgdb_registration_lock);
    + mutex_unlock(&kgdb_registration_lock);
    return err;
    }
    }

    - dbg_io_ops = new_dbg_io_ops;
    + list_add(&new_dbg_io_ops->list, &dbg_io_list);
    + if (first) {
    + /* Arm KGDB now. */
    + kgdb_register_callbacks();

    - spin_unlock(&kgdb_registration_lock);
    + if (kgdb_break_asap)
    + kgdb_initial_breakpoint();
    + }
    +
    + mutex_unlock(&kgdb_registration_lock);

    printk(KERN_INFO "kgdb: Registered I/O driver %s.\n",
    new_dbg_io_ops->name);

    - /* Arm KGDB now. */
    - kgdb_register_callbacks();
    -
    - if (kgdb_break_asap)
    - kgdb_initial_breakpoint();
    -
    return 0;
    }
    EXPORT_SYMBOL_GPL(kgdb_register_io_module);
    @@ -913,37 +928,64 @@ void kgdb_unregister_io_module(struct kgdb_io *old_dbg_io_ops)
    {
    BUG_ON(kgdb_connected);

    - /*
    - * KGDB is no longer able to communicate out, so
    - * unregister our callbacks and reset state.
    - */
    - kgdb_unregister_callbacks();
    + mutex_lock(&kgdb_registration_lock);
    + if (list_is_singular(&dbg_io_list)) {
    + /*
    + * KGDB is no longer able to communicate out, so
    + * unregister our callbacks and reset state.
    + */
    + kgdb_unregister_callbacks();
    + printk(KERN_INFO
    + "kgdb: debugger disabled.\n");
    + }

    - spin_lock(&kgdb_registration_lock);
    + list_del(&old_dbg_io_ops->list);
    + mutex_unlock(&kgdb_registration_lock);

    - WARN_ON_ONCE(dbg_io_ops != old_dbg_io_ops);
    - dbg_io_ops = NULL;
    + printk(KERN_INFO
    + "kgdb: Unregistered I/O driver %s.\n",
    + old_dbg_io_ops->name);

    - spin_unlock(&kgdb_registration_lock);

    - printk(KERN_INFO
    - "kgdb: Unregistered I/O driver %s, debugger disabled.\n",
    - old_dbg_io_ops->name);
    }
    EXPORT_SYMBOL_GPL(kgdb_unregister_io_module);

    int dbg_io_get_char(void)
    {
    - int ret = dbg_io_ops->read_char();
    - if (ret == NO_POLL_CHAR)
    - return -1;
    - if (!dbg_kdb_mode)
    + struct kgdb_io *kio;
    + int ret = NO_POLL_CHAR;
    +
    + list_for_each_entry(kio, &dbg_io_list, list) {
    + ret = kio->read_char();
    + if (ret == NO_POLL_CHAR)
    + continue;
    + if (!dbg_kdb_mode)
    + return ret;
    + if (ret == 127)
    + return 8;
    return ret;
    - if (ret == 127)
    - return 8;
    + }
    return ret;
    }

    +void dbg_io_flush(void)
    +{
    + struct kgdb_io *kio;
    +
    + list_for_each_entry(kio, &dbg_io_list, list)
    + if (kio->flush)
    + kio->flush();
    +}
    +
    +void dbg_io_put_char(u8 data, bool skip_con)
    +{
    + struct kgdb_io *kio;
    +
    + list_for_each_entry(kio, &dbg_io_list, list)
    + if (!kio->is_console || !skip_con)
    + kio->write_char(data);
    +}
    +
    /**
    * kgdb_breakpoint - generate breakpoint exception
    *
    diff --git a/kernel/debug/gdbstub.c b/kernel/debug/gdbstub.c
    index c22d8c2..cf4fdfd 100644
    --- a/kernel/debug/gdbstub.c
    +++ b/kernel/debug/gdbstub.c
    @@ -79,9 +79,9 @@ static int gdbstub_read_wait(void)
    #else
    static int gdbstub_read_wait(void)
    {
    - int ret = dbg_io_ops->read_char();
    + int ret = dbg_io_get_char();
    while (ret == NO_POLL_CHAR)
    - ret = dbg_io_ops->read_char();
    + ret = dbg_io_get_char();
    return ret;
    }
    #endif
    @@ -125,12 +125,11 @@ static void get_packet(char *buffer)

    if (checksum != xmitcsum)
    /* failed checksum */
    - dbg_io_ops->write_char('-');
    + dbg_io_put_char('-', false);
    else
    /* successful transfer */
    - dbg_io_ops->write_char('+');
    - if (dbg_io_ops->flush)
    - dbg_io_ops->flush();
    + dbg_io_put_char('+', false);
    + dbg_io_flush();
    }
    buffer[count] = 0;
    } while (checksum != xmitcsum);
    @@ -150,21 +149,20 @@ static void put_packet(char *buffer)
    * $<packet info>#<checksum>.
    */
    while (1) {
    - dbg_io_ops->write_char('$');
    + dbg_io_put_char('$', false);
    checksum = 0;
    count = 0;

    while ((ch = buffer[count])) {
    - dbg_io_ops->write_char(ch);
    + dbg_io_put_char(ch, false);
    checksum += ch;
    count++;
    }

    - dbg_io_ops->write_char('#');
    - dbg_io_ops->write_char(hex_asc_hi(checksum));
    - dbg_io_ops->write_char(hex_asc_lo(checksum));
    - if (dbg_io_ops->flush)
    - dbg_io_ops->flush();
    + dbg_io_put_char('#', false);
    + dbg_io_put_char(hex_asc_hi(checksum), false);
    + dbg_io_put_char(hex_asc_lo(checksum), false);
    + dbg_io_flush();

    /* Now see what we get in reply. */
    ch = gdbstub_read_wait();
    @@ -183,9 +181,8 @@ static void put_packet(char *buffer)
    * packet.
    */
    if (ch == '$') {
    - dbg_io_ops->write_char('-');
    - if (dbg_io_ops->flush)
    - dbg_io_ops->flush();
    + dbg_io_put_char('-', false);
    + dbg_io_flush();
    return;
    }
    }
    @@ -1097,7 +1094,7 @@ int gdbstub_state(struct kgdb_state *ks, char *cmd)
    gdbstub_prev_in_buf_pos = 0;
    return 0;
    }
    - dbg_io_ops->write_char('+');
    + dbg_io_put_char('+', false);
    put_packet(remcom_out_buffer);
    return 0;
    }
    @@ -1115,19 +1112,19 @@ void gdbstub_exit(int status)
    buffer[1] = hex_asc_hi(status);
    buffer[2] = hex_asc_lo(status);

    - dbg_io_ops->write_char('$');
    + dbg_io_put_char('$', false);
    checksum = 0;

    for (loop = 0; loop < 3; loop++) {
    ch = buffer[loop];
    checksum += ch;
    - dbg_io_ops->write_char(ch);
    + dbg_io_put_char(ch, false);
    }

    - dbg_io_ops->write_char('#');
    - dbg_io_ops->write_char(hex_asc_hi(checksum));
    - dbg_io_ops->write_char(hex_asc_lo(checksum));
    + dbg_io_put_char('#', false);
    + dbg_io_put_char(hex_asc_hi(checksum), false);
    + dbg_io_put_char(hex_asc_lo(checksum), false);

    /* make sure the output is flushed, lest the bootloader clobber it */
    - dbg_io_ops->flush();
    + dbg_io_flush();
    }
    diff --git a/kernel/debug/kdb/kdb_io.c b/kernel/debug/kdb/kdb_io.c
    index 5eb7e23..35ef3cb 100644
    --- a/kernel/debug/kdb/kdb_io.c
    +++ b/kernel/debug/kdb/kdb_io.c
    @@ -689,14 +689,11 @@ kdb_printit:
    if (!dbg_kdb_mode && kgdb_connected) {
    gdbstub_msg_write(kdb_buffer, retlen);
    } else {
    - if (!dbg_io_ops->is_console) {
    - len = strlen(kdb_buffer);
    - cp = kdb_buffer;
    - while (len--) {
    - dbg_io_ops->write_char(*cp);
    - cp++;
    - }
    - }
    + len = strlen(kdb_buffer);
    + cp = kdb_buffer;
    + while (len--)
    + dbg_io_put_char(*cp++, true);
    +
    while (c) {
    c->write(c, kdb_buffer, retlen);
    touch_nmi_watchdog();
    @@ -743,14 +740,13 @@ kdb_printit:
    kdb_input_flush();
    c = console_drivers;

    - if (!dbg_io_ops->is_console) {
    - len = strlen(moreprompt);
    - cp = moreprompt;
    - while (len--) {
    - dbg_io_ops->write_char(*cp);
    - cp++;
    - }
    + len = strlen(moreprompt);
    + cp = moreprompt;
    + while (len--) {
    + dbg_io_put_char(*cp, true);
    + cp++;
    }
    +
    while (c) {
    c->write(c, moreprompt, strlen(moreprompt));
    touch_nmi_watchdog();
    --
    1.7.8.3


    \
     
     \ /
      Last update: 2012-02-27 05:33    [W:0.054 / U:60.996 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site