📄 kgdb-stub.c
字号:
while (i--) *scan++ = 0; *scan++ = (value >> 24) & 0xff; *scan++ = (value >> 16) & 0xff; *scan++ = (value >> 8) & 0xff; *scan++ = (value & 0xff);}/* Return a task structure ptr for a particular pid */static struct task_struct * get_thread(int pid){ struct task_struct *thread; /* Use PID_MAX w/gdb for pid 0 */ if (pid == PID_MAX) pid = 0; /* First check via PID */ thread = find_task_by_pid(pid); if (thread) return thread; /* Start at the start */ thread = init_tasks[0]; /* Walk along the linked list of tasks */ do { if (thread->pid == pid) return thread; thread = thread->next_task; } while (thread != init_tasks[0]); return NULL;}#endif /* CONFIG_KGDB_THREAD */void kgdb_msg(const char * msg){ const char *emsg; for (emsg = msg; *emsg; emsg++) ; remcomOutBuffer[0] = 'O'; mem2hex(msg, remcomOutBuffer+1, emsg-msg); if (kgdb_active()) kgdb_put_packet(remcomOutBuffer);}static void send_ok_msg(void){ kgdb_put_packet("OK");}static void send_err_msg(void){ kgdb_put_packet("E01");}static void send_empty_msg(void){ kgdb_put_packet("");}static void send_signal_msg(const int signum){#ifndef CONFIG_KGDB_THREAD remcomOutBuffer[0] = 'S'; remcomOutBuffer[1] = hexchars[(signum >> 4) & 0xf]; remcomOutBuffer[2] = hexchars[signum % 16]; remcomOutBuffer[3] = 0;#else /* CONFIG_KGDB_THREAD */ int threadid; threadref thref; char *out = remcomOutBuffer; const char *tstring = "thread"; *out++ = 'T'; *out++ = hexchars[(signum >> 4) & 0xf]; *out++ = hexchars[signum % 16]; while (*tstring) { *out++ = *tstring++; } *out++ = ':'; threadid = trapped_thread->pid; if (threadid == 0) threadid = PID_MAX; int_to_threadref(&thref, threadid); pack_threadid(out, &thref); out += BUF_THREAD_ID_SIZE; *out++ = ';'; *out = 0;#endif /* CONFIG_KGDB_THREAD */ kgdb_put_packet(remcomOutBuffer);}static void send_regs_msg(void){#ifdef CONFIG_KGDB_THREAD if (!current_thread) kregs2gregs(&kgdb_regs, gdb_regs); else tregs2gregs(current_thread, gdb_regs);#else kregs2gregs(&kgdb_regs, gdb_regs);#endif mem2hex((const char *)gdb_regs, remcomOutBuffer, GDB_REGBYTES); kgdb_put_packet(remcomOutBuffer);}/* Set register contents - currently can't set other thread's registers */static void set_regs_msg(void){#ifdef CONFIG_KGDB_THREAD if (!current_thread) {#endif kregs2gregs(&kgdb_regs, gdb_regs); hex2mem(&remcomInBuffer[1], (char *) gdb_regs, GDB_REGBYTES); gregs2kregs(gdb_regs, &kgdb_regs); send_ok_msg();#ifdef CONFIG_KGDB_THREAD } else send_err_msg();#endif}/* The following provides support for recovery from bus * errors during kgdb memory read/write operations. */void kgdb_handle_bus_error(void){ kgdb_longjmp(fault_jmp_buf, 1);}/* Read memory due to 'm' message */static void read_mem_msg(void){ char *ptr; int addr; int length; /* Jmp, disable bus error handler */ if (kgdb_setjmp(fault_jmp_buf) == 0) { kgdb_fault_expected = 1; /* Walk through, have m<addr>,<length> */ ptr = &remcomInBuffer[1]; if (hex2int(&ptr, &addr) && (*ptr++ == ',')) if (hex2int(&ptr, &length)) { ptr = 0; if (length * 2 > BUFMAX) length = BUFMAX / 2; mem2hex((char *) addr, remcomOutBuffer, length); } if (ptr) send_err_msg(); else kgdb_put_packet(remcomOutBuffer); } else send_err_msg(); /* Restore bus error handler */ kgdb_fault_expected = 0;}/* Write memory due to 'M' or 'X' message */static void write_mem_msg(int binary){ char *ptr; int addr; int length; if (kgdb_setjmp(fault_jmp_buf) == 0) { kgdb_fault_expected = 1; /* Walk through, have M<addr>,<length>:<data> */ ptr = &remcomInBuffer[1]; if (hex2int(&ptr, &addr) && (*ptr++ == ',')) if (hex2int(&ptr, &length) && (*ptr++ == ':')) { if (binary) ebin2mem(ptr, (char*)addr, length); else hex2mem(ptr, (char*)addr, length); ptr = 0; /* * Trap breakpoints */ if(length == 4 && !(addr & 0x3) && *((unsigned *)addr) == GDB_BREAKINST) *((unsigned *)addr) = KGDB_BREAKINST; send_ok_msg(); } if (ptr) send_err_msg(); } else send_err_msg(); /* Restore bus error handler */ kgdb_fault_expected = 0;}static void continue_msg(void){ /* Try to read optional parameter, PC unchanged if none */ char *ptr = &remcomInBuffer[1]; int addr; if (hex2int(&ptr, &addr)) kgdb_regs.ARM_pc = addr; strcpy(remcomOutBuffer, "OK"); kgdb_put_packet(remcomOutBuffer);}static void continue_with_sig_msg(void){ int signal; char *ptr = &remcomInBuffer[1]; int addr; /* Report limitation */ kgdb_msg("Cannot force signal in kgdb, continuing anyway.\n"); /* Signal */ hex2int(&ptr, &signal); if (*ptr == ';') ptr++; /* Optional address */ if (hex2int(&ptr, &addr)) kgdb_regs.ARM_pc = addr; strcpy(remcomOutBuffer, "OK"); kgdb_put_packet(remcomOutBuffer);}void do_single_step(void){ step_addr = (unsigned int *) get_next_pc(&kgdb_regs); step_instr = *step_addr; *step_addr = KGDB_BREAKINST;}static void undo_single_step(void){ if (step_addr != NULL) { *step_addr = step_instr; step_addr = NULL; step_instr = 0; }}static void step_msg(void){ continue_msg(); do_single_step();}static void step_with_sig_msg(void){ continue_with_sig_msg(); do_single_step();}/* Set the status for a thread */void set_thread_msg(void){#ifndef CONFIG_KGDB_THREAD strcpy(remcomOutBuffer, "OK"); kgdb_put_packet(remcomOutBuffer);#else int threadid; struct task_struct *thread = NULL; char *ptr; switch (remcomInBuffer[1]) { /* To select which thread for gG etc messages, i.e. supported */ case 'g': ptr = &remcomInBuffer[2]; hex2int(&ptr, &threadid); thread = get_thread(threadid); /* If we haven't found it */ if (!thread) { send_err_msg(); break; } /* Set current_thread (or not) */ if (thread == trapped_thread) current_thread = NULL; else current_thread = thread; send_ok_msg(); break; /* To select which thread for cCsS messages, i.e. unsupported */ case 'c': send_ok_msg(); break; default: send_empty_msg(); break; }#endif}#ifdef CONFIG_KGDB_THREAD/* Is a thread alive? */static void thread_status_msg(void){ char *ptr; int threadid; struct task_struct *thread = NULL; ptr = &remcomInBuffer[1]; hex2int(&ptr, &threadid); thread = get_thread(threadid); if (thread) send_ok_msg(); else send_err_msg();}/* Send the current thread ID */static void thread_id_msg(void){ int threadid; threadref thref; remcomOutBuffer[0] = 'Q'; remcomOutBuffer[1] = 'C'; if (current_thread) threadid = current_thread->pid; else if (trapped_thread) threadid = trapped_thread->pid; else /* Impossible, but just in case! */ { send_err_msg(); return; } /* Translate pid 0 to PID_MAX for gdb */ if (threadid == 0) threadid = PID_MAX; int_to_threadref(&thref, threadid); pack_threadid(remcomOutBuffer + 2, &thref); remcomOutBuffer[2 + BUF_THREAD_ID_SIZE] = '\0'; kgdb_put_packet(remcomOutBuffer);}/* Send thread info */static void thread_info_msg(void){ struct task_struct *thread = NULL; int threadid; char *pos; threadref thref; /* Start with 'm' */ remcomOutBuffer[0] = 'm'; pos = &remcomOutBuffer[1]; /* For all possible thread IDs - this will overrun if > 44 threads! */ /* Start at 1 and include PID_MAX (since GDB won't use pid 0...) */ for (threadid = 1; threadid <= PID_MAX; threadid++) { read_lock(&tasklist_lock); thread = get_thread(threadid); read_unlock(&tasklist_lock); /* If it's a valid thread */ if (thread) { int_to_threadref(&thref, threadid); pack_threadid(pos, &thref); pos += BUF_THREAD_ID_SIZE; *pos++ = ','; } } *--pos = 0; /* Lose final comma */ kgdb_put_packet(remcomOutBuffer);}/* Return printable info for gdb's 'info threads' command */static void thread_extra_info_msg(void){ int threadid; struct task_struct *thread = NULL; char buffer[20], *ptr; int i; /* Extract thread ID */ ptr = &remcomInBuffer[17]; hex2int(&ptr, &threadid); thread = get_thread(threadid); /* If we don't recognise it, say so */ if (thread == NULL) strcpy(buffer, "(unknown)"); else strcpy(buffer, thread->comm); /* Construct packet */ for (i = 0, ptr = remcomOutBuffer; buffer[i]; i++) ptr = pack_hex_byte(ptr, buffer[i]);#if 0 /* REVISIT! */ if (thread->thread.pc == (unsigned long)ret_from_fork) { strcpy(buffer, "<new fork>"); for (i = 0; buffer[i]; i++) ptr = pack_hex_byte(ptr, buffer[i]); }#endif *ptr = '\0'; kgdb_put_packet(remcomOutBuffer);}/* Handle all qFooBarBaz messages - have to use an if statement as opposed to a switch because q messages can have > 1 char id. */static void query_msg(void){ const char *q_start = &remcomInBuffer[1]; /* qC = return current thread ID */ if (strncmp(q_start, "C", 1) == 0) thread_id_msg(); /* qfThreadInfo = query all threads (first) */ else if (strncmp(q_start, "fThreadInfo", 11) == 0) thread_info_msg(); /* qsThreadInfo = query all threads (subsequent). We know we have sent them all after the qfThreadInfo message, so there are no to send */ else if (strncmp(q_start, "sThreadInfo", 11) == 0) kgdb_put_packet("l"); /* el = last */ /* qThreadExtraInfo = supply printable information per thread */ else if (strncmp(q_start, "ThreadExtraInfo", 15) == 0) thread_extra_info_msg(); /* Unsupported - empty message as per spec */ else send_empty_msg();}#endif /* CONFIG_KGDB_THREAD *//* * This function does all command procesing for interfacing to gdb. */void do_kgdb(struct pt_regs *trap_regs, unsigned char sigval){ unsigned long flags; save_flags_cli(flags); kgdb_regs = *trap_regs; /* Quick and dirty clone of pt_regs */ /* * reply to host that an exception has occurred * * We don't do this on the first call as it would cause a sync problem. */ if (kgdb_initialized) { send_signal_msg(sigval); } else { /* * This is the first breakpoint, called from * start_kernel or elsewhere. We need to * (re-)initialize the I/O subsystem. */ printk("Breaking into KGDB\n"); if(kgdb_io_init()) { printk("KGB I/O INIT FAILED...HALTING!"); while(1){ }; } } kgdb_initialized = 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -