diff options
Diffstat (limited to 'gdb/gdbserver/remote-utils.c')
-rw-r--r-- | gdb/gdbserver/remote-utils.c | 113 |
1 files changed, 107 insertions, 6 deletions
diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c index 164ce6a..3dfd1c9 100644 --- a/gdb/gdbserver/remote-utils.c +++ b/gdb/gdbserver/remote-utils.c @@ -1127,7 +1127,7 @@ write_enn (char *buf) } void -convert_int_to_ascii (unsigned char *from, char *to, int n) +convert_int_to_ascii (const unsigned char *from, char *to, int n) { int nib; int ch; @@ -1144,7 +1144,7 @@ convert_int_to_ascii (unsigned char *from, char *to, int n) void -convert_ascii_to_int (char *from, unsigned char *to, int n) +convert_ascii_to_int (const char *from, unsigned char *to, int n) { int nib1, nib2; while (n--) @@ -1354,7 +1354,7 @@ decode_m_packet (char *from, CORE_ADDR *mem_addr_ptr, unsigned int *len_ptr) void decode_M_packet (char *from, CORE_ADDR *mem_addr_ptr, unsigned int *len_ptr, - unsigned char *to) + unsigned char **to_p) { int i = 0; char ch; @@ -1372,12 +1372,15 @@ decode_M_packet (char *from, CORE_ADDR *mem_addr_ptr, unsigned int *len_ptr, *len_ptr |= fromhex (ch) & 0x0f; } - convert_ascii_to_int (&from[i++], to, *len_ptr); + if (*to_p == NULL) + *to_p = xmalloc (*len_ptr); + + convert_ascii_to_int (&from[i++], *to_p, *len_ptr); } int decode_X_packet (char *from, int packet_len, CORE_ADDR *mem_addr_ptr, - unsigned int *len_ptr, unsigned char *to) + unsigned int *len_ptr, unsigned char **to_p) { int i = 0; char ch; @@ -1395,8 +1398,11 @@ decode_X_packet (char *from, int packet_len, CORE_ADDR *mem_addr_ptr, *len_ptr |= fromhex (ch) & 0x0f; } + if (*to_p == NULL) + *to_p = xmalloc (*len_ptr); + if (remote_unescape_input ((const gdb_byte *) &from[i], packet_len - i, - to, *len_ptr) != *len_ptr) + *to_p, *len_ptr) != *len_ptr) return -1; return 0; @@ -1565,6 +1571,101 @@ look_up_one_symbol (const char *name, CORE_ADDR *addrp, int may_ask_gdb) return 1; } +/* Relocate an instruction to execute at a different address. OLDLOC + is the address in the inferior memory where the instruction to + relocate is currently at. On input, TO points to the destination + where we want the instruction to be copied (and possibly adjusted) + to. On output, it points to one past the end of the resulting + instruction(s). The effect of executing the instruction at TO + shall be the same as if executing it at FROM. For example, call + instructions that implicitly push the return address on the stack + should be adjusted to return to the instruction after OLDLOC; + relative branches, and other PC-relative instructions need the + offset adjusted; etc. Returns 0 on success, -1 on failure. */ + +int +relocate_instruction (CORE_ADDR *to, CORE_ADDR oldloc) +{ + char own_buf[266]; + int len; + ULONGEST written = 0; + + /* Send the request. */ + strcpy (own_buf, "qRelocInsn:"); + sprintf (own_buf, "qRelocInsn:%s;%s", paddress (oldloc), + paddress (*to)); + if (putpkt (own_buf) < 0) + return -1; + + /* FIXME: Eventually add buffer overflow checking (to getpkt?) */ + len = getpkt (own_buf); + if (len < 0) + return -1; + + /* We ought to handle pretty much any packet at this point while we + wait for the qRelocInsn "response". That requires re-entering + the main loop. For now, this is an adequate approximation; allow + GDB to access memory. */ + while (own_buf[0] == 'm' || own_buf[0] == 'M' || own_buf[0] == 'X') + { + CORE_ADDR mem_addr; + unsigned char *mem_buf = NULL; + unsigned int mem_len; + + if (own_buf[0] == 'm') + { + decode_m_packet (&own_buf[1], &mem_addr, &mem_len); + mem_buf = xmalloc (mem_len); + if (read_inferior_memory (mem_addr, mem_buf, mem_len) == 0) + convert_int_to_ascii (mem_buf, own_buf, mem_len); + else + write_enn (own_buf); + } + else if (own_buf[0] == 'X') + { + if (decode_X_packet (&own_buf[1], len - 1, &mem_addr, + &mem_len, &mem_buf) < 0 + || write_inferior_memory (mem_addr, mem_buf, mem_len) != 0) + write_enn (own_buf); + else + write_ok (own_buf); + } + else + { + decode_M_packet (&own_buf[1], &mem_addr, &mem_len, &mem_buf); + if (write_inferior_memory (mem_addr, mem_buf, mem_len) == 0) + write_ok (own_buf); + else + write_enn (own_buf); + } + free (mem_buf); + if (putpkt (own_buf) < 0) + return -1; + len = getpkt (own_buf); + if (len < 0) + return -1; + } + + if (own_buf[0] == 'E') + { + warning ("An error occurred while relocating an instruction: %s\n", + own_buf); + return -1; + } + + if (strncmp (own_buf, "qRelocInsn:", strlen ("qRelocInsn:")) != 0) + { + warning ("Malformed response to qRelocInsn, ignoring: %s\n", + own_buf); + return -1; + } + + unpack_varlen_hex (own_buf + strlen ("qRelocInsn:"), &written); + + *to += written; + return 0; +} + void monitor_output (const char *msg) { |