diff options
Diffstat (limited to 'debuggerd/libdebuggerd/utility.cpp')
-rw-r--r-- | debuggerd/libdebuggerd/utility.cpp | 202 |
1 files changed, 174 insertions, 28 deletions
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp index 1b746527e..247d806ba 100644 --- a/debuggerd/libdebuggerd/utility.cpp +++ b/debuggerd/libdebuggerd/utility.cpp | |||
@@ -21,6 +21,8 @@ | |||
21 | #include <errno.h> | 21 | #include <errno.h> |
22 | #include <signal.h> | 22 | #include <signal.h> |
23 | #include <string.h> | 23 | #include <string.h> |
24 | #include <sys/capability.h> | ||
25 | #include <sys/prctl.h> | ||
24 | #include <sys/ptrace.h> | 26 | #include <sys/ptrace.h> |
25 | #include <sys/uio.h> | 27 | #include <sys/uio.h> |
26 | #include <sys/wait.h> | 28 | #include <sys/wait.h> |
@@ -34,7 +36,9 @@ | |||
34 | #include <android-base/strings.h> | 36 | #include <android-base/strings.h> |
35 | #include <android-base/unique_fd.h> | 37 | #include <android-base/unique_fd.h> |
36 | #include <backtrace/Backtrace.h> | 38 | #include <backtrace/Backtrace.h> |
39 | #include <debuggerd/handler.h> | ||
37 | #include <log/log.h> | 40 | #include <log/log.h> |
41 | #include <unwindstack/Memory.h> | ||
38 | 42 | ||
39 | using android::base::unique_fd; | 43 | using android::base::unique_fd; |
40 | 44 | ||
@@ -117,34 +121,10 @@ void _LOG(log_t* log, enum logtype ltype, const char* fmt, ...) { | |||
117 | } | 121 | } |
118 | } | 122 | } |
119 | 123 | ||
120 | bool wait_for_signal(pid_t tid, siginfo_t* siginfo) { | ||
121 | while (true) { | ||
122 | int status; | ||
123 | pid_t n = TEMP_FAILURE_RETRY(waitpid(tid, &status, __WALL)); | ||
124 | if (n == -1) { | ||
125 | ALOGE("waitpid failed: tid %d, %s", tid, strerror(errno)); | ||
126 | return false; | ||
127 | } else if (n == tid) { | ||
128 | if (WIFSTOPPED(status)) { | ||
129 | if (ptrace(PTRACE_GETSIGINFO, tid, nullptr, siginfo) != 0) { | ||
130 | ALOGE("PTRACE_GETSIGINFO failed: %s", strerror(errno)); | ||
131 | return false; | ||
132 | } | ||
133 | return true; | ||
134 | } else { | ||
135 | ALOGE("unexpected waitpid response: n=%d, status=%08x\n", n, status); | ||
136 | // This is the only circumstance under which we can allow a detach | ||
137 | // to fail with ESRCH, which indicates the tid has exited. | ||
138 | return false; | ||
139 | } | ||
140 | } | ||
141 | } | ||
142 | } | ||
143 | |||
144 | #define MEMORY_BYTES_TO_DUMP 256 | 124 | #define MEMORY_BYTES_TO_DUMP 256 |
145 | #define MEMORY_BYTES_PER_LINE 16 | 125 | #define MEMORY_BYTES_PER_LINE 16 |
146 | 126 | ||
147 | void dump_memory(log_t* log, Backtrace* backtrace, uintptr_t addr, const char* fmt, ...) { | 127 | void dump_memory(log_t* log, unwindstack::Memory* memory, uintptr_t addr, const char* fmt, ...) { |
148 | std::string log_msg; | 128 | std::string log_msg; |
149 | va_list ap; | 129 | va_list ap; |
150 | va_start(ap, fmt); | 130 | va_start(ap, fmt); |
@@ -172,7 +152,7 @@ void dump_memory(log_t* log, Backtrace* backtrace, uintptr_t addr, const char* f | |||
172 | // Dump 256 bytes | 152 | // Dump 256 bytes |
173 | uintptr_t data[MEMORY_BYTES_TO_DUMP/sizeof(uintptr_t)]; | 153 | uintptr_t data[MEMORY_BYTES_TO_DUMP/sizeof(uintptr_t)]; |
174 | memset(data, 0, MEMORY_BYTES_TO_DUMP); | 154 | memset(data, 0, MEMORY_BYTES_TO_DUMP); |
175 | size_t bytes = backtrace->Read(addr, reinterpret_cast<uint8_t*>(data), sizeof(data)); | 155 | size_t bytes = memory->Read(addr, reinterpret_cast<uint8_t*>(data), sizeof(data)); |
176 | if (bytes % sizeof(uintptr_t) != 0) { | 156 | if (bytes % sizeof(uintptr_t) != 0) { |
177 | // This should never happen, but just in case. | 157 | // This should never happen, but just in case. |
178 | ALOGE("Bytes read %zu, is not a multiple of %zu", bytes, sizeof(uintptr_t)); | 158 | ALOGE("Bytes read %zu, is not a multiple of %zu", bytes, sizeof(uintptr_t)); |
@@ -199,8 +179,8 @@ void dump_memory(log_t* log, Backtrace* backtrace, uintptr_t addr, const char* f | |||
199 | // into a readable map. Only requires one extra read because a map has | 179 | // into a readable map. Only requires one extra read because a map has |
200 | // to contain at least one page, and the total number of bytes to dump | 180 | // to contain at least one page, and the total number of bytes to dump |
201 | // is smaller than a page. | 181 | // is smaller than a page. |
202 | size_t bytes2 = backtrace->Read(addr + start + bytes, reinterpret_cast<uint8_t*>(data) + bytes, | 182 | size_t bytes2 = memory->Read(addr + start + bytes, reinterpret_cast<uint8_t*>(data) + bytes, |
203 | sizeof(data) - bytes - start); | 183 | sizeof(data) - bytes - start); |
204 | bytes += bytes2; | 184 | bytes += bytes2; |
205 | if (bytes2 > 0 && bytes % sizeof(uintptr_t) != 0) { | 185 | if (bytes2 > 0 && bytes % sizeof(uintptr_t) != 0) { |
206 | // This should never happen, but we'll try and continue any way. | 186 | // This should never happen, but we'll try and continue any way. |
@@ -264,3 +244,169 @@ void read_with_default(const char* path, char* buf, size_t len, const char* defa | |||
264 | } | 244 | } |
265 | strcpy(buf, default_value); | 245 | strcpy(buf, default_value); |
266 | } | 246 | } |
247 | |||
248 | void drop_capabilities() { | ||
249 | __user_cap_header_struct capheader; | ||
250 | memset(&capheader, 0, sizeof(capheader)); | ||
251 | capheader.version = _LINUX_CAPABILITY_VERSION_3; | ||
252 | capheader.pid = 0; | ||
253 | |||
254 | __user_cap_data_struct capdata[2]; | ||
255 | memset(&capdata, 0, sizeof(capdata)); | ||
256 | |||
257 | if (capset(&capheader, &capdata[0]) == -1) { | ||
258 | PLOG(FATAL) << "failed to drop capabilities"; | ||
259 | } | ||
260 | |||
261 | if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0) { | ||
262 | PLOG(FATAL) << "failed to set PR_SET_NO_NEW_PRIVS"; | ||
263 | } | ||
264 | } | ||
265 | |||
266 | bool signal_has_si_addr(int si_signo, int si_code) { | ||
267 | // Manually sent signals won't have si_addr. | ||
268 | if (si_code == SI_USER || si_code == SI_QUEUE || si_code == SI_TKILL) { | ||
269 | return false; | ||
270 | } | ||
271 | |||
272 | switch (si_signo) { | ||
273 | case SIGBUS: | ||
274 | case SIGFPE: | ||
275 | case SIGILL: | ||
276 | case SIGSEGV: | ||
277 | case SIGTRAP: | ||
278 | return true; | ||
279 | default: | ||
280 | return false; | ||
281 | } | ||
282 | } | ||
283 | |||
284 | const char* get_signame(int sig) { | ||
285 | switch (sig) { | ||
286 | case SIGABRT: return "SIGABRT"; | ||
287 | case SIGBUS: return "SIGBUS"; | ||
288 | case SIGFPE: return "SIGFPE"; | ||
289 | case SIGILL: return "SIGILL"; | ||
290 | case SIGSEGV: return "SIGSEGV"; | ||
291 | #if defined(SIGSTKFLT) | ||
292 | case SIGSTKFLT: return "SIGSTKFLT"; | ||
293 | #endif | ||
294 | case SIGSTOP: return "SIGSTOP"; | ||
295 | case SIGSYS: return "SIGSYS"; | ||
296 | case SIGTRAP: return "SIGTRAP"; | ||
297 | case DEBUGGER_SIGNAL: return "<debuggerd signal>"; | ||
298 | default: return "?"; | ||
299 | } | ||
300 | } | ||
301 | |||
302 | const char* get_sigcode(int signo, int code) { | ||
303 | // Try the signal-specific codes... | ||
304 | switch (signo) { | ||
305 | case SIGILL: | ||
306 | switch (code) { | ||
307 | case ILL_ILLOPC: return "ILL_ILLOPC"; | ||
308 | case ILL_ILLOPN: return "ILL_ILLOPN"; | ||
309 | case ILL_ILLADR: return "ILL_ILLADR"; | ||
310 | case ILL_ILLTRP: return "ILL_ILLTRP"; | ||
311 | case ILL_PRVOPC: return "ILL_PRVOPC"; | ||
312 | case ILL_PRVREG: return "ILL_PRVREG"; | ||
313 | case ILL_COPROC: return "ILL_COPROC"; | ||
314 | case ILL_BADSTK: return "ILL_BADSTK"; | ||
315 | } | ||
316 | static_assert(NSIGILL == ILL_BADSTK, "missing ILL_* si_code"); | ||
317 | break; | ||
318 | case SIGBUS: | ||
319 | switch (code) { | ||
320 | case BUS_ADRALN: return "BUS_ADRALN"; | ||
321 | case BUS_ADRERR: return "BUS_ADRERR"; | ||
322 | case BUS_OBJERR: return "BUS_OBJERR"; | ||
323 | case BUS_MCEERR_AR: return "BUS_MCEERR_AR"; | ||
324 | case BUS_MCEERR_AO: return "BUS_MCEERR_AO"; | ||
325 | } | ||
326 | static_assert(NSIGBUS == BUS_MCEERR_AO, "missing BUS_* si_code"); | ||
327 | break; | ||
328 | case SIGFPE: | ||
329 | switch (code) { | ||
330 | case FPE_INTDIV: return "FPE_INTDIV"; | ||
331 | case FPE_INTOVF: return "FPE_INTOVF"; | ||
332 | case FPE_FLTDIV: return "FPE_FLTDIV"; | ||
333 | case FPE_FLTOVF: return "FPE_FLTOVF"; | ||
334 | case FPE_FLTUND: return "FPE_FLTUND"; | ||
335 | case FPE_FLTRES: return "FPE_FLTRES"; | ||
336 | case FPE_FLTINV: return "FPE_FLTINV"; | ||
337 | case FPE_FLTSUB: return "FPE_FLTSUB"; | ||
338 | } | ||
339 | static_assert(NSIGFPE == FPE_FLTSUB, "missing FPE_* si_code"); | ||
340 | break; | ||
341 | case SIGSEGV: | ||
342 | switch (code) { | ||
343 | case SEGV_MAPERR: return "SEGV_MAPERR"; | ||
344 | case SEGV_ACCERR: return "SEGV_ACCERR"; | ||
345 | #if defined(SEGV_BNDERR) | ||
346 | case SEGV_BNDERR: return "SEGV_BNDERR"; | ||
347 | #endif | ||
348 | #if defined(SEGV_PKUERR) | ||
349 | case SEGV_PKUERR: return "SEGV_PKUERR"; | ||
350 | #endif | ||
351 | } | ||
352 | #if defined(SEGV_PKUERR) | ||
353 | static_assert(NSIGSEGV == SEGV_PKUERR, "missing SEGV_* si_code"); | ||
354 | #elif defined(SEGV_BNDERR) | ||
355 | static_assert(NSIGSEGV == SEGV_BNDERR, "missing SEGV_* si_code"); | ||
356 | #else | ||
357 | static_assert(NSIGSEGV == SEGV_ACCERR, "missing SEGV_* si_code"); | ||
358 | #endif | ||
359 | break; | ||
360 | #if defined(SYS_SECCOMP) // Our glibc is too old, and we build this for the host too. | ||
361 | case SIGSYS: | ||
362 | switch (code) { | ||
363 | case SYS_SECCOMP: return "SYS_SECCOMP"; | ||
364 | } | ||
365 | static_assert(NSIGSYS == SYS_SECCOMP, "missing SYS_* si_code"); | ||
366 | break; | ||
367 | #endif | ||
368 | case SIGTRAP: | ||
369 | switch (code) { | ||
370 | case TRAP_BRKPT: return "TRAP_BRKPT"; | ||
371 | case TRAP_TRACE: return "TRAP_TRACE"; | ||
372 | case TRAP_BRANCH: return "TRAP_BRANCH"; | ||
373 | case TRAP_HWBKPT: return "TRAP_HWBKPT"; | ||
374 | } | ||
375 | if ((code & 0xff) == SIGTRAP) { | ||
376 | switch ((code >> 8) & 0xff) { | ||
377 | case PTRACE_EVENT_FORK: | ||
378 | return "PTRACE_EVENT_FORK"; | ||
379 | case PTRACE_EVENT_VFORK: | ||
380 | return "PTRACE_EVENT_VFORK"; | ||
381 | case PTRACE_EVENT_CLONE: | ||
382 | return "PTRACE_EVENT_CLONE"; | ||
383 | case PTRACE_EVENT_EXEC: | ||
384 | return "PTRACE_EVENT_EXEC"; | ||
385 | case PTRACE_EVENT_VFORK_DONE: | ||
386 | return "PTRACE_EVENT_VFORK_DONE"; | ||
387 | case PTRACE_EVENT_EXIT: | ||
388 | return "PTRACE_EVENT_EXIT"; | ||
389 | case PTRACE_EVENT_SECCOMP: | ||
390 | return "PTRACE_EVENT_SECCOMP"; | ||
391 | case PTRACE_EVENT_STOP: | ||
392 | return "PTRACE_EVENT_STOP"; | ||
393 | } | ||
394 | } | ||
395 | static_assert(NSIGTRAP == TRAP_HWBKPT, "missing TRAP_* si_code"); | ||
396 | break; | ||
397 | } | ||
398 | // Then the other codes... | ||
399 | switch (code) { | ||
400 | case SI_USER: return "SI_USER"; | ||
401 | case SI_KERNEL: return "SI_KERNEL"; | ||
402 | case SI_QUEUE: return "SI_QUEUE"; | ||
403 | case SI_TIMER: return "SI_TIMER"; | ||
404 | case SI_MESGQ: return "SI_MESGQ"; | ||
405 | case SI_ASYNCIO: return "SI_ASYNCIO"; | ||
406 | case SI_SIGIO: return "SI_SIGIO"; | ||
407 | case SI_TKILL: return "SI_TKILL"; | ||
408 | case SI_DETHREAD: return "SI_DETHREAD"; | ||
409 | } | ||
410 | // Then give up... | ||
411 | return "?"; | ||
412 | } | ||