return gdb_write_mem(tcp->pid, off, current_wordsize, (char*)&buffer);
}
-
+/**
+ * readlink(2) implementation.
+ * - Returns amount of bytes written to buf or -1 on error.
+ * - Doesn't write terminating null byte.
+ * - If result is more than bufsize, bufsize bytes is returned (result
+ * is truncated)
+ */
int
-gdb_getfdpath(struct tcb *tcp, int fd, char *buf, unsigned bufsize)
+gdb_readlink(struct tcb *tcp, const char *linkpath,
+ char *buf, size_t bufsize)
{
- if (!gdb || fd < 0)
+ char *parameters = gdb_encode_hex_string(linkpath);
+ if (!parameters) {
+ errno = ENAMETOOLONG;
return -1;
+ }
- /*
- * As long as we assume a Linux target, we can peek at their procfs
- * just like normal getfdpath does. Maybe that won't always be true.
- */
- char linkpath[sizeof("/proc/%u/fd/%u") + 2 * sizeof(int)*3];
- sprintf(linkpath, "/proc/%u/fd/%u", tcp->pid, fd);
- return gdb_readlink(gdb, linkpath, buf, bufsize);
-}
+ struct vfile_response res = gdb_vfile(gdb, "readlink", parameters);
+ free(parameters);
+
+ int ret = -1;
+ if (res.result >= 0 && res.attachment != NULL &&
+ res.result == (int64_t) res.attachment_size) {
+ uint64_t data_len = res.attachment_size;
+
+ if (data_len >= bufsize)
+ data_len = bufsize;
+ if (data_len > SSIZE_MAX)
+ data_len = SSIZE_MAX;
+
+ if (gdb_decode_hex_buf(res.attachment, data_len << 1, buf))
+ res.errnum = EIO;
+ else
+ ret = data_len;
+ }
+
+ free(res.reply);
+
+ if (ret == -1)
+ errno = res.errnum;
+
+ return ret;
+}
bool
gdb_verify_args(const char *username, bool daemon, unsigned int *follow_fork)
.next_event = gdb_next_event,
.handle_exec = (0),
- .handle_group_stop = gdb_handle_group_stop,
- .get_siginfo = (0),
.restart_process = gdb_restart_process,
.clear_regs = (0),
.get_regs = gdb_get_registers,
.get_scno = gdb_get_scno,
.set_scno = gdb_set_scno,
- .set_error = ptrace_set_error,
- .set_success = ptrace_set_success,
- .get_syscall_result = ptrace_get_syscall_result,
+
+ .set_error = /* XXX */ ptrace_set_error,
+ .set_success = /* XXX */ ptrace_set_success,
+
+ .get_instruction_pointer = generic_get_instruction_pointer,
+ .get_stack_pointer = generic_get_stack_pointer,
+ .get_syscall_args = /* XXX */ ptrace_get_syscall_args,
+ .get_syscall_result = /* XXX */ ptrace_get_syscall_result,
.umoven = gdb_umoven,
.umovestr = gdb_umovestr,
.open = (0),
.pread = (0),
.close = (0),
- .readlink = (0),
+ .readlink = gdb_tracee_readlink,
.getxattr = (0),
.socket = (0),
.sendmsg = (0),
return NULL;
}
-struct vfile_response {
- char *reply;
- int64_t result;
- int64_t errnum; /* avoid 'errno' macros */
- size_t attachment_size;
- const char *attachment;
-};
-
static struct vfile_response
gdb_vfile(struct gdb_conn *conn, const char *operation, const char *parameters)
{
char *cmd;
int cmd_size = asprintf(&cmd, "vFile:%s:%s", operation, parameters);
if (cmd_size < 0)
- /* XXX Returns automatic variable! */
return res;
gdb_send(conn, cmd, strlen(cmd));
}
const char *errnum = memchr(res.reply, ',', size - res.attachment_size);
+ /*
+ * XXX convert errno value
+ * https://sourceware.org/gdb/onlinedocs/gdb/Errno-Values.html
+ */
if (errnum)
res.errnum = gdb_decode_signed_hex_str(errnum + 1);
}
- /* XXX Returns automatic variable! */
- return res;
-}
-
-int
-gdb_readlink(struct gdb_conn *conn, const char *linkpath,
- char *buf, unsigned bufsize)
-{
- char *parameters = gdb_encode_hex_string(linkpath);
- if (!parameters)
- return -1;
- struct vfile_response res = gdb_vfile(conn, "readlink", parameters);
- free(parameters);
-
- int ret = -1;
-
- if (res.result >= 0 && res.attachment != NULL &&
- res.result == (int64_t) res.attachment_size) {
- size_t data_len = res.attachment_size;
-
- if (data_len >= bufsize)
- data_len = bufsize - 1; /* XXX truncate -- ok? */
-
- memcpy(buf, res.attachment, data_len);
- buf[data_len] = 0;
- ret = data_len;
- }
-
- free(res.reply);
-
- return ret;
+ return res;
}
struct gdb_conn;
+/**
+ * Structure containing response for vFile requests[1].
+ *
+ * [1] https://sourceware.org/gdb/onlinedocs/gdb/Host-I_002fO-Packets.html
+ */
+struct vfile_response {
+ /** The whole reply, callee-allocated. */
+ char *reply;
+ /** Result, returned from the target */
+ int64_t result;
+ /** Error number returned from the target */
+ int64_t errnum;
+ /** Size of attachment, in bytes */
+ uint64_t attachment_size;
+ /**
+ * Pointer to the attachment inside reply. The attachment is hex-encoded
+ * (should be subjected to gdb_decode_hex* before usage).
+ */
+ const char *attachment;
+};
+
void gdb_encode_hex(uint8_t byte, char *out);
uint16_t gdb_decode_hex(char msb, char lsb);
uint64_t gdb_decode_hex_n(const char *bytes, size_t n);