Skip to content

Commit 84ddb34

Browse files
committed
Fix debuggerd issues.
- Fix a problem where a tid exits before the attach completes, and it causes debuggerd to self terminate. - Fix a problem where sibling tid dumps do not properly wait for the tid to get signalled. Bug: 17800180 Bug: 12567315 Change-Id: Ic3cd619cc2c72402f9a45f14abeed4721b50d64d
1 parent 4cafe2f commit 84ddb34

File tree

5 files changed

+56
-63
lines changed

5 files changed

+56
-63
lines changed

debuggerd/backtrace.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,9 @@ static void dump_thread(
8888
return;
8989
}
9090

91-
wait_for_stop(tid, total_sleep_time_usec);
91+
if (!attached && wait_for_sigstop(tid, total_sleep_time_usec, detach_failed) == -1) {
92+
return;
93+
}
9294

9395
UniquePtr<Backtrace> backtrace(Backtrace::Create(tid, BACKTRACE_CURRENT_THREAD));
9496
if (backtrace->Unwind(0)) {

debuggerd/debuggerd.cpp

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ static void wait_for_user_action(const debugger_request_t &request) {
7777
"*\n"
7878
"* Wait for gdb to start, then press the VOLUME DOWN key\n"
7979
"* to let the process continue crashing.\n"
80-
"********************************************************\n",
80+
"********************************************************",
8181
request.pid, exe, request.tid);
8282

8383
// Wait for VOLUME DOWN.
@@ -129,11 +129,11 @@ static int read_request(int fd, debugger_request_t* out_request) {
129129
socklen_t len = sizeof(cr);
130130
int status = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &len);
131131
if (status != 0) {
132-
ALOGE("cannot get credentials\n");
132+
ALOGE("cannot get credentials");
133133
return -1;
134134
}
135135

136-
ALOGV("reading tid\n");
136+
ALOGV("reading tid");
137137
fcntl(fd, F_SETFL, O_NONBLOCK);
138138

139139
pollfd pollfds[1];
@@ -227,6 +227,7 @@ static void handle_request(int fd) {
227227
ALOGE("ptrace attach failed: %s\n", strerror(errno));
228228
} else {
229229
bool detach_failed = false;
230+
bool tid_unresponsive = false;
230231
bool attach_gdb = should_attach_gdb(&request);
231232
if (TEMP_FAILURE_RETRY(write(fd, "\0", 1)) != 1) {
232233
ALOGE("failed responding to client: %s\n", strerror(errno));
@@ -240,8 +241,9 @@ static void handle_request(int fd) {
240241

241242
int total_sleep_time_usec = 0;
242243
for (;;) {
243-
int signal = wait_for_signal(request.tid, &total_sleep_time_usec);
244-
if (signal < 0) {
244+
int signal = wait_for_sigstop(request.tid, &total_sleep_time_usec, &detach_failed);
245+
if (signal == -1) {
246+
tid_unresponsive = true;
245247
break;
246248
}
247249

@@ -308,27 +310,21 @@ static void handle_request(int fd) {
308310
free(tombstone_path);
309311
}
310312

311-
ALOGV("detaching\n");
312-
if (attach_gdb) {
313-
// stop the process so we can debug
314-
kill(request.pid, SIGSTOP);
315-
316-
// detach so we can attach gdbserver
317-
if (ptrace(PTRACE_DETACH, request.tid, 0, 0)) {
318-
ALOGE("ptrace detach from %d failed: %s\n", request.tid, strerror(errno));
319-
detach_failed = true;
313+
if (!tid_unresponsive) {
314+
ALOGV("detaching");
315+
if (attach_gdb) {
316+
// stop the process so we can debug
317+
kill(request.pid, SIGSTOP);
320318
}
321-
322-
// if debug.db.uid is set, its value indicates if we should wait
323-
// for user action for the crashing process.
324-
// in this case, we log a message and turn the debug LED on
325-
// waiting for a gdb connection (for instance)
326-
wait_for_user_action(request);
327-
} else {
328-
// just detach
329319
if (ptrace(PTRACE_DETACH, request.tid, 0, 0)) {
330-
ALOGE("ptrace detach from %d failed: %s\n", request.tid, strerror(errno));
320+
ALOGE("ptrace detach from %d failed: %s", request.tid, strerror(errno));
331321
detach_failed = true;
322+
} else if (attach_gdb) {
323+
// if debug.db.uid is set, its value indicates if we should wait
324+
// for user action for the crashing process.
325+
// in this case, we log a message and turn the debug LED on
326+
// waiting for a gdb connection (for instance)
327+
wait_for_user_action(request);
332328
}
333329
}
334330

debuggerd/tombstone.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -374,11 +374,7 @@ static void dump_nearby_maps(BacktraceMap* map, log_t* log, pid_t tid) {
374374
}
375375
}
376376

377-
static void dump_thread(
378-
Backtrace* backtrace, log_t* log, int* total_sleep_time_usec) {
379-
380-
wait_for_stop(backtrace->Tid(), total_sleep_time_usec);
381-
377+
static void dump_thread(Backtrace* backtrace, log_t* log) {
382378
dump_registers(log, backtrace->Tid());
383379
dump_backtrace_and_stack(backtrace, log);
384380

@@ -421,13 +417,17 @@ static bool dump_sibling_thread_report(
421417
continue;
422418
}
423419

420+
if (wait_for_sigstop(new_tid, total_sleep_time_usec, &detach_failed) == -1) {
421+
continue;
422+
}
423+
424424
log->current_tid = new_tid;
425425
_LOG(log, logtype::THREAD, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
426426
dump_thread_info(log, pid, new_tid);
427427

428428
UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, new_tid, map));
429429
if (backtrace->Unwind(0)) {
430-
dump_thread(backtrace.get(), log, total_sleep_time_usec);
430+
dump_thread(backtrace.get(), log);
431431
}
432432

433433
log->current_tid = log->crashed_tid;
@@ -628,7 +628,7 @@ static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, int si_code
628628
UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, tid, map.get()));
629629
if (backtrace->Unwind(0)) {
630630
dump_abort_message(backtrace.get(), log, abort_msg_address);
631-
dump_thread(backtrace.get(), log, total_sleep_time_usec);
631+
dump_thread(backtrace.get(), log);
632632
}
633633

634634
if (want_logs) {

debuggerd/utility.cpp

Lines changed: 25 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@
2828
#include <backtrace/Backtrace.h>
2929
#include <log/log.h>
3030

31-
const int sleep_time_usec = 50000; // 0.05 seconds
32-
const int max_total_sleep_usec = 10000000; // 10 seconds
31+
const int SLEEP_TIME_USEC = 50000; // 0.05 seconds
32+
const int MAX_TOTAL_SLEEP_USEC = 10000000; // 10 seconds
3333

3434
static int write_to_am(int fd, const char* buf, int len) {
3535
int to_write = len;
@@ -91,48 +91,44 @@ void _LOG(log_t* log, enum logtype ltype, const char* fmt, ...) {
9191
}
9292
}
9393

94-
int wait_for_signal(pid_t tid, int* total_sleep_time_usec) {
94+
int wait_for_sigstop(pid_t tid, int* total_sleep_time_usec, bool* detach_failed) {
95+
bool allow_dead_tid = false;
9596
for (;;) {
9697
int status;
97-
pid_t n = waitpid(tid, &status, __WALL | WNOHANG);
98-
if (n < 0) {
99-
if (errno == EAGAIN)
100-
continue;
101-
ALOGE("waitpid failed: %s\n", strerror(errno));
102-
return -1;
103-
} else if (n > 0) {
104-
ALOGV("waitpid: n=%d status=%08x\n", n, status);
98+
pid_t n = TEMP_FAILURE_RETRY(waitpid(tid, &status, __WALL | WNOHANG));
99+
if (n == -1) {
100+
ALOGE("waitpid failed: tid %d, %s", tid, strerror(errno));
101+
break;
102+
} else if (n == tid) {
105103
if (WIFSTOPPED(status)) {
106104
return WSTOPSIG(status);
107105
} else {
108106
ALOGE("unexpected waitpid response: n=%d, status=%08x\n", n, status);
109-
return -1;
107+
// This is the only circumstance under which we can allow a detach
108+
// to fail with ESRCH, which indicates the tid has exited.
109+
allow_dead_tid = true;
110+
break;
110111
}
111112
}
112113

113-
if (*total_sleep_time_usec > max_total_sleep_usec) {
114-
ALOGE("timed out waiting for tid=%d to die\n", tid);
115-
return -1;
114+
if (*total_sleep_time_usec > MAX_TOTAL_SLEEP_USEC) {
115+
ALOGE("timed out waiting for stop signal: tid=%d", tid);
116+
break;
116117
}
117118

118-
// not ready yet
119-
ALOGV("not ready yet\n");
120-
usleep(sleep_time_usec);
121-
*total_sleep_time_usec += sleep_time_usec;
119+
usleep(SLEEP_TIME_USEC);
120+
*total_sleep_time_usec += SLEEP_TIME_USEC;
122121
}
123-
}
124122

125-
void wait_for_stop(pid_t tid, int* total_sleep_time_usec) {
126-
siginfo_t si;
127-
while (TEMP_FAILURE_RETRY(ptrace(PTRACE_GETSIGINFO, tid, 0, &si)) < 0 && errno == ESRCH) {
128-
if (*total_sleep_time_usec > max_total_sleep_usec) {
129-
ALOGE("timed out waiting for tid=%d to stop\n", tid);
130-
break;
123+
if (ptrace(PTRACE_DETACH, tid, 0, 0) != 0) {
124+
if (allow_dead_tid && errno == ESRCH) {
125+
ALOGE("tid exited before attach completed: tid %d", tid);
126+
} else {
127+
*detach_failed = true;
128+
ALOGE("detach failed: tid %d, %s", tid, strerror(errno));
131129
}
132-
133-
usleep(sleep_time_usec);
134-
*total_sleep_time_usec += sleep_time_usec;
135130
}
131+
return -1;
136132
}
137133

138134
#if defined (__mips__)

debuggerd/utility.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,11 @@ enum logtype {
6767
LOGS
6868
};
6969

70-
/* Log information onto the tombstone. */
70+
// Log information onto the tombstone.
7171
void _LOG(log_t* log, logtype ltype, const char *fmt, ...)
7272
__attribute__ ((format(printf, 3, 4)));
7373

74-
int wait_for_signal(pid_t tid, int* total_sleep_time_usec);
75-
void wait_for_stop(pid_t tid, int* total_sleep_time_usec);
74+
int wait_for_sigstop(pid_t, int*, bool*);
7675

7776
void dump_memory(log_t* log, pid_t tid, uintptr_t addr);
7877

0 commit comments

Comments
 (0)