static void enhanced_gdb_listing_cmd(char *arg, int from_tty, int cmdNbr, void (*cmd)(char*, int)) { if (from_tty && isatty(STDOUT_FILENO) && gdb_get_int("$__prevcmd__") == cmdNbr) { if (!macsbug_screen) { if (!(arg && *arg)) gdb_printf(CURSOR_UP CLEAR_LINE, 2); } else if (macsbug_screen && arg && *arg) gdb_printf("\n"); } if (macsbug_screen) cmd(arg, from_tty); /* just do cmd if we have screen */ else { GDB_FILE *redirect_stdout, *prev_stdout; redirect_stdout = gdb_open_output(stdout, listing_filter, &prev_stdout); prev_stdout = gdb_redirect_output(redirect_stdout); cmd(arg, from_tty); /* filter output with listing_filter() */ gdb_close_output(redirect_stdout); } gdb_set_int("$__lastcmd__", cmdNbr); }
static int run_final_status(struct gdb_data *data) { address_t regs[DEVICE_NUM_REGS]; int i; if (device_getregs(regs) < 0) return gdb_send(data, "E00"); gdb_packet_start(data); gdb_printf(data, "T05"); for (i = 0; i < 16; i++) { address_t value = regs[i]; int j; /* NOTE: this only gives GDB the lower 16 bits of each * register. It complains if we give the full data. */ gdb_printf(data, "%02x:", i); for (j = 0; j < 2; j++) { gdb_printf(data, "%02x", value & 0xff); value >>= 8; } gdb_printf(data, ";"); } gdb_packet_end(data); return gdb_flush_ack(data); }
static void send_message(char *message, int len) { if (len == 0) { len = strlen(message); } unsigned char checksum = compute_checksum(message, len); gdb_printf(GDB_RESPONSE_START "$%s#%02X", message, checksum); gdb_printf(GDB_RESPONSE_END); }
static int gdb_send_supported(struct gdb_data *data) { gdb_packet_start(data); gdb_printf(data, "PacketSize=%x", GDB_MAX_XFER * 2); gdb_packet_end(data); return gdb_flush_ack(data); }
static int read_memory(struct gdb_data *data, char *text) { char *length_text = strchr(text, ','); address_t length, addr; uint8_t buf[GDB_MAX_XFER]; int i; if (!length_text) { printc_err("gdb: malformed memory read request\n"); return gdb_send(data, "E00"); } *(length_text++) = 0; length = strtoul(length_text, NULL, 16); addr = strtoul(text, NULL, 16); if (length > sizeof(buf)) length = sizeof(buf); printc("Reading %4d bytes from 0x%04x\n", length, addr); if (device_readmem(addr, buf, length) < 0) return gdb_send(data, "E00"); gdb_packet_start(data); for (i = 0; i < length; i++) gdb_printf(data, "%02x", buf[i]); gdb_packet_end(data); return gdb_flush_ack(data); }
static void new_breakpoint(GDB_ADDRESS address, int enabled) { int i; if (!enabled) /* can this ever happen? */ return; i = find_breakpt(address); /* find the breakpoint */ if (i >= 0) /* if already recorded... */ return; /* ...don't record duplicates */ if (++bkpt_tbl_index >= bkpt_tbl_sz) { /* add it to the bkpt_tbl */ bkpt_tbl_sz += BKPT_DELTA; bkpt_tbl = gdb_realloc(bkpt_tbl, bkpt_tbl_sz * sizeof(GDB_ADDRESS)); } bkpt_tbl[bkpt_tbl_index] = address; qsort(bkpt_tbl, bkpt_tbl_index+1, /* always keep table sorted */ sizeof(GDB_ADDRESS), qsort_compar_bkpt); fix_pc_area_if_necessary(address); if (0) for (i = 0; i <= bkpt_tbl_index; ++i) gdb_printf("after add: %2d. 0x%.8llX\n", i+1, (long long)bkpt_tbl[i]); }
static int monitor_command(struct gdb_data *data, char *buf) { char cmd[128]; int len = 0; int i; struct monitor_buf mbuf; while (len + 1 < sizeof(cmd) && *buf && buf[1]) { if (len + 1 >= sizeof(cmd)) break; cmd[len++] = (hexval(buf[0]) << 4) | hexval(buf[1]); buf += 2; } cmd[len] = 0; printc("Monitor command received: %s\n", cmd); mbuf.len = 0; mbuf.trunc = 0; capture_start(monitor_capture, &mbuf); process_command(cmd); capture_end(); if (!mbuf.len) return gdb_send(data, "OK"); gdb_packet_start(data); for (i = 0; i < mbuf.len; i++) gdb_printf(data, "%02x", mbuf.buf[i]); gdb_packet_end(data); return gdb_flush_ack(data); }
static void exit_handler(void) { if (log_stream) { /* close log file if it's open... */ gdb_printf("Closing log\n"); fclose(log_stream); log_stream = NULL; } position_cursor_for_shell_input(); }
static void set_arch(char *theSetting, Gdb_Set_Type type, void *value, int show, int confirm) { static int len = sizeof(DEFAULT_TARGET_ARCH) + 1; if (new_arch && *new_arch) if (strcmp(new_arch, "32") == 0) { target_arch = force_arch = 4; need_CurApName = 1; if (macsbug_screen && strcmp(prev_arch, new_arch) != 0) refresh(NULL, 0); else define_macsbug_screen_positions(pc_area_lines, cmd_area_lines); strcpy(prev_arch, new_arch); gdb_printf("Display architecture always assumes 32-bit.\n"); } else if (strcmp(new_arch, "64") == 0) { target_arch = force_arch = 8; need_CurApName = 1; if (macsbug_screen && strcmp(prev_arch, new_arch) != 0) refresh(NULL, 0); else define_macsbug_screen_positions(pc_area_lines, cmd_area_lines); strcpy(prev_arch, new_arch); gdb_printf("Display architecture always assumes 64-bit.\n"); } else { new_arch = (char *)gdb_realloc(new_arch, strlen(prev_arch) + 1); strcpy(new_arch, prev_arch); gdb_error("invalid value - 32, or 64, or no value (for default) is expected"); } else { new_arch = new_arch ? (char *)gdb_realloc(new_arch, len) : (char *)gdb_malloc(len); force_arch = 0; target_arch = gdb_target_arch(); strcpy(new_arch, DEFAULT_TARGET_ARCH); need_CurApName = 1; if (macsbug_screen && strcmp(prev_arch, new_arch) != 0) refresh(NULL, 0); else define_macsbug_screen_positions(pc_area_lines, cmd_area_lines); strcpy(prev_arch, new_arch); gdb_printf("Display architecture is set according to inferior.\n"); } }
static void show_the_command(char *cmd, char *arg, int from_tty) { if (arg && from_tty && macsbug_screen) { gdb_printf("%s %s\n", cmd, arg); gdb_fflush(gdb_current_stdout); gdb_define_raw_input_handler(my_raw_input_handler); gdb_control_prompt_position(my_prompt_position_function); gdb_set_raw_input_prompt_handler(my_raw_input_prompt_setter); } control_level = reading_raw = 1; gdb_set_int("$__lastcmd__", -1); }
/* * gdb_write_membytes: * Write bytes from the gdb client command buffer to our memory */ void gdb_write_membytes(CPU_REGISTERS *ctx) { int addr; int length; char *ptr; char *p; size_t actual; size_t valid; void *trans; if(parse2hexnum(&inbuf[1],&addr,&length)) { ptr = strchr(inbuf,':') + 1; /* point 1 past the colon */ #ifdef DEBUG_GDB kprintf("Writemem: addr = %x\n", addr); #endif p = ptr; for( ;; ) { trans = gdb_mapping_add(addr, length, PROT_READ|PROT_WRITE, &valid); if(trans == NULL) break; actual = min(valid, length); hex2mem(p, trans, actual); CPU_CACHE_FLUSH(trans, addr, actual); gdb_mapping_del(trans, valid); p += actual * 2; addr += actual; length -= actual; if(length == 0) break; } if((p == ptr) && (trans == NULL)) { strcpy(outbuf,"E03"); if(gdb_debug) gdb_printf("bus error"); } } else { strcpy(outbuf,"E02"); if(gdb_debug) gdb_printf("malformed write memory command: %s",inbuf); } }
/* * gdb_read_membytes: * Read bytes from our memory and return to gdb client */ void gdb_read_membytes(CPU_REGISTERS *ctx) { int addr; int length; size_t actual; char *p; size_t valid; void *trans; if(parse2hexnum(&inbuf[1],&addr,&length)) { #ifdef DEBUG_GDB kprintf("Readmem: addr = %x, ", addr); kprintf("data = %x\n", safe_read(addr)); #endif p = outbuf; for( ;; ) { trans = gdb_mapping_add(addr, length, PROT_READ, &valid); if(trans == NULL) break; if(valid == 0) break; actual = min(valid, length); mem2hex(trans, p, actual); gdb_mapping_del(trans, valid); p += actual * 2; addr += actual; length -= actual; if(length == 0) break; } if(p == outbuf && valid == 0) { strcpy(outbuf,"E03"); if(gdb_debug) gdb_printf("bus error"); } } else { strcpy(outbuf,"E01"); if(gdb_debug) gdb_printf("malformed read memory command: %s", inbuf); } }
static void delete_breakpoint(GDB_ADDRESS address, int enabled) { int i, j; i = find_breakpt(address); /* find the breakpoint */ if (i >= 0) { /* if found, delete it... */ j = i++; /* ...do it by moving all the items */ while (i <= bkpt_tbl_index) /* one entry lower in the bkpt_tbl */ bkpt_tbl[j++] = bkpt_tbl[i++]; /* starting with 1 beyond the one */ --bkpt_tbl_index; /* that was found */ } fix_pc_area_if_necessary(address); if (0) for (i = 0; i <= bkpt_tbl_index; ++i) gdb_printf("after delete: %2d. 0x%llX\n", i+1, (long long)bkpt_tbl[i]); }
static void changed_breakpoint(GDB_ADDRESS address, int enabled) { int i; i = find_breakpt(address); /* find the breakpoint */ if (i < 0) { /* if not found... */ if (enabled) /* ...if being enabled... */ new_breakpoint(address, 1); /* ...just recreate it in bkpt_tbl */ return; } if (!enabled) /* if found and being disabled... */ delete_breakpoint(address, 0); /* ...delete it */ if (0) for (i = 0; i <= bkpt_tbl_index; ++i) gdb_printf("after change: %2d. 0x%llX\n", i+1, (long long)bkpt_tbl[i]); }
static int handle_gdb(void) { // Acknowledge packet gdb_printf(GDB_RESPONSE_START GDB_ACK GDB_RESPONSE_END "\n"); // Get command and checksum int command_length = buf.checksum_index-1; char *command_ptr = &buf.data[COMMAND_START]; char command[GETCHAR_BUFSIZ + 1] = {0}; strncpy(command, command_ptr, command_length); char *checksum = &buf.data[buf.checksum_index + 1]; // Calculate checksum of data if (DEBUG_PRINT) printf("command: %s\n", command); unsigned char computed_checksum = compute_checksum(command, command_length); unsigned char received_checksum = (unsigned char) strtol(checksum, NULL, HEX_STRING); if (computed_checksum != received_checksum) { if (DEBUG_PRINT) printf("Checksum error, computed %x, received %x received_checksum\n", computed_checksum, received_checksum); } // Parse the command handle_command(command); return 0; }
/* * gdb_show_exception_info: * Print out some information on the exception taken */ void gdb_show_exception_info(ulong_t signal, CPU_REGISTERS *ctx) { gdb_printf("signal=%d, eip=%x\n", signal, ctx->eip); }
/* * This function does all command procesing for interfacing to gdb. */ static boolean do_gdb_interface(struct kdebug_entry *entry, CPU_REGISTERS *ctx, ulong_t signal) { int length; struct kdebug_info *kinfo; const struct kdebug_private *kprivate; THREAD *thread; /* * Indicate that we've gone back to debug mode */ for (length = 0; length < 4; length++) dbg_putc('|'); if(protocol == 0) { // generic GDB 4.16 wants the response to the continue/step // command sent before it transmits anything else. ksprintf(outbuf,"S%02xk", (unsigned)signal); putpacket(); } while(getpacket()) { connected = TRUE; outbuf[0] = 0; #ifdef DEBUG_GDB kprintf("Processing packet '%s'\n", inbuf); #endif switch(inbuf[0]) { /* Tell the gdb client our signal number */ case '?' : if(gdb_test_reloc_sem()) { paddr_t base; char *str = SYSPAGE_ENTRY(strings)->data; struct asinfo_entry *as = SYSPAGE_ENTRY(asinfo); while(strcmp(&str[as->name], "imagefs") != 0) { ++as; } base = gdb_image_base(as->start); gdb_clear_reloc_sem(); ksprintf(outbuf,"N%02x%P;%P;%P", (unsigned)signal, base, base, (paddr_t)(base + as->end - as->start + 1)); } else { ksprintf(outbuf,"S%02xk", (unsigned)signal); } for(length=1;outbuf[length];length++) { if((outbuf[length] >= 'A') && (outbuf[length] <='Z')) outbuf[length]=outbuf[length]+('a'-'A'); } if(gdb_debug) gdb_printf("%s", outbuf); break; /* toggle debug flag */ case 'd' : gdb_debug = !(gdb_debug); break; /* return the value of the CPU registers */ case 'g' : /* temp solution, need to add an offset item in kdebug_private for fpu data */ if((kinfo = private->kdebug_info)== NULL || (kprivate = kinfo->kdbg_private) == NULL || (thread = ((void **)kprivate->actives)[0]) == NULL) { gdb_get_cpuregs(ctx,NULL); } else { gdb_get_cpuregs(ctx,thread->fpudata); } break; /* set the value of the CPU registers - return OK */ case 'G' : /* temp solution, need to add an offset item in kdebug_private for fpu data */ if((kinfo = private->kdebug_info)== NULL || (kprivate = kinfo->kdbg_private) == NULL || (thread = ((void **)kprivate->actives)[0]) == NULL) { gdb_set_cpuregs(ctx,NULL); } else { gdb_set_cpuregs(ctx,thread->fpudata); } strcpy(outbuf,"OK"); break; /* get target information */ case 'i': gdb_get_info(); break; /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ case 'm' : gdb_read_membytes(ctx); break; /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ case 'M' : gdb_write_membytes(ctx); break; /* cAA..AA Continue at address AA..AA(optional) */ case 'c' : gdb_proc_continue(ctx, 0); /* continue the process */ return(TRUE); /* sAA..AA Step one instruction from AA..AA(optional) */ case 's' : gdb_proc_continue(ctx, 1); /* step one instruction */ return(TRUE); /* q???? Generic query */ case 'q': if(memcmp(&inbuf[1], "Rcmd,", 5) == 0) { // remote command char *p; p = &inbuf[6]; hex2mem(p, scratch, strlen(p)); #define MEM_CMD "mem " if(memcmp(scratch, MEM_CMD, sizeof(MEM_CMD)-1) == 0) { monitor_mem(&scratch[sizeof(MEM_CMD)-1]); } } break; /* k Kill program */ case 'k' : putpacket(); /*ACK the packet early (since we're going bye-bye) */ gdb_prep_reboot(); SYSPAGE_ENTRY(callout)->reboot(_syspage_ptr, 0); break; /* D Detach from host */ case 'D' : connected = FALSE; return(FALSE); } /* switch */
static void help_command(char *arg, int from_tty) { gdb_help_command(arg, from_tty); if (!arg) gdb_printf("\nType \"help mb-notes\" or just \"mb-notes\" to get additional info about MacsBug.\n"); }
/*------------------------------------------* | macsbug_set - handle MacsBug SET options | *------------------------------------------* Common routine used by both mset() and all macsbug options that accept settings of the form: [m]set setting [on | off | now | show] The parameters to this function are: cmd "set" | "mset" | "dx" arg "" | on | off | now | show value pointer to int switch to be set according to option meaning string to prefix "is [still] {en|dis}abled" messages confirm 1 if SET/SHOW is entered from terminal and SET confirm on additional_stuff NULL or function to call to do additional stuff when state changes The prototype for this function is: additiona_stuff(int state, int confirm); As a standard gdb SET command the setting's arguments are handled as a arbitrary string to allow us to handle the case when no options are specified. I'd like to use the enum form but that requires a argument. */ static void macsbug_set(char *cmd, char **arg, int *value, char *meaning, int confirm, void (*additional_stuff)(int state, int confirm)) { int argc, err = 0; char *argv[4], tmpCmdLine[1024]; static char *options[] = {"ON", "OFF", "NOW", "SHOW", NULL}; gdb_setup_argv(safe_strcpy(tmpCmdLine, *arg), cmd, &argc, argv, 3); if (argc == 1) { if (*value) { *value = 0; if (additional_stuff) additional_stuff(0, confirm); if (confirm) gdb_printf("%s is disabled.\n", meaning); } else { *value = 1; if (additional_stuff) additional_stuff(1, confirm); if (confirm) gdb_printf("%s is enabled.\n", meaning); } } else if (argc == 2) { switch (gdb_keyword(argv[1], options)) { case 0: /* on */ if (*value) { if (confirm) gdb_printf("%s is still enabled.\n", meaning); } else { *value = 1; if (additional_stuff) additional_stuff(1, confirm); if (confirm) gdb_printf("%s is enabled.\n", meaning); } break; case 1: /* off */ if (*value) { *value = 0; if (additional_stuff) additional_stuff(0, confirm); if (confirm) gdb_printf("%s is disabled.\n", meaning); } else if (confirm) gdb_printf("%s is still disabled.\n", meaning); break; case 2: /* now */ case 3: /* show */ if (*value) gdb_printf("%s is still enabled.\n", meaning); else gdb_printf("%s is still disabled.\n", meaning); break; default: err = 1; } } else err = 1; gdb_set_int("$__lastcmd__", 40); if (*value) if (*arg) *arg = strcpy((char *)gdb_realloc(*arg, 3), "on"); else *arg = strcpy((char *)gdb_malloc(3), "on"); else if (*arg) *arg = strcpy((char *)gdb_realloc(*arg, 4), "off"); else *arg = strcpy((char *)gdb_malloc(4), "off"); if (err) gdb_error("\"on\", \"off\", \"now\", or \"show\" expected."); }
/* * scan for the sequence $<data>#<checksum> */ boolean getpacket() { unsigned char checksum; unsigned char xmitcsum; int i; int count; int ch; int cs1; int cs2; int (*init_getc)(void); init_getc = connected ? dbg_getc : dbg_getc_connect_check; for( ;; ) { try_again: /* wait around for the start character, ignore all other characters */ do { ch = init_getc(); if(ch == -1) return(FALSE); } while(ch != '$'); try_again2: checksum = 0; count = 0; cs1 = cs2 = 0; /* now, read until a # or end of buffer is found */ for( ;; ) { if(count >= BUFMAX) goto try_again; ch = dbg_getc(); if(ch == -1) return(FALSE); if(ch == '#') break; if(ch == '$') goto try_again2; checksum = checksum + ch; scratch[count++] = ch; } /* collect the checksum */ cs1 = dbg_getc(); if(cs1 == -1) return(FALSE); cs2 = dbg_getc(); if(cs2 == -1) return(FALSE); scratch[count] = 0; gdb_expand(scratch, inbuf); xmitcsum = (chartohex(cs1) << 4) + chartohex(cs2); if(checksum == xmitcsum) break; if(gdb_debug) { gdb_printf("bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n", checksum,xmitcsum,inbuf); } dbg_putc('-'); /* failed checksum */ } dbg_putc('+'); /* successful transfer */ /* if a sequence char is present, reply the sequence ID */ if(inbuf[2] == ':') { dbg_putc(inbuf[0]); dbg_putc(inbuf[1]); /* remove sequence chars from buffer */ i = 3; for( ;; ) { inbuf[i-3] = inbuf[i]; if(inbuf[i] == '\0') break; ++i; } } return(TRUE); }