mirror of
https://github.com/armbian/linux-cix.git
synced 2026-01-06 12:30:45 -08:00
kdb: core for kgdb back end (1 of 2)
This patch contains only the kdb core. Because the change set was large, it was split. The next patch in the series includes the instrumentation into the core kernel which are mainly helper functions for kdb. This work is directly derived from kdb v4.4 found at: ftp://oss.sgi.com/projects/kdb/download/v4.4/ The kdb internals have been re-organized to make them mostly platform independent and to connect everything to the debug core which is used by gdbstub (which has long been known as kgdb). The original version of kdb was 58,000 lines worth of changes to support x86. From that implementation only the kdb shell, and basic commands for memory access, runcontrol, lsmod, and dmesg where carried forward. This is a generic implementation which aims to cover all the current architectures using the kgdb core: ppc, arm, x86, mips, sparc, sh and blackfin. More archictectures can be added by implementing the architecture specific kgdb functions. [mort@sgi.com: Compile fix with hugepages enabled] [mort@sgi.com: Clean breakpoint code renaming kdba_ -> kdb_] [mort@sgi.com: fix new line after printing registers] [mort@sgi.com: Remove the concept of global vs. local breakpoints] [mort@sgi.com: Rework kdb_si_swapinfo to use more generic name] [mort@sgi.com: fix the information dump macros, remove 'arch' from the names] [sfr@canb.auug.org.au: include fixup to include linux/slab.h] CC: linux-arch@vger.kernel.org Signed-off-by: Jason Wessel <jason.wessel@windriver.com> Signed-off-by: Martin Hicks <mort@sgi.com>
This commit is contained in:
113
include/linux/kdb.h
Normal file
113
include/linux/kdb.h
Normal file
@@ -0,0 +1,113 @@
|
||||
#ifndef _KDB_H
|
||||
#define _KDB_H
|
||||
|
||||
/*
|
||||
* Kernel Debugger Architecture Independent Global Headers
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
* Copyright (c) 2000-2007 Silicon Graphics, Inc. All Rights Reserved.
|
||||
* Copyright (C) 2000 Stephane Eranian <eranian@hpl.hp.com>
|
||||
* Copyright (C) 2009 Jason Wessel <jason.wessel@windriver.com>
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_KGDB_KDB
|
||||
#include <linux/init.h>
|
||||
#include <linux/sched.h>
|
||||
#include <asm/atomic.h>
|
||||
|
||||
#define KDB_POLL_FUNC_MAX 5
|
||||
|
||||
/*
|
||||
* kdb_initial_cpu is initialized to -1, and is set to the cpu
|
||||
* number whenever the kernel debugger is entered.
|
||||
*/
|
||||
extern int kdb_initial_cpu;
|
||||
extern atomic_t kdb_event;
|
||||
|
||||
/*
|
||||
* kdb_diemsg
|
||||
*
|
||||
* Contains a pointer to the last string supplied to the
|
||||
* kernel 'die' panic function.
|
||||
*/
|
||||
extern const char *kdb_diemsg;
|
||||
|
||||
#define KDB_FLAG_EARLYKDB (1 << 0) /* set from boot parameter kdb=early */
|
||||
#define KDB_FLAG_CATASTROPHIC (1 << 1) /* A catastrophic event has occurred */
|
||||
#define KDB_FLAG_CMD_INTERRUPT (1 << 2) /* Previous command was interrupted */
|
||||
#define KDB_FLAG_NOIPI (1 << 3) /* Do not send IPIs */
|
||||
#define KDB_FLAG_ONLY_DO_DUMP (1 << 4) /* Only do a dump, used when
|
||||
* kdb is off */
|
||||
#define KDB_FLAG_NO_CONSOLE (1 << 5) /* No console is available,
|
||||
* kdb is disabled */
|
||||
#define KDB_FLAG_NO_VT_CONSOLE (1 << 6) /* No VT console is available, do
|
||||
* not use keyboard */
|
||||
#define KDB_FLAG_NO_I8042 (1 << 7) /* No i8042 chip is available, do
|
||||
* not use keyboard */
|
||||
|
||||
extern int kdb_flags; /* Global flags, see kdb_state for per cpu state */
|
||||
|
||||
extern void kdb_save_flags(void);
|
||||
extern void kdb_restore_flags(void);
|
||||
|
||||
#define KDB_FLAG(flag) (kdb_flags & KDB_FLAG_##flag)
|
||||
#define KDB_FLAG_SET(flag) ((void)(kdb_flags |= KDB_FLAG_##flag))
|
||||
#define KDB_FLAG_CLEAR(flag) ((void)(kdb_flags &= ~KDB_FLAG_##flag))
|
||||
|
||||
/*
|
||||
* External entry point for the kernel debugger. The pt_regs
|
||||
* at the time of entry are supplied along with the reason for
|
||||
* entry to the kernel debugger.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
KDB_REASON_ENTER = 1, /* KDB_ENTER() trap/fault - regs valid */
|
||||
KDB_REASON_ENTER_SLAVE, /* KDB_ENTER_SLAVE() trap/fault - regs valid */
|
||||
KDB_REASON_BREAK, /* Breakpoint inst. - regs valid */
|
||||
KDB_REASON_DEBUG, /* Debug Fault - regs valid */
|
||||
KDB_REASON_OOPS, /* Kernel Oops - regs valid */
|
||||
KDB_REASON_SWITCH, /* CPU switch - regs valid*/
|
||||
KDB_REASON_KEYBOARD, /* Keyboard entry - regs valid */
|
||||
KDB_REASON_NMI, /* Non-maskable interrupt; regs valid */
|
||||
KDB_REASON_RECURSE, /* Recursive entry to kdb;
|
||||
* regs probably valid */
|
||||
KDB_REASON_SSTEP, /* Single Step trap. - regs valid */
|
||||
} kdb_reason_t;
|
||||
|
||||
extern int kdb_printf(const char *, ...)
|
||||
__attribute__ ((format (printf, 1, 2)));
|
||||
typedef int (*kdb_printf_t)(const char *, ...)
|
||||
__attribute__ ((format (printf, 1, 2)));
|
||||
|
||||
extern void kdb_init(int level);
|
||||
|
||||
/* Access to kdb specific polling devices */
|
||||
typedef int (*get_char_func)(void);
|
||||
extern get_char_func kdb_poll_funcs[];
|
||||
extern int kdb_get_kbd_char(void);
|
||||
|
||||
static inline
|
||||
int kdb_process_cpu(const struct task_struct *p)
|
||||
{
|
||||
unsigned int cpu = task_thread_info(p)->cpu;
|
||||
if (cpu > num_possible_cpus())
|
||||
cpu = 0;
|
||||
return cpu;
|
||||
}
|
||||
|
||||
/* kdb access to register set for stack dumping */
|
||||
extern struct pt_regs *kdb_current_regs;
|
||||
|
||||
#else /* ! CONFIG_KGDB_KDB */
|
||||
#define kdb_printf(...)
|
||||
#define kdb_init(x)
|
||||
#endif /* CONFIG_KGDB_KDB */
|
||||
enum {
|
||||
KDB_NOT_INITIALIZED,
|
||||
KDB_INIT_EARLY,
|
||||
KDB_INIT_FULL,
|
||||
};
|
||||
#endif /* !_KDB_H */
|
||||
@@ -3,3 +3,4 @@
|
||||
#
|
||||
|
||||
obj-$(CONFIG_KGDB) += debug_core.o gdbstub.o
|
||||
obj-$(CONFIG_KGDB_KDB) += kdb/
|
||||
|
||||
1
kernel/debug/kdb/.gitignore
vendored
Normal file
1
kernel/debug/kdb/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
gen-kdb_cmds.c
|
||||
24
kernel/debug/kdb/Makefile
Normal file
24
kernel/debug/kdb/Makefile
Normal file
@@ -0,0 +1,24 @@
|
||||
# This file is subject to the terms and conditions of the GNU General Public
|
||||
# License. See the file "COPYING" in the main directory of this archive
|
||||
# for more details.
|
||||
#
|
||||
# Copyright (c) 1999-2004 Silicon Graphics, Inc. All Rights Reserved.
|
||||
# Copyright (c) 2009 Wind River Systems, Inc. All Rights Reserved.
|
||||
#
|
||||
|
||||
CCVERSION := $(shell $(CC) -v 2>&1 | sed -ne '$$p')
|
||||
obj-y := kdb_io.o kdb_main.o kdb_support.o kdb_bt.o gen-kdb_cmds.o kdb_bp.o kdb_debugger.o
|
||||
|
||||
clean-files := gen-kdb_cmds.c
|
||||
|
||||
quiet_cmd_gen-kdb = GENKDB $@
|
||||
cmd_gen-kdb = $(AWK) 'BEGIN {print "\#include <linux/stddef.h>"; print "\#include <linux/init.h>"} \
|
||||
/^\#/{next} \
|
||||
/^[ \t]*$$/{next} \
|
||||
{gsub(/"/, "\\\"", $$0); \
|
||||
print "static __initdata char kdb_cmd" cmds++ "[] = \"" $$0 "\\n\";"} \
|
||||
END {print "extern char *kdb_cmds[]; char __initdata *kdb_cmds[] = {"; for (i = 0; i < cmds; ++i) {print " kdb_cmd" i ","}; print(" NULL\n};");}' \
|
||||
$(filter-out %/Makefile,$^) > $@#
|
||||
|
||||
$(obj)/gen-kdb_cmds.c: $(src)/kdb_cmds $(src)/Makefile
|
||||
$(call cmd,gen-kdb)
|
||||
564
kernel/debug/kdb/kdb_bp.c
Normal file
564
kernel/debug/kdb/kdb_bp.c
Normal file
File diff suppressed because it is too large
Load Diff
208
kernel/debug/kdb/kdb_bt.c
Normal file
208
kernel/debug/kdb/kdb_bt.c
Normal file
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* Kernel Debugger Architecture Independent Stack Traceback
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
* Copyright (c) 1999-2004 Silicon Graphics, Inc. All Rights Reserved.
|
||||
* Copyright (c) 2009 Wind River Systems, Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kdb.h>
|
||||
#include <linux/nmi.h>
|
||||
#include <asm/system.h>
|
||||
#include "kdb_private.h"
|
||||
|
||||
|
||||
static void kdb_show_stack(struct task_struct *p, void *addr)
|
||||
{
|
||||
int old_lvl = console_loglevel;
|
||||
console_loglevel = 15;
|
||||
kdb_set_current_task(p);
|
||||
if (addr) {
|
||||
show_stack((struct task_struct *)p, addr);
|
||||
} else if (kdb_current_regs) {
|
||||
#ifdef CONFIG_X86
|
||||
show_stack(p, &kdb_current_regs->sp);
|
||||
#else
|
||||
show_stack(p, NULL);
|
||||
#endif
|
||||
} else {
|
||||
show_stack(p, NULL);
|
||||
}
|
||||
console_loglevel = old_lvl;
|
||||
}
|
||||
|
||||
/*
|
||||
* kdb_bt
|
||||
*
|
||||
* This function implements the 'bt' command. Print a stack
|
||||
* traceback.
|
||||
*
|
||||
* bt [<address-expression>] (addr-exp is for alternate stacks)
|
||||
* btp <pid> Kernel stack for <pid>
|
||||
* btt <address-expression> Kernel stack for task structure at
|
||||
* <address-expression>
|
||||
* bta [DRSTCZEUIMA] All useful processes, optionally
|
||||
* filtered by state
|
||||
* btc [<cpu>] The current process on one cpu,
|
||||
* default is all cpus
|
||||
*
|
||||
* bt <address-expression> refers to a address on the stack, that location
|
||||
* is assumed to contain a return address.
|
||||
*
|
||||
* btt <address-expression> refers to the address of a struct task.
|
||||
*
|
||||
* Inputs:
|
||||
* argc argument count
|
||||
* argv argument vector
|
||||
* Outputs:
|
||||
* None.
|
||||
* Returns:
|
||||
* zero for success, a kdb diagnostic if error
|
||||
* Locking:
|
||||
* none.
|
||||
* Remarks:
|
||||
* Backtrack works best when the code uses frame pointers. But even
|
||||
* without frame pointers we should get a reasonable trace.
|
||||
*
|
||||
* mds comes in handy when examining the stack to do a manual traceback or
|
||||
* to get a starting point for bt <address-expression>.
|
||||
*/
|
||||
|
||||
static int
|
||||
kdb_bt1(struct task_struct *p, unsigned long mask,
|
||||
int argcount, int btaprompt)
|
||||
{
|
||||
char buffer[2];
|
||||
if (kdb_getarea(buffer[0], (unsigned long)p) ||
|
||||
kdb_getarea(buffer[0], (unsigned long)(p+1)-1))
|
||||
return KDB_BADADDR;
|
||||
if (!kdb_task_state(p, mask))
|
||||
return 0;
|
||||
kdb_printf("Stack traceback for pid %d\n", p->pid);
|
||||
kdb_ps1(p);
|
||||
kdb_show_stack(p, NULL);
|
||||
if (btaprompt) {
|
||||
kdb_getstr(buffer, sizeof(buffer),
|
||||
"Enter <q> to end, <cr> to continue:");
|
||||
if (buffer[0] == 'q') {
|
||||
kdb_printf("\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
touch_nmi_watchdog();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
kdb_bt(int argc, const char **argv)
|
||||
{
|
||||
int diag;
|
||||
int argcount = 5;
|
||||
int btaprompt = 1;
|
||||
int nextarg;
|
||||
unsigned long addr;
|
||||
long offset;
|
||||
|
||||
kdbgetintenv("BTARGS", &argcount); /* Arguments to print */
|
||||
kdbgetintenv("BTAPROMPT", &btaprompt); /* Prompt after each
|
||||
* proc in bta */
|
||||
|
||||
if (strcmp(argv[0], "bta") == 0) {
|
||||
struct task_struct *g, *p;
|
||||
unsigned long cpu;
|
||||
unsigned long mask = kdb_task_state_string(argc ? argv[1] :
|
||||
NULL);
|
||||
if (argc == 0)
|
||||
kdb_ps_suppressed();
|
||||
/* Run the active tasks first */
|
||||
for_each_online_cpu(cpu) {
|
||||
p = kdb_curr_task(cpu);
|
||||
if (kdb_bt1(p, mask, argcount, btaprompt))
|
||||
return 0;
|
||||
}
|
||||
/* Now the inactive tasks */
|
||||
kdb_do_each_thread(g, p) {
|
||||
if (task_curr(p))
|
||||
continue;
|
||||
if (kdb_bt1(p, mask, argcount, btaprompt))
|
||||
return 0;
|
||||
} kdb_while_each_thread(g, p);
|
||||
} else if (strcmp(argv[0], "btp") == 0) {
|
||||
struct task_struct *p;
|
||||
unsigned long pid;
|
||||
if (argc != 1)
|
||||
return KDB_ARGCOUNT;
|
||||
diag = kdbgetularg((char *)argv[1], &pid);
|
||||
if (diag)
|
||||
return diag;
|
||||
p = find_task_by_pid_ns(pid, &init_pid_ns);
|
||||
if (p) {
|
||||
kdb_set_current_task(p);
|
||||
return kdb_bt1(p, ~0UL, argcount, 0);
|
||||
}
|
||||
kdb_printf("No process with pid == %ld found\n", pid);
|
||||
return 0;
|
||||
} else if (strcmp(argv[0], "btt") == 0) {
|
||||
if (argc != 1)
|
||||
return KDB_ARGCOUNT;
|
||||
diag = kdbgetularg((char *)argv[1], &addr);
|
||||
if (diag)
|
||||
return diag;
|
||||
kdb_set_current_task((struct task_struct *)addr);
|
||||
return kdb_bt1((struct task_struct *)addr, ~0UL, argcount, 0);
|
||||
} else if (strcmp(argv[0], "btc") == 0) {
|
||||
unsigned long cpu = ~0;
|
||||
struct task_struct *save_current_task = kdb_current_task;
|
||||
char buf[80];
|
||||
if (argc > 1)
|
||||
return KDB_ARGCOUNT;
|
||||
if (argc == 1) {
|
||||
diag = kdbgetularg((char *)argv[1], &cpu);
|
||||
if (diag)
|
||||
return diag;
|
||||
}
|
||||
/* Recursive use of kdb_parse, do not use argv after
|
||||
* this point */
|
||||
argv = NULL;
|
||||
if (cpu != ~0) {
|
||||
if (cpu >= num_possible_cpus() || !cpu_online(cpu)) {
|
||||
kdb_printf("no process for cpu %ld\n", cpu);
|
||||
return 0;
|
||||
}
|
||||
sprintf(buf, "btt 0x%p\n", KDB_TSK(cpu));
|
||||
kdb_parse(buf);
|
||||
return 0;
|
||||
}
|
||||
kdb_printf("btc: cpu status: ");
|
||||
kdb_parse("cpu\n");
|
||||
for_each_online_cpu(cpu) {
|
||||
sprintf(buf, "btt 0x%p\n", KDB_TSK(cpu));
|
||||
kdb_parse(buf);
|
||||
touch_nmi_watchdog();
|
||||
}
|
||||
kdb_set_current_task(save_current_task);
|
||||
return 0;
|
||||
} else {
|
||||
if (argc) {
|
||||
nextarg = 1;
|
||||
diag = kdbgetaddrarg(argc, argv, &nextarg, &addr,
|
||||
&offset, NULL);
|
||||
if (diag)
|
||||
return diag;
|
||||
kdb_show_stack(kdb_current_task, (void *)addr);
|
||||
return 0;
|
||||
} else {
|
||||
return kdb_bt1(kdb_current_task, ~0UL, argcount, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* NOTREACHED */
|
||||
return 0;
|
||||
}
|
||||
35
kernel/debug/kdb/kdb_cmds
Normal file
35
kernel/debug/kdb/kdb_cmds
Normal file
@@ -0,0 +1,35 @@
|
||||
# Initial commands for kdb, alter to suit your needs.
|
||||
# These commands are executed in kdb_init() context, no SMP, no
|
||||
# processes. Commands that require process data (including stack or
|
||||
# registers) are not reliable this early. set and bp commands should
|
||||
# be safe. Global breakpoint commands affect each cpu as it is booted.
|
||||
|
||||
# Standard debugging information for first level support, just type archkdb
|
||||
# or archkdbcpu or archkdbshort at the kdb prompt.
|
||||
|
||||
defcmd dumpcommon "" "Common kdb debugging"
|
||||
set BTAPROMPT 0
|
||||
set LINES 10000
|
||||
-summary
|
||||
-cpu
|
||||
-ps
|
||||
-dmesg 600
|
||||
-bt
|
||||
endefcmd
|
||||
|
||||
defcmd dumpall "" "First line debugging"
|
||||
set BTSYMARG 1
|
||||
set BTARGS 9
|
||||
pid R
|
||||
-dumpcommon
|
||||
-bta
|
||||
endefcmd
|
||||
|
||||
defcmd dumpcpu "" "Same as dumpall but only tasks on cpus"
|
||||
set BTSYMARG 1
|
||||
set BTARGS 9
|
||||
pid R
|
||||
-dumpcommon
|
||||
-btc
|
||||
endefcmd
|
||||
|
||||
159
kernel/debug/kdb/kdb_debugger.c
Normal file
159
kernel/debug/kdb/kdb_debugger.c
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Created by: Jason Wessel <jason.wessel@windriver.com>
|
||||
*
|
||||
* Copyright (c) 2009 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/kgdb.h>
|
||||
#include <linux/kdb.h>
|
||||
#include <linux/kdebug.h>
|
||||
#include "kdb_private.h"
|
||||
#include "../debug_core.h"
|
||||
|
||||
/*
|
||||
* KDB interface to KGDB internals
|
||||
*/
|
||||
get_char_func kdb_poll_funcs[] = {
|
||||
dbg_io_get_char,
|
||||
NULL,
|
||||
};
|
||||
|
||||
int kdb_stub(struct kgdb_state *ks)
|
||||
{
|
||||
int error = 0;
|
||||
kdb_bp_t *bp;
|
||||
unsigned long addr = kgdb_arch_pc(ks->ex_vector, ks->linux_regs);
|
||||
kdb_reason_t reason = KDB_REASON_OOPS;
|
||||
kdb_dbtrap_t db_result = KDB_DB_NOBPT;
|
||||
int i;
|
||||
|
||||
if (KDB_STATE(REENTRY)) {
|
||||
reason = KDB_REASON_SWITCH;
|
||||
KDB_STATE_CLEAR(REENTRY);
|
||||
addr = instruction_pointer(ks->linux_regs);
|
||||
}
|
||||
ks->pass_exception = 0;
|
||||
if (atomic_read(&kgdb_setting_breakpoint))
|
||||
reason = KDB_REASON_KEYBOARD;
|
||||
|
||||
for (i = 0, bp = kdb_breakpoints; i < KDB_MAXBPT; i++, bp++) {
|
||||
if ((bp->bp_enabled) && (bp->bp_addr == addr)) {
|
||||
reason = KDB_REASON_BREAK;
|
||||
db_result = KDB_DB_BPT;
|
||||
if (addr != instruction_pointer(ks->linux_regs))
|
||||
kgdb_arch_set_pc(ks->linux_regs, addr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (reason == KDB_REASON_BREAK || reason == KDB_REASON_SWITCH) {
|
||||
for (i = 0, bp = kdb_breakpoints; i < KDB_MAXBPT; i++, bp++) {
|
||||
if (bp->bp_free)
|
||||
continue;
|
||||
if (bp->bp_addr == addr) {
|
||||
bp->bp_delay = 1;
|
||||
bp->bp_delayed = 1;
|
||||
/*
|
||||
* SSBPT is set when the kernel debugger must single step a
|
||||
* task in order to re-establish an instruction breakpoint
|
||||
* which uses the instruction replacement mechanism. It is
|
||||
* cleared by any action that removes the need to single-step
|
||||
* the breakpoint.
|
||||
*/
|
||||
reason = KDB_REASON_BREAK;
|
||||
db_result = KDB_DB_BPT;
|
||||
KDB_STATE_SET(SSBPT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (reason != KDB_REASON_BREAK && ks->ex_vector == 0 &&
|
||||
ks->signo == SIGTRAP) {
|
||||
reason = KDB_REASON_SSTEP;
|
||||
db_result = KDB_DB_BPT;
|
||||
}
|
||||
/* Set initial kdb state variables */
|
||||
KDB_STATE_CLEAR(KGDB_TRANS);
|
||||
kdb_initial_cpu = ks->cpu;
|
||||
kdb_current_task = kgdb_info[ks->cpu].task;
|
||||
kdb_current_regs = kgdb_info[ks->cpu].debuggerinfo;
|
||||
/* Remove any breakpoints as needed by kdb and clear single step */
|
||||
kdb_bp_remove();
|
||||
KDB_STATE_CLEAR(DOING_SS);
|
||||
KDB_STATE_CLEAR(DOING_SSB);
|
||||
/* zero out any offline cpu data */
|
||||
for_each_present_cpu(i) {
|
||||
if (!cpu_online(i)) {
|
||||
kgdb_info[i].debuggerinfo = NULL;
|
||||
kgdb_info[i].task = NULL;
|
||||
}
|
||||
}
|
||||
if (ks->err_code == DIE_OOPS || reason == KDB_REASON_OOPS) {
|
||||
ks->pass_exception = 1;
|
||||
KDB_FLAG_SET(CATASTROPHIC);
|
||||
}
|
||||
kdb_initial_cpu = ks->cpu;
|
||||
if (KDB_STATE(SSBPT) && reason == KDB_REASON_SSTEP) {
|
||||
KDB_STATE_CLEAR(SSBPT);
|
||||
KDB_STATE_CLEAR(DOING_SS);
|
||||
} else {
|
||||
/* Start kdb main loop */
|
||||
error = kdb_main_loop(KDB_REASON_ENTER, reason,
|
||||
ks->err_code, db_result, ks->linux_regs);
|
||||
}
|
||||
/*
|
||||
* Upon exit from the kdb main loop setup break points and restart
|
||||
* the system based on the requested continue state
|
||||
*/
|
||||
kdb_initial_cpu = -1;
|
||||
kdb_current_task = NULL;
|
||||
kdb_current_regs = NULL;
|
||||
kdbnearsym_cleanup();
|
||||
if (error == KDB_CMD_KGDB) {
|
||||
if (KDB_STATE(DOING_KGDB) || KDB_STATE(DOING_KGDB2)) {
|
||||
/*
|
||||
* This inteface glue which allows kdb to transition in into
|
||||
* the gdb stub. In order to do this the '?' or '' gdb serial
|
||||
* packet response is processed here. And then control is
|
||||
* passed to the gdbstub.
|
||||
*/
|
||||
if (KDB_STATE(DOING_KGDB))
|
||||
gdbstub_state(ks, "?");
|
||||
else
|
||||
gdbstub_state(ks, "");
|
||||
KDB_STATE_CLEAR(DOING_KGDB);
|
||||
KDB_STATE_CLEAR(DOING_KGDB2);
|
||||
}
|
||||
return DBG_PASS_EVENT;
|
||||
}
|
||||
kdb_bp_install(ks->linux_regs);
|
||||
dbg_activate_sw_breakpoints();
|
||||
/* Set the exit state to a single step or a continue */
|
||||
if (KDB_STATE(DOING_SS))
|
||||
gdbstub_state(ks, "s");
|
||||
else
|
||||
gdbstub_state(ks, "c");
|
||||
|
||||
KDB_FLAG_CLEAR(CATASTROPHIC);
|
||||
|
||||
/* Invoke arch specific exception handling prior to system resume */
|
||||
kgdb_info[ks->cpu].ret_state = gdbstub_state(ks, "e");
|
||||
if (ks->pass_exception)
|
||||
kgdb_info[ks->cpu].ret_state = 1;
|
||||
if (error == KDB_CMD_CPU) {
|
||||
KDB_STATE_SET(REENTRY);
|
||||
/*
|
||||
* Force clear the single step bit because kdb emulates this
|
||||
* differently vs the gdbstub
|
||||
*/
|
||||
kgdb_single_step = 0;
|
||||
dbg_deactivate_sw_breakpoints();
|
||||
return DBG_SWITCH_CPU_EVENT;
|
||||
}
|
||||
return kgdb_info[ks->cpu].ret_state;
|
||||
}
|
||||
|
||||
789
kernel/debug/kdb/kdb_io.c
Normal file
789
kernel/debug/kdb/kdb_io.c
Normal file
File diff suppressed because it is too large
Load Diff
2845
kernel/debug/kdb/kdb_main.c
Normal file
2845
kernel/debug/kdb/kdb_main.c
Normal file
File diff suppressed because it is too large
Load Diff
301
kernel/debug/kdb/kdb_private.h
Normal file
301
kernel/debug/kdb/kdb_private.h
Normal file
@@ -0,0 +1,301 @@
|
||||
#ifndef _KDBPRIVATE_H
|
||||
#define _KDBPRIVATE_H
|
||||
|
||||
/*
|
||||
* Kernel Debugger Architecture Independent Private Headers
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
* Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved.
|
||||
* Copyright (c) 2009 Wind River Systems, Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
#include <linux/kgdb.h>
|
||||
#include "../debug_core.h"
|
||||
|
||||
/* Kernel Debugger Error codes. Must not overlap with command codes. */
|
||||
#define KDB_NOTFOUND (-1)
|
||||
#define KDB_ARGCOUNT (-2)
|
||||
#define KDB_BADWIDTH (-3)
|
||||
#define KDB_BADRADIX (-4)
|
||||
#define KDB_NOTENV (-5)
|
||||
#define KDB_NOENVVALUE (-6)
|
||||
#define KDB_NOTIMP (-7)
|
||||
#define KDB_ENVFULL (-8)
|
||||
#define KDB_ENVBUFFULL (-9)
|
||||
#define KDB_TOOMANYBPT (-10)
|
||||
#define KDB_TOOMANYDBREGS (-11)
|
||||
#define KDB_DUPBPT (-12)
|
||||
#define KDB_BPTNOTFOUND (-13)
|
||||
#define KDB_BADMODE (-14)
|
||||
#define KDB_BADINT (-15)
|
||||
#define KDB_INVADDRFMT (-16)
|
||||
#define KDB_BADREG (-17)
|
||||
#define KDB_BADCPUNUM (-18)
|
||||
#define KDB_BADLENGTH (-19)
|
||||
#define KDB_NOBP (-20)
|
||||
#define KDB_BADADDR (-21)
|
||||
|
||||
/* Kernel Debugger Command codes. Must not overlap with error codes. */
|
||||
#define KDB_CMD_GO (-1001)
|
||||
#define KDB_CMD_CPU (-1002)
|
||||
#define KDB_CMD_SS (-1003)
|
||||
#define KDB_CMD_SSB (-1004)
|
||||
#define KDB_CMD_KGDB (-1005)
|
||||
#define KDB_CMD_KGDB2 (-1006)
|
||||
|
||||
/* Internal debug flags */
|
||||
#define KDB_DEBUG_FLAG_BP 0x0002 /* Breakpoint subsystem debug */
|
||||
#define KDB_DEBUG_FLAG_BB_SUMM 0x0004 /* Basic block analysis, summary only */
|
||||
#define KDB_DEBUG_FLAG_AR 0x0008 /* Activation record, generic */
|
||||
#define KDB_DEBUG_FLAG_ARA 0x0010 /* Activation record, arch specific */
|
||||
#define KDB_DEBUG_FLAG_BB 0x0020 /* All basic block analysis */
|
||||
#define KDB_DEBUG_FLAG_STATE 0x0040 /* State flags */
|
||||
#define KDB_DEBUG_FLAG_MASK 0xffff /* All debug flags */
|
||||
#define KDB_DEBUG_FLAG_SHIFT 16 /* Shift factor for dbflags */
|
||||
|
||||
#define KDB_DEBUG(flag) (kdb_flags & \
|
||||
(KDB_DEBUG_FLAG_##flag << KDB_DEBUG_FLAG_SHIFT))
|
||||
#define KDB_DEBUG_STATE(text, value) if (KDB_DEBUG(STATE)) \
|
||||
kdb_print_state(text, value)
|
||||
|
||||
#if BITS_PER_LONG == 32
|
||||
|
||||
#define KDB_PLATFORM_ENV "BYTESPERWORD=4"
|
||||
|
||||
#define kdb_machreg_fmt "0x%lx"
|
||||
#define kdb_machreg_fmt0 "0x%08lx"
|
||||
#define kdb_bfd_vma_fmt "0x%lx"
|
||||
#define kdb_bfd_vma_fmt0 "0x%08lx"
|
||||
#define kdb_elfw_addr_fmt "0x%x"
|
||||
#define kdb_elfw_addr_fmt0 "0x%08x"
|
||||
#define kdb_f_count_fmt "%d"
|
||||
|
||||
#elif BITS_PER_LONG == 64
|
||||
|
||||
#define KDB_PLATFORM_ENV "BYTESPERWORD=8"
|
||||
|
||||
#define kdb_machreg_fmt "0x%lx"
|
||||
#define kdb_machreg_fmt0 "0x%016lx"
|
||||
#define kdb_bfd_vma_fmt "0x%lx"
|
||||
#define kdb_bfd_vma_fmt0 "0x%016lx"
|
||||
#define kdb_elfw_addr_fmt "0x%x"
|
||||
#define kdb_elfw_addr_fmt0 "0x%016x"
|
||||
#define kdb_f_count_fmt "%ld"
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* KDB_MAXBPT describes the total number of breakpoints
|
||||
* supported by this architecure.
|
||||
*/
|
||||
#define KDB_MAXBPT 16
|
||||
|
||||
/* Maximum number of arguments to a function */
|
||||
#define KDB_MAXARGS 16
|
||||
|
||||
typedef enum {
|
||||
KDB_REPEAT_NONE = 0, /* Do not repeat this command */
|
||||
KDB_REPEAT_NO_ARGS, /* Repeat the command without arguments */
|
||||
KDB_REPEAT_WITH_ARGS, /* Repeat the command including its arguments */
|
||||
} kdb_repeat_t;
|
||||
|
||||
typedef int (*kdb_func_t)(int, const char **);
|
||||
|
||||
/* Symbol table format returned by kallsyms. */
|
||||
typedef struct __ksymtab {
|
||||
unsigned long value; /* Address of symbol */
|
||||
const char *mod_name; /* Module containing symbol or
|
||||
* "kernel" */
|
||||
unsigned long mod_start;
|
||||
unsigned long mod_end;
|
||||
const char *sec_name; /* Section containing symbol */
|
||||
unsigned long sec_start;
|
||||
unsigned long sec_end;
|
||||
const char *sym_name; /* Full symbol name, including
|
||||
* any version */
|
||||
unsigned long sym_start;
|
||||
unsigned long sym_end;
|
||||
} kdb_symtab_t;
|
||||
extern int kallsyms_symbol_next(char *prefix_name, int flag);
|
||||
extern int kallsyms_symbol_complete(char *prefix_name, int max_len);
|
||||
|
||||
/* Exported Symbols for kernel loadable modules to use. */
|
||||
extern int kdb_register(char *, kdb_func_t, char *, char *, short);
|
||||
extern int kdb_register_repeat(char *, kdb_func_t, char *, char *,
|
||||
short, kdb_repeat_t);
|
||||
extern int kdb_unregister(char *);
|
||||
|
||||
extern int kdb_getarea_size(void *, unsigned long, size_t);
|
||||
extern int kdb_putarea_size(unsigned long, void *, size_t);
|
||||
|
||||
/*
|
||||
* Like get_user and put_user, kdb_getarea and kdb_putarea take variable
|
||||
* names, not pointers. The underlying *_size functions take pointers.
|
||||
*/
|
||||
#define kdb_getarea(x, addr) kdb_getarea_size(&(x), addr, sizeof((x)))
|
||||
#define kdb_putarea(addr, x) kdb_putarea_size(addr, &(x), sizeof((x)))
|
||||
|
||||
extern int kdb_getphysword(unsigned long *word,
|
||||
unsigned long addr, size_t size);
|
||||
extern int kdb_getword(unsigned long *, unsigned long, size_t);
|
||||
extern int kdb_putword(unsigned long, unsigned long, size_t);
|
||||
|
||||
extern int kdbgetularg(const char *, unsigned long *);
|
||||
extern int kdb_set(int, const char **);
|
||||
extern char *kdbgetenv(const char *);
|
||||
extern int kdbgetintenv(const char *, int *);
|
||||
extern int kdbgetaddrarg(int, const char **, int*, unsigned long *,
|
||||
long *, char **);
|
||||
extern int kdbgetsymval(const char *, kdb_symtab_t *);
|
||||
extern int kdbnearsym(unsigned long, kdb_symtab_t *);
|
||||
extern void kdbnearsym_cleanup(void);
|
||||
extern char *kdb_strdup(const char *str, gfp_t type);
|
||||
extern void kdb_symbol_print(unsigned long, const kdb_symtab_t *, unsigned int);
|
||||
|
||||
/* Routine for debugging the debugger state. */
|
||||
extern void kdb_print_state(const char *, int);
|
||||
|
||||
extern int kdb_state;
|
||||
#define KDB_STATE_KDB 0x00000001 /* Cpu is inside kdb */
|
||||
#define KDB_STATE_LEAVING 0x00000002 /* Cpu is leaving kdb */
|
||||
#define KDB_STATE_CMD 0x00000004 /* Running a kdb command */
|
||||
#define KDB_STATE_KDB_CONTROL 0x00000008 /* This cpu is under
|
||||
* kdb control */
|
||||
#define KDB_STATE_HOLD_CPU 0x00000010 /* Hold this cpu inside kdb */
|
||||
#define KDB_STATE_DOING_SS 0x00000020 /* Doing ss command */
|
||||
#define KDB_STATE_DOING_SSB 0x00000040 /* Doing ssb command,
|
||||
* DOING_SS is also set */
|
||||
#define KDB_STATE_SSBPT 0x00000080 /* Install breakpoint
|
||||
* after one ss, independent of
|
||||
* DOING_SS */
|
||||
#define KDB_STATE_REENTRY 0x00000100 /* Valid re-entry into kdb */
|
||||
#define KDB_STATE_SUPPRESS 0x00000200 /* Suppress error messages */
|
||||
#define KDB_STATE_PAGER 0x00000400 /* pager is available */
|
||||
#define KDB_STATE_GO_SWITCH 0x00000800 /* go is switching
|
||||
* back to initial cpu */
|
||||
#define KDB_STATE_PRINTF_LOCK 0x00001000 /* Holds kdb_printf lock */
|
||||
#define KDB_STATE_WAIT_IPI 0x00002000 /* Waiting for kdb_ipi() NMI */
|
||||
#define KDB_STATE_RECURSE 0x00004000 /* Recursive entry to kdb */
|
||||
#define KDB_STATE_IP_ADJUSTED 0x00008000 /* Restart IP has been
|
||||
* adjusted */
|
||||
#define KDB_STATE_GO1 0x00010000 /* go only releases one cpu */
|
||||
#define KDB_STATE_KEYBOARD 0x00020000 /* kdb entered via
|
||||
* keyboard on this cpu */
|
||||
#define KDB_STATE_KEXEC 0x00040000 /* kexec issued */
|
||||
#define KDB_STATE_DOING_KGDB 0x00080000 /* kgdb enter now issued */
|
||||
#define KDB_STATE_DOING_KGDB2 0x00100000 /* kgdb enter now issued */
|
||||
#define KDB_STATE_KGDB_TRANS 0x00200000 /* Transition to kgdb */
|
||||
#define KDB_STATE_ARCH 0xff000000 /* Reserved for arch
|
||||
* specific use */
|
||||
|
||||
#define KDB_STATE(flag) (kdb_state & KDB_STATE_##flag)
|
||||
#define KDB_STATE_SET(flag) ((void)(kdb_state |= KDB_STATE_##flag))
|
||||
#define KDB_STATE_CLEAR(flag) ((void)(kdb_state &= ~KDB_STATE_##flag))
|
||||
|
||||
extern int kdb_nextline; /* Current number of lines displayed */
|
||||
|
||||
typedef struct _kdb_bp {
|
||||
unsigned long bp_addr; /* Address breakpoint is present at */
|
||||
unsigned int bp_free:1; /* This entry is available */
|
||||
unsigned int bp_enabled:1; /* Breakpoint is active in register */
|
||||
unsigned int bp_type:4; /* Uses hardware register */
|
||||
unsigned int bp_installed:1; /* Breakpoint is installed */
|
||||
unsigned int bp_delay:1; /* Do delayed bp handling */
|
||||
unsigned int bp_delayed:1; /* Delayed breakpoint */
|
||||
unsigned int bph_length; /* HW break length */
|
||||
} kdb_bp_t;
|
||||
|
||||
#ifdef CONFIG_KGDB_KDB
|
||||
extern kdb_bp_t kdb_breakpoints[/* KDB_MAXBPT */];
|
||||
|
||||
/* The KDB shell command table */
|
||||
typedef struct _kdbtab {
|
||||
char *cmd_name; /* Command name */
|
||||
kdb_func_t cmd_func; /* Function to execute command */
|
||||
char *cmd_usage; /* Usage String for this command */
|
||||
char *cmd_help; /* Help message for this command */
|
||||
short cmd_flags; /* Parsing flags */
|
||||
short cmd_minlen; /* Minimum legal # command
|
||||
* chars required */
|
||||
kdb_repeat_t cmd_repeat; /* Does command auto repeat on enter? */
|
||||
} kdbtab_t;
|
||||
|
||||
extern int kdb_bt(int, const char **); /* KDB display back trace */
|
||||
|
||||
/* KDB breakpoint management functions */
|
||||
extern void kdb_initbptab(void);
|
||||
extern void kdb_bp_install(struct pt_regs *);
|
||||
extern void kdb_bp_remove(void);
|
||||
|
||||
typedef enum {
|
||||
KDB_DB_BPT, /* Breakpoint */
|
||||
KDB_DB_SS, /* Single-step trap */
|
||||
KDB_DB_SSB, /* Single step to branch */
|
||||
KDB_DB_SSBPT, /* Single step over breakpoint */
|
||||
KDB_DB_NOBPT /* Spurious breakpoint */
|
||||
} kdb_dbtrap_t;
|
||||
|
||||
extern int kdb_main_loop(kdb_reason_t, kdb_reason_t,
|
||||
int, kdb_dbtrap_t, struct pt_regs *);
|
||||
|
||||
/* Miscellaneous functions and data areas */
|
||||
extern int kdb_grepping_flag;
|
||||
extern char kdb_grep_string[];
|
||||
extern int kdb_grep_leading;
|
||||
extern int kdb_grep_trailing;
|
||||
extern char *kdb_cmds[];
|
||||
extern void kdb_syslog_data(char *syslog_data[]);
|
||||
extern unsigned long kdb_task_state_string(const char *);
|
||||
extern char kdb_task_state_char (const struct task_struct *);
|
||||
extern unsigned long kdb_task_state(const struct task_struct *p,
|
||||
unsigned long mask);
|
||||
extern void kdb_ps_suppressed(void);
|
||||
extern void kdb_ps1(const struct task_struct *p);
|
||||
extern int kdb_parse(const char *cmdstr);
|
||||
extern void kdb_print_nameval(const char *name, unsigned long val);
|
||||
extern void kdb_send_sig_info(struct task_struct *p, struct siginfo *info);
|
||||
extern void kdb_meminfo_proc_show(void);
|
||||
extern const char *kdb_walk_kallsyms(loff_t *pos);
|
||||
extern char *kdb_getstr(char *, size_t, char *);
|
||||
|
||||
/* Defines for kdb_symbol_print */
|
||||
#define KDB_SP_SPACEB 0x0001 /* Space before string */
|
||||
#define KDB_SP_SPACEA 0x0002 /* Space after string */
|
||||
#define KDB_SP_PAREN 0x0004 /* Parenthesis around string */
|
||||
#define KDB_SP_VALUE 0x0008 /* Print the value of the address */
|
||||
#define KDB_SP_SYMSIZE 0x0010 /* Print the size of the symbol */
|
||||
#define KDB_SP_NEWLINE 0x0020 /* Newline after string */
|
||||
#define KDB_SP_DEFAULT (KDB_SP_VALUE|KDB_SP_PAREN)
|
||||
|
||||
#define KDB_TSK(cpu) kgdb_info[cpu].task
|
||||
#define KDB_TSKREGS(cpu) kgdb_info[cpu].debuggerinfo
|
||||
|
||||
extern struct task_struct *kdb_curr_task(int);
|
||||
|
||||
#define kdb_task_has_cpu(p) (task_curr(p))
|
||||
|
||||
/* Simplify coexistence with NPTL */
|
||||
#define kdb_do_each_thread(g, p) do_each_thread(g, p)
|
||||
#define kdb_while_each_thread(g, p) while_each_thread(g, p)
|
||||
|
||||
#define GFP_KDB (in_interrupt() ? GFP_ATOMIC : GFP_KERNEL)
|
||||
|
||||
extern void *debug_kmalloc(size_t size, gfp_t flags);
|
||||
extern void debug_kfree(void *);
|
||||
extern void debug_kusage(void);
|
||||
|
||||
extern void kdb_set_current_task(struct task_struct *);
|
||||
extern struct task_struct *kdb_current_task;
|
||||
#ifdef CONFIG_MODULES
|
||||
extern struct list_head *kdb_modules;
|
||||
#endif /* CONFIG_MODULES */
|
||||
|
||||
extern char kdb_prompt_str[];
|
||||
|
||||
#define KDB_WORD_SIZE ((int)sizeof(unsigned long))
|
||||
|
||||
#endif /* CONFIG_KGDB_KDB */
|
||||
#endif /* !_KDBPRIVATE_H */
|
||||
927
kernel/debug/kdb/kdb_support.c
Normal file
927
kernel/debug/kdb/kdb_support.c
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user