Android——coredump 配置

南丶煙發表於2015-07-16

撰寫不易,轉載需註明出處:http://blog.csdn.net/jscese/article/details/46699117本文來自 【jscese】的部落格!


kernel支援:

由linux支援,程式崩潰時記錄儲存堆疊空間,暫存器等相關內容,保留致命現場資料,便於分析查詢根源。
編譯項:

Symbol: COREDUMP [=y] 
Type  : boolean
Prompt: Enable core dump support
  Location:
(1) -> Userspace binary formats
 Defined at fs/Kconfig.binfmt:182  

/kernel/signal.c中的訊號處理函式:get_signal_to_deliver中有這麼一段:

        if (sig_kernel_coredump(signr)) {
            if (print_fatal_signals)
                print_fatal_signal(info->si_signo);
            proc_coredump_connector(current);
            /*
             * If it was able to dump core, this kills all
             * other threads in the group and synchronizes with
             * their demise.  If we lost the race with another
             * thread getting here, it set group_exit_code
             * first and our do_group_exit call below will use
             * that value and ignore the one we pass it.
             */
            do_coredump(info);
        }

展開巨集如下:

(((signr) < 32) && ((1UL << ((signr) - 1)) & ((\
        (1UL << ((3) - 1))   |  (1UL << ((4) - 1))    | \
    (1UL << ((5) - 1))   |  (1UL << ((6) - 1))   | \
        (1UL << ((8) - 1))    |  (1UL << ((11) - 1))   | \
    (1UL << ((10) - 1))    |  (1UL << ((12) - 1))    | \
        (1UL << ((24) - 1))   |  (1UL << ((25) - 1))   | \
    (1UL << ((7) - 1))      

可對照signal列表檢視,

do_coredump函式實現在/fs/coredump.c

void do_coredump(siginfo_t *siginfo)
{
...
struct mm_struct *mm = current->mm;
struct linux_binfmt * binfmt;
...
    struct coredump_params cprm = {
        .siginfo = siginfo,
        .regs = signal_pt_regs(),
        .limit = rlimit(RLIMIT_CORE),  //獲取當前程式的rlimit
        /*
         * We must use the same mm->flags while dumping core to avoid
         * inconsistency of bit flags, since this flag is not protected
         * by any locks.
         */
        .mm_flags = mm->flags,
    };
...
binfmt = mm->binfmt;
...
    if (cprm.limit < binfmt->min_coredump)    //判斷rlimit 必須大於定的一個最小值: 
            goto fail_unlock;
...
}
這個最小值定義在binfmt_elf.c中
static struct linux_binfmt elf_format = {
    .module     = THIS_MODULE,
    .load_binary    = load_elf_binary,
    .load_shlib = load_elf_library,
    .core_dump  = elf_core_dump,
    .min_coredump   = ELF_EXEC_PAGESIZE,
};

#define ELF_EXEC_PAGESIZE 4096

kernel中的就先記錄這些準備資訊,如有需要可再深入檢視coredump時抓取儲存的細節


Android native 層面配置

上patch:

diff --git a/init.{ro.hardware}.rc b/init.{ro.hardware}.rc
index 8571839..a161071 100755
--- a/init.{ro.hardware}.rc
+++ b/init.ro.hardware.rc
@@ -106,6 +106,10 @@ on fs
mount debugfs none /sys/kernel/debug
+    # config coredump
+   mkdir /data/coredump 0777 system system
+   checkenable /data/coredump/enable
+   # end


diff --git a/init/builtins.c b/init/builtins.c
index 81f9b2c..c21a192 100755
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -949,3 +949,60 @@ int do_wait(int nargs, char **args)
     } else
         return -1;
 }
+
+/*(jiangbin: command check enable from file;operation )*/
+int do_checkenable(int nargs, char **args) {
+
+   int fd,len;
+   char buf[10];
+
+
+   ERROR("do_checkenable in init");
+    if (nargs == 2) {
+
+       if((fd = open(args[1], O_RDONLY|O_CREAT, 0664)) < 0)
+       {
+           return -1;
+       }
+
+       len = read(fd, buf, sizeof buf);
+       if (len < 0) {
+           close (fd);
+           return -1;
+       }
+       close (fd);
+       buf[len] = '\0';
+       if(atoi(buf)==1) /*is enable*/
+       {
+           if(strcmp(args[1],"/data/coredump/enable")==0)
+           {
+               struct rlimit coredump;
+               memset(&coredump, 0, sizeof(struct rlimit));
+               coredump.rlim_cur = RLIM_INFINITY;
+               coredump.rlim_max = RLIM_INFINITY;
+               if(setrlimit(RLIMIT_CORE, &coredump)==0)
+               {
+                   NOTICE("in init command do_checkenable coredump cur==%lu , max==%lu pid==%lu\n",coredump.rlim_cur,coredump.rlim_max, getpid());
+               }else
+               {
+                   ERROR("setrlimit unlimit fail");
+                   return -1;
+               }
+               int iret=0;
+               iret=write_file("/proc/sys/kernel/core_pattern","/data/coredump/core.%e.%p.%s");
+               iret=write_file("/proc/sys/fs/suid_dumpable","1");
+               return iret;
+
+
+           }
+
+       }
+
+
+       return 0;
+
+    }
+    return -1;
+
+}
+/*end*/
diff --git a/init/init_parser.c b/init/init_parser.c
old mode 100644
new mode 100755
index 6466db2..569b910
--- a/init/init_parser.c
+++ b/init/init_parser.c
@@ -89,6 +89,7 @@ static int lookup_keyword(const char *s)
         if (!strcmp(s, "hown")) return K_chown;
         if (!strcmp(s, "hmod")) return K_chmod;
         if (!strcmp(s, "ritical")) return K_critical;
+        if (!strcmp(s, "heckenable")) return K_checkenable;/*jiangbin add for checkenable*/
         break;
     case 'd':
         if (!strcmp(s, "isabled")) return K_disabled;
diff --git a/init/keywords.h b/init/keywords.h
old mode 100644
new mode 100755
index 2d97e5b..cf8792d
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -41,6 +41,7 @@ int do_loglevel(int nargs, char **args);
 int do_load_persist_props(int nargs, char **args);
 int do_load_all_props(int nargs, char **args);
 int do_wait(int nargs, char **args);
+int do_checkenable(int nargs, char **args);
 #define __MAKE_KEYWORD_ENUM__
 #define KEYWORD(symbol, flags, nargs, func) K_##symbol,
 enum {
@@ -104,6 +105,7 @@ enum {
     KEYWORD(load_persist_props,    COMMAND, 0, do_load_persist_props)
     KEYWORD(load_all_props,        COMMAND, 0, do_load_all_props)
     KEYWORD(ioprio,      OPTION,  0, 0)
+    KEYWORD(checkenable,        COMMAND, 1, do_checkenable)
 #ifdef __MAKE_KEYWORD_ENUM__
     KEYWORD_COUNT,
 };


作為開關新增了一個checkenable command 方便修改操作.

最終生成core檔案 /data/coredump/core.%e.%p.%s 含義:

%p 出Core程式的PID
%u 出Core程式的UID
%s 造成Core的signal號
%t 出Core的時間,從1970-01-0100:00:00開始的秒數
%e 出Core程式對應的可執行檔名

可使用ulimit -c 檢視


Android Application 層配置:

按道理init程式按照上面那樣設定之後,它的子程式zygote應該也是具備coredump能力的,自然fork的app程式也是
但是發現在zygote fork程式之後進行的:

    private static void callPostForkChildHooks(int debugFlags, String instructionSet) {
        long startTime = SystemClock.elapsedRealtime();
        VM_HOOKS.postForkChild(debugFlags, instructionSet);
        checkTime(startTime, "Zygote.callPostForkChildHooks");
    }

中呼叫到 dalvik.system.ZygoteHooks 中進一步初始化
libcore/dalvik/src/main/java/dalvik/system/ZygoteHooks.java
native:
/art/runtime/native/dalvik_system_ZygoteHooks.cc

呼叫邏輯不多描述其中會進入這個函式:

static void EnableDebugger() {
  // To let a non-privileged gdbserver attach to this
  // process, we must set our dumpable flag.
#if defined(HAVE_PRCTL)
  if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) {
    PLOG(ERROR) << "prctl(PR_SET_DUMPABLE) failed for pid " << getpid();
  }
#endif
  // We don't want core dumps, though, so set the core dump size to 0.
  rlimit rl;
  rl.rlim_cur = 0;
  rl.rlim_max = RLIM_INFINITY;
  if (setrlimit(RLIMIT_CORE, &rl) == -1) {
    PLOG(ERROR) << "setrlimit(RLIMIT_CORE) failed for pid " << getpid();
  }
}

所以zygote fork出來的process 最後都是current rlimit_core 為0
導致無法coredump

解決辦法patch如下:

diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
old mode 100644
new mode 100755
index 4f5e08b..f9782c3
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -35,6 +35,7 @@
 #include <sys/utsname.h>
 #include <sys/wait.h>

+#include <cutils/properties.h>

 #include <cutils/fs.h>
 #include <cutils/multiuser.h>
@@ -165,6 +166,26 @@ static void SetGids(JNIEnv* env, jintArray javaGids) {
   }
 }
-       delete se_name; 

+
+/*actions_code(jiangbin:native interface to setrlimit for app process:coredump)*/
+static void Zygote_nativesetrlimit()
+{
+   struct rlimit coredump;
+   memset(&coredump, 0, sizeof(struct rlimit));
+   coredump.rlim_cur = RLIM_INFINITY;
+   coredump.rlim_max = RLIM_INFINITY;
+   if(setrlimit(RLIMIT_CORE, &coredump)==0)
+   {
+       ALOGD("in zygotejni setunlimit cur==%lu , max==%lu pid==%lu\n",coredump.rlim_cur,coredump.rlim_max, getpid());
+   }else
+   {
+       ALOGE("setrlimit unlimit fail in zygotejni");
+   }
+}
+/*end*/
+
+
+
 // Sets the resource limits via setrlimit(2) for the values in the
 // two-dimensional array of integers that's passed in. The second dimension
 // contains a tuple of length 3: (resource, rlim_cur, rlim_max). NULL is
@@ -577,6 +598,17 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
       ALOGE("Error calling post fork hooks.");
       RuntimeAbort(env);
     }
+
+    /*actions_code(jiangbin:to setrlimit for app process:coredump after PostForkChildHooks)*/
+    char propcoredump[PROPERTY_VALUE_MAX];
+    property_get("persist.sys.zygotedump", propcoredump, "");
+   if(strstr(propcoredump,se_name_c_str)!=NULL)
+   {
+      Zygote_nativesetrlimit();
+   }
+   /*end*/
+       delete se_name; 
+
   } else if (pid > 0) {
     // the parent process
   }

同樣留有開關用於控制~
下篇記錄 coredump 檔案解析流程

相關文章