Skip to content

Commit

Permalink
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/jwessel/linux-2.6-kgdb

* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/linux-2.6-kgdb:
  kgdb,ppc: Individual register get/set for ppc
  kgdbts: prevent re-entry to kgdbts before it unregisters
  debug_core,x86,blackfin: Clean up hw debug disable API
  kdb: Fix early debugging crash regression
  kgdb,arm: fix register dump
  kdb: fix per_cpu command to remove supress mask
  kdb: Add kdb kernel module sample
  • Loading branch information
torvalds committed Oct 29, 2010
2 parents 75d7312 + ff10b88 commit 1e431a9
Show file tree
Hide file tree
Showing 15 changed files with 235 additions and 143 deletions.
13 changes: 12 additions & 1 deletion Documentation/DocBook/kgdb.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -710,7 +710,18 @@ Task Addr Pid Parent [*] cpu State Thread Command
<listitem><para>A simple shell</para></listitem>
<listitem><para>The kdb core command set</para></listitem>
<listitem><para>A registration API to register additional kdb shell commands.</para>
<para>A good example of a self-contained kdb module is the "ftdump" command for dumping the ftrace buffer. See: kernel/trace/trace_kdb.c</para></listitem>
<itemizedlist>
<listitem><para>A good example of a self-contained kdb module
is the "ftdump" command for dumping the ftrace buffer. See:
kernel/trace/trace_kdb.c</para></listitem>
<listitem><para>For an example of how to dynamically register
a new kdb command you can build the kdb_hello.ko kernel module
from samples/kdb/kdb_hello.c. To build this example you can
set CONFIG_SAMPLES=y and CONFIG_SAMPLE_KDB=m in your kernel
config. Later run "modprobe kdb_hello" and the next time you
enter the kdb shell, you can run the "hello"
command.</para></listitem>
</itemizedlist></listitem>
<listitem><para>The implementation for kdb_printf() which
emits messages directly to I/O drivers, bypassing the kernel
log.</para></listitem>
Expand Down
5 changes: 3 additions & 2 deletions arch/arm/include/asm/kgdb.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ extern int kgdb_fault_expected;
#define _GP_REGS 16
#define _FP_REGS 8
#define _EXTRA_REGS 2
#define DBG_MAX_REG_NUM (_GP_REGS + (_FP_REGS * 3) + _EXTRA_REGS)
#define GDB_MAX_REGS (_GP_REGS + (_FP_REGS * 3) + _EXTRA_REGS)
#define DBG_MAX_REG_NUM (_GP_REGS + _FP_REGS + _EXTRA_REGS)

#define KGDB_MAX_NO_CPUS 1
#define BUFMAX 400
Expand All @@ -93,7 +94,7 @@ extern int kgdb_fault_expected;
#define _SPT 13
#define _LR 14
#define _PC 15
#define _CPSR (DBG_MAX_REG_NUM - 1)
#define _CPSR (GDB_MAX_REGS - 1)

/*
* So that we can denote the end of a frame for tracing,
Expand Down
2 changes: 1 addition & 1 deletion arch/arm/kernel/kgdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task)
return;

/* Initialize to zero */
for (regno = 0; regno < DBG_MAX_REG_NUM; regno++)
for (regno = 0; regno < GDB_MAX_REGS; regno++)
gdb_regs[regno] = 0;

/* Otherwise, we have only some registers from switch_to() */
Expand Down
3 changes: 2 additions & 1 deletion arch/blackfin/kernel/kgdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ static void bfin_correct_hw_break(void)
}
}

void kgdb_disable_hw_debug(struct pt_regs *regs)
static void bfin_disable_hw_debug(struct pt_regs *regs)
{
/* Disable hardware debugging while we are in kgdb */
bfin_write_WPIACTL(0);
Expand Down Expand Up @@ -406,6 +406,7 @@ struct kgdb_arch arch_kgdb_ops = {
#endif
.set_hw_breakpoint = bfin_set_hw_break,
.remove_hw_breakpoint = bfin_remove_hw_break,
.disable_hw_break = bfin_disable_hw_debug,
.remove_all_hw_break = bfin_remove_all_hw_break,
.correct_hw_break = bfin_correct_hw_break,
};
Expand Down
1 change: 1 addition & 0 deletions arch/powerpc/include/asm/kgdb.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ static inline void arch_kgdb_breakpoint(void)
asm(".long 0x7d821008"); /* twge r2, r2 */
}
#define CACHE_FLUSH_IS_SAFE 1
#define DBG_MAX_REG_NUM 70

/* The number bytes of registers we have to save depends on a few
* things. For 64bit we default to not including vector registers and
Expand Down
188 changes: 125 additions & 63 deletions arch/powerpc/kernel/kgdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -194,40 +194,6 @@ static int kgdb_dabr_match(struct pt_regs *regs)
ptr = (unsigned long *)ptr32; \
} while (0)


void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
{
unsigned long *ptr = gdb_regs;
int reg;

memset(gdb_regs, 0, NUMREGBYTES);

for (reg = 0; reg < 32; reg++)
PACK64(ptr, regs->gpr[reg]);

#ifdef CONFIG_FSL_BOOKE
#ifdef CONFIG_SPE
for (reg = 0; reg < 32; reg++)
PACK64(ptr, current->thread.evr[reg]);
#else
ptr += 32;
#endif
#else
/* fp registers not used by kernel, leave zero */
ptr += 32 * 8 / sizeof(long);
#endif

PACK64(ptr, regs->nip);
PACK64(ptr, regs->msr);
PACK32(ptr, regs->ccr);
PACK64(ptr, regs->link);
PACK64(ptr, regs->ctr);
PACK32(ptr, regs->xer);

BUG_ON((unsigned long)ptr >
(unsigned long)(((void *)gdb_regs) + NUMREGBYTES));
}

void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
{
struct pt_regs *regs = (struct pt_regs *)(p->thread.ksp +
Expand Down Expand Up @@ -271,44 +237,140 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
(unsigned long)(((void *)gdb_regs) + NUMREGBYTES));
}

#define UNPACK64(dest, ptr) do { dest = *(ptr++); } while (0)
#define GDB_SIZEOF_REG sizeof(unsigned long)
#define GDB_SIZEOF_REG_U32 sizeof(u32)

#define UNPACK32(dest, ptr) do { \
u32 *ptr32; \
ptr32 = (u32 *)ptr; \
dest = *(ptr32++); \
ptr = (unsigned long *)ptr32; \
} while (0)
#ifdef CONFIG_FSL_BOOKE
#define GDB_SIZEOF_FLOAT_REG sizeof(unsigned long)
#else
#define GDB_SIZEOF_FLOAT_REG sizeof(u64)
#endif

void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
{
unsigned long *ptr = gdb_regs;
int reg;

for (reg = 0; reg < 32; reg++)
UNPACK64(regs->gpr[reg], ptr);
{ "r0", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[0]) },
{ "r1", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[1]) },
{ "r2", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[2]) },
{ "r3", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[3]) },
{ "r4", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[4]) },
{ "r5", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[5]) },
{ "r6", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[6]) },
{ "r7", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[7]) },
{ "r8", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[8]) },
{ "r9", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[9]) },
{ "r10", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[10]) },
{ "r11", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[11]) },
{ "r12", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[12]) },
{ "r13", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[13]) },
{ "r14", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[14]) },
{ "r15", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[15]) },
{ "r16", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[16]) },
{ "r17", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[17]) },
{ "r18", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[18]) },
{ "r19", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[19]) },
{ "r20", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[20]) },
{ "r21", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[21]) },
{ "r22", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[22]) },
{ "r23", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[23]) },
{ "r24", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[24]) },
{ "r25", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[25]) },
{ "r26", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[26]) },
{ "r27", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[27]) },
{ "r28", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[28]) },
{ "r29", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[29]) },
{ "r30", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[30]) },
{ "r31", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[31]) },

