Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/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
This commit is contained in:
Коммит
1e431a9d64
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
@ -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,
|
||||
|
|
|
@ -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() */
|
||||
|
|
|
@ -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);
|
||||
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 +
|
||||
|
@ -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 UNPACK32(dest, ptr) do { \
|
||||
u32 *ptr32; \
|
||||
ptr32 = (u32 *)ptr; \
|
||||
dest = *(ptr32++); \
|
||||
ptr = (unsigned long *)ptr32; \
|
||||
} while (0)
|
||||
|
||||
void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
|
||||
{
|
||||
unsigned long *ptr = gdb_regs;
|
||||
int reg;
|
||||
|
||||
for (reg = 0; reg < 32; reg++)
|
||||
UNPACK64(regs->gpr[reg], ptr);
|
||||
#define GDB_SIZEOF_REG sizeof(unsigned long)
|
||||
#define GDB_SIZEOF_REG_U32 sizeof(u32)
|
||||
|
||||
#ifdef CONFIG_FSL_BOOKE
|
||||
#ifdef CONFIG_SPE
|
||||
for (reg = 0; reg < 32; reg++)
|
||||
UNPACK64(current->thread.evr[reg], ptr);
|
||||
#define GDB_SIZEOF_FLOAT_REG sizeof(unsigned long)
|
||||
#else
|
||||
ptr += 32;
|
||||
#endif
|
||||
#else
|
||||
/* fp registers not used by kernel, leave zero */
|
||||
ptr += 32 * 8 / sizeof(int);
|
||||
#define GDB_SIZEOF_FLOAT_REG sizeof(u64)
|
||||
#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);
|
||||
struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
|
||||
{
|
||||
{ "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]) },
|
||||
|
||||
BUG_ON((unsigned long)ptr >
|
||||
(unsigned long)(((void *)gdb_regs) + NUMREGBYTES));
|
||||
{ "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) },
|
||||
};
|
||||
|
||||
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
|
||||
/* 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 */
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)
|
||||
|
|
|
@ -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();
|
||||
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -209,18 +209,6 @@ int __weak kgdb_skipexception(int exception, struct pt_regs *regs)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* kgdb_disable_hw_debug - Disable hardware debugging while we in kgdb.
|
||||
* @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.
|
||||
*/
|
||||
void __weak kgdb_disable_hw_debug(struct pt_regs *regs)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Some architectures need cache flushes when we set/clear a
|
||||
* breakpoint:
|
||||
|
@ -484,7 +472,9 @@ static int kgdb_cpu_enter(struct kgdb_state *ks, struct pt_regs *regs,
|
|||
atomic_inc(&masters_in_kgdb);
|
||||
else
|
||||
atomic_inc(&slaves_in_kgdb);
|
||||
kgdb_disable_hw_debug(ks->linux_regs);
|
||||
|
||||
if (arch_kgdb_ops.disable_hw_break)
|
||||
arch_kgdb_ops.disable_hw_break(regs);
|
||||
|
||||
acquirelock:
|
||||
/*
|
||||
|
|
|
@ -1127,7 +1127,7 @@ static int kdb_local(kdb_reason_t reason, int error, struct pt_regs *regs,
|
|||
/* special case below */
|
||||
} else {
|
||||
kdb_printf("\nEntering kdb (current=0x%p, pid %d) ",
|
||||
kdb_current, kdb_current->pid);
|
||||
kdb_current, kdb_current ? kdb_current->pid : 0);
|
||||
#if defined(CONFIG_SMP)
|
||||
kdb_printf("on processor %d ", raw_smp_processor_id());
|
||||
#endif
|
||||
|
@ -2603,20 +2603,17 @@ static int kdb_summary(int argc, const char **argv)
|
|||
*/
|
||||
static int kdb_per_cpu(int argc, const char **argv)
|
||||
{
|
||||
char buf[256], fmtstr[64];
|
||||
kdb_symtab_t symtab;
|
||||
cpumask_t suppress = CPU_MASK_NONE;
|
||||
int cpu, diag;
|
||||
unsigned long addr, val, bytesperword = 0, whichcpu = ~0UL;
|
||||
char fmtstr[64];
|
||||
int cpu, diag, nextarg = 1;
|
||||
unsigned long addr, symaddr, val, bytesperword = 0, whichcpu = ~0UL;
|
||||
|
||||
if (argc < 1 || argc > 3)
|
||||
return KDB_ARGCOUNT;
|
||||
|
||||
snprintf(buf, sizeof(buf), "per_cpu__%s", argv[1]);
|
||||
if (!kdbgetsymval(buf, &symtab)) {
|
||||
kdb_printf("%s is not a per_cpu variable\n", argv[1]);
|
||||
return KDB_BADADDR;
|
||||
}
|
||||
diag = kdbgetaddrarg(argc, argv, &nextarg, &symaddr, NULL, NULL);
|
||||
if (diag)
|
||||
return diag;
|
||||
|
||||
if (argc >= 2) {
|
||||
diag = kdbgetularg(argv[2], &bytesperword);
|
||||
if (diag)
|
||||
|
@ -2649,46 +2646,25 @@ static int kdb_per_cpu(int argc, const char **argv)
|
|||
#define KDB_PCU(cpu) 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
for_each_online_cpu(cpu) {
|
||||
if (KDB_FLAG(CMD_INTERRUPT))
|
||||
return 0;
|
||||
|
||||
if (whichcpu != ~0UL && whichcpu != cpu)
|
||||
continue;
|
||||
addr = symtab.sym_start + KDB_PCU(cpu);
|
||||
addr = symaddr + KDB_PCU(cpu);
|
||||
diag = kdb_getword(&val, addr, bytesperword);
|
||||
if (diag) {
|
||||
kdb_printf("%5d " kdb_bfd_vma_fmt0 " - unable to "
|
||||
"read, diag=%d\n", cpu, addr, diag);
|
||||
continue;
|
||||
}
|
||||
#ifdef CONFIG_SMP
|
||||
if (!val) {
|
||||
cpu_set(cpu, suppress);
|
||||
continue;
|
||||
}
|
||||
#endif /* CONFIG_SMP */
|
||||
kdb_printf("%5d ", cpu);
|
||||
kdb_md_line(fmtstr, addr,
|
||||
bytesperword == KDB_WORD_SIZE,
|
||||
1, bytesperword, 1, 1, 0);
|
||||
}
|
||||
if (cpus_weight(suppress) == 0)
|
||||
return 0;
|
||||
kdb_printf("Zero suppressed cpu(s):");
|
||||
for (cpu = first_cpu(suppress); cpu < num_possible_cpus();
|
||||
cpu = next_cpu(cpu, suppress)) {
|
||||
kdb_printf(" %d", cpu);
|
||||
if (cpu == num_possible_cpus() - 1 ||
|
||||
next_cpu(cpu, suppress) != cpu + 1)
|
||||
continue;
|
||||
while (cpu < num_possible_cpus() &&
|
||||
next_cpu(cpu, suppress) == cpu + 1)
|
||||
++cpu;
|
||||
kdb_printf("-%d", cpu);
|
||||
}
|
||||
kdb_printf("\n");
|
||||
|
||||
#undef KDB_PCU
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -54,4 +54,11 @@ config SAMPLE_KFIFO
|
|||
|
||||
If in doubt, say "N" here.
|
||||
|
||||
config SAMPLE_KDB
|
||||
tristate "Build kdb command exmaple -- loadable modules only"
|
||||
depends on KGDB_KDB && m
|
||||
help
|
||||
Build an example of how to dynamically add the hello
|
||||
command to the kdb shell.
|
||||
|
||||
endif # SAMPLES
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Makefile for Linux samples code
|
||||
|
||||
obj-$(CONFIG_SAMPLES) += kobject/ kprobes/ tracepoints/ trace_events/ \
|
||||
hw_breakpoint/ kfifo/
|
||||
hw_breakpoint/ kfifo/ kdb/
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
obj-$(CONFIG_SAMPLE_KDB) += kdb_hello.o
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Created by: Jason Wessel <jason.wessel@windriver.com>
|
||||
*
|
||||
* Copyright (c) 2010 Wind River Systems, Inc. All Rights Reserved.
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kdb.h>
|
||||
|
||||
/*
|
||||
* All kdb shell command call backs receive argc and argv, where
|
||||
* argv[0] is the command the end user typed
|
||||
*/
|
||||
static int kdb_hello_cmd(int argc, const char **argv)
|
||||
{
|
||||
if (argc > 1)
|
||||
return KDB_ARGCOUNT;
|
||||
|
||||
if (argc)
|
||||
kdb_printf("Hello %s.\n", argv[1]);
|
||||
else
|
||||
kdb_printf("Hello world!\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int __init kdb_hello_cmd_init(void)
|
||||
{
|
||||
/*
|
||||
* Registration of a dynamically added kdb command is done with
|
||||
* kdb_register() with the arguments being:
|
||||
* 1: The name of the shell command
|
||||
* 2: The function that processes the command
|
||||
* 3: Description of the usage of any arguments
|
||||
* 4: Descriptive text when you run help
|
||||
* 5: Number of characters to complete the command
|
||||
* 0 == type the whole command
|
||||
* 1 == match both "g" and "go" for example
|
||||
*/
|
||||
kdb_register("hello", kdb_hello_cmd, "[string]",
|
||||
"Say Hello World or Hello [string]", 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit kdb_hello_cmd_exit(void)
|
||||
{
|
||||
kdb_unregister("hello");
|
||||
}
|
||||
|
||||
module_init(kdb_hello_cmd_init);
|
||||
module_exit(kdb_hello_cmd_exit);
|
||||
|
||||
MODULE_AUTHOR("WindRiver");
|
||||
MODULE_DESCRIPTION("KDB example to add a hello command");
|
||||
MODULE_LICENSE("GPL");
|
Загрузка…
Ссылка в новой задаче