/* * Occures when key is pressed. * Handles debug Run/Stop/... and add/remove breakpoint activities */ gboolean keys_callback(guint key_id) { switch (key_id) { case KEY_RUN: debug_run(); break; case KEY_STOP: debug_stop(); break; case KEY_RESTART: debug_restart(); break; case KEY_STEP_OVER: debug_step_over(); break; case KEY_STEP_INTO: debug_step_into(); break; case KEY_STEP_OUT: debug_step_out(); break; case KEY_EXECUTE_UNTIL: { GeanyDocument *doc = document_get_current(); if (doc) { int line = sci_get_current_line(doc->editor->sci) + 1; debug_execute_until(DOC_FILENAME(doc), line); } break; } case KEY_BREAKPOINT: { GeanyDocument *doc = document_get_current(); if (doc) { int line = sci_get_current_line(doc->editor->sci) + 1; break_state bs = breaks_get_state(DOC_FILENAME(doc), line); if (BS_NOT_SET == bs) breaks_add(DOC_FILENAME(doc), line, NULL, TRUE, 0); else if (BS_ENABLED == bs) breaks_remove(DOC_FILENAME(doc), line); else if (BS_DISABLED == bs) breaks_switch(DOC_FILENAME(doc), line); scintilla_send_message(doc->editor->sci, SCI_SETFOCUS, TRUE, 0); } break; } case KEY_CURRENT_INSTRUCTION: { if (DBS_STOPPED == debug_get_state() && debug_current_instruction_have_sources()) { debug_jump_to_current_instruction(); gtk_widget_set_sensitive(tab_call_stack, FALSE); stree_select_first_frame(FALSE); gtk_widget_set_sensitive(tab_call_stack, TRUE); } } } return TRUE; }
/* pkt is null-terminated */ void debug_exec(struct gdbcontext *ctx, const char *pkt) { char *cs; /* start of the checksum */ int i; int check = 0, scheck; #ifdef SHOW_PACKETS msg("Got packet %s", pkt); #endif if (pkt[0] != '$') { return; } cs = strchr(pkt, '#'); if (cs == NULL) { return; } *cs = 0; cs++; for (i=1; pkt[i]; i++) { check += pkt[i]; } scheck = strtoul(cs, NULL, 16); if (scheck != check % 256) { write(ctx->myfd, "-", 1); return; } else { write(ctx->myfd, "+", 1); } switch (pkt[1]) { case '!': /* * Enable extended mode -- extended mode is apparently * where gdb can ask to rerun the program. We can't do * that... although it could probably be arranged. * * Reply with "OK" if extended mode is enabled. */ debug_notsupp(ctx); break; case '?': /* Report why the target stopped. */ debug_send_stopinfo(ctx); break; case 'A': /* * Set argv[]. We can't do this, although it might make * sense if we grow support for reloading the kernel. */ debug_notsupp(ctx); break; case 'b': if (pkt[2] == 0) { /* Set serial bit rate; deprecated. */ debug_notsupp(ctx); break; } else if (pkt[2] == 'c') { /* Backward continue - resume executing, backwards */ } else if (pkt[2] == 's') { /* Backward single step - execute one insn backwards */ } else { /* ? */ } debug_notsupp(ctx); break; case 'B': /* Set or clear breakpoint; old, deprecated. */ debug_notsupp(ctx); break; case 'c': /* * Continue. If an address follows the 'c', continue * from that address. debug_restart() does that. */ debug_restart(ctx, pkt + 2); unset_breakcond(); break; case 'C': /* * Continue with signal. A signal number in hex * follows the C; that may be followed with a * semicolon and an address to continue at. We don't * have signals per se; in theory we could fake up * some mapping of signals to hardware traps, but that * would be difficult to arrange and not serve much * purpose. */ debug_notsupp(ctx); break; case 'd': /* Toggle debug flag (whatever that means); deprecated. */ debug_notsupp(ctx); break; case 'D': /* * Detach. With a process-id, detach only one process, * if the multiprocess extension is in use. */ debug_send(ctx, "OK"); unset_breakcond(); break; case 'F': /* * File I/O extension reply; for now at least we have * no use for this. */ debug_notsupp(ctx); break; case 'g': /* Read general-purpose registers */ debug_register_print(ctx); break; case 'G': /* * Write general-purpose registers. The G is followed * by a register dump in the same format as the 'g' * reply. */ // XXX gcc docs say this is required debug_notsupp(ctx); break; case 'H': /* * Hc followed by a thread ID sets the thread that * step and continue operations should affect; Hg * followed by a thread ID sets the thread that * other operations should affect. */ if (pkt[2] == 'c') { debug_notsupp(ctx); } else if (pkt[2] == 'g') { unsigned cpunum; cpunum = getthreadid(pkt+3); if (cpunum >= cpu_numcpus()) { debug_send(ctx, "E00"); break; } debug_cpu = cpunum; debug_send(ctx, "OK"); } else { debug_send(ctx, "OK"); } break; case 'i': /* Step by cycle count */ debug_notsupp(ctx); break; case 'I': /* Step by cycle count with signal (apparently) */ debug_notsupp(ctx); break; case 'k': /* Kill the target */ // don't do this - debugger hangs up and we get SIGPIPE //debug_send(ctx, "OK"); msg("Debugger requested kill"); reqdie(); // To continue running instead of dying, do this instead //unset_breakcond(); break; case 'm': /* Read target memory */ debug_read_mem(ctx, pkt + 2); break; case 'M': /* Write target memory */ debug_write_mem(ctx, pkt + 2); break; case 'p': /* read one register */ debug_notsupp(ctx); break; case 'P': /* write one register */ debug_notsupp(ctx); break; case 'q': /* General query */ if (strcmp(pkt + 2, "C") == 0) { /* Return current thread id */ debug_sendf(ctx,"QC%x", mkthreadid(debug_cpu)); } else if (!strcmp(pkt+2, "fThreadInfo")) { char buf[128]; unsigned i; strcpy(buf, "m"); for (i=0; i<cpu_numcpus(); i++) { if (!cpu_enabled(i)) { continue; } if (i > 0) { strcat(buf, ","); } printbyte(buf, sizeof(buf), mkthreadid(i)); } debug_send(ctx, buf); } else if (!strcmp(pkt+2, "sThreadInfo")) { debug_send(ctx, "l"); } else if (strcmp(pkt+2, "Offsets") == 0) { /* Return info about load-time relocations */ debug_notsupp(ctx); } else if (strcmp(pkt+2, "Supported") == 0) { /* Features handshake */ debug_notsupp(ctx); } else if (!strncmp(pkt+2, "ThreadExtraInfo,", 16)) { debug_getthreadinfo(ctx, pkt+2+16); } else { debug_notsupp(ctx); } break; case 'Q': /* General set mode (I think) */ debug_notsupp(ctx); break; case 'r': /* Reset target - deprecated */ debug_notsupp(ctx); break; case 'R': /* * Restart target (only with extended mode enabled). * Do not reply. */ break; case 's': /* Single step */ debug_restart(ctx, pkt + 2); onecycle(); debug_send_stopinfo(ctx); break; case 'S': /* Single step with signal */ debug_notsupp(ctx); break; case 't': /* search memory for a pattern (underdocumented) */ debug_notsupp(ctx); break; case 'T': /* check if a thread is alive (OK - yes; E.. - no) */ debug_checkthread(ctx, pkt + 2); break; case 'v': /* various longer commands */ debug_notsupp(ctx); break; case 'X': /* Write target memory with a more efficient encoding */ debug_notsupp(ctx); break; case 'z': case 'Z': /* insert (Z) or remove (z) one of the following: */ switch (pkt[2]) { case '0': /* set or clear memory breakpoint */ debug_notsupp(ctx); break; case '1': /* set or clear hardware breakpoint */ debug_notsupp(ctx); break; case '2': /* set or clear write watchpoint */ debug_notsupp(ctx); break; case '3': /* set or clear read watchpoint */ debug_notsupp(ctx); break; case '4': /* set or clear access watchpoint */ debug_notsupp(ctx); break; default: /* ? */ debug_notsupp(ctx); break; } break; default: debug_notsupp(ctx); break; } }