{ "f0", GDB_SIZEOF_FLOAT_REG, 0 },
{ "f1", GDB_SIZEOF_FLOAT_REG, 1 },
{ "f2", GDB_SIZEOF_FLOAT_REG, 2 },
{ "f3", GDB_SIZEOF_FLOAT_REG, 3 },
{ "f4", GDB_SIZEOF_FLOAT_REG, 4 },
{ "f5", GDB_SIZEOF_FLOAT_REG, 5 },
{ "f6", GDB_SIZEOF_FLOAT_REG, 6 },
{ "f7", GDB_SIZEOF_FLOAT_REG, 7 },
{ "f8", GDB_SIZEOF_FLOAT_REG, 8 },
{ "f9", GDB_SIZEOF_FLOAT_REG, 9 },
{ "f10", GDB_SIZEOF_FLOAT_REG, 10 },
{ "f11", GDB_SIZEOF_FLOAT_REG, 11 },
{ "f12", GDB_SIZEOF_FLOAT_REG, 12 },
{ "f13", GDB_SIZEOF_FLOAT_REG, 13 },
{ "f14", GDB_SIZEOF_FLOAT_REG, 14 },
{ "f15", GDB_SIZEOF_FLOAT_REG, 15 },
{ "f16", GDB_SIZEOF_FLOAT_REG, 16 },
{ "f17", GDB_SIZEOF_FLOAT_REG, 17 },
{ "f18", GDB_SIZEOF_FLOAT_REG, 18 },
{ "f19", GDB_SIZEOF_FLOAT_REG, 19 },
{ "f20", GDB_SIZEOF_FLOAT_REG, 20 },
{ "f21", GDB_SIZEOF_FLOAT_REG, 21 },
{ "f22", GDB_SIZEOF_FLOAT_REG, 22 },
{ "f23", GDB_SIZEOF_FLOAT_REG, 23 },
{ "f24", GDB_SIZEOF_FLOAT_REG, 24 },
{ "f25", GDB_SIZEOF_FLOAT_REG, 25 },
{ "f26", GDB_SIZEOF_FLOAT_REG, 26 },
{ "f27", GDB_SIZEOF_FLOAT_REG, 27 },
{ "f28", GDB_SIZEOF_FLOAT_REG, 28 },
{ "f29", GDB_SIZEOF_FLOAT_REG, 29 },
{ "f30", GDB_SIZEOF_FLOAT_REG, 30 },
{ "f31", GDB_SIZEOF_FLOAT_REG, 31 },

{ "pc", GDB_SIZEOF_REG, offsetof(struct pt_regs, nip) },
{ "msr", GDB_SIZEOF_REG, offsetof(struct pt_regs, msr) },
{ "cr", GDB_SIZEOF_REG_U32, offsetof(struct pt_regs, ccr) },
{ "lr", GDB_SIZEOF_REG, offsetof(struct pt_regs, link) },
{ "ctr", GDB_SIZEOF_REG_U32, offsetof(struct pt_regs, ctr) },
{ "xer", GDB_SIZEOF_REG, offsetof(struct pt_regs, xer) },
};

#ifdef CONFIG_FSL_BOOKE
#ifdef CONFIG_SPE
for (reg = 0; reg < 32; reg++)
UNPACK64(current->thread.evr[reg], ptr);
char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
{
if (regno >= DBG_MAX_REG_NUM || regno < 0)
return NULL;

if (regno < 32 || regno >= 64)
/* First 0 -> 31 gpr registers*/
/* pc, msr, ls... registers 64 -> 69 */
memcpy(mem, (void *)regs + dbg_reg_def[regno].offset,
dbg_reg_def[regno].size);

if (regno >= 32 && regno < 64) {
/* FP registers 32 -> 63 */
#if defined(CONFIG_FSL_BOOKE) && defined(CONFIG_SPE)
if (current)
memcpy(mem, current->thread.evr[regno-32],
dbg_reg_def[regno].size);
#else
ptr += 32;
/* fp registers not used by kernel, leave zero */
memset(mem, 0, dbg_reg_def[regno].size);
#endif
}

return dbg_reg_def[regno].name;
}

int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
{
if (regno >= DBG_MAX_REG_NUM || regno < 0)
return -EINVAL;

if (regno < 32 || regno >= 64)
/* First 0 -> 31 gpr registers*/
/* pc, msr, ls... registers 64 -> 69 */
memcpy((void *)regs + dbg_reg_def[regno].offset, mem,
dbg_reg_def[regno].size);

if (regno >= 32 && regno < 64) {
/* FP registers 32 -> 63 */
#if defined(CONFIG_FSL_BOOKE) && defined(CONFIG_SPE)
memcpy(current->thread.evr[regno-32], mem,
dbg_reg_def[regno].size);
#else
/* fp registers not used by kernel, leave zero */
ptr += 32 * 8 / sizeof(int);
/* fp registers not used by kernel, leave zero */
return 0;
#endif
}

UNPACK64(regs->nip, ptr);
UNPACK64(regs->msr, ptr);
UNPACK32(regs->ccr, ptr);
UNPACK64(regs->link, ptr);
UNPACK64(regs->ctr, ptr);
UNPACK32(regs->xer, ptr);

BUG_ON((unsigned long)ptr >
(unsigned long)(((void *)gdb_regs) + NUMREGBYTES));
return 0;
}

