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

📄 kgdb.c

📁 Kernel code of linux kernel
💻 C
📖 第 1 页 / 共 3 页
字号:
	/* Wait till primary CPU is done with debugging */	while (atomic_read(&passive_cpu_wait[cpu]))		cpu_relax();	kgdb_info[cpu].debuggerinfo = NULL;	kgdb_info[cpu].task = NULL;	/* fix up hardware debug registers on local cpu */	if (arch_kgdb_ops.correct_hw_break)		arch_kgdb_ops.correct_hw_break();	/* Signal the primary CPU that we are done: */	atomic_set(&cpu_in_kgdb[cpu], 0);	touch_softlockup_watchdog();	clocksource_touch_watchdog();	local_irq_restore(flags);}#endif/* * Some architectures need cache flushes when we set/clear a * breakpoint: */static void kgdb_flush_swbreak_addr(unsigned long addr){	if (!CACHE_FLUSH_IS_SAFE)		return;	if (current->mm && current->mm->mmap_cache) {		flush_cache_range(current->mm->mmap_cache,				  addr, addr + BREAK_INSTR_SIZE);	}	/* Force flush instruction cache if it was outside the mm */	flush_icache_range(addr, addr + BREAK_INSTR_SIZE);}/* * SW breakpoint management: */static int kgdb_activate_sw_breakpoints(void){	unsigned long addr;	int error = 0;	int i;	for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) {		if (kgdb_break[i].state != BP_SET)			continue;		addr = kgdb_break[i].bpt_addr;		error = kgdb_arch_set_breakpoint(addr,				kgdb_break[i].saved_instr);		if (error)			return error;		kgdb_flush_swbreak_addr(addr);		kgdb_break[i].state = BP_ACTIVE;	}	return 0;}static int kgdb_set_sw_break(unsigned long addr){	int err = kgdb_validate_break_address(addr);	int breakno = -1;	int i;	if (err)		return err;	for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) {		if ((kgdb_break[i].state == BP_SET) &&					(kgdb_break[i].bpt_addr == addr))			return -EEXIST;	}	for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) {		if (kgdb_break[i].state == BP_REMOVED &&					kgdb_break[i].bpt_addr == addr) {			breakno = i;			break;		}	}	if (breakno == -1) {		for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) {			if (kgdb_break[i].state == BP_UNDEFINED) {				breakno = i;				break;			}		}	}	if (breakno == -1)		return -E2BIG;	kgdb_break[breakno].state = BP_SET;	kgdb_break[breakno].type = BP_BREAKPOINT;	kgdb_break[breakno].bpt_addr = addr;	return 0;}static int kgdb_deactivate_sw_breakpoints(void){	unsigned long addr;	int error = 0;	int i;	for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) {		if (kgdb_break[i].state != BP_ACTIVE)			continue;		addr = kgdb_break[i].bpt_addr;		error = kgdb_arch_remove_breakpoint(addr,					kgdb_break[i].saved_instr);		if (error)			return error;		kgdb_flush_swbreak_addr(addr);		kgdb_break[i].state = BP_SET;	}	return 0;}static int kgdb_remove_sw_break(unsigned long addr){	int i;	for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) {		if ((kgdb_break[i].state == BP_SET) &&				(kgdb_break[i].bpt_addr == addr)) {			kgdb_break[i].state = BP_REMOVED;			return 0;		}	}	return -ENOENT;}int kgdb_isremovedbreak(unsigned long addr){	int i;	for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) {		if ((kgdb_break[i].state == BP_REMOVED) &&					(kgdb_break[i].bpt_addr == addr))			return 1;	}	return 0;}static int remove_all_break(void){	unsigned long addr;	int error;	int i;	/* Clear memory breakpoints. */	for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) {		if (kgdb_break[i].state != BP_ACTIVE)			goto setundefined;		addr = kgdb_break[i].bpt_addr;		error = kgdb_arch_remove_breakpoint(addr,				kgdb_break[i].saved_instr);		if (error)			printk(KERN_ERR "KGDB: breakpoint remove failed: %lx\n",			   addr);setundefined:		kgdb_break[i].state = BP_UNDEFINED;	}	/* Clear hardware breakpoints. */	if (arch_kgdb_ops.remove_all_hw_break)		arch_kgdb_ops.remove_all_hw_break();	return 0;}/* * 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 -raw_smp_processor_id() - 2;}static char gdbmsgbuf[BUFMAX + 1];static void kgdb_msg_write(const char *s, int len){	char *bufptr;	int wcount;	int i;	/* 'O'utput */	gdbmsgbuf[0] = 'O';	/* Fill and send buffers... */	while (len > 0) {		bufptr = gdbmsgbuf + 1;		/* Calculate how many this time */		if ((len << 1) > (BUFMAX - 2))			wcount = (BUFMAX - 2) >> 1;		else			wcount = len;		/* Pack in hex chars */		for (i = 0; i < wcount; i++)			bufptr = pack_hex_byte(bufptr, s[i]);		*bufptr = '\0';		/* Move up */		s += wcount;		len -= wcount;		/* Write packet */		put_packet(gdbmsgbuf);	}}/* * Return true if there is a valid kgdb I/O module.  Also if no * debugger is attached a message can be printed to the console about * waiting for the debugger to attach. * * The print_wait argument is only to be true when called from inside * the core kgdb_handle_exception, because it will wait for the * debugger to attach. */static int kgdb_io_ready(int print_wait){	if (!kgdb_io_ops)		return 0;	if (kgdb_connected)		return 1;	if (atomic_read(&kgdb_setting_breakpoint))		return 1;	if (print_wait)		printk(KERN_CRIT "KGDB: Waiting for remote debugger\n");	return 1;}/* * All the functions that start with gdb_cmd are the various * operations to implement the handlers for the gdbserial protocol * where KGDB is communicating with an external debugger *//* Handle the '?' status packets */static void gdb_cmd_status(struct kgdb_state *ks){	/*	 * We know that this packet is only sent	 * during initial connect.  So to be safe,	 * we clear out our breakpoints now in case	 * GDB is reconnecting.	 */	remove_all_break();	remcom_out_buffer[0] = 'S';	pack_hex_byte(&remcom_out_buffer[1], ks->signo);}/* Handle the 'g' get registers request */static void gdb_cmd_getregs(struct kgdb_state *ks){	struct task_struct *thread;	void *local_debuggerinfo;	int i;	thread = kgdb_usethread;	if (!thread) {		thread = kgdb_info[ks->cpu].task;		local_debuggerinfo = kgdb_info[ks->cpu].debuggerinfo;	} else {		local_debuggerinfo = NULL;		for_each_online_cpu(i) {			/*			 * Try to find the task on some other			 * or possibly this node if we do not			 * find the matching task then we try			 * to approximate the results.			 */			if (thread == kgdb_info[i].task)				local_debuggerinfo = kgdb_info[i].debuggerinfo;		}	}	/*	 * All threads that don't have debuggerinfo should be	 * in __schedule() sleeping, since all other CPUs	 * are in kgdb_wait, and thus have debuggerinfo.	 */	if (local_debuggerinfo) {		pt_regs_to_gdb_regs(gdb_regs, local_debuggerinfo);	} else {		/*		 * Pull stuff saved during switch_to; nothing		 * else is accessible (or even particularly		 * relevant).		 *		 * This should be enough for a stack trace.		 */		sleeping_thread_to_gdb_regs(gdb_regs, thread);	}	kgdb_mem2hex((char *)gdb_regs, remcom_out_buffer, NUMREGBYTES);}/* Handle the 'G' set registers request */static void gdb_cmd_setregs(struct kgdb_state *ks){	kgdb_hex2mem(&remcom_in_buffer[1], (char *)gdb_regs, NUMREGBYTES);	if (kgdb_usethread && kgdb_usethread != current) {		error_packet(remcom_out_buffer, -EINVAL);	} else {		gdb_regs_to_pt_regs(gdb_regs, ks->linux_regs);		strcpy(remcom_out_buffer, "OK");	}}/* Handle the 'm' memory read bytes */static void gdb_cmd_memread(struct kgdb_state *ks){	char *ptr = &remcom_in_buffer[1];	unsigned long length;	unsigned long addr;	int err;	if (kgdb_hex2long(&ptr, &addr) > 0 && *ptr++ == ',' &&					kgdb_hex2long(&ptr, &length) > 0) {		err = kgdb_mem2hex((char *)addr, remcom_out_buffer, length);		if (err)			error_packet(remcom_out_buffer, err);	} else {		error_packet(remcom_out_buffer, -EINVAL);	}}/* Handle the 'M' memory write bytes */static void gdb_cmd_memwrite(struct kgdb_state *ks){	int err = write_mem_msg(0);	if (err)		error_packet(remcom_out_buffer, err);	else		strcpy(remcom_out_buffer, "OK");}/* Handle the 'X' memory binary write bytes */static void gdb_cmd_binwrite(struct kgdb_state *ks){	int err = write_mem_msg(1);	if (err)		error_packet(remcom_out_buffer, err);	else		strcpy(remcom_out_buffer, "OK");}/* Handle the 'D' or 'k', detach or kill packets */static void gdb_cmd_detachkill(struct kgdb_state *ks){	int error;	/* The detach case */	if (remcom_in_buffer[0] == 'D') {		error = remove_all_break();		if (error < 0) {			error_packet(remcom_out_buffer, error);		} else {			strcpy(remcom_out_buffer, "OK");			kgdb_connected = 0;		}		put_packet(remcom_out_buffer);	} else {		/*		 * Assume the kill case, with no exit code checking,		 * trying to force detach the debugger:		 */		remove_all_break();		kgdb_connected = 0;	}}/* Handle the 'R' reboot packets */static int gdb_cmd_reboot(struct kgdb_state *ks){	/* For now, only honor R0 */	if (strcmp(remcom_in_buffer, "R0") == 0) {		printk(KERN_CRIT "Executing emergency reboot\n");		strcpy(remcom_out_buffer, "OK");		put_packet(remcom_out_buffer);		/*		 * Execution should not return from		 * machine_emergency_restart()		 */		machine_emergency_restart();		kgdb_connected = 0;		return 1;	}	return 0;}/* Handle the 'q' query packets */static void gdb_cmd_query(struct kgdb_state *ks){	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':	case 'f':		if (memcmp(remcom_in_buffer + 2, "ThreadInfo", 10)) {			error_packet(remcom_out_buffer, -EINVAL);			break;		}		i = 0;		remcom_out_buffer[0] = 'm';		ptr = remcom_out_buffer + 1;		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;	case 'C':		/* Current thread id */		strcpy(remcom_out_buffer, "QC");		ks->threadid = shadow_pid(current->pid);		int_to_threadref(thref, ks->threadid);		pack_threadid(remcom_out_buffer + 2, thref);		break;	case 'T':		if (memcmp(remcom_in_buffer + 1, "ThreadExtraInfo,", 16)) {			error_packet(remcom_out_buffer, -EINVAL);			break;		}		ks->threadid = 0;		ptr = remcom_in_buffer + 17;		kgdb_hex2long(&ptr, &ks->threadid);		if (!getthread(ks->linux_regs, ks->threadid)) {			error_packet(remcom_out_buffer, -EINVAL);			break;		}		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, "shadowCPU%d",					(int)(-ks->threadid - 2));			kgdb_mem2hex(tmpstr, remcom_out_buffer, strlen(tmpstr));		}		break;	}}/* Handle the 'H' task query packets */static void gdb_cmd_task(struct kgdb_state *ks){	struct task_struct *thread;	char *ptr;	switch (remcom_in_buffer[1]) {	case 'g':		ptr = &remcom_in_buffer[2];		kgdb_hex2long(&ptr, &ks->threadid);		thread = getthread(ks->linux_regs, ks->threadid);		if (!thread && ks->threadid > 0) {			error_packet(remcom_out_buffer, -EINVAL);			break;		}		kgdb_usethread = thread;		ks->kgdb_usethreadid = ks->threadid;		strcpy(remcom_out_buffer, "OK");		break;	case 'c':		ptr = &remcom_in_buffer[2];		kgdb_hex2long(&ptr, &ks->threadid);		if (!ks->threadid) {			kgdb_contthread = NULL;		} else {			thread = getthread(ks->linux_regs, ks->threadid);			if (!thread && ks->threadid > 0) {				error_packet(remcom_out_buffer, -EINVAL);				break;			}			kgdb_contthread = thread;		}		strcpy(remcom_out_buffer, "OK");		break;	}}/* Handle the 'T' thread query packets */static void gdb_cmd_thread(struct kgdb_state *ks){	char *ptr = &remcom_in_buffer[1];	struct task_struct *thread;	kgdb_hex2long(&ptr, &ks->threadid);	thread = getthread(ks->linux_regs, ks->threadid);	if (thread)		strcpy(remcom_out_buffer, "OK");	else		error_packet(remcom_out_buffer, -EINVAL);}/* Handle the 'z' or 'Z' breakpoint remove or set packets */static void gdb_cmd_break(struct kgdb_state *ks){	/*	 * Since GDB-5.3, it's been drafted that '0' is a software	 * breakpoint, '1' is a hardware breakpoint, so let's do that.	 */	char *bpt_type = &remcom_in_buffer[1];	char *ptr = &remcom_in_buffer[2];	unsigned long addr;	unsigned long length;	int error = 0;	if (arch_kgdb_ops.set_hw_breakpoint && *bpt_type >= '1') {		/* Unsupported */		if (*bpt_type > '4')			return;	} else {		if (*bpt_type != '0' && *bpt_type != '1')			/* Unsupported. */			return;	}	/*	 * Test if this is a hardware breakpoint, and	 * if we support it:	 */	if (*bpt_type == '1' && !(arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT))		/* Unsupported. */		return;	if (*(ptr++) != ',') {		error_packet(remcom_out_buffer, -EINVAL);		return;

⌨️ 快捷键说明

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