📄 server-main.c
字号:
/* * handle_write_registers * * This stores away all the registers... In the grand tradition of * gdb, we don't actually write down to the board till we restart. */inthandle_write_registers (char *input_buffer){ char *buffer = alloca(REGISTER_BYTES); if (!low_update_registers ()) { putpkt ("ENN"); return 0; } convert_ascii_to_bytes (input_buffer, buffer, REGISTER_BYTES, 0); memcpy (&aregisters, (char *) buffer, REGISTER_BYTES); registers_are_dirty = 1; low_write_registers (); return 1;}/* * handle_write_a_register * * This writes a single register into the register array. The register * is not actually written down to the board at this point. */inthandle_write_a_register (char *input_buffer){ char *val_ptr; int regno; if (!low_update_registers ()) { putpkt ("ENN"); return 0; } val_ptr = (char *) strchr (input_buffer, '='); if (val_ptr == NULL) { if (debug_on) { output_error ("Malformed P request - no \"=\": %s\n", input_buffer); } putpkt ("ENN"); return 0; } *val_ptr = '\0'; sscanf (input_buffer, "%x", ®no); /* FIXME - Check that regno is a valid register */ val_ptr++; if (strlen (val_ptr) != (REGISTER_RAW_SIZE (regno) * 2)) { output_error ("Malformed register value for register %d ", regno); output_error ("- wrong size: %s\n", val_ptr); return 0; } convert_ascii_to_bytes (val_ptr, &aregisters[REGISTER_BYTE (regno)], REGISTER_RAW_SIZE (regno), 0); registers_are_dirty = 1; /* For now, I am always flushing the changes so I can test the code. Remove this from the production version. */ low_write_registers(); putpkt("OK"); return 1;}inthandle_read_memory (char *input_buffer){ unsigned int len, nbytes, nchars; char static_buf[1024]; char *buffer = static_buf; CORE_ADDR start_addr; int result; decode_m_packet (input_buffer, &start_addr, &nbytes); if (debug_on) { output ("Reading %d bytes starting at 0x%x\n", nbytes, start_addr); } nchars = 2 * nbytes + 1; if (nchars > 1024) { buffer = (char *) malloc (nchars); } len = low_read_memory (buffer, start_addr, nbytes); if (len > 0) { result = 1; } else { /* HACK ALERT: When gdb first tries to connect, to the target, the fp often points into never-never land. If tries to decode the prolog, and than ends up getting it to read invalid memory, and the whole thing chokes. To keep this from happening, I will return as many zeros as requested... */ memset (buffer, '0', nchars); output_error ("Failed to read memory at address 0x%x\n", start_addr); result = 0; } putpkt (buffer); if (buffer != static_buf) { free (buffer); } return result;}inthandle_write_memory (char *input_buffer){ unsigned int len, nbytes; char data[1024]; /* FIXME -static buffer used! */ CORE_ADDR start_addr; decode_M_packet (input_buffer, data, &start_addr, &nbytes); if (debug_on) { output ("Writing %d bytes starting at 0x%x\n", nbytes, start_addr); } len = low_write_memory (data, start_addr, nbytes); if (len == nbytes) { putpkt ("OK"); return 1; } else { putpkt ("ENN"); return 0; }}/* * remove_signal * * This strips the signal part off the C & S packets, and returns * the value in SIGNO. It returns a pointer to the first character in * input_buffer after the ';', or NULL for error. */char *remove_signal (char *input_buffer, int *signo){ char *p; p = (char *) strchr (input_buffer, ';'); /* If there is no ";", then the whole thing is the signal... */ if (p == NULL) { sscanf (input_buffer, "%x", signo); p = input_buffer + strlen(input_buffer); } else { *p = '\0'; sscanf (input_buffer, "%x", signo); p = input_buffer++; } return p;}/* * handle_resume * * This resumes the target. RESUME_MODE is one of RESUME_STEP or * RESUME_CONTINUE. The input buffer can be blank, or can optionally contain * the line at which to resume execution. SIGNO is the signal with which * to resume. It is ignored. */inthandle_resume (char *input_buffer, enum resume_mode mode, int signo){ int stop_signal; char return_pkt[128]; char PC_reg[16], SP_reg[16]; /* Forget about 'selected' thread */ selected_thread = 0; current_thread = 0; /* * See if there is an address to resume at, if not default * to the current PC. */ if (*input_buffer != '\0') { convert_ascii_to_bytes (input_buffer, &aregisters[REGISTER_BYTE (PC_REGNUM)], REGISTER_RAW_SIZE (PC_REGNUM), 0); } if (debug_on && (mode == RESUME_CONTINUE)) { output ("Executing...\n"); } enable_async_io(); stop_signal = low_resume (mode, signo); disable_async_io(); if (debug_on && (mode == RESUME_CONTINUE)) { output ("Stopped...\n"); } /* We have run, so the registers are no longer up-to-date */ registers_up_to_date = 0; registers_are_dirty = 0; /* Now write the return signal. */ sprintf (return_pkt, "S%02x", stop_signal); update_current_thread(); if (current_thread != 0) { /* Return thread-based result, registers are up-to-date */ convert_bytes_to_ascii(&aregisters[REGISTER_BYTE (PC_REGNUM)], PC_reg, REGISTER_RAW_SIZE (PC_REGNUM), 0); convert_bytes_to_ascii(&aregisters[REGISTER_BYTE (SP_REGNUM)], SP_reg, REGISTER_RAW_SIZE (SP_REGNUM), 0); sprintf (return_pkt, "T%02xthread:%08x;%02x:%s;%02x:%s;", stop_signal, current_thread, PC_REGNUM, PC_reg, SP_REGNUM, SP_reg); } else { /* Now write the return signal. */ sprintf (return_pkt, "S%02x", stop_signal); } putpkt (return_pkt); return 1;}/* * handle_last_signal * * Actually, this returns the last reason for stopping. */inthandle_last_signal (char *input_buffer){ enum target_signal signal; char buffer[8]; signal = low_query_last_signal (); sprintf (buffer, "S%02x", signal); putpkt (buffer); return 1;}/* * handle_detach * * This detaches from the remote connection, and the we wait for * another connection. */inthandle_detach (char *input_buffer){ close_connection_now = 1; putpkt ("OK"); return 1;}/* * handle_restart * * I am hijacking this to mean kill the server. Not great, but it * is better than kill or detach. */inthandle_restart (char *input_buffer){ close_connection_now = 1; exit_now = 1; return 1;}/* * handle_toggle_debug * * This toggles the internal debugging flag. */inthandle_toggle_debug (char *input_buffer){ if (debug_on) debug_on = 0; else debug_on = 1; return 1;}inthandle_reset (char *input_buffer){ return 1;}/* * handle_kill_target * * This actually just disconnects. Since gdb issues 'k' when it exits * it would be very inconvenient if this were to kill the target. */inthandle_kill_target (char *input_buffer){ close_connection_now = 1; return 1;}/* * handle_search_memory * * Currently a no-op */inthandle_search_memory (char *input_buffer){ return 1;}/* * handle_general_query * * This handles the 'q' packets. Right now it does qOffset, and the * thread query (though this returns nothing useful since you can't * query threads through the RDI. */inthandle_general_query (char *input_buffer){ char key; long thread_id; char *result, *ptr; int res; /* I couldn't find a general enumeration of the general query messages... So these are all I could find. */ key = input_buffer[0]; switch (key) { case 'C': /* This is the Current thread request */ res = low_thread_op(input_buffer-1, &result); if (res) { // Look at result to decode answer if (strncmp(result, "QC", 2) == 0) { using_threads = 1; current_thread = strtol (result+2, &ptr, 0x10); // Protocol uses hex values } else { current_thread = 0; // Unknown } putpkt(result); } else { putpkt(""); } return res; case 'O': /* The offsets query */ { char buffer[256]; CORE_ADDR text, data, bss; if (low_get_offsets (&text, &data, &bss)) { sprintf (buffer, "Text=%x;Data=%x;Bss=%x", text, data, bss); putpkt (buffer); return 1; } else { putpkt (""); return 0; } } case 'L': /* Get thread list */ case 'P': /* This is the thread info request */ res = low_thread_op(input_buffer-1, NULL); if (!res) putpkt(""); return res; case 'E': /* This is for private use, to do tests... */ return run_test(++input_buffer); default: putpkt (""); return 1; } return 1;}/* * handle_general_set * * This would handle the catchall set commands. For now we do nothing. * Set thread is about the only one I currently know what to do anything * about, and that doesn't work for RDI1.50, so there... */inthandle_general_set (char *input_buffer){ return 1;}/* * handle_breakpoint * * This handles setting and deleting breakpoints. ACTION is one of * BREAKPOINT_SET of BREAKPOINT_DELETE. The rest of INPUT_BUFFER * contains the address. */inthandle_breakpoint (enum bp_action_type action, char *input_buffer){ char ch; char *p; CORE_ADDR bp_addr; int result; int size = 0; if ((p = (char *) strchr(input_buffer, ',')) != NULL) { *p = '\0'; p++; sscanf (p, "%d", &size); } bp_addr = 0; while ((ch = *(input_buffer++)) != '\0') { bp_addr = bp_addr << 4; bp_addr |= fromhex (ch) & 0x0f; } switch (action) { case BREAKPOINT_SET: if (debug_on) { output ("Setting breakpoint at %x of length %d\n", bp_addr, size); } result = low_set_breakpoint (bp_addr, size); break; case BREAKPOINT_DELETE: if (debug_on) { output ("Removing breakpoint at %x of length %d\n", bp_addr, size); } result = low_delete_breakpoint (bp_addr, size); break; } if (result) { putpkt ("OK"); } else { putpkt ("ENN"); } return result;}/* * handle_watchpoint * * This would handle watchpoint requests. These are not yet wired into * the target vector, however, so I don't think that gdb can send them... */int handle_watchpoint (enum bp_action_type action, enum watch_type type, char *input_buffer){ char ch; char *p; CORE_ADDR watch_addr; int result; int size = 0; if ((p = (char *) strchr(input_buffer, ',')) != NULL) { *p = '\0'; p++; sscanf (p, "%d", &size); } watch_addr = 0; while ((ch = *(input_buffer++)) != '\0') { watch_addr = watch_addr << 4; watch_addr |= fromhex (ch) & 0x0f; } switch (action) { case BREAKPOINT_SET: if (debug_on) { output ("Setting watchpoint at %x of length %d\n", watch_addr, size); } result = low_set_watchpoint (watch_addr, size, type); break; case BREAKPOINT_DELETE: if (debug_on) { output ("Removing watchpoint at %x of length %d\n", watch_addr, size); } result = low_delete_watchpoint (watch_addr, size, type); break; } if (result) { putpkt ("OK"); } else { putpkt ("ENN"); } return result;}/* * enable_extended_ops * * Store away the fact that we are using the extended remote protocol. */void enable_extended_ops (){ use_extended_ops = 1;}/* * exit_handler * * Flag the main loop to exit. */voidexit_handler(){ exit_now = 1; close_connection_now = 1;}#define ARMword unsigned intextern void record_register (int regno, ARMword val);extern ARMword restore_register (int regno);/* run_test * * This does nothing now, but you can shove in anything here, and * sending an 'qE' packet will activate it. Just for testing. */intrun_test (char *input_buffer){ return low_test (input_buffer);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -