Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 31582b09 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/linux-2.6-kgdb:
  kgdb: fix gdb serial thread queries
  kgdb: fix kgdb_validate_break_address to perform a mem write
  kgdb: remove the requirement for CONFIG_FRAME_POINTER
parents df1efe6f 25fc9999
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -98,6 +98,24 @@
    "Kernel debugging" select "KGDB: kernel debugging with remote gdb".
    </para>
    <para>
    It is advised, but not required that you turn on the
    CONFIG_FRAME_POINTER kernel option.  This option inserts code to
    into the compiled executable which saves the frame information in
    registers or on the stack at different points which will allow a
    debugger such as gdb to more accurately construct stack back traces
    while debugging the kernel.
    </para>
    <para>
    If the architecture that you are using supports the kernel option
    CONFIG_DEBUG_RODATA, you should consider turning it off.  This
    option will prevent the use of software breakpoints because it
    marks certain regions of the kernel's memory space as read-only.
    If kgdb supports it for the architecture you are using, you can
    use hardware breakpoints if you desire to run with the
    CONFIG_DEBUG_RODATA option turned on, else you need to turn off
    this option.
    </para>
    <para>
    Next you should choose one of more I/O drivers to interconnect debugging
    host and debugged target.  Early boot debugging requires a KGDB
    I/O driver that supports early debugging and the driver must be
+69 −25
Original line number Diff line number Diff line
@@ -56,12 +56,14 @@

static int kgdb_break_asap;

#define KGDB_MAX_THREAD_QUERY 17
struct kgdb_state {
	int			ex_vector;
	int			signo;
	int			err_code;
	int			cpu;
	int			pass_exception;
	unsigned long		thr_query;
	unsigned long		threadid;
	long			kgdb_usethreadid;
	struct pt_regs		*linux_regs;
@@ -166,13 +168,6 @@ early_param("nokgdbroundup", opt_nokgdbroundup);
 * Weak aliases for breakpoint management,
 * can be overriden by architectures when needed:
 */
int __weak kgdb_validate_break_address(unsigned long addr)
{
	char tmp_variable[BREAK_INSTR_SIZE];

	return probe_kernel_read(tmp_variable, (char *)addr, BREAK_INSTR_SIZE);
}

int __weak kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr)
{
	int err;
@@ -191,6 +186,25 @@ int __weak kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle)
				  (char *)bundle, BREAK_INSTR_SIZE);
}

int __weak kgdb_validate_break_address(unsigned long addr)
{
	char tmp_variable[BREAK_INSTR_SIZE];
	int err;
	/* Validate setting the breakpoint and then removing it.  In the
	 * remove fails, the kernel needs to emit a bad message because we
	 * are deep trouble not being able to put things back the way we
	 * found them.
	 */
	err = kgdb_arch_set_breakpoint(addr, tmp_variable);
	if (err)
		return err;
	err = kgdb_arch_remove_breakpoint(addr, tmp_variable);
	if (err)
		printk(KERN_ERR "KGDB: Critical breakpoint error, kernel "
		   "memory destroyed at: %lx", addr);
	return err;
}

unsigned long __weak kgdb_arch_pc(int exception, struct pt_regs *regs)
{
	return instruction_pointer(regs);
@@ -433,9 +447,14 @@ int kgdb_hex2long(char **ptr, unsigned long *long_val)
{
	int hex_val;
	int num = 0;
	int negate = 0;

	*long_val = 0;

	if (**ptr == '-') {
		negate = 1;
		(*ptr)++;
	}
	while (**ptr) {
		hex_val = hex(**ptr);
		if (hex_val < 0)
@@ -446,6 +465,9 @@ int kgdb_hex2long(char **ptr, unsigned long *long_val)
		(*ptr)++;
	}

	if (negate)
		*long_val = -*long_val;

	return num;
}

@@ -515,10 +537,16 @@ static void int_to_threadref(unsigned char *id, int value)
static struct task_struct *getthread(struct pt_regs *regs, int tid)
{
	/*
	 * Non-positive TIDs are remapped idle tasks:
	 * Non-positive TIDs are remapped to the cpu shadow information
	 */
	if (tid <= 0)
		return idle_task(-tid);
	if (tid == 0 || tid == -1)
		tid = -atomic_read(&kgdb_active) - 2;
	if (tid < 0) {
		if (kgdb_info[-tid - 2].task)
			return kgdb_info[-tid - 2].task;
		else
			return idle_task(-tid - 2);
	}

	/*
	 * find_task_by_pid_ns() does not take the tasklist lock anymore
@@ -725,14 +753,15 @@ static int remove_all_break(void)
}

/*
 * Remap normal tasks to their real PID, idle tasks to -1 ... -NR_CPUs:
 * Remap normal tasks to their real PID,
 * CPU shadow threads are mapped to -CPU - 2
 */
static inline int shadow_pid(int realpid)
{
	if (realpid)
		return realpid;

	return -1-raw_smp_processor_id();
	return -raw_smp_processor_id() - 2;
}

static char gdbmsgbuf[BUFMAX + 1];
@@ -826,7 +855,7 @@ static void gdb_cmd_getregs(struct kgdb_state *ks)
		local_debuggerinfo = kgdb_info[ks->cpu].debuggerinfo;
	} else {
		local_debuggerinfo = NULL;
		for (i = 0; i < NR_CPUS; i++) {
		for_each_online_cpu(i) {
			/*
			 * Try to find the task on some other
			 * or possibly this node if we do not
@@ -960,10 +989,13 @@ static int gdb_cmd_reboot(struct kgdb_state *ks)
/* Handle the 'q' query packets */
static void gdb_cmd_query(struct kgdb_state *ks)
{
	struct task_struct *thread;
	struct task_struct *g;
	struct task_struct *p;
	unsigned char thref[8];
	char *ptr;
	int i;
	int cpu;
	int finished = 0;

	switch (remcom_in_buffer[1]) {
	case 's':
@@ -973,22 +1005,34 @@ static void gdb_cmd_query(struct kgdb_state *ks)
			break;
		}

		if (remcom_in_buffer[1] == 'f')
			ks->threadid = 1;

		i = 0;
		remcom_out_buffer[0] = 'm';
		ptr = remcom_out_buffer + 1;

		for (i = 0; i < 17; ks->threadid++) {
			thread = getthread(ks->linux_regs, ks->threadid);
			if (thread) {
				int_to_threadref(thref, ks->threadid);
		if (remcom_in_buffer[1] == 'f') {
			/* Each cpu is a shadow thread */
			for_each_online_cpu(cpu) {
				ks->thr_query = 0;
				int_to_threadref(thref, -cpu - 2);
				pack_threadid(ptr, thref);
				ptr += BUF_THREAD_ID_SIZE;
				*(ptr++) = ',';
				i++;
			}
		}

		do_each_thread(g, p) {
			if (i >= ks->thr_query && !finished) {
				int_to_threadref(thref, p->pid);
				pack_threadid(ptr, thref);
				ptr += BUF_THREAD_ID_SIZE;
				*(ptr++) = ',';
				ks->thr_query++;
				if (ks->thr_query % KGDB_MAX_THREAD_QUERY == 0)
					finished = 1;
			}
			i++;
		} while_each_thread(g, p);

		*(--ptr) = '\0';
		break;

@@ -1011,15 +1055,15 @@ static void gdb_cmd_query(struct kgdb_state *ks)
			error_packet(remcom_out_buffer, -EINVAL);
			break;
		}
		if (ks->threadid > 0) {
		if ((int)ks->threadid > 0) {
			kgdb_mem2hex(getthread(ks->linux_regs,
					ks->threadid)->comm,
					remcom_out_buffer, 16);
		} else {
			static char tmpstr[23 + BUF_THREAD_ID_SIZE];

			sprintf(tmpstr, "Shadow task %d for pid 0",
					(int)(-ks->threadid-1));
			sprintf(tmpstr, "shadowCPU%d",
					(int)(-ks->threadid - 2));
			kgdb_mem2hex(tmpstr, remcom_out_buffer, strlen(tmpstr));
		}
		break;
+7 −4
Original line number Diff line number Diff line
@@ -4,14 +4,17 @@ config HAVE_ARCH_KGDB

menuconfig KGDB
	bool "KGDB: kernel debugging with remote gdb"
	select FRAME_POINTER
	depends on HAVE_ARCH_KGDB
	depends on DEBUG_KERNEL && EXPERIMENTAL
	help
	  If you say Y here, it will be possible to remotely debug the
	  kernel using gdb.  Documentation of kernel debugger is available
	  at http://kgdb.sourceforge.net as well as in DocBook form
	  in Documentation/DocBook/.  If unsure, say N.
	  kernel using gdb.  It is recommended but not required, that
	  you also turn on the kernel config option
	  CONFIG_FRAME_POINTER to aid in producing more reliable stack
	  backtraces in the external debugger.  Documentation of
	  kernel debugger is available at http://kgdb.sourceforge.net
	  as well as in DocBook form in Documentation/DocBook/.  If
	  unsure, say N.

if KGDB