Skip to content

Commit

Permalink
io_gdb: gdb://host:port/pid support; Add gdbr_{attach,detach,detach_p…
Browse files Browse the repository at this point in the history
…id,kill_pid} to gdbclient. (#7759)

Try to activate extended mode; Attach helper function requires extended mode to actually do something.

Tries to attach to the given pid in io_gdb.
This isn't proper, but it's better than running into the two-pid-vals-no-sync issue.
  • Loading branch information
vifino authored and radare committed Jun 17, 2017
1 parent ba1bba5 commit d8f5cdb
Show file tree
Hide file tree
Showing 9 changed files with 219 additions and 20 deletions.
4 changes: 1 addition & 3 deletions libr/debug/p/debug_gdb.c
Expand Up @@ -206,9 +206,7 @@ static int r_debug_gdb_attach(RDebug *dbg, int pid) {
}

static int r_debug_gdb_detach(RDebug *dbg, int pid) {
gdbr_disconnect (desc);
free (reg_buf);
return true;
return gdbr_detach_pid (desc, pid);
}

static const char *r_debug_gdb_reg_profile(RDebug *dbg) {
Expand Down
22 changes: 18 additions & 4 deletions libr/io/p/io_gdb.c
Expand Up @@ -75,7 +75,7 @@ static int debug_gdb_write_at(const ut8 *buf, int sz, ut64 addr) {

static RIODesc *__open(RIO *io, const char *file, int rw, int mode) {
RIOGdb *riog;
char host[128], *port, *p;
char host[128], *port, *pid;

if (!__plugin_open (io, file, 0))
return NULL;
Expand All @@ -87,13 +87,17 @@ static RIODesc *__open(RIO *io, const char *file, int rw, int mode) {
host [sizeof (host)-1] = '\0';
port = strchr (host , ':');
if (!port) {
eprintf ("Port not specified. Please use gdb://[host]:[port]\n");
eprintf ("Port not specified. Please use gdb://host:port[/port]\n");
return NULL;
}
*port = '\0';
port++;
p = strchr (port, '/');
if (p) *p = 0;

pid = strchr (port, '/');
if (pid) {
*pid = 0;
pid++;
}

if (r_sandbox_enable (0)) {
eprintf ("sandbox: Cannot use network\n");
Expand All @@ -102,8 +106,18 @@ static RIODesc *__open(RIO *io, const char *file, int rw, int mode) {
riog = R_NEW0 (RIOGdb);
gdbr_init (&riog->desc, false);
int i_port = atoi(port);
int i_pid = -1;
if (pid)
i_pid = atoi(pid);

if (gdbr_connect (&riog->desc, host, i_port) == 0) {
desc = &riog->desc;
desc->pid = i_pid;
if (pid) { // FIXME this is here for now because RDebug's pid and libgdbr's aren't properly synced.
int ret = gdbr_attach (desc, i_pid);
if (ret < 0)
eprintf ("gdbr: Failed to attach to PID %i\n", i_pid);
}
riogdb = r_io_desc_new (&r_io_plugin_gdb, riog->desc.sock->fd, file, rw, mode, riog);
return riogdb;
}
Expand Down
24 changes: 23 additions & 1 deletion shlr/gdb/include/gdbclient/commands.h
Expand Up @@ -19,12 +19,34 @@ int gdbr_connect(libgdbr_t *g, const char *server, int port);
*/
int gdbr_disconnect(libgdbr_t *g);

/*!
* \brief checks for extended mode availability
* \returns a failure code (currently -1) or 0 if call successfully
*/
int gdbr_check_extended_mode(libgdbr_t *g);

/*!
* \brief attaches to a process
* \param pid of the process to attach to
* \returns a failure code (currently -1) or 0 if call successfully
*/
int gdbr_attach(libgdbr_t *g, int pid);

/*!
* \brief detaches from a process
* \param pid of the process to detach from (only the multiprocess/pid variant)
* \returns a failure code (currently -1) or 0 if call successfully
*/
int gdbr_detach(libgdbr_t *g);
int gdbr_detach_pid(libgdbr_t *g, int pid);

/*!
* \brief kills the process the remote gdbserver is debugging (TODO: handle pid)
* \param pid of the process to detach from (only the multiprocess/pid variant)
* \retuns a failure code (currently -1) or 0 if call successfully
*/
bool gdbr_kill(libgdbr_t *g);

bool gdbr_kill_pid(libgdbr_t *g, int pid);

// Commands
int gdbr_continue(libgdbr_t *g, int thread_id);
Expand Down
4 changes: 4 additions & 0 deletions shlr/gdb/include/gdbclient/core.h
Expand Up @@ -13,6 +13,10 @@
#include "../utils.h"
#include "../arch.h"

#define CMD_ATTACH "vAttach;"
#define CMD_DETACH_MP "D;"
#define CMD_KILL_MP "vKill;"

#define CMD_READREGS "g"
#define CMD_WRITEREGS "G"
#define CMD_READREG "p"
Expand Down
1 change: 1 addition & 0 deletions shlr/gdb/include/gdbclient/responses.h
Expand Up @@ -28,5 +28,6 @@ int handle_fstat(libgdbr_t* g);
int handle_qSupported(libgdbr_t* g);
int handle_setbp(libgdbr_t* g);
int handle_removebp(libgdbr_t* g);
int handle_attach(libgdbr_t* g);

#endif // RESPONSES_H
2 changes: 2 additions & 0 deletions shlr/gdb/include/libgdbr.h
Expand Up @@ -83,6 +83,8 @@ typedef struct libgdbr_stub_features_t {
bool BreakpointCommands;
// Cannot be determined with qSupported, found out on query
bool qC;

bool extended_mode;
} libgdbr_stub_features_t;

/*!
Expand Down
163 changes: 155 additions & 8 deletions shlr/gdb/src/gdbclient/core.c
Expand Up @@ -139,6 +139,9 @@ int gdbr_connect(libgdbr_t *g, const char *host, int port) {
if (strncmp (g->data, "OK", 2)) {
// return -1;
}

gdbr_check_extended_mode (g);

return ret;
}

Expand All @@ -151,26 +154,170 @@ int gdbr_disconnect(libgdbr_t *g) {
return 0;
}

bool gdbr_kill(libgdbr_t *g) {
char buf[20];

int gdbr_check_extended_mode(libgdbr_t *g) {
int ret;

// Activate extended mode if possible.
ret = send_msg (g, "!");
if (ret < 0) {
g->stub_features.extended_mode = false;
return ret;
}
read_packet (g);
ret = send_ack (g);
if (strncmp (g->data, "OK", 2)) {
g->stub_features.extended_mode = false;
return -1;
}

g->stub_features.extended_mode = true;
return 0;
}


int gdbr_attach(libgdbr_t *g, int pid) {
int ret;
char *cmd;
size_t buffer_size;

if (!g || !g->sock || !g->stub_features.multiprocess) {
return -1;
}

if (!g->stub_features.extended_mode) {
// vAttach needs extended mode to do anything.
return -2;
}

buffer_size = strlen (CMD_ATTACH) + (sizeof (int) * 2) + 1;
cmd = calloc (buffer_size, sizeof (char));
if (!cmd) {
return -1;
}

ret = snprintf (cmd, buffer_size, "%s%x", CMD_ATTACH, pid);
if (ret < 0) {
free(cmd);
return ret;
}

ret = send_msg (g, cmd);
free(cmd);
if (ret < 0) {
return ret;
}

if (read_packet (g) >= 0) {
return handle_attach (g);
}
return -1;
}

int gdbr_detach(libgdbr_t *g) {
int ret;

if (!g || !g->sock) {
return -1;
}

if (g->stub_features.multiprocess) {
if (!g->pid) {
return -1;
}
return gdbr_detach_pid (g, g->pid);
}

ret = send_msg (g, "D");
if (ret < 0) {
return -1;
}
return 0;
}

int gdbr_detach_pid(libgdbr_t *g, int pid) {
char *cmd;
int ret;
size_t buffer_size;

if (!g || !g->sock || !g->stub_features.multiprocess) {
return -1;
}

buffer_size = strlen (CMD_DETACH_MP) + (sizeof (pid) * 2) + 1;
cmd = calloc(buffer_size, sizeof (char));
if (!cmd) {
return -1;
}

if ((snprintf (cmd, buffer_size, "%s%x", CMD_DETACH_MP, g->pid)) < 0) {
free(cmd);
return -1;
}

ret = send_msg (g, cmd);
free(cmd);
if (ret < 0) {
return ret;
}

read_packet (g);
if ((ret = send_ack (g)) < 0) {
return ret;
}

if (strncmp (g->data, "OK", 2)) {
return -1;
}
return 0;
}

bool gdbr_kill(libgdbr_t *g) {
int ret;

if (!g || g->sock) {
return false;
}

if (g->stub_features.multiprocess) {
if (!g->pid) {
return false;
}
snprintf (buf, sizeof (buf) - 1, "vKill;%x", g->pid);
} else {
snprintf (buf, sizeof (buf) - 1, "k");
return gdbr_kill_pid (g, g->pid);
}
if ((ret = send_msg (g, buf)) < 0) {

ret = send_msg (g, "k");
if (ret < 0) {
return false;
}
if (!g->stub_features.multiprocess) {
return true;
return true;
}

bool gdbr_kill_pid(libgdbr_t *g, int pid) {
char *cmd;
int ret;
size_t buffer_size;

if (!g || !g->sock || !g->stub_features.multiprocess) {
return false;
}

buffer_size = strlen(CMD_KILL_MP) + (sizeof(pid) * 2) + 1;
cmd = calloc(buffer_size, sizeof (char));
if (!cmd) {
return false;
}

if ((snprintf (cmd, buffer_size, "%s%x", CMD_KILL_MP, g->pid)) < 0) {
free(cmd);
return false;
}
ret = send_msg (g, cmd);
free(cmd);
if (ret < 0) {
return false;
}

read_packet (g);
if ((ret = send_ack (g)) < 0) {
return false;
Expand Down
8 changes: 8 additions & 0 deletions shlr/gdb/src/gdbclient/responses.c
Expand Up @@ -170,3 +170,11 @@ int handle_setbp(libgdbr_t *g) {
int handle_removebp(libgdbr_t *g) {
return send_ack (g);
}

int handle_attach(libgdbr_t *g) {
if (g->data_len == 3 && g->data[0] == 'E') {
send_ack (g);
return -1;
}
return send_ack (g);
}
11 changes: 7 additions & 4 deletions sys/rebuild.sh
@@ -1,5 +1,8 @@
#!/bin/sh

# Requires GNU Make, but some distros probably don't have the gmake symlink.
[ -z "$MAKE" ] && MAKE=make

while : ; do
if [ -f sys/rebuild.sh ]; then
break
Expand All @@ -13,14 +16,14 @@ done

Rebuild() {
cd "$1" || exit 1
make clean
make -j8 || exit 1
$MAKE clean
$MAKE -j8 || exit 1
cd -
}

Build() {
cd "$1" || exit 1
make -j8 || exit 1
$MAKE -j8 || exit 1
cd -
}

Expand All @@ -29,7 +32,7 @@ RebuildIOSDebug() {
# Rebuild libr/util
# Rebuild libr/core
Rebuild binr/radare2
make -C binr/radare2 ios-sign
$MAKE -C binr/radare2 ios-sign
if [ -n "${IOSIP}" ]; then
scp binr/radare2/radare2 root@"${IOSIP}:."
else
Expand Down

0 comments on commit d8f5cdb

Please sign in to comment.