diff options
Diffstat (limited to 'kernel/kgdb.c')
| -rw-r--r-- | kernel/kgdb.c | 58 | 
1 files changed, 41 insertions, 17 deletions
| diff --git a/kernel/kgdb.c b/kernel/kgdb.c index 9147a3190c9d..2eb517e23514 100644 --- a/kernel/kgdb.c +++ b/kernel/kgdb.c @@ -129,6 +129,7 @@ struct task_struct		*kgdb_usethread;  struct task_struct		*kgdb_contthread;  int				kgdb_single_step; +pid_t				kgdb_sstep_pid;  /* Our I/O buffers. */  static char			remcom_in_buffer[BUFMAX]; @@ -541,12 +542,17 @@ static struct task_struct *getthread(struct pt_regs *regs, int tid)  	 */  	if (tid == 0 || tid == -1)  		tid = -atomic_read(&kgdb_active) - 2; -	if (tid < 0) { +	if (tid < -1 && tid > -NR_CPUS - 2) {  		if (kgdb_info[-tid - 2].task)  			return kgdb_info[-tid - 2].task;  		else  			return idle_task(-tid - 2);  	} +	if (tid <= 0) { +		printk(KERN_ERR "KGDB: Internal thread select error\n"); +		dump_stack(); +		return NULL; +	}  	/*  	 * find_task_by_pid_ns() does not take the tasklist lock anymore @@ -619,7 +625,8 @@ static void kgdb_flush_swbreak_addr(unsigned long addr)  static int kgdb_activate_sw_breakpoints(void)  {  	unsigned long addr; -	int error = 0; +	int error; +	int ret = 0;  	int i;  	for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) { @@ -629,13 +636,16 @@ static int kgdb_activate_sw_breakpoints(void)  		addr = kgdb_break[i].bpt_addr;  		error = kgdb_arch_set_breakpoint(addr,  				kgdb_break[i].saved_instr); -		if (error) -			return error; +		if (error) { +			ret = error; +			printk(KERN_INFO "KGDB: BP install failed: %lx", addr); +			continue; +		}  		kgdb_flush_swbreak_addr(addr);  		kgdb_break[i].state = BP_ACTIVE;  	} -	return 0; +	return ret;  }  static int kgdb_set_sw_break(unsigned long addr) @@ -682,7 +692,8 @@ static int kgdb_set_sw_break(unsigned long addr)  static int kgdb_deactivate_sw_breakpoints(void)  {  	unsigned long addr; -	int error = 0; +	int error; +	int ret = 0;  	int i;  	for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) { @@ -691,13 +702,15 @@ static int kgdb_deactivate_sw_breakpoints(void)  		addr = kgdb_break[i].bpt_addr;  		error = kgdb_arch_remove_breakpoint(addr,  					kgdb_break[i].saved_instr); -		if (error) -			return error; +		if (error) { +			printk(KERN_INFO "KGDB: BP remove failed: %lx\n", addr); +			ret = error; +		}  		kgdb_flush_swbreak_addr(addr);  		kgdb_break[i].state = BP_SET;  	} -	return 0; +	return ret;  }  static int kgdb_remove_sw_break(unsigned long addr) @@ -870,7 +883,7 @@ static void gdb_cmd_getregs(struct kgdb_state *ks)  	/*  	 * All threads that don't have debuggerinfo should be -	 * in __schedule() sleeping, since all other CPUs +	 * in schedule() sleeping, since all other CPUs  	 * are in kgdb_wait, and thus have debuggerinfo.  	 */  	if (local_debuggerinfo) { @@ -1204,8 +1217,10 @@ static int gdb_cmd_exception_pass(struct kgdb_state *ks)  		return 1;  	} else { -		error_packet(remcom_out_buffer, -EINVAL); -		return 0; +		kgdb_msg_write("KGDB only knows signal 9 (pass)" +			" and 15 (pass and disconnect)\n" +			"Executing a continue without signal passing\n", 0); +		remcom_in_buffer[0] = 'c';  	}  	/* Indicate fall through */ @@ -1395,6 +1410,7 @@ kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs)  	struct kgdb_state kgdb_var;  	struct kgdb_state *ks = &kgdb_var;  	unsigned long flags; +	int sstep_tries = 100;  	int error = 0;  	int i, cpu; @@ -1425,13 +1441,14 @@ acquirelock:  		cpu_relax();  	/* -	 * Do not start the debugger connection on this CPU if the last -	 * instance of the exception handler wanted to come into the -	 * debugger on a different CPU via a single step +	 * For single stepping, try to only enter on the processor +	 * that was single stepping.  To gaurd against a deadlock, the +	 * kernel will only try for the value of sstep_tries before +	 * giving up and continuing on.  	 */  	if (atomic_read(&kgdb_cpu_doing_single_step) != -1 && -	    atomic_read(&kgdb_cpu_doing_single_step) != cpu) { - +	    (kgdb_info[cpu].task && +	     kgdb_info[cpu].task->pid != kgdb_sstep_pid) && --sstep_tries) {  		atomic_set(&kgdb_active, -1);  		touch_softlockup_watchdog();  		clocksource_touch_watchdog(); @@ -1524,6 +1541,13 @@ acquirelock:  	}  kgdb_restore: +	if (atomic_read(&kgdb_cpu_doing_single_step) != -1) { +		int sstep_cpu = atomic_read(&kgdb_cpu_doing_single_step); +		if (kgdb_info[sstep_cpu].task) +			kgdb_sstep_pid = kgdb_info[sstep_cpu].task->pid; +		else +			kgdb_sstep_pid = 0; +	}  	/* Free kgdb_active */  	atomic_set(&kgdb_active, -1);  	touch_softlockup_watchdog(); |