void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)
Expand Down
3 changes: 2 additions & 1 deletion arch/x86/kernel/kgdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ kgdb_set_hw_break(unsigned long addr, int len, enum kgdb_bptype bptype)
* disable hardware debugging while it is processing gdb packets or
* handling exception.
*/
void kgdb_disable_hw_debug(struct pt_regs *regs)
static void kgdb_disable_hw_debug(struct pt_regs *regs)
{
int i;
int cpu = raw_smp_processor_id();
Expand Down Expand Up @@ -724,6 +724,7 @@ struct kgdb_arch arch_kgdb_ops = {
.flags = KGDB_HW_BREAKPOINT,
.set_hw_breakpoint = kgdb_set_hw_break,
.remove_hw_breakpoint = kgdb_remove_hw_break,
.disable_hw_break = kgdb_disable_hw_debug,
.remove_all_hw_break = kgdb_remove_all_hw_break,
.correct_hw_break = kgdb_correct_hw_break,
};
16 changes: 2 additions & 14 deletions drivers/misc/kgdbts.c
Original file line number Diff line number Diff line change
Expand Up @@ -1044,12 +1044,6 @@ static int __init init_kgdbts(void)
return configure_kgdbts();
}

static void cleanup_kgdbts(void)
{
if (configured == 1)
kgdb_unregister_io_module(&kgdbts_io_ops);
}

static int kgdbts_get_char(void)
{
int val = 0;
Expand Down Expand Up @@ -1081,10 +1075,8 @@ static int param_set_kgdbts_var(const char *kmessage, struct kernel_param *kp)
return 0;
}

if (kgdb_connected) {
printk(KERN_ERR
"kgdbts: Cannot reconfigure while KGDB is connected.\n");

if (configured == 1) {
printk(KERN_ERR "kgdbts: ERROR: Already configured and running.\n");
return -EBUSY;
}

Expand All @@ -1093,9 +1085,6 @@ static int param_set_kgdbts_var(const char *kmessage, struct kernel_param *kp)
if (config[len - 1] == '\n')
config[len - 1] = '\0';

if (configured == 1)
cleanup_kgdbts();

/* Go and configure with the new params. */
return configure_kgdbts();
}
Expand Down Expand Up @@ -1123,7 +1112,6 @@ static struct kgdb_io kgdbts_io_ops = {
};

module_init(init_kgdbts);
module_exit(cleanup_kgdbts);
module_param_call(kgdbts, param_set_kgdbts_var, param_get_string, &kps, 0644);
MODULE_PARM_DESC(kgdbts, "<A|V1|V2>[F#|S#][N#]");
MODULE_DESCRIPTION("KGDB Test Suite");
Expand Down
13 changes: 3 additions & 10 deletions include/linux/kgdb.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,6 @@ struct pt_regs;
*/
extern int kgdb_skipexception(int exception, struct pt_regs *regs);

/**
* kgdb_disable_hw_debug - (optional) Disable hardware debugging hook
* @regs: Current &struct pt_regs.
*
* This function will be called if the particular architecture must
* disable hardware debugging while it is processing gdb packets or
* handling exception.
*/
extern void kgdb_disable_hw_debug(struct pt_regs *regs);

struct tasklet_struct;
struct task_struct;
struct uart_port;
Expand Down Expand Up @@ -243,6 +233,8 @@ extern void kgdb_arch_late(void);
* breakpoint.
* @remove_hw_breakpoint: Allow an architecture to specify how to remove a
* hardware breakpoint.
* @disable_hw_break: Allow an architecture to specify how to disable
* hardware breakpoints for a single cpu.
* @remove_all_hw_break: Allow an architecture to specify how to remove all
* hardware breakpoints.
* @correct_hw_break: Allow an architecture to specify how to correct the
Expand All @@ -256,6 +248,7 @@ struct kgdb_arch {
int (*remove_breakpoint)(unsigned long, char *);
int (*set_hw_breakpoint)(unsigned long, int, enum kgdb_bptype);
int (*remove_hw_breakpoint)(unsigned long, int, enum kgdb_bptype);
void (*disable_hw_break)(struct pt_regs *regs);
void (*remove_all_hw_break)(void);
void (*correct_hw_break)(void);
};
Expand Down
Loading

0 comments on commit 1e431a9

Please sign in to comment.