Home | History | Annotate | Download | only in debuggerd
      1 /*
      2  * Copyright 2008, The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define LOG_TAG "DEBUG"
     18 
     19 #include "utility.h"
     20 
     21 #include <errno.h>
     22 #include <signal.h>
     23 #include <string.h>
     24 #include <unistd.h>
     25 #include <sys/ptrace.h>
     26 #include <sys/wait.h>
     27 
     28 #include <backtrace/Backtrace.h>
     29 #include <log/log.h>
     30 
     31 const int SLEEP_TIME_USEC = 50000;         // 0.05 seconds
     32 const int MAX_TOTAL_SLEEP_USEC = 10000000; // 10 seconds
     33 
     34 static int write_to_am(int fd, const char* buf, int len) {
     35   int to_write = len;
     36   while (to_write > 0) {
     37     int written = TEMP_FAILURE_RETRY(write(fd, buf + len - to_write, to_write));
     38     if (written < 0) {
     39       // hard failure
     40       ALOGE("AM write failure (%d / %s)\n", errno, strerror(errno));
     41       return -1;
     42     }
     43     to_write -= written;
     44   }
     45   return len;
     46 }
     47 
     48 // Whitelist output desired in the logcat output.
     49 bool is_allowed_in_logcat(enum logtype ltype) {
     50   if ((ltype == ERROR)
     51    || (ltype == HEADER)
     52    || (ltype == REGISTERS)
     53    || (ltype == BACKTRACE)) {
     54     return true;
     55   }
     56   return false;
     57 }
     58 
     59 void _LOG(log_t* log, enum logtype ltype, const char* fmt, ...) {
     60   bool write_to_tombstone = (log->tfd != -1);
     61   bool write_to_logcat = is_allowed_in_logcat(ltype)
     62                       && log->crashed_tid != -1
     63                       && log->current_tid != -1
     64                       && (log->crashed_tid == log->current_tid);
     65   bool write_to_activitymanager = (log->amfd != -1);
     66 
     67   char buf[512];
     68   va_list ap;
     69   va_start(ap, fmt);
     70   vsnprintf(buf, sizeof(buf), fmt, ap);
     71   va_end(ap);
     72 
     73   size_t len = strlen(buf);
     74   if (len <= 0) {
     75     return;
     76   }
     77 
     78   if (write_to_tombstone) {
     79     TEMP_FAILURE_RETRY(write(log->tfd, buf, len));
     80   }
     81 
     82   if (write_to_logcat) {
     83     __android_log_buf_write(LOG_ID_CRASH, ANDROID_LOG_INFO, LOG_TAG, buf);
     84     if (write_to_activitymanager) {
     85       int written = write_to_am(log->amfd, buf, len);
     86       if (written <= 0) {
     87         // timeout or other failure on write; stop informing the activity manager
     88         log->amfd = -1;
     89       }
     90     }
     91   }
     92 }
     93 
     94 int wait_for_sigstop(pid_t tid, int* total_sleep_time_usec, bool* detach_failed) {
     95   bool allow_dead_tid = false;
     96   for (;;) {
     97     int 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) {
    103       if (WIFSTOPPED(status)) {
    104         return WSTOPSIG(status);
    105       } else {
    106         ALOGE("unexpected waitpid response: n=%d, status=%08x\n", n, status);
    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;
    111       }
    112     }
    113 
    114     if (*total_sleep_time_usec > MAX_TOTAL_SLEEP_USEC) {
    115       ALOGE("timed out waiting for stop signal: tid=%d", tid);
    116       break;
    117     }
    118 
    119     usleep(SLEEP_TIME_USEC);
    120     *total_sleep_time_usec += SLEEP_TIME_USEC;
    121   }
    122 
    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));
    129     }
    130   }
    131   return -1;
    132 }
    133 
    134 #if defined (__mips__)
    135 #define DUMP_MEMORY_AS_ASCII 1
    136 #else
    137 #define DUMP_MEMORY_AS_ASCII 0
    138 #endif
    139 
    140 void dump_memory(log_t* log, pid_t tid, uintptr_t addr) {
    141     char code_buffer[64];
    142     char ascii_buffer[32];
    143     uintptr_t p, end;
    144 
    145     p = addr & ~(sizeof(long) - 1);
    146     /* Dump 32 bytes before addr */
    147     p -= 32;
    148     if (p > addr) {
    149         /* catch underflow */
    150         p = 0;
    151     }
    152     /* Dump 256 bytes */
    153     end = p + 256;
    154     /* catch overflow; 'end - p' has to be multiples of 16 */
    155     while (end < p) {
    156         end -= 16;
    157     }
    158 
    159     /* Dump the code around PC as:
    160      *  addr             contents                           ascii
    161      *  0000000000008d34 ef000000e8bd0090 e1b00000512fff1e  ............../Q
    162      *  0000000000008d44 ea00b1f9e92d0090 e3a070fcef000000  ......-..p......
    163      * On 32-bit machines, there are still 16 bytes per line but addresses and
    164      * words are of course presented differently.
    165      */
    166     while (p < end) {
    167         char* asc_out = ascii_buffer;
    168 
    169         int len = snprintf(code_buffer, sizeof(code_buffer), "%" PRIPTR " ", p);
    170 
    171         for (size_t i = 0; i < 16/sizeof(long); i++) {
    172             long data = ptrace(PTRACE_PEEKTEXT, tid, (void*)p, NULL);
    173             if (data == -1 && errno != 0) {
    174                 // ptrace failed, probably because we're dumping memory in an
    175                 // unmapped or inaccessible page.
    176 #ifdef __LP64__
    177                 len += sprintf(code_buffer + len, "---------------- ");
    178 #else
    179                 len += sprintf(code_buffer + len, "-------- ");
    180 #endif
    181             } else {
    182                 len += sprintf(code_buffer + len, "%" PRIPTR " ",
    183                                static_cast<uintptr_t>(data));
    184             }
    185 
    186 #if DUMP_MEMORY_AS_ASCII
    187             for (size_t j = 0; j < sizeof(long); j++) {
    188                 /*
    189                  * Our isprint() allows high-ASCII characters that display
    190                  * differently (often badly) in different viewers, so we
    191                  * just use a simpler test.
    192                  */
    193                 char val = (data >> (j*8)) & 0xff;
    194                 if (val >= 0x20 && val < 0x7f) {
    195                     *asc_out++ = val;
    196                 } else {
    197                     *asc_out++ = '.';
    198                 }
    199             }
    200 #endif
    201             p += sizeof(long);
    202         }
    203         *asc_out = '\0';
    204         _LOG(log, logtype::MEMORY, "    %s %s\n", code_buffer, ascii_buffer);
    205     }
    206 }
    207