⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 kgdb.c

📁 Kernel code of linux kernel
💻 C
📖 第 1 页 / 共 3 页
字号:
	}	if (!kgdb_hex2long(&ptr, &addr)) {		error_packet(remcom_out_buffer, -EINVAL);		return;	}	if (*(ptr++) != ',' ||		!kgdb_hex2long(&ptr, &length)) {		error_packet(remcom_out_buffer, -EINVAL);		return;	}	if (remcom_in_buffer[0] == 'Z' && *bpt_type == '0')		error = kgdb_set_sw_break(addr);	else if (remcom_in_buffer[0] == 'z' && *bpt_type == '0')		error = kgdb_remove_sw_break(addr);	else if (remcom_in_buffer[0] == 'Z')		error = arch_kgdb_ops.set_hw_breakpoint(addr,			(int)length, *bpt_type - '0');	else if (remcom_in_buffer[0] == 'z')		error = arch_kgdb_ops.remove_hw_breakpoint(addr,			(int) length, *bpt_type - '0');	if (error == 0)		strcpy(remcom_out_buffer, "OK");	else		error_packet(remcom_out_buffer, error);}/* Handle the 'C' signal / exception passing packets */static int gdb_cmd_exception_pass(struct kgdb_state *ks){	/* C09 == pass exception	 * C15 == detach kgdb, pass exception	 */	if (remcom_in_buffer[1] == '0' && remcom_in_buffer[2] == '9') {		ks->pass_exception = 1;		remcom_in_buffer[0] = 'c';	} else if (remcom_in_buffer[1] == '1' && remcom_in_buffer[2] == '5') {		ks->pass_exception = 1;		remcom_in_buffer[0] = 'D';		remove_all_break();		kgdb_connected = 0;		return 1;	} else {		error_packet(remcom_out_buffer, -EINVAL);		return 0;	}	/* Indicate fall through */	return -1;}/* * This function performs all gdbserial command procesing */static int gdb_serial_stub(struct kgdb_state *ks){	int error = 0;	int tmp;	/* Clear the out buffer. */	memset(remcom_out_buffer, 0, sizeof(remcom_out_buffer));	if (kgdb_connected) {		unsigned char thref[8];		char *ptr;		/* Reply to host that an exception has occurred */		ptr = remcom_out_buffer;		*ptr++ = 'T';		ptr = pack_hex_byte(ptr, ks->signo);		ptr += strlen(strcpy(ptr, "thread:"));		int_to_threadref(thref, shadow_pid(current->pid));		ptr = pack_threadid(ptr, thref);		*ptr++ = ';';		put_packet(remcom_out_buffer);	}	kgdb_usethread = kgdb_info[ks->cpu].task;	ks->kgdb_usethreadid = shadow_pid(kgdb_info[ks->cpu].task->pid);	ks->pass_exception = 0;	while (1) {		error = 0;		/* Clear the out buffer. */		memset(remcom_out_buffer, 0, sizeof(remcom_out_buffer));		get_packet(remcom_in_buffer);		switch (remcom_in_buffer[0]) {		case '?': /* gdbserial status */			gdb_cmd_status(ks);			break;		case 'g': /* return the value of the CPU registers */			gdb_cmd_getregs(ks);			break;		case 'G': /* set the value of the CPU registers - return OK */			gdb_cmd_setregs(ks);			break;		case 'm': /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */			gdb_cmd_memread(ks);			break;		case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA..AA */			gdb_cmd_memwrite(ks);			break;		case 'X': /* XAA..AA,LLLL: Write LLLL bytes at address AA..AA */			gdb_cmd_binwrite(ks);			break;			/* kill or detach. KGDB should treat this like a			 * continue.			 */		case 'D': /* Debugger detach */		case 'k': /* Debugger detach via kill */			gdb_cmd_detachkill(ks);			goto default_handle;		case 'R': /* Reboot */			if (gdb_cmd_reboot(ks))				goto default_handle;			break;		case 'q': /* query command */			gdb_cmd_query(ks);			break;		case 'H': /* task related */			gdb_cmd_task(ks);			break;		case 'T': /* Query thread status */			gdb_cmd_thread(ks);			break;		case 'z': /* Break point remove */		case 'Z': /* Break point set */			gdb_cmd_break(ks);			break;		case 'C': /* Exception passing */			tmp = gdb_cmd_exception_pass(ks);			if (tmp > 0)				goto default_handle;			if (tmp == 0)				break;			/* Fall through on tmp < 0 */		case 'c': /* Continue packet */		case 's': /* Single step packet */			if (kgdb_contthread && kgdb_contthread != current) {				/* Can't switch threads in kgdb */				error_packet(remcom_out_buffer, -EINVAL);				break;			}			kgdb_activate_sw_breakpoints();			/* Fall through to default processing */		default:default_handle:			error = kgdb_arch_handle_exception(ks->ex_vector,						ks->signo,						ks->err_code,						remcom_in_buffer,						remcom_out_buffer,						ks->linux_regs);			/*			 * Leave cmd processing on error, detach,			 * kill, continue, or single step.			 */			if (error >= 0 || remcom_in_buffer[0] == 'D' ||			    remcom_in_buffer[0] == 'k') {				error = 0;				goto kgdb_exit;			}		}		/* reply to the request */		put_packet(remcom_out_buffer);	}kgdb_exit:	if (ks->pass_exception)		error = 1;	return error;}static int kgdb_reenter_check(struct kgdb_state *ks){	unsigned long addr;	if (atomic_read(&kgdb_active) != raw_smp_processor_id())		return 0;	/* Panic on recursive debugger calls: */	exception_level++;	addr = kgdb_arch_pc(ks->ex_vector, ks->linux_regs);	kgdb_deactivate_sw_breakpoints();	/*	 * If the break point removed ok at the place exception	 * occurred, try to recover and print a warning to the end	 * user because the user planted a breakpoint in a place that	 * KGDB needs in order to function.	 */	if (kgdb_remove_sw_break(addr) == 0) {		exception_level = 0;		kgdb_skipexception(ks->ex_vector, ks->linux_regs);		kgdb_activate_sw_breakpoints();		printk(KERN_CRIT "KGDB: re-enter error: breakpoint removed %lx\n",			addr);		WARN_ON_ONCE(1);		return 1;	}	remove_all_break();	kgdb_skipexception(ks->ex_vector, ks->linux_regs);	if (exception_level > 1) {		dump_stack();		panic("Recursive entry to debugger");	}	printk(KERN_CRIT "KGDB: re-enter exception: ALL breakpoints killed\n");	dump_stack();	panic("Recursive entry to debugger");	return 1;}/* * kgdb_handle_exception() - main entry point from a kernel exception * * Locking hierarchy: *	interface locks, if any (begin_session) *	kgdb lock (kgdb_active) */intkgdb_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 error = 0;	int i, cpu;	ks->cpu			= raw_smp_processor_id();	ks->ex_vector		= evector;	ks->signo		= signo;	ks->ex_vector		= evector;	ks->err_code		= ecode;	ks->kgdb_usethreadid	= 0;	ks->linux_regs		= regs;	if (kgdb_reenter_check(ks))		return 0; /* Ouch, double exception ! */acquirelock:	/*	 * Interrupts will be restored by the 'trap return' code, except when	 * single stepping.	 */	local_irq_save(flags);	cpu = raw_smp_processor_id();	/*	 * Acquire the kgdb_active lock:	 */	while (atomic_cmpxchg(&kgdb_active, -1, cpu) != -1)		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	 */	if (atomic_read(&kgdb_cpu_doing_single_step) != -1 &&	    atomic_read(&kgdb_cpu_doing_single_step) != cpu) {		atomic_set(&kgdb_active, -1);		touch_softlockup_watchdog();		clocksource_touch_watchdog();		local_irq_restore(flags);		goto acquirelock;	}	if (!kgdb_io_ready(1)) {		error = 1;		goto kgdb_restore; /* No I/O connection, so resume the system */	}	/*	 * Don't enter if we have hit a removed breakpoint.	 */	if (kgdb_skipexception(ks->ex_vector, ks->linux_regs))		goto kgdb_restore;	/* Call the I/O driver's pre_exception routine */	if (kgdb_io_ops->pre_exception)		kgdb_io_ops->pre_exception();	kgdb_info[ks->cpu].debuggerinfo = ks->linux_regs;	kgdb_info[ks->cpu].task = current;	kgdb_disable_hw_debug(ks->linux_regs);	/*	 * Get the passive CPU lock which will hold all the non-primary	 * CPU in a spin state while the debugger is active	 */	if (!kgdb_single_step) {		for (i = 0; i < NR_CPUS; i++)			atomic_set(&passive_cpu_wait[i], 1);	}	/*	 * spin_lock code is good enough as a barrier so we don't	 * need one here:	 */	atomic_set(&cpu_in_kgdb[ks->cpu], 1);#ifdef CONFIG_SMP	/* Signal the other CPUs to enter kgdb_wait() */	if ((!kgdb_single_step) && kgdb_do_roundup)		kgdb_roundup_cpus(flags);#endif	/*	 * Wait for the other CPUs to be notified and be waiting for us:	 */	for_each_online_cpu(i) {		while (!atomic_read(&cpu_in_kgdb[i]))			cpu_relax();	}	/*	 * At this point the primary processor is completely	 * in the debugger and all secondary CPUs are quiescent	 */	kgdb_post_primary_code(ks->linux_regs, ks->ex_vector, ks->err_code);	kgdb_deactivate_sw_breakpoints();	kgdb_single_step = 0;	kgdb_contthread = current;	exception_level = 0;	/* Talk to debugger with gdbserial protocol */	error = gdb_serial_stub(ks);	/* Call the I/O driver's post_exception routine */	if (kgdb_io_ops->post_exception)		kgdb_io_ops->post_exception();	kgdb_info[ks->cpu].debuggerinfo = NULL;	kgdb_info[ks->cpu].task = NULL;	atomic_set(&cpu_in_kgdb[ks->cpu], 0);	if (!kgdb_single_step) {		for (i = NR_CPUS-1; i >= 0; i--)			atomic_set(&passive_cpu_wait[i], 0);		/*		 * Wait till all the CPUs have quit		 * from the debugger.		 */		for_each_online_cpu(i) {			while (atomic_read(&cpu_in_kgdb[i]))				cpu_relax();		}	}kgdb_restore:	/* Free kgdb_active */	atomic_set(&kgdb_active, -1);	touch_softlockup_watchdog();	clocksource_touch_watchdog();	local_irq_restore(flags);	return error;}int kgdb_nmicallback(int cpu, void *regs){#ifdef CONFIG_SMP	if (!atomic_read(&cpu_in_kgdb[cpu]) &&			atomic_read(&kgdb_active) != cpu &&			atomic_read(&cpu_in_kgdb[atomic_read(&kgdb_active)])) {		kgdb_wait((struct pt_regs *)regs);		return 0;	}#endif	return 1;}static void kgdb_console_write(struct console *co, const char *s,   unsigned count){	unsigned long flags;	/* If we're debugging, or KGDB has not connected, don't try	 * and print. */	if (!kgdb_connected || atomic_read(&kgdb_active) != -1)		return;	local_irq_save(flags);	kgdb_msg_write(s, count);	local_irq_restore(flags);}static struct console kgdbcons = {	.name		= "kgdb",	.write		= kgdb_console_write,	.flags		= CON_PRINTBUFFER | CON_ENABLED,	.index		= -1,};#ifdef CONFIG_MAGIC_SYSRQstatic void sysrq_handle_gdb(int key, struct tty_struct *tty){	if (!kgdb_io_ops) {		printk(KERN_CRIT "ERROR: No KGDB I/O module available\n");		return;	}	if (!kgdb_connected)		printk(KERN_CRIT "Entering KGDB\n");	kgdb_breakpoint();}static struct sysrq_key_op sysrq_gdb_op = {	.handler	= sysrq_handle_gdb,	.help_msg	= "Gdb",	.action_msg	= "GDB",};#endifstatic void kgdb_register_callbacks(void){	if (!kgdb_io_module_registered) {		kgdb_io_module_registered = 1;		kgdb_arch_init();#ifdef CONFIG_MAGIC_SYSRQ		register_sysrq_key('g', &sysrq_gdb_op);#endif		if (kgdb_use_con && !kgdb_con_registered) {			register_console(&kgdbcons);			kgdb_con_registered = 1;		}	}}static void kgdb_unregister_callbacks(void){	/*	 * When this routine is called KGDB should unregister from the	 * panic handler and clean up, making sure it is not handling any	 * break exceptions at the time.	 */	if (kgdb_io_module_registered) {		kgdb_io_module_registered = 0;		kgdb_arch_exit();#ifdef CONFIG_MAGIC_SYSRQ		unregister_sysrq_key('g', &sysrq_gdb_op);#endif		if (kgdb_con_registered) {			unregister_console(&kgdbcons);			kgdb_con_registered = 0;		}	}}static void kgdb_initial_breakpoint(void){	kgdb_break_asap = 0;	printk(KERN_CRIT "kgdb: Waiting for connection from remote gdb...\n");	kgdb_breakpoint();}/** *	kgdb_register_io_module - register KGDB IO module *	@new_kgdb_io_ops: the io ops vector * *	Register it with the KGDB core. */int kgdb_register_io_module(struct kgdb_io *new_kgdb_io_ops){	int err;	spin_lock(&kgdb_registration_lock);	if (kgdb_io_ops) {		spin_unlock(&kgdb_registration_lock);		printk(KERN_ERR "kgdb: Another I/O driver is already "				"registered with KGDB.\n");		return -EBUSY;	}	if (new_kgdb_io_ops->init) {		err = new_kgdb_io_ops->init();		if (err) {			spin_unlock(&kgdb_registration_lock);			return err;		}	}	kgdb_io_ops = new_kgdb_io_ops;	spin_unlock(&kgdb_registration_lock);	printk(KERN_INFO "kgdb: Registered I/O driver %s.\n",	       new_kgdb_io_ops->name);	/* Arm KGDB now. */	kgdb_register_callbacks();	if (kgdb_break_asap)		kgdb_initial_breakpoint();	return 0;}EXPORT_SYMBOL_GPL(kgdb_register_io_module);/** *	kkgdb_unregister_io_module - unregister KGDB IO module *	@old_kgdb_io_ops: the io ops vector * *	Unregister it with the KGDB core. */void kgdb_unregister_io_module(struct kgdb_io *old_kgdb_io_ops){	BUG_ON(kgdb_connected);	/*	 * KGDB is no longer able to communicate out, so	 * unregister our callbacks and reset state.	 */	kgdb_unregister_callbacks();	spin_lock(&kgdb_registration_lock);	WARN_ON_ONCE(kgdb_io_ops != old_kgdb_io_ops);	kgdb_io_ops = NULL;	spin_unlock(&kgdb_registration_lock);	printk(KERN_INFO		"kgdb: Unregistered I/O driver %s, debugger disabled.\n",		old_kgdb_io_ops->name);}EXPORT_SYMBOL_GPL(kgdb_unregister_io_module);/** * kgdb_breakpoint - generate breakpoint exception * * This function will generate a breakpoint exception.  It is used at the * beginning of a program to sync up with a debugger and can be used * otherwise as a quick means to stop program execution and "break" into * the debugger. */void kgdb_breakpoint(void){	atomic_set(&kgdb_setting_breakpoint, 1);	wmb(); /* Sync point before breakpoint */	arch_kgdb_breakpoint();	wmb(); /* Sync point after breakpoint */	atomic_set(&kgdb_setting_breakpoint, 0);}EXPORT_SYMBOL_GPL(kgdb_breakpoint);static int __init opt_kgdb_wait(char *str){	kgdb_break_asap = 1;	if (kgdb_io_module_registered)		kgdb_initial_breakpoint();	return 0;}early_param("kgdbwait", opt_kgdb_wait);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -