Skip to content

Commit

Permalink
Return a special error code if a debugger request is made for a dead …
Browse files Browse the repository at this point in the history
…target.
  • Loading branch information
joneschrisg committed Oct 3, 2013
1 parent 71da949 commit ede4159
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 3 deletions.
18 changes: 18 additions & 0 deletions src/replayer/dbg_gdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -713,6 +713,24 @@ static int process_packet(struct dbg_context* dbg)
return ret;
}

void dbg_notify_no_such_thread(struct dbg_context* dbg,
const struct dbg_request* req)
{
assert(!memcmp(&dbg->req, req, sizeof(dbg->req)));

/* '10' is the errno ECHILD. We use it as a magic code to
* notify the user that the thread that was the target of this
* request has died, and either gdb didn't notice that, or rr
* didn't notify gdb. Either way, the user should restart
* their debugging session. */
log_err(
"Targeted thread no longer exists; this is the result of either a gdb or\n"
"rr bug. Please restart your debugging session and avoid doing whatever\n"
"triggered this bug.");
write_packet(dbg, "E10");
consume_request(dbg);
}

struct dbg_request dbg_get_request(struct dbg_context* dbg)
{
/* Can't ask for the next request until you've satisfied the
Expand Down
8 changes: 8 additions & 0 deletions src/replayer/dbg_gdb.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,14 @@ struct dbg_context* dbg_await_client_connection(const char* addr,
unsigned short port,
int probe);

/**
* Call this when the target of |req| is needed to fulfill the
* request, but the target is dead. This situation is a symptom of a
* gdb or rr bug.
*/
void dbg_notify_no_such_thread(struct dbg_context* dbg,
const struct dbg_request* req);

/**
* Return the current request made by the debugger host, that needs to
* be satisfied. This function will block until either there's a
Expand Down
8 changes: 6 additions & 2 deletions src/replayer/replayer.c
Original file line number Diff line number Diff line change
Expand Up @@ -346,8 +346,12 @@ static struct dbg_request process_debugger_requests(struct dbg_context* dbg,
}

/* These requests require a valid target task. We
* trust gdb to use the information provided above to
* only query valid tasks. */
* don't trust the debugger to use the information
* provided above to only query valid tasks. */
if (!target) {
dbg_notify_no_such_thread(dbg, &req);
continue;
}
switch (req.type) {
case DREQ_GET_MEM: {
size_t len;
Expand Down
15 changes: 14 additions & 1 deletion src/test/dead_thread_target.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from rrutil import *
import re

send_gdb('b hit_barrier\n')
expect_gdb('Breakpoint 1')
Expand All @@ -16,6 +17,18 @@
expect_gdb('Switching to thread 2')

send_gdb('c\n')
expect_gdb('Breakpoint 2, joined_threads')
# TODO: with the gdb in fedora 19, if a thread dies while it's the
# resume target, then rr notifies gdb, but gdb doesn't ask for a new
# thread list. This seems like a gdb bug, because we don't have any
# other way to notify gdb of thread death, and the same code works
# just fine in concurrent ubuntu and older versions.
#
# So we work around that problem by returning this special error code
# to the user. Once gdb has made this mistake, the debugging session
# is "stuck" because won't let any other threads continue. But at
# least this error code tells the user that they need to restart the
# session.
expect_gdb(re.compile(
r'Breakpoint 2, joined_threads|Remote failure reply: E10'))

ok()

0 comments on commit ede4159

Please sign in to comment.