1*53197fc4SJason Wessel /* 2*53197fc4SJason Wessel * Kernel Debug Core 3*53197fc4SJason Wessel * 4*53197fc4SJason Wessel * Maintainer: Jason Wessel <jason.wessel@windriver.com> 5*53197fc4SJason Wessel * 6*53197fc4SJason Wessel * Copyright (C) 2000-2001 VERITAS Software Corporation. 7*53197fc4SJason Wessel * Copyright (C) 2002-2004 Timesys Corporation 8*53197fc4SJason Wessel * Copyright (C) 2003-2004 Amit S. Kale <amitkale@linsyssoft.com> 9*53197fc4SJason Wessel * Copyright (C) 2004 Pavel Machek <pavel@suse.cz> 10*53197fc4SJason Wessel * Copyright (C) 2004-2006 Tom Rini <trini@kernel.crashing.org> 11*53197fc4SJason Wessel * Copyright (C) 2004-2006 LinSysSoft Technologies Pvt. Ltd. 12*53197fc4SJason Wessel * Copyright (C) 2005-2009 Wind River Systems, Inc. 13*53197fc4SJason Wessel * Copyright (C) 2007 MontaVista Software, Inc. 14*53197fc4SJason Wessel * Copyright (C) 2008 Red Hat, Inc., Ingo Molnar <mingo@redhat.com> 15*53197fc4SJason Wessel * 16*53197fc4SJason Wessel * Contributors at various stages not listed above: 17*53197fc4SJason Wessel * Jason Wessel ( jason.wessel@windriver.com ) 18*53197fc4SJason Wessel * George Anzinger <george@mvista.com> 19*53197fc4SJason Wessel * Anurekh Saxena (anurekh.saxena@timesys.com) 20*53197fc4SJason Wessel * Lake Stevens Instrument Division (Glenn Engel) 21*53197fc4SJason Wessel * Jim Kingdon, Cygnus Support. 22*53197fc4SJason Wessel * 23*53197fc4SJason Wessel * Original KGDB stub: David Grothe <dave@gcom.com>, 24*53197fc4SJason Wessel * Tigran Aivazian <tigran@sco.com> 25*53197fc4SJason Wessel * 26*53197fc4SJason Wessel * This file is licensed under the terms of the GNU General Public License 27*53197fc4SJason Wessel * version 2. This program is licensed "as is" without any warranty of any 28*53197fc4SJason Wessel * kind, whether express or implied. 29*53197fc4SJason Wessel */ 30*53197fc4SJason Wessel 31*53197fc4SJason Wessel #include <linux/kernel.h> 32*53197fc4SJason Wessel #include <linux/kgdb.h> 33*53197fc4SJason Wessel #include <linux/reboot.h> 34*53197fc4SJason Wessel #include <linux/uaccess.h> 35*53197fc4SJason Wessel #include <asm/cacheflush.h> 36*53197fc4SJason Wessel #include <asm/unaligned.h> 37*53197fc4SJason Wessel #include "debug_core.h" 38*53197fc4SJason Wessel 39*53197fc4SJason Wessel #define KGDB_MAX_THREAD_QUERY 17 40*53197fc4SJason Wessel 41*53197fc4SJason Wessel /* Our I/O buffers. */ 42*53197fc4SJason Wessel static char remcom_in_buffer[BUFMAX]; 43*53197fc4SJason Wessel static char remcom_out_buffer[BUFMAX]; 44*53197fc4SJason Wessel 45*53197fc4SJason Wessel /* Storage for the registers, in GDB format. */ 46*53197fc4SJason Wessel static unsigned long gdb_regs[(NUMREGBYTES + 47*53197fc4SJason Wessel sizeof(unsigned long) - 1) / 48*53197fc4SJason Wessel sizeof(unsigned long)]; 49*53197fc4SJason Wessel 50*53197fc4SJason Wessel /* 51*53197fc4SJason Wessel * GDB remote protocol parser: 52*53197fc4SJason Wessel */ 53*53197fc4SJason Wessel 54*53197fc4SJason Wessel static int hex(char ch) 55*53197fc4SJason Wessel { 56*53197fc4SJason Wessel if ((ch >= 'a') && (ch <= 'f')) 57*53197fc4SJason Wessel return ch - 'a' + 10; 58*53197fc4SJason Wessel if ((ch >= '0') && (ch <= '9')) 59*53197fc4SJason Wessel return ch - '0'; 60*53197fc4SJason Wessel if ((ch >= 'A') && (ch <= 'F')) 61*53197fc4SJason Wessel return ch - 'A' + 10; 62*53197fc4SJason Wessel return -1; 63*53197fc4SJason Wessel } 64*53197fc4SJason Wessel 65*53197fc4SJason Wessel /* scan for the sequence $<data>#<checksum> */ 66*53197fc4SJason Wessel static void get_packet(char *buffer) 67*53197fc4SJason Wessel { 68*53197fc4SJason Wessel unsigned char checksum; 69*53197fc4SJason Wessel unsigned char xmitcsum; 70*53197fc4SJason Wessel int count; 71*53197fc4SJason Wessel char ch; 72*53197fc4SJason Wessel 73*53197fc4SJason Wessel do { 74*53197fc4SJason Wessel /* 75*53197fc4SJason Wessel * Spin and wait around for the start character, ignore all 76*53197fc4SJason Wessel * other characters: 77*53197fc4SJason Wessel */ 78*53197fc4SJason Wessel while ((ch = (dbg_io_ops->read_char())) != '$') 79*53197fc4SJason Wessel /* nothing */; 80*53197fc4SJason Wessel 81*53197fc4SJason Wessel kgdb_connected = 1; 82*53197fc4SJason Wessel checksum = 0; 83*53197fc4SJason Wessel xmitcsum = -1; 84*53197fc4SJason Wessel 85*53197fc4SJason Wessel count = 0; 86*53197fc4SJason Wessel 87*53197fc4SJason Wessel /* 88*53197fc4SJason Wessel * now, read until a # or end of buffer is found: 89*53197fc4SJason Wessel */ 90*53197fc4SJason Wessel while (count < (BUFMAX - 1)) { 91*53197fc4SJason Wessel ch = dbg_io_ops->read_char(); 92*53197fc4SJason Wessel if (ch == '#') 93*53197fc4SJason Wessel break; 94*53197fc4SJason Wessel checksum = checksum + ch; 95*53197fc4SJason Wessel buffer[count] = ch; 96*53197fc4SJason Wessel count = count + 1; 97*53197fc4SJason Wessel } 98*53197fc4SJason Wessel buffer[count] = 0; 99*53197fc4SJason Wessel 100*53197fc4SJason Wessel if (ch == '#') { 101*53197fc4SJason Wessel xmitcsum = hex(dbg_io_ops->read_char()) << 4; 102*53197fc4SJason Wessel xmitcsum += hex(dbg_io_ops->read_char()); 103*53197fc4SJason Wessel 104*53197fc4SJason Wessel if (checksum != xmitcsum) 105*53197fc4SJason Wessel /* failed checksum */ 106*53197fc4SJason Wessel dbg_io_ops->write_char('-'); 107*53197fc4SJason Wessel else 108*53197fc4SJason Wessel /* successful transfer */ 109*53197fc4SJason Wessel dbg_io_ops->write_char('+'); 110*53197fc4SJason Wessel if (dbg_io_ops->flush) 111*53197fc4SJason Wessel dbg_io_ops->flush(); 112*53197fc4SJason Wessel } 113*53197fc4SJason Wessel } while (checksum != xmitcsum); 114*53197fc4SJason Wessel } 115*53197fc4SJason Wessel 116*53197fc4SJason Wessel /* 117*53197fc4SJason Wessel * Send the packet in buffer. 118*53197fc4SJason Wessel * Check for gdb connection if asked for. 119*53197fc4SJason Wessel */ 120*53197fc4SJason Wessel static void put_packet(char *buffer) 121*53197fc4SJason Wessel { 122*53197fc4SJason Wessel unsigned char checksum; 123*53197fc4SJason Wessel int count; 124*53197fc4SJason Wessel char ch; 125*53197fc4SJason Wessel 126*53197fc4SJason Wessel /* 127*53197fc4SJason Wessel * $<packet info>#<checksum>. 128*53197fc4SJason Wessel */ 129*53197fc4SJason Wessel while (1) { 130*53197fc4SJason Wessel dbg_io_ops->write_char('$'); 131*53197fc4SJason Wessel checksum = 0; 132*53197fc4SJason Wessel count = 0; 133*53197fc4SJason Wessel 134*53197fc4SJason Wessel while ((ch = buffer[count])) { 135*53197fc4SJason Wessel dbg_io_ops->write_char(ch); 136*53197fc4SJason Wessel checksum += ch; 137*53197fc4SJason Wessel count++; 138*53197fc4SJason Wessel } 139*53197fc4SJason Wessel 140*53197fc4SJason Wessel dbg_io_ops->write_char('#'); 141*53197fc4SJason Wessel dbg_io_ops->write_char(hex_asc_hi(checksum)); 142*53197fc4SJason Wessel dbg_io_ops->write_char(hex_asc_lo(checksum)); 143*53197fc4SJason Wessel if (dbg_io_ops->flush) 144*53197fc4SJason Wessel dbg_io_ops->flush(); 145*53197fc4SJason Wessel 146*53197fc4SJason Wessel /* Now see what we get in reply. */ 147*53197fc4SJason Wessel ch = dbg_io_ops->read_char(); 148*53197fc4SJason Wessel 149*53197fc4SJason Wessel if (ch == 3) 150*53197fc4SJason Wessel ch = dbg_io_ops->read_char(); 151*53197fc4SJason Wessel 152*53197fc4SJason Wessel /* If we get an ACK, we are done. */ 153*53197fc4SJason Wessel if (ch == '+') 154*53197fc4SJason Wessel return; 155*53197fc4SJason Wessel 156*53197fc4SJason Wessel /* 157*53197fc4SJason Wessel * If we get the start of another packet, this means 158*53197fc4SJason Wessel * that GDB is attempting to reconnect. We will NAK 159*53197fc4SJason Wessel * the packet being sent, and stop trying to send this 160*53197fc4SJason Wessel * packet. 161*53197fc4SJason Wessel */ 162*53197fc4SJason Wessel if (ch == '$') { 163*53197fc4SJason Wessel dbg_io_ops->write_char('-'); 164*53197fc4SJason Wessel if (dbg_io_ops->flush) 165*53197fc4SJason Wessel dbg_io_ops->flush(); 166*53197fc4SJason Wessel return; 167*53197fc4SJason Wessel } 168*53197fc4SJason Wessel } 169*53197fc4SJason Wessel } 170*53197fc4SJason Wessel 171*53197fc4SJason Wessel static char gdbmsgbuf[BUFMAX + 1]; 172*53197fc4SJason Wessel 173*53197fc4SJason Wessel void gdbstub_msg_write(const char *s, int len) 174*53197fc4SJason Wessel { 175*53197fc4SJason Wessel char *bufptr; 176*53197fc4SJason Wessel int wcount; 177*53197fc4SJason Wessel int i; 178*53197fc4SJason Wessel 179*53197fc4SJason Wessel /* 'O'utput */ 180*53197fc4SJason Wessel gdbmsgbuf[0] = 'O'; 181*53197fc4SJason Wessel 182*53197fc4SJason Wessel /* Fill and send buffers... */ 183*53197fc4SJason Wessel while (len > 0) { 184*53197fc4SJason Wessel bufptr = gdbmsgbuf + 1; 185*53197fc4SJason Wessel 186*53197fc4SJason Wessel /* Calculate how many this time */ 187*53197fc4SJason Wessel if ((len << 1) > (BUFMAX - 2)) 188*53197fc4SJason Wessel wcount = (BUFMAX - 2) >> 1; 189*53197fc4SJason Wessel else 190*53197fc4SJason Wessel wcount = len; 191*53197fc4SJason Wessel 192*53197fc4SJason Wessel /* Pack in hex chars */ 193*53197fc4SJason Wessel for (i = 0; i < wcount; i++) 194*53197fc4SJason Wessel bufptr = pack_hex_byte(bufptr, s[i]); 195*53197fc4SJason Wessel *bufptr = '\0'; 196*53197fc4SJason Wessel 197*53197fc4SJason Wessel /* Move up */ 198*53197fc4SJason Wessel s += wcount; 199*53197fc4SJason Wessel len -= wcount; 200*53197fc4SJason Wessel 201*53197fc4SJason Wessel /* Write packet */ 202*53197fc4SJason Wessel put_packet(gdbmsgbuf); 203*53197fc4SJason Wessel } 204*53197fc4SJason Wessel } 205*53197fc4SJason Wessel 206*53197fc4SJason Wessel /* 207*53197fc4SJason Wessel * Convert the memory pointed to by mem into hex, placing result in 208*53197fc4SJason Wessel * buf. Return a pointer to the last char put in buf (null). May 209*53197fc4SJason Wessel * return an error. 210*53197fc4SJason Wessel */ 211*53197fc4SJason Wessel int kgdb_mem2hex(char *mem, char *buf, int count) 212*53197fc4SJason Wessel { 213*53197fc4SJason Wessel char *tmp; 214*53197fc4SJason Wessel int err; 215*53197fc4SJason Wessel 216*53197fc4SJason Wessel /* 217*53197fc4SJason Wessel * We use the upper half of buf as an intermediate buffer for the 218*53197fc4SJason Wessel * raw memory copy. Hex conversion will work against this one. 219*53197fc4SJason Wessel */ 220*53197fc4SJason Wessel tmp = buf + count; 221*53197fc4SJason Wessel 222*53197fc4SJason Wessel err = probe_kernel_read(tmp, mem, count); 223*53197fc4SJason Wessel if (!err) { 224*53197fc4SJason Wessel while (count > 0) { 225*53197fc4SJason Wessel buf = pack_hex_byte(buf, *tmp); 226*53197fc4SJason Wessel tmp++; 227*53197fc4SJason Wessel count--; 228*53197fc4SJason Wessel } 229*53197fc4SJason Wessel 230*53197fc4SJason Wessel *buf = 0; 231*53197fc4SJason Wessel } 232*53197fc4SJason Wessel 233*53197fc4SJason Wessel return err; 234*53197fc4SJason Wessel } 235*53197fc4SJason Wessel 236*53197fc4SJason Wessel /* 237*53197fc4SJason Wessel * Convert the hex array pointed to by buf into binary to be placed in 238*53197fc4SJason Wessel * mem. Return a pointer to the character AFTER the last byte 239*53197fc4SJason Wessel * written. May return an error. 240*53197fc4SJason Wessel */ 241*53197fc4SJason Wessel int kgdb_hex2mem(char *buf, char *mem, int count) 242*53197fc4SJason Wessel { 243*53197fc4SJason Wessel char *tmp_raw; 244*53197fc4SJason Wessel char *tmp_hex; 245*53197fc4SJason Wessel 246*53197fc4SJason Wessel /* 247*53197fc4SJason Wessel * We use the upper half of buf as an intermediate buffer for the 248*53197fc4SJason Wessel * raw memory that is converted from hex. 249*53197fc4SJason Wessel */ 250*53197fc4SJason Wessel tmp_raw = buf + count * 2; 251*53197fc4SJason Wessel 252*53197fc4SJason Wessel tmp_hex = tmp_raw - 1; 253*53197fc4SJason Wessel while (tmp_hex >= buf) { 254*53197fc4SJason Wessel tmp_raw--; 255*53197fc4SJason Wessel *tmp_raw = hex(*tmp_hex--); 256*53197fc4SJason Wessel *tmp_raw |= hex(*tmp_hex--) << 4; 257*53197fc4SJason Wessel } 258*53197fc4SJason Wessel 259*53197fc4SJason Wessel return probe_kernel_write(mem, tmp_raw, count); 260*53197fc4SJason Wessel } 261*53197fc4SJason Wessel 262*53197fc4SJason Wessel /* 263*53197fc4SJason Wessel * While we find nice hex chars, build a long_val. 264*53197fc4SJason Wessel * Return number of chars processed. 265*53197fc4SJason Wessel */ 266*53197fc4SJason Wessel int kgdb_hex2long(char **ptr, unsigned long *long_val) 267*53197fc4SJason Wessel { 268*53197fc4SJason Wessel int hex_val; 269*53197fc4SJason Wessel int num = 0; 270*53197fc4SJason Wessel int negate = 0; 271*53197fc4SJason Wessel 272*53197fc4SJason Wessel *long_val = 0; 273*53197fc4SJason Wessel 274*53197fc4SJason Wessel if (**ptr == '-') { 275*53197fc4SJason Wessel negate = 1; 276*53197fc4SJason Wessel (*ptr)++; 277*53197fc4SJason Wessel } 278*53197fc4SJason Wessel while (**ptr) { 279*53197fc4SJason Wessel hex_val = hex(**ptr); 280*53197fc4SJason Wessel if (hex_val < 0) 281*53197fc4SJason Wessel break; 282*53197fc4SJason Wessel 283*53197fc4SJason Wessel *long_val = (*long_val << 4) | hex_val; 284*53197fc4SJason Wessel num++; 285*53197fc4SJason Wessel (*ptr)++; 286*53197fc4SJason Wessel } 287*53197fc4SJason Wessel 288*53197fc4SJason Wessel if (negate) 289*53197fc4SJason Wessel *long_val = -*long_val; 290*53197fc4SJason Wessel 291*53197fc4SJason Wessel return num; 292*53197fc4SJason Wessel } 293*53197fc4SJason Wessel 294*53197fc4SJason Wessel /* 295*53197fc4SJason Wessel * Copy the binary array pointed to by buf into mem. Fix $, #, and 296*53197fc4SJason Wessel * 0x7d escaped with 0x7d. Return -EFAULT on failure or 0 on success. 297*53197fc4SJason Wessel * The input buf is overwitten with the result to write to mem. 298*53197fc4SJason Wessel */ 299*53197fc4SJason Wessel static int kgdb_ebin2mem(char *buf, char *mem, int count) 300*53197fc4SJason Wessel { 301*53197fc4SJason Wessel int size = 0; 302*53197fc4SJason Wessel char *c = buf; 303*53197fc4SJason Wessel 304*53197fc4SJason Wessel while (count-- > 0) { 305*53197fc4SJason Wessel c[size] = *buf++; 306*53197fc4SJason Wessel if (c[size] == 0x7d) 307*53197fc4SJason Wessel c[size] = *buf++ ^ 0x20; 308*53197fc4SJason Wessel size++; 309*53197fc4SJason Wessel } 310*53197fc4SJason Wessel 311*53197fc4SJason Wessel return probe_kernel_write(mem, c, size); 312*53197fc4SJason Wessel } 313*53197fc4SJason Wessel 314*53197fc4SJason Wessel /* Write memory due to an 'M' or 'X' packet. */ 315*53197fc4SJason Wessel static int write_mem_msg(int binary) 316*53197fc4SJason Wessel { 317*53197fc4SJason Wessel char *ptr = &remcom_in_buffer[1]; 318*53197fc4SJason Wessel unsigned long addr; 319*53197fc4SJason Wessel unsigned long length; 320*53197fc4SJason Wessel int err; 321*53197fc4SJason Wessel 322*53197fc4SJason Wessel if (kgdb_hex2long(&ptr, &addr) > 0 && *(ptr++) == ',' && 323*53197fc4SJason Wessel kgdb_hex2long(&ptr, &length) > 0 && *(ptr++) == ':') { 324*53197fc4SJason Wessel if (binary) 325*53197fc4SJason Wessel err = kgdb_ebin2mem(ptr, (char *)addr, length); 326*53197fc4SJason Wessel else 327*53197fc4SJason Wessel err = kgdb_hex2mem(ptr, (char *)addr, length); 328*53197fc4SJason Wessel if (err) 329*53197fc4SJason Wessel return err; 330*53197fc4SJason Wessel if (CACHE_FLUSH_IS_SAFE) 331*53197fc4SJason Wessel flush_icache_range(addr, addr + length); 332*53197fc4SJason Wessel return 0; 333*53197fc4SJason Wessel } 334*53197fc4SJason Wessel 335*53197fc4SJason Wessel return -EINVAL; 336*53197fc4SJason Wessel } 337*53197fc4SJason Wessel 338*53197fc4SJason Wessel static void error_packet(char *pkt, int error) 339*53197fc4SJason Wessel { 340*53197fc4SJason Wessel error = -error; 341*53197fc4SJason Wessel pkt[0] = 'E'; 342*53197fc4SJason Wessel pkt[1] = hex_asc[(error / 10)]; 343*53197fc4SJason Wessel pkt[2] = hex_asc[(error % 10)]; 344*53197fc4SJason Wessel pkt[3] = '\0'; 345*53197fc4SJason Wessel } 346*53197fc4SJason Wessel 347*53197fc4SJason Wessel /* 348*53197fc4SJason Wessel * Thread ID accessors. We represent a flat TID space to GDB, where 349*53197fc4SJason Wessel * the per CPU idle threads (which under Linux all have PID 0) are 350*53197fc4SJason Wessel * remapped to negative TIDs. 351*53197fc4SJason Wessel */ 352*53197fc4SJason Wessel 353*53197fc4SJason Wessel #define BUF_THREAD_ID_SIZE 16 354*53197fc4SJason Wessel 355*53197fc4SJason Wessel static char *pack_threadid(char *pkt, unsigned char *id) 356*53197fc4SJason Wessel { 357*53197fc4SJason Wessel char *limit; 358*53197fc4SJason Wessel 359*53197fc4SJason Wessel limit = pkt + BUF_THREAD_ID_SIZE; 360*53197fc4SJason Wessel while (pkt < limit) 361*53197fc4SJason Wessel pkt = pack_hex_byte(pkt, *id++); 362*53197fc4SJason Wessel 363*53197fc4SJason Wessel return pkt; 364*53197fc4SJason Wessel } 365*53197fc4SJason Wessel 366*53197fc4SJason Wessel static void int_to_threadref(unsigned char *id, int value) 367*53197fc4SJason Wessel { 368*53197fc4SJason Wessel unsigned char *scan; 369*53197fc4SJason Wessel int i = 4; 370*53197fc4SJason Wessel 371*53197fc4SJason Wessel scan = (unsigned char *)id; 372*53197fc4SJason Wessel while (i--) 373*53197fc4SJason Wessel *scan++ = 0; 374*53197fc4SJason Wessel put_unaligned_be32(value, scan); 375*53197fc4SJason Wessel } 376*53197fc4SJason Wessel 377*53197fc4SJason Wessel static struct task_struct *getthread(struct pt_regs *regs, int tid) 378*53197fc4SJason Wessel { 379*53197fc4SJason Wessel /* 380*53197fc4SJason Wessel * Non-positive TIDs are remapped to the cpu shadow information 381*53197fc4SJason Wessel */ 382*53197fc4SJason Wessel if (tid == 0 || tid == -1) 383*53197fc4SJason Wessel tid = -atomic_read(&kgdb_active) - 2; 384*53197fc4SJason Wessel if (tid < -1 && tid > -NR_CPUS - 2) { 385*53197fc4SJason Wessel if (kgdb_info[-tid - 2].task) 386*53197fc4SJason Wessel return kgdb_info[-tid - 2].task; 387*53197fc4SJason Wessel else 388*53197fc4SJason Wessel return idle_task(-tid - 2); 389*53197fc4SJason Wessel } 390*53197fc4SJason Wessel if (tid <= 0) { 391*53197fc4SJason Wessel printk(KERN_ERR "KGDB: Internal thread select error\n"); 392*53197fc4SJason Wessel dump_stack(); 393*53197fc4SJason Wessel return NULL; 394*53197fc4SJason Wessel } 395*53197fc4SJason Wessel 396*53197fc4SJason Wessel /* 397*53197fc4SJason Wessel * find_task_by_pid_ns() does not take the tasklist lock anymore 398*53197fc4SJason Wessel * but is nicely RCU locked - hence is a pretty resilient 399*53197fc4SJason Wessel * thing to use: 400*53197fc4SJason Wessel */ 401*53197fc4SJason Wessel return find_task_by_pid_ns(tid, &init_pid_ns); 402*53197fc4SJason Wessel } 403*53197fc4SJason Wessel 404*53197fc4SJason Wessel 405*53197fc4SJason Wessel /* 406*53197fc4SJason Wessel * Remap normal tasks to their real PID, 407*53197fc4SJason Wessel * CPU shadow threads are mapped to -CPU - 2 408*53197fc4SJason Wessel */ 409*53197fc4SJason Wessel static inline int shadow_pid(int realpid) 410*53197fc4SJason Wessel { 411*53197fc4SJason Wessel if (realpid) 412*53197fc4SJason Wessel return realpid; 413*53197fc4SJason Wessel 414*53197fc4SJason Wessel return -raw_smp_processor_id() - 2; 415*53197fc4SJason Wessel } 416*53197fc4SJason Wessel 417*53197fc4SJason Wessel /* 418*53197fc4SJason Wessel * All the functions that start with gdb_cmd are the various 419*53197fc4SJason Wessel * operations to implement the handlers for the gdbserial protocol 420*53197fc4SJason Wessel * where KGDB is communicating with an external debugger 421*53197fc4SJason Wessel */ 422*53197fc4SJason Wessel 423*53197fc4SJason Wessel /* Handle the '?' status packets */ 424*53197fc4SJason Wessel static void gdb_cmd_status(struct kgdb_state *ks) 425*53197fc4SJason Wessel { 426*53197fc4SJason Wessel /* 427*53197fc4SJason Wessel * We know that this packet is only sent 428*53197fc4SJason Wessel * during initial connect. So to be safe, 429*53197fc4SJason Wessel * we clear out our breakpoints now in case 430*53197fc4SJason Wessel * GDB is reconnecting. 431*53197fc4SJason Wessel */ 432*53197fc4SJason Wessel dbg_remove_all_break(); 433*53197fc4SJason Wessel 434*53197fc4SJason Wessel remcom_out_buffer[0] = 'S'; 435*53197fc4SJason Wessel pack_hex_byte(&remcom_out_buffer[1], ks->signo); 436*53197fc4SJason Wessel } 437*53197fc4SJason Wessel 438*53197fc4SJason Wessel /* Handle the 'g' get registers request */ 439*53197fc4SJason Wessel static void gdb_cmd_getregs(struct kgdb_state *ks) 440*53197fc4SJason Wessel { 441*53197fc4SJason Wessel struct task_struct *thread; 442*53197fc4SJason Wessel void *local_debuggerinfo; 443*53197fc4SJason Wessel int i; 444*53197fc4SJason Wessel 445*53197fc4SJason Wessel thread = kgdb_usethread; 446*53197fc4SJason Wessel if (!thread) { 447*53197fc4SJason Wessel thread = kgdb_info[ks->cpu].task; 448*53197fc4SJason Wessel local_debuggerinfo = kgdb_info[ks->cpu].debuggerinfo; 449*53197fc4SJason Wessel } else { 450*53197fc4SJason Wessel local_debuggerinfo = NULL; 451*53197fc4SJason Wessel for_each_online_cpu(i) { 452*53197fc4SJason Wessel /* 453*53197fc4SJason Wessel * Try to find the task on some other 454*53197fc4SJason Wessel * or possibly this node if we do not 455*53197fc4SJason Wessel * find the matching task then we try 456*53197fc4SJason Wessel * to approximate the results. 457*53197fc4SJason Wessel */ 458*53197fc4SJason Wessel if (thread == kgdb_info[i].task) 459*53197fc4SJason Wessel local_debuggerinfo = kgdb_info[i].debuggerinfo; 460*53197fc4SJason Wessel } 461*53197fc4SJason Wessel } 462*53197fc4SJason Wessel 463*53197fc4SJason Wessel /* 464*53197fc4SJason Wessel * All threads that don't have debuggerinfo should be 465*53197fc4SJason Wessel * in schedule() sleeping, since all other CPUs 466*53197fc4SJason Wessel * are in kgdb_wait, and thus have debuggerinfo. 467*53197fc4SJason Wessel */ 468*53197fc4SJason Wessel if (local_debuggerinfo) { 469*53197fc4SJason Wessel pt_regs_to_gdb_regs(gdb_regs, local_debuggerinfo); 470*53197fc4SJason Wessel } else { 471*53197fc4SJason Wessel /* 472*53197fc4SJason Wessel * Pull stuff saved during switch_to; nothing 473*53197fc4SJason Wessel * else is accessible (or even particularly 474*53197fc4SJason Wessel * relevant). 475*53197fc4SJason Wessel * 476*53197fc4SJason Wessel * This should be enough for a stack trace. 477*53197fc4SJason Wessel */ 478*53197fc4SJason Wessel sleeping_thread_to_gdb_regs(gdb_regs, thread); 479*53197fc4SJason Wessel } 480*53197fc4SJason Wessel kgdb_mem2hex((char *)gdb_regs, remcom_out_buffer, NUMREGBYTES); 481*53197fc4SJason Wessel } 482*53197fc4SJason Wessel 483*53197fc4SJason Wessel /* Handle the 'G' set registers request */ 484*53197fc4SJason Wessel static void gdb_cmd_setregs(struct kgdb_state *ks) 485*53197fc4SJason Wessel { 486*53197fc4SJason Wessel kgdb_hex2mem(&remcom_in_buffer[1], (char *)gdb_regs, NUMREGBYTES); 487*53197fc4SJason Wessel 488*53197fc4SJason Wessel if (kgdb_usethread && kgdb_usethread != current) { 489*53197fc4SJason Wessel error_packet(remcom_out_buffer, -EINVAL); 490*53197fc4SJason Wessel } else { 491*53197fc4SJason Wessel gdb_regs_to_pt_regs(gdb_regs, ks->linux_regs); 492*53197fc4SJason Wessel strcpy(remcom_out_buffer, "OK"); 493*53197fc4SJason Wessel } 494*53197fc4SJason Wessel } 495*53197fc4SJason Wessel 496*53197fc4SJason Wessel /* Handle the 'm' memory read bytes */ 497*53197fc4SJason Wessel static void gdb_cmd_memread(struct kgdb_state *ks) 498*53197fc4SJason Wessel { 499*53197fc4SJason Wessel char *ptr = &remcom_in_buffer[1]; 500*53197fc4SJason Wessel unsigned long length; 501*53197fc4SJason Wessel unsigned long addr; 502*53197fc4SJason Wessel int err; 503*53197fc4SJason Wessel 504*53197fc4SJason Wessel if (kgdb_hex2long(&ptr, &addr) > 0 && *ptr++ == ',' && 505*53197fc4SJason Wessel kgdb_hex2long(&ptr, &length) > 0) { 506*53197fc4SJason Wessel err = kgdb_mem2hex((char *)addr, remcom_out_buffer, length); 507*53197fc4SJason Wessel if (err) 508*53197fc4SJason Wessel error_packet(remcom_out_buffer, err); 509*53197fc4SJason Wessel } else { 510*53197fc4SJason Wessel error_packet(remcom_out_buffer, -EINVAL); 511*53197fc4SJason Wessel } 512*53197fc4SJason Wessel } 513*53197fc4SJason Wessel 514*53197fc4SJason Wessel /* Handle the 'M' memory write bytes */ 515*53197fc4SJason Wessel static void gdb_cmd_memwrite(struct kgdb_state *ks) 516*53197fc4SJason Wessel { 517*53197fc4SJason Wessel int err = write_mem_msg(0); 518*53197fc4SJason Wessel 519*53197fc4SJason Wessel if (err) 520*53197fc4SJason Wessel error_packet(remcom_out_buffer, err); 521*53197fc4SJason Wessel else 522*53197fc4SJason Wessel strcpy(remcom_out_buffer, "OK"); 523*53197fc4SJason Wessel } 524*53197fc4SJason Wessel 525*53197fc4SJason Wessel /* Handle the 'X' memory binary write bytes */ 526*53197fc4SJason Wessel static void gdb_cmd_binwrite(struct kgdb_state *ks) 527*53197fc4SJason Wessel { 528*53197fc4SJason Wessel int err = write_mem_msg(1); 529*53197fc4SJason Wessel 530*53197fc4SJason Wessel if (err) 531*53197fc4SJason Wessel error_packet(remcom_out_buffer, err); 532*53197fc4SJason Wessel else 533*53197fc4SJason Wessel strcpy(remcom_out_buffer, "OK"); 534*53197fc4SJason Wessel } 535*53197fc4SJason Wessel 536*53197fc4SJason Wessel /* Handle the 'D' or 'k', detach or kill packets */ 537*53197fc4SJason Wessel static void gdb_cmd_detachkill(struct kgdb_state *ks) 538*53197fc4SJason Wessel { 539*53197fc4SJason Wessel int error; 540*53197fc4SJason Wessel 541*53197fc4SJason Wessel /* The detach case */ 542*53197fc4SJason Wessel if (remcom_in_buffer[0] == 'D') { 543*53197fc4SJason Wessel error = dbg_remove_all_break(); 544*53197fc4SJason Wessel if (error < 0) { 545*53197fc4SJason Wessel error_packet(remcom_out_buffer, error); 546*53197fc4SJason Wessel } else { 547*53197fc4SJason Wessel strcpy(remcom_out_buffer, "OK"); 548*53197fc4SJason Wessel kgdb_connected = 0; 549*53197fc4SJason Wessel } 550*53197fc4SJason Wessel put_packet(remcom_out_buffer); 551*53197fc4SJason Wessel } else { 552*53197fc4SJason Wessel /* 553*53197fc4SJason Wessel * Assume the kill case, with no exit code checking, 554*53197fc4SJason Wessel * trying to force detach the debugger: 555*53197fc4SJason Wessel */ 556*53197fc4SJason Wessel dbg_remove_all_break(); 557*53197fc4SJason Wessel kgdb_connected = 0; 558*53197fc4SJason Wessel } 559*53197fc4SJason Wessel } 560*53197fc4SJason Wessel 561*53197fc4SJason Wessel /* Handle the 'R' reboot packets */ 562*53197fc4SJason Wessel static int gdb_cmd_reboot(struct kgdb_state *ks) 563*53197fc4SJason Wessel { 564*53197fc4SJason Wessel /* For now, only honor R0 */ 565*53197fc4SJason Wessel if (strcmp(remcom_in_buffer, "R0") == 0) { 566*53197fc4SJason Wessel printk(KERN_CRIT "Executing emergency reboot\n"); 567*53197fc4SJason Wessel strcpy(remcom_out_buffer, "OK"); 568*53197fc4SJason Wessel put_packet(remcom_out_buffer); 569*53197fc4SJason Wessel 570*53197fc4SJason Wessel /* 571*53197fc4SJason Wessel * Execution should not return from 572*53197fc4SJason Wessel * machine_emergency_restart() 573*53197fc4SJason Wessel */ 574*53197fc4SJason Wessel machine_emergency_restart(); 575*53197fc4SJason Wessel kgdb_connected = 0; 576*53197fc4SJason Wessel 577*53197fc4SJason Wessel return 1; 578*53197fc4SJason Wessel } 579*53197fc4SJason Wessel return 0; 580*53197fc4SJason Wessel } 581*53197fc4SJason Wessel 582*53197fc4SJason Wessel /* Handle the 'q' query packets */ 583*53197fc4SJason Wessel static void gdb_cmd_query(struct kgdb_state *ks) 584*53197fc4SJason Wessel { 585*53197fc4SJason Wessel struct task_struct *g; 586*53197fc4SJason Wessel struct task_struct *p; 587*53197fc4SJason Wessel unsigned char thref[8]; 588*53197fc4SJason Wessel char *ptr; 589*53197fc4SJason Wessel int i; 590*53197fc4SJason Wessel int cpu; 591*53197fc4SJason Wessel int finished = 0; 592*53197fc4SJason Wessel 593*53197fc4SJason Wessel switch (remcom_in_buffer[1]) { 594*53197fc4SJason Wessel case 's': 595*53197fc4SJason Wessel case 'f': 596*53197fc4SJason Wessel if (memcmp(remcom_in_buffer + 2, "ThreadInfo", 10)) { 597*53197fc4SJason Wessel error_packet(remcom_out_buffer, -EINVAL); 598*53197fc4SJason Wessel break; 599*53197fc4SJason Wessel } 600*53197fc4SJason Wessel 601*53197fc4SJason Wessel i = 0; 602*53197fc4SJason Wessel remcom_out_buffer[0] = 'm'; 603*53197fc4SJason Wessel ptr = remcom_out_buffer + 1; 604*53197fc4SJason Wessel if (remcom_in_buffer[1] == 'f') { 605*53197fc4SJason Wessel /* Each cpu is a shadow thread */ 606*53197fc4SJason Wessel for_each_online_cpu(cpu) { 607*53197fc4SJason Wessel ks->thr_query = 0; 608*53197fc4SJason Wessel int_to_threadref(thref, -cpu - 2); 609*53197fc4SJason Wessel pack_threadid(ptr, thref); 610*53197fc4SJason Wessel ptr += BUF_THREAD_ID_SIZE; 611*53197fc4SJason Wessel *(ptr++) = ','; 612*53197fc4SJason Wessel i++; 613*53197fc4SJason Wessel } 614*53197fc4SJason Wessel } 615*53197fc4SJason Wessel 616*53197fc4SJason Wessel do_each_thread(g, p) { 617*53197fc4SJason Wessel if (i >= ks->thr_query && !finished) { 618*53197fc4SJason Wessel int_to_threadref(thref, p->pid); 619*53197fc4SJason Wessel pack_threadid(ptr, thref); 620*53197fc4SJason Wessel ptr += BUF_THREAD_ID_SIZE; 621*53197fc4SJason Wessel *(ptr++) = ','; 622*53197fc4SJason Wessel ks->thr_query++; 623*53197fc4SJason Wessel if (ks->thr_query % KGDB_MAX_THREAD_QUERY == 0) 624*53197fc4SJason Wessel finished = 1; 625*53197fc4SJason Wessel } 626*53197fc4SJason Wessel i++; 627*53197fc4SJason Wessel } while_each_thread(g, p); 628*53197fc4SJason Wessel 629*53197fc4SJason Wessel *(--ptr) = '\0'; 630*53197fc4SJason Wessel break; 631*53197fc4SJason Wessel 632*53197fc4SJason Wessel case 'C': 633*53197fc4SJason Wessel /* Current thread id */ 634*53197fc4SJason Wessel strcpy(remcom_out_buffer, "QC"); 635*53197fc4SJason Wessel ks->threadid = shadow_pid(current->pid); 636*53197fc4SJason Wessel int_to_threadref(thref, ks->threadid); 637*53197fc4SJason Wessel pack_threadid(remcom_out_buffer + 2, thref); 638*53197fc4SJason Wessel break; 639*53197fc4SJason Wessel case 'T': 640*53197fc4SJason Wessel if (memcmp(remcom_in_buffer + 1, "ThreadExtraInfo,", 16)) { 641*53197fc4SJason Wessel error_packet(remcom_out_buffer, -EINVAL); 642*53197fc4SJason Wessel break; 643*53197fc4SJason Wessel } 644*53197fc4SJason Wessel ks->threadid = 0; 645*53197fc4SJason Wessel ptr = remcom_in_buffer + 17; 646*53197fc4SJason Wessel kgdb_hex2long(&ptr, &ks->threadid); 647*53197fc4SJason Wessel if (!getthread(ks->linux_regs, ks->threadid)) { 648*53197fc4SJason Wessel error_packet(remcom_out_buffer, -EINVAL); 649*53197fc4SJason Wessel break; 650*53197fc4SJason Wessel } 651*53197fc4SJason Wessel if ((int)ks->threadid > 0) { 652*53197fc4SJason Wessel kgdb_mem2hex(getthread(ks->linux_regs, 653*53197fc4SJason Wessel ks->threadid)->comm, 654*53197fc4SJason Wessel remcom_out_buffer, 16); 655*53197fc4SJason Wessel } else { 656*53197fc4SJason Wessel static char tmpstr[23 + BUF_THREAD_ID_SIZE]; 657*53197fc4SJason Wessel 658*53197fc4SJason Wessel sprintf(tmpstr, "shadowCPU%d", 659*53197fc4SJason Wessel (int)(-ks->threadid - 2)); 660*53197fc4SJason Wessel kgdb_mem2hex(tmpstr, remcom_out_buffer, strlen(tmpstr)); 661*53197fc4SJason Wessel } 662*53197fc4SJason Wessel break; 663*53197fc4SJason Wessel } 664*53197fc4SJason Wessel } 665*53197fc4SJason Wessel 666*53197fc4SJason Wessel /* Handle the 'H' task query packets */ 667*53197fc4SJason Wessel static void gdb_cmd_task(struct kgdb_state *ks) 668*53197fc4SJason Wessel { 669*53197fc4SJason Wessel struct task_struct *thread; 670*53197fc4SJason Wessel char *ptr; 671*53197fc4SJason Wessel 672*53197fc4SJason Wessel switch (remcom_in_buffer[1]) { 673*53197fc4SJason Wessel case 'g': 674*53197fc4SJason Wessel ptr = &remcom_in_buffer[2]; 675*53197fc4SJason Wessel kgdb_hex2long(&ptr, &ks->threadid); 676*53197fc4SJason Wessel thread = getthread(ks->linux_regs, ks->threadid); 677*53197fc4SJason Wessel if (!thread && ks->threadid > 0) { 678*53197fc4SJason Wessel error_packet(remcom_out_buffer, -EINVAL); 679*53197fc4SJason Wessel break; 680*53197fc4SJason Wessel } 681*53197fc4SJason Wessel kgdb_usethread = thread; 682*53197fc4SJason Wessel ks->kgdb_usethreadid = ks->threadid; 683*53197fc4SJason Wessel strcpy(remcom_out_buffer, "OK"); 684*53197fc4SJason Wessel break; 685*53197fc4SJason Wessel case 'c': 686*53197fc4SJason Wessel ptr = &remcom_in_buffer[2]; 687*53197fc4SJason Wessel kgdb_hex2long(&ptr, &ks->threadid); 688*53197fc4SJason Wessel if (!ks->threadid) { 689*53197fc4SJason Wessel kgdb_contthread = NULL; 690*53197fc4SJason Wessel } else { 691*53197fc4SJason Wessel thread = getthread(ks->linux_regs, ks->threadid); 692*53197fc4SJason Wessel if (!thread && ks->threadid > 0) { 693*53197fc4SJason Wessel error_packet(remcom_out_buffer, -EINVAL); 694*53197fc4SJason Wessel break; 695*53197fc4SJason Wessel } 696*53197fc4SJason Wessel kgdb_contthread = thread; 697*53197fc4SJason Wessel } 698*53197fc4SJason Wessel strcpy(remcom_out_buffer, "OK"); 699*53197fc4SJason Wessel break; 700*53197fc4SJason Wessel } 701*53197fc4SJason Wessel } 702*53197fc4SJason Wessel 703*53197fc4SJason Wessel /* Handle the 'T' thread query packets */ 704*53197fc4SJason Wessel static void gdb_cmd_thread(struct kgdb_state *ks) 705*53197fc4SJason Wessel { 706*53197fc4SJason Wessel char *ptr = &remcom_in_buffer[1]; 707*53197fc4SJason Wessel struct task_struct *thread; 708*53197fc4SJason Wessel 709*53197fc4SJason Wessel kgdb_hex2long(&ptr, &ks->threadid); 710*53197fc4SJason Wessel thread = getthread(ks->linux_regs, ks->threadid); 711*53197fc4SJason Wessel if (thread) 712*53197fc4SJason Wessel strcpy(remcom_out_buffer, "OK"); 713*53197fc4SJason Wessel else 714*53197fc4SJason Wessel error_packet(remcom_out_buffer, -EINVAL); 715*53197fc4SJason Wessel } 716*53197fc4SJason Wessel 717*53197fc4SJason Wessel /* Handle the 'z' or 'Z' breakpoint remove or set packets */ 718*53197fc4SJason Wessel static void gdb_cmd_break(struct kgdb_state *ks) 719*53197fc4SJason Wessel { 720*53197fc4SJason Wessel /* 721*53197fc4SJason Wessel * Since GDB-5.3, it's been drafted that '0' is a software 722*53197fc4SJason Wessel * breakpoint, '1' is a hardware breakpoint, so let's do that. 723*53197fc4SJason Wessel */ 724*53197fc4SJason Wessel char *bpt_type = &remcom_in_buffer[1]; 725*53197fc4SJason Wessel char *ptr = &remcom_in_buffer[2]; 726*53197fc4SJason Wessel unsigned long addr; 727*53197fc4SJason Wessel unsigned long length; 728*53197fc4SJason Wessel int error = 0; 729*53197fc4SJason Wessel 730*53197fc4SJason Wessel if (arch_kgdb_ops.set_hw_breakpoint && *bpt_type >= '1') { 731*53197fc4SJason Wessel /* Unsupported */ 732*53197fc4SJason Wessel if (*bpt_type > '4') 733*53197fc4SJason Wessel return; 734*53197fc4SJason Wessel } else { 735*53197fc4SJason Wessel if (*bpt_type != '0' && *bpt_type != '1') 736*53197fc4SJason Wessel /* Unsupported. */ 737*53197fc4SJason Wessel return; 738*53197fc4SJason Wessel } 739*53197fc4SJason Wessel 740*53197fc4SJason Wessel /* 741*53197fc4SJason Wessel * Test if this is a hardware breakpoint, and 742*53197fc4SJason Wessel * if we support it: 743*53197fc4SJason Wessel */ 744*53197fc4SJason Wessel if (*bpt_type == '1' && !(arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT)) 745*53197fc4SJason Wessel /* Unsupported. */ 746*53197fc4SJason Wessel return; 747*53197fc4SJason Wessel 748*53197fc4SJason Wessel if (*(ptr++) != ',') { 749*53197fc4SJason Wessel error_packet(remcom_out_buffer, -EINVAL); 750*53197fc4SJason Wessel return; 751*53197fc4SJason Wessel } 752*53197fc4SJason Wessel if (!kgdb_hex2long(&ptr, &addr)) { 753*53197fc4SJason Wessel error_packet(remcom_out_buffer, -EINVAL); 754*53197fc4SJason Wessel return; 755*53197fc4SJason Wessel } 756*53197fc4SJason Wessel if (*(ptr++) != ',' || 757*53197fc4SJason Wessel !kgdb_hex2long(&ptr, &length)) { 758*53197fc4SJason Wessel error_packet(remcom_out_buffer, -EINVAL); 759*53197fc4SJason Wessel return; 760*53197fc4SJason Wessel } 761*53197fc4SJason Wessel 762*53197fc4SJason Wessel if (remcom_in_buffer[0] == 'Z' && *bpt_type == '0') 763*53197fc4SJason Wessel error = dbg_set_sw_break(addr); 764*53197fc4SJason Wessel else if (remcom_in_buffer[0] == 'z' && *bpt_type == '0') 765*53197fc4SJason Wessel error = dbg_remove_sw_break(addr); 766*53197fc4SJason Wessel else if (remcom_in_buffer[0] == 'Z') 767*53197fc4SJason Wessel error = arch_kgdb_ops.set_hw_breakpoint(addr, 768*53197fc4SJason Wessel (int)length, *bpt_type - '0'); 769*53197fc4SJason Wessel else if (remcom_in_buffer[0] == 'z') 770*53197fc4SJason Wessel error = arch_kgdb_ops.remove_hw_breakpoint(addr, 771*53197fc4SJason Wessel (int) length, *bpt_type - '0'); 772*53197fc4SJason Wessel 773*53197fc4SJason Wessel if (error == 0) 774*53197fc4SJason Wessel strcpy(remcom_out_buffer, "OK"); 775*53197fc4SJason Wessel else 776*53197fc4SJason Wessel error_packet(remcom_out_buffer, error); 777*53197fc4SJason Wessel } 778*53197fc4SJason Wessel 779*53197fc4SJason Wessel /* Handle the 'C' signal / exception passing packets */ 780*53197fc4SJason Wessel static int gdb_cmd_exception_pass(struct kgdb_state *ks) 781*53197fc4SJason Wessel { 782*53197fc4SJason Wessel /* C09 == pass exception 783*53197fc4SJason Wessel * C15 == detach kgdb, pass exception 784*53197fc4SJason Wessel */ 785*53197fc4SJason Wessel if (remcom_in_buffer[1] == '0' && remcom_in_buffer[2] == '9') { 786*53197fc4SJason Wessel 787*53197fc4SJason Wessel ks->pass_exception = 1; 788*53197fc4SJason Wessel remcom_in_buffer[0] = 'c'; 789*53197fc4SJason Wessel 790*53197fc4SJason Wessel } else if (remcom_in_buffer[1] == '1' && remcom_in_buffer[2] == '5') { 791*53197fc4SJason Wessel 792*53197fc4SJason Wessel ks->pass_exception = 1; 793*53197fc4SJason Wessel remcom_in_buffer[0] = 'D'; 794*53197fc4SJason Wessel dbg_remove_all_break(); 795*53197fc4SJason Wessel kgdb_connected = 0; 796*53197fc4SJason Wessel return 1; 797*53197fc4SJason Wessel 798*53197fc4SJason Wessel } else { 799*53197fc4SJason Wessel gdbstub_msg_write("KGDB only knows signal 9 (pass)" 800*53197fc4SJason Wessel " and 15 (pass and disconnect)\n" 801*53197fc4SJason Wessel "Executing a continue without signal passing\n", 0); 802*53197fc4SJason Wessel remcom_in_buffer[0] = 'c'; 803*53197fc4SJason Wessel } 804*53197fc4SJason Wessel 805*53197fc4SJason Wessel /* Indicate fall through */ 806*53197fc4SJason Wessel return -1; 807*53197fc4SJason Wessel } 808*53197fc4SJason Wessel 809*53197fc4SJason Wessel /* 810*53197fc4SJason Wessel * This function performs all gdbserial command procesing 811*53197fc4SJason Wessel */ 812*53197fc4SJason Wessel int gdb_serial_stub(struct kgdb_state *ks) 813*53197fc4SJason Wessel { 814*53197fc4SJason Wessel int error = 0; 815*53197fc4SJason Wessel int tmp; 816*53197fc4SJason Wessel 817*53197fc4SJason Wessel /* Clear the out buffer. */ 818*53197fc4SJason Wessel memset(remcom_out_buffer, 0, sizeof(remcom_out_buffer)); 819*53197fc4SJason Wessel 820*53197fc4SJason Wessel if (kgdb_connected) { 821*53197fc4SJason Wessel unsigned char thref[8]; 822*53197fc4SJason Wessel char *ptr; 823*53197fc4SJason Wessel 824*53197fc4SJason Wessel /* Reply to host that an exception has occurred */ 825*53197fc4SJason Wessel ptr = remcom_out_buffer; 826*53197fc4SJason Wessel *ptr++ = 'T'; 827*53197fc4SJason Wessel ptr = pack_hex_byte(ptr, ks->signo); 828*53197fc4SJason Wessel ptr += strlen(strcpy(ptr, "thread:")); 829*53197fc4SJason Wessel int_to_threadref(thref, shadow_pid(current->pid)); 830*53197fc4SJason Wessel ptr = pack_threadid(ptr, thref); 831*53197fc4SJason Wessel *ptr++ = ';'; 832*53197fc4SJason Wessel put_packet(remcom_out_buffer); 833*53197fc4SJason Wessel } 834*53197fc4SJason Wessel 835*53197fc4SJason Wessel kgdb_usethread = kgdb_info[ks->cpu].task; 836*53197fc4SJason Wessel ks->kgdb_usethreadid = shadow_pid(kgdb_info[ks->cpu].task->pid); 837*53197fc4SJason Wessel ks->pass_exception = 0; 838*53197fc4SJason Wessel 839*53197fc4SJason Wessel while (1) { 840*53197fc4SJason Wessel error = 0; 841*53197fc4SJason Wessel 842*53197fc4SJason Wessel /* Clear the out buffer. */ 843*53197fc4SJason Wessel memset(remcom_out_buffer, 0, sizeof(remcom_out_buffer)); 844*53197fc4SJason Wessel 845*53197fc4SJason Wessel get_packet(remcom_in_buffer); 846*53197fc4SJason Wessel 847*53197fc4SJason Wessel switch (remcom_in_buffer[0]) { 848*53197fc4SJason Wessel case '?': /* gdbserial status */ 849*53197fc4SJason Wessel gdb_cmd_status(ks); 850*53197fc4SJason Wessel break; 851*53197fc4SJason Wessel case 'g': /* return the value of the CPU registers */ 852*53197fc4SJason Wessel gdb_cmd_getregs(ks); 853*53197fc4SJason Wessel break; 854*53197fc4SJason Wessel case 'G': /* set the value of the CPU registers - return OK */ 855*53197fc4SJason Wessel gdb_cmd_setregs(ks); 856*53197fc4SJason Wessel break; 857*53197fc4SJason Wessel case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ 858*53197fc4SJason Wessel gdb_cmd_memread(ks); 859*53197fc4SJason Wessel break; 860*53197fc4SJason Wessel case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA..AA */ 861*53197fc4SJason Wessel gdb_cmd_memwrite(ks); 862*53197fc4SJason Wessel break; 863*53197fc4SJason Wessel case 'X': /* XAA..AA,LLLL: Write LLLL bytes at address AA..AA */ 864*53197fc4SJason Wessel gdb_cmd_binwrite(ks); 865*53197fc4SJason Wessel break; 866*53197fc4SJason Wessel /* kill or detach. KGDB should treat this like a 867*53197fc4SJason Wessel * continue. 868*53197fc4SJason Wessel */ 869*53197fc4SJason Wessel case 'D': /* Debugger detach */ 870*53197fc4SJason Wessel case 'k': /* Debugger detach via kill */ 871*53197fc4SJason Wessel gdb_cmd_detachkill(ks); 872*53197fc4SJason Wessel goto default_handle; 873*53197fc4SJason Wessel case 'R': /* Reboot */ 874*53197fc4SJason Wessel if (gdb_cmd_reboot(ks)) 875*53197fc4SJason Wessel goto default_handle; 876*53197fc4SJason Wessel break; 877*53197fc4SJason Wessel case 'q': /* query command */ 878*53197fc4SJason Wessel gdb_cmd_query(ks); 879*53197fc4SJason Wessel break; 880*53197fc4SJason Wessel case 'H': /* task related */ 881*53197fc4SJason Wessel gdb_cmd_task(ks); 882*53197fc4SJason Wessel break; 883*53197fc4SJason Wessel case 'T': /* Query thread status */ 884*53197fc4SJason Wessel gdb_cmd_thread(ks); 885*53197fc4SJason Wessel break; 886*53197fc4SJason Wessel case 'z': /* Break point remove */ 887*53197fc4SJason Wessel case 'Z': /* Break point set */ 888*53197fc4SJason Wessel gdb_cmd_break(ks); 889*53197fc4SJason Wessel break; 890*53197fc4SJason Wessel case 'C': /* Exception passing */ 891*53197fc4SJason Wessel tmp = gdb_cmd_exception_pass(ks); 892*53197fc4SJason Wessel if (tmp > 0) 893*53197fc4SJason Wessel goto default_handle; 894*53197fc4SJason Wessel if (tmp == 0) 895*53197fc4SJason Wessel break; 896*53197fc4SJason Wessel /* Fall through on tmp < 0 */ 897*53197fc4SJason Wessel case 'c': /* Continue packet */ 898*53197fc4SJason Wessel case 's': /* Single step packet */ 899*53197fc4SJason Wessel if (kgdb_contthread && kgdb_contthread != current) { 900*53197fc4SJason Wessel /* Can't switch threads in kgdb */ 901*53197fc4SJason Wessel error_packet(remcom_out_buffer, -EINVAL); 902*53197fc4SJason Wessel break; 903*53197fc4SJason Wessel } 904*53197fc4SJason Wessel dbg_activate_sw_breakpoints(); 905*53197fc4SJason Wessel /* Fall through to default processing */ 906*53197fc4SJason Wessel default: 907*53197fc4SJason Wessel default_handle: 908*53197fc4SJason Wessel error = kgdb_arch_handle_exception(ks->ex_vector, 909*53197fc4SJason Wessel ks->signo, 910*53197fc4SJason Wessel ks->err_code, 911*53197fc4SJason Wessel remcom_in_buffer, 912*53197fc4SJason Wessel remcom_out_buffer, 913*53197fc4SJason Wessel ks->linux_regs); 914*53197fc4SJason Wessel /* 915*53197fc4SJason Wessel * Leave cmd processing on error, detach, 916*53197fc4SJason Wessel * kill, continue, or single step. 917*53197fc4SJason Wessel */ 918*53197fc4SJason Wessel if (error >= 0 || remcom_in_buffer[0] == 'D' || 919*53197fc4SJason Wessel remcom_in_buffer[0] == 'k') { 920*53197fc4SJason Wessel error = 0; 921*53197fc4SJason Wessel goto kgdb_exit; 922*53197fc4SJason Wessel } 923*53197fc4SJason Wessel 924*53197fc4SJason Wessel } 925*53197fc4SJason Wessel 926*53197fc4SJason Wessel /* reply to the request */ 927*53197fc4SJason Wessel put_packet(remcom_out_buffer); 928*53197fc4SJason Wessel } 929*53197fc4SJason Wessel 930*53197fc4SJason Wessel kgdb_exit: 931*53197fc4SJason Wessel if (ks->pass_exception) 932*53197fc4SJason Wessel error = 1; 933*53197fc4SJason Wessel return error; 934*53197fc4SJason Wessel } 935