Ò»¡¢±³¾°
ÔÚAndroidƽ̨£¬native crashÒ»Ö±ÊÇcrashÀïµÄ´óÍ·¡£native crash¾ßÓÐÉÏÏÂÎIJ»È«¡¢³ö´íÐÅϢģºý¡¢ÄÑÒÔ²¶×½µÈÌØµã£¬±Èjava
crash¸üÄÑÐÞ¸´¡£ËùÒÔÒ»¸öºÏ¸ñµÄÒì³£²¶»ñ×é¼þÒ²ÒªÄÜ´ïµ½ÒÔÏÂÄ¿µÄ£º
Ö§³ÖÔÚcrashʱ½øÐиü¶àÀ©Õ¹²Ù×÷£¬È磺
1.´òÓ¡logcatºÍÓ¦ÓÃÈÕÖ¾
2.Éϱ¨crash´ÎÊý
3.¶Ô²»Í¬µÄcrash×ö²»Í¬µÄ»Ö¸´´ëÊ©
4.¿ÉÒÔÕë¶ÔÒµÎñ²»¶Ï¸Ä½øºÍÊÊÓ¦
¶þ¡¢ÏÖÓеķ½°¸

Æäʵ3¸ö·½°¸ÔÚAndroidƽ̨µÄʵÏÖÔÀí¶¼ÊÇ»ù±¾Ò»Öµģ¬×ۺϿ¼ÂÇ£¬¿ÉÒÔ»ùÓÚcoffeecatch¸Ä½ø¡£
Èý¡¢ÐźŻúÖÆ
1.³ÌÐò±¼À£
ÔÚUnix-likeϵͳÖУ¬ËùÓеıÀÀ£¶¼ÊDZà³Ì´íÎó»òÕßÓ²¼þ´íÎóÏà¹ØµÄ£¬ÏµÍ³Óöµ½²»¿É»Ö¸´µÄ´íÎóʱ»á´¥·¢±ÀÀ£»úÖÆÈóÌÐòÍ˳ö£¬Èç³ýÁã¡¢¶ÎµØÖ·´íÎóµÈ¡£
Òì³£·¢Éúʱ£¬CPUͨ¹ýÒì³£Öжϵķ½Ê½£¬´¥·¢Òì³£´¦ÀíÁ÷³Ì¡£²»Í¬µÄ´¦ÀíÆ÷£¬Óв»Í¬µÄÒì³£ÖжÏÀàÐͺÍÖжϴ¦Àí·½Ê½¡£
linux°ÑÕâЩÖжϴ¦Àí£¬Í³Ò»ÎªÐźÅÁ¿£¬¿ÉÒÔ×¢²áÐźÅÁ¿ÏòÁ¿½øÐд¦Àí¡£
ÐźŻúÖÆÊǽø³ÌÖ®¼äÏ໥´«µÝÏûÏ¢µÄÒ»ÖÖ·½·¨£¬ÐźÅÈ«³ÆÎªÈíÖжÏÐźš£
2.ÐźŻúÖÆ
º¯ÊýÔËÐÐÔÚÓû§Ì¬£¬µ±Óöµ½ÏµÍ³µ÷Óá¢ÖжϻòÊÇÒì³£µÄÇé¿öʱ£¬³ÌÐò»á½øÈëÄÚºË̬¡£ÐźÅÉæ¼°µ½ÁËÕâÁ½ÖÖ״̬֮¼äµÄת»»¡£

(1) ÐźŵĽÓÊÕ
½ÓÊÕÐźŵÄÈÎÎñÊÇÓÉÄں˴úÀíµÄ£¬µ±Äں˽ÓÊÕµ½Ðźź󣬻ὫÆä·Åµ½¶ÔÓ¦½ø³ÌµÄÐźŶÓÁÐÖУ¬Í¬Ê±Ïò½ø³Ì·¢ËÍÒ»¸öÖжϣ¬Ê¹ÆäÏÝÈëÄÚºË̬¡£×¢Ò⣬´ËʱÐźŻ¹Ö»ÊÇÔÚ¶ÓÁÐÖУ¬¶Ô½ø³ÌÀ´ËµÔÝʱÊDz»ÖªµÀÓÐÐźŵ½À´µÄ¡£
(2) Ðźŵļì²â
½ø³ÌÏÝÈëÄÚºË̬ºó£¬ÓÐÁ½ÖÖ³¡¾°»á¶ÔÐźŽøÐмì²â£º
½ø³Ì´ÓÄÚºË̬·µ»Øµ½Óû§Ì¬Ç°½øÐÐÐźżì²â
½ø³ÌÔÚÄÚºË̬ÖУ¬´Ó˯Ãß״̬±»»½ÐѵÄʱºò½øÐÐÐźżì²â
µ±·¢ÏÖÓÐÐÂÐźÅʱ£¬±ã»á½øÈëÏÂÒ»²½£¬ÐźŵĴ¦Àí¡£
(3) ÐźŵĴ¦Àí
ÐźŴ¦Àíº¯ÊýÊÇÔËÐÐÔÚÓû§Ì¬µÄ£¬µ÷Óô¦Àíº¯Êýǰ£¬Äں˻Ὣµ±Ç°ÄÚºËÕ»µÄÄÚÈݱ¸·Ý¿½±´µ½Óû§Õ»ÉÏ£¬²¢ÇÒÐÞ¸ÄÖ¸Áî¼Ä´æÆ÷£¨eip£©½«ÆäÖ¸ÏòÐźŴ¦Àíº¯Êý¡£
½ÓÏÂÀ´½ø³Ì·µ»Øµ½Óû§Ì¬ÖУ¬Ö´ÐÐÏàÓ¦µÄÐźŴ¦Àíº¯Êý¡£
ÐźŴ¦Àíº¯ÊýÖ´ÐÐÍê³Éºó£¬»¹ÐèÒª·µ»ØÄÚºË̬£¬¼ì²éÊÇ·ñ»¹ÓÐÆäËüÐźÅδ´¦Àí¡£Èç¹ûËùÓÐÐźŶ¼´¦ÀíÍê³É£¬¾Í»á½«ÄÚºËÕ»»Ö¸´£¨´ÓÓû§Õ»µÄ±¸·Ý¿½±´»ØÀ´£©£¬Í¬Ê±»Ö¸´Ö¸Áî¼Ä´æÆ÷£¨eip£©½«ÆäÖ¸ÏòÖжÏǰµÄÔËÐÐλÖã¬×îºó»Øµ½Óû§Ì¬¼ÌÐøÖ´Ðнø³Ì¡£
ÖÁ´Ë£¬Ò»¸öÍêÕûµÄÐźŴ¦ÀíÁ÷³Ì±ã½áÊøÁË£¬Èç¹ûͬʱÓжà¸öÐźŵ½´ï£¬ÉÏÃæµÄ´¦ÀíÁ÷³Ì»áÔÚµÚ2²½ºÍµÚ3²½Öè¼äÖØ¸´½øÐС£
(4) ³£¼ûÐźÅÁ¿ÀàÐÍ

ËÄ¡¢²¶×½native crash
1.×¢²áÐźŴ¦Àíº¯Êý
µÚÒ»²½¾ÍÊÇÒªÓÃÐźŴ¦Àíº¯Êý²¶»ñµ½native crash(SIGSEGV,
SIGBUSµÈ)¡£ÔÚposixϵͳ£¬¿ÉÒÔÓÃsigaction()£º
#include
<signal.h>
int sigaction(int signum,const struct
sigaction *act,struct
sigaction *oldact)); |
1.signum£º´ú±íÐźűàÂ룬¿ÉÒÔÊdzýSIGKILL¼°SIGSTOPÍâµÄÈκÎÒ»¸öÌØ¶¨ÓÐЧµÄÐźţ¬Èç¹ûΪÕâÁ½¸öÐźŶ¨Òå×Ô¼ºµÄ´¦Àíº¯Êý£¬½«µ¼ÖÂÐźŰ²×°´íÎó¡£
2.act£ºÖ¸Ïò½á¹¹ÌåsigactionµÄÒ»¸öʵÀýµÄÖ¸Õ룬¸ÃʵÀýÖ¸¶¨Á˶ÔÌØ¶¨ÐźŵĴ¦Àí£¬Èç¹ûÉèÖÃΪ¿Õ£¬½ø³Ì»áÖ´ÐÐĬÈÏ´¦Àí¡£
3.oldact£ººÍ²ÎÊýactÀàËÆ£¬Ö»²»¹ý±£´æµÄÊÇÔÀ´¶ÔÏàÓ¦ÐźŵĴ¦Àí£¬Ò²¿ÉÉèÖÃΪNULL¡£
struct
sigaction sa_old;
memset(&sa, 0, sizeof(sa));
sigemptyset(&sa.sa_mask);
sa.sa_sigaction = my_handler;
sa.sa_flags = SA_SIGINFO;
if (sigaction(sig, &sa, &sa_old) ==
0) {
...
} |
2.ÉèÖöîÍâÕ»¿Õ¼ä
#include
<signal.h>
int sigaltstack(const stack_t *ss,
stack_t *oss); |
SIGSEGVºÜÓпÉÄÜÊÇÕ»Òç³öÒýÆðµÄ£¬Èç¹ûÔÚĬÈϵÄÕ»ÉÏÔËÐкÜÓпÉÄÜ»áÆÆ»µ³ÌÐòÔËÐеÄÏÖ³¡£¬ÎÞ·¨»ñÈ¡µ½ÕýÈ·µÄÉÏÏÂÎÄ¡£¶øÇÒµ±Õ»ÂúÁË£¨Ì«¶à´ÎµÝ¹é£¬Õ»ÉÏÌ«¶à¶ÔÏ󣩣¬ÏµÍ³»áÔÚͬһ¸öÒѾÂúÁ˵ÄÕ»Éϵ÷ÓÃSIGSEGVµÄÐźŴ¦Àíº¯Êý£¬ÓÖÔÙÒ»´ÎÒýÆðͬÑùµÄÐźš£
ÎÒÃÇÓ¦¸Ã¿ª±ÙÒ»¿éеĿռä×÷ΪÔËÐÐÐźŴ¦Àíº¯ÊýµÄÕ»¡£¿ÉÒÔʹÓÃsigaltstackÔÚÈÎÒâÏß³Ì×¢²áÒ»¸ö¿ÉÑ¡µÄÕ»£¬±£ÁôÒ»ÏÂÔÚ½ô¼±Çé¿öÏÂʹÓõĿռ䡣£¨ÏµÍ³»áÔÚΣÏÕÇé¿öϰÑÕ»Ö¸ÕëÖ¸ÏòÕâ¸öµØ·½£¬Ê¹µÃ¿ÉÒÔÔÚÒ»¸öеÄÕ»ÉÏÔËÐÐÐźŴ¦Àíº¯Êý£©
stack_t
stack;
memset(&stack, 0, sizeof(stack));
/* Reserver the system default stack size.
We don't need that
much by the way. */
stack.ss_size = SIGSTKSZ;
stack.ss_sp = malloc(stack.ss_size);
stack.ss_flags = 0;
/* Install alternate stack size. Be sure
the memory region
is valid until you revert it. */
if (stack.ss_sp != NULL && sigaltstack
(&stack, NULL)
== 0) {
...
} |
3.¼æÈÝÆäËûsignal´¦Àí
static
void my_handler(const int code, siginfo_t
*const si, void
*const sc) {
...
/* Call previous handler. */
old_handler.sa_sigaction(code, si, sc);
} |
ijЩÐźſÉÄÜÔÚ֮ǰÒѾ±»°²×°¹ýÐźŴ¦Àíº¯Êý£¬¶øsigactionÒ»¸öÐźÅÁ¿Ö»ÄÜ×¢²áÒ»¸ö´¦Àíº¯Êý£¬ÕâÒâζ×ÅÎÒÃǵĴ¦Àíº¯Êý»á¸²¸ÇÆäËûÈ˵Ĵ¦ÀíÐźÅ
±£´æ¾ÉµÄ´¦Àíº¯Êý£¬ÔÚ´¦ÀíÍêÎÒÃǵÄÐźŴ¦Àíº¯Êýºó£¬ÔÚÖØÐÂÔËÐÐÀϵĴ¦Àíº¯Êý¾ÍÄÜÍê³É¼æÈÝ¡£
Îå¡¢×¢ÒâÊÂÏî
1.·ÀÖ¹ËÀËø»òÕßËÀÑ»·
Ê×ÏÈÎÒÃÇÒªÁ˽âasync-signal-safeºÍ¿ÉÖØÈ뺯Êý¸ÅÄ

»ØÏëÏÂÔÚ¡°ÐźŻúÖÆ¡±Ò»½ÚÖеÄͼʾ£¬½ø³Ì²¶×½µ½ÐźŲ¢¶ÔÆä½øÐд¦Àíʱ£¬½ø³ÌÕýÔÚÖ´ÐеÄÕý³£Ö¸ÁîÐòÁоͱ»ÐźŴ¦Àí³ÌÐòÁÙʱÖжϣ¬ËüÊ×ÏÈÖ´ÐиÃÐźŴ¦Àí³ÌÐòÖеÄÖ¸ÁÀàËÆ·¢ÉúÓ²¼þÖжϣ©¡£µ«ÔÚÐźŴ¦Àí³ÌÐòÖУ¬²»ÄÜÅжϲ¶×½µ½ÐźÅʱ½ø³ÌÖ´Ðе½ºÎ´¦¡£Èç¹û½ø³ÌÕýÔÚÖ´ÐÐmalloc£¬ÔÚÆä¶ÑÖзÖÅäÁíÍâµÄ´æ´¢¿Õ¼ä£¬¶ø´ËʱÓÉÓÚ²¶×½µ½ÐźŶø²åÈëÖ´ÐиÃÐźŴ¦Àí³ÌÐò£¬ÆäÖÐÓÖµ÷ÓÃmalloc£¬Õâʱ»á·¢Éúʲô£¿Õâ¿ÉÄÜ»á¶Ô½ø³ÌÔì³ÉÆÆ»µ£¬ÒòΪmallocͨ³£ÎªËüËù·ÖÅäµÄ´æ´¢ÇøÎ¬»¤Ò»¸öÁ´±í£¬¶ø²åÈëÖ´ÐÐÐźŴ¦Àí³ÌÐòʱ£¬½ø³Ì¿ÉÄÜÕýÔÚ¸ü¸Ä´ËÁ´±í¡££¨²Î¿¼¡¶UNIX»·¾³¸ß¼¶±à³Ì¡·£©
Single UNIX Specification˵Ã÷ÁËÔÚÐźŴ¦Àí³ÌÐòÖб£Ö¤µ÷Óð²È«µÄº¯Êý¡£ÕâЩº¯ÊýÊÇ¿ÉÖØÈëµÄ²¢±»³ÆÎªÊÇÒì²½ÐźŰ²È«£¨async-signal-safe£©¡£³ýÁË¿ÉÖØÈëÒÔÍ⣬ÔÚÐźŴ¦Àí²Ù×÷ÆÚ¼ä£¬Ëü»á×èÈûÈκλáÒýÆð²»Ò»ÖµÄÐźŷ¢ËÍ¡£ÏÂÃæÊÇÕâЩÒì²½ÐźŰ²È«º¯Êý£º

µ«¼´Ê¹ÎÒÃÇ×Ô¼ºÔÚÐźŴ¦Àí³ÌÐòÖв»Ê¹Óò»¿ÉÖØÈëµÄº¯Êý£¬Ò²ÎÞ·¨±£Ö¤±£´æµÄ¾ÉµÄÐźŴ¦Àí³ÌÐòÖв»»áÓзÇÒì²½ÐźŰ²È«µÄº¯Êý¡£ËùÒÔҪʹÓÃalarm±£Ö¤ÐźŴ¦Àí³ÌÐò²»»áÏÝÈëËÀËø»òÕßËÀÑ»·µÄ״̬¡£
static
void signal_handler(const int code, siginfo_t
*const si,
void *const sc) {
/* Ensure we do not deadlock.
Default of
ALRM is to die.
* (signal() and alarm() are signal-safe) */
signal(code, SIG_DFL);
signal(SIGALRM, SIG_DFL);
/* Ensure we do not deadlock. Default of
ALRM is to die.
* (signal() and alarm() are signal-safe) */
(void) alarm(8);
....
} |
2.ÔÚÄÄÀï´òÓ¡¶ÑÕ»
(1) ×Ó½ø³Ì
¿¼Âǵ½ÐźŴ¦Àí³ÌÐòÖеÄÖî¶àÏÞÖÆ£¬Ò»°ã»ácloneÒ»¸öеĽø³Ì£¬ÔÚÆäÖÐÍê³É½âÎö¶ÑÕ»µÈÈÎÎñ¡£
ÏÂÃæÊÇGoogle BreakpadµÄÁ÷³Ìͼ£¬ÔÚеĽø³ÌÖÐDoDump£¬Ê¹ÓÃptrace½âÎöcrash½ø³ÌµÄ¶ÑÕ»£¬Í¬Ê±ÐźŴ¦Àí³ÌÐòµÈ´ý×Ó½ø³ÌÍê³ÉÈÎÎñºó£¬ÔÙµ÷ÓþɵÄÐźŴ¦Àíº¯Êý¡£¸¸×Ó½ø³ÌʹÓùܵÀͨÐÅ¡£

(2) ×ÓÏß³Ì
ÔÚÎÒµÄʵÑéÖУ¬ÔÚ×Ó½ø³Ì»òÕßÐźŴ¦Àíº¯ÊýÖУ¬¾³£ÎÞ·¨»Øµ÷¸øjava²ã¡£ÓÚÊÇÎÒÑ¡ÔñÁËÔÚ³õʼ»¯µÄʱºò¾Í½¨Á¢ÁË×ÓÏ̲߳¢Ò»Ö±µÈ´ý£¬µÈµ½²¶×½µ½crashÐźÅʱ£¬»½ÐÑÕâÌõÏß³Ìdump³öcrash¶ÑÕ»£¬²¢°Ñcrash¶ÑÕ»»Øµ÷¸øjava¡£
static
void nativeInit(JNIEnv* env, jclass
javaClass, jstring
packageNameStr, jstring
tombstoneFilePathStr,
jobject obj) {
...
initCondition();
pthread_t thd;
int ret = pthread_create(&thd, NULL,
DumpThreadEntry, NULL); if(ret)
{
qmlog("%s", "pthread_create error");
}
}
void* DumpThreadEntry(void *argv)
{
JNIEnv* env = NULL;
if((*g_jvm)->AttachCurrentThread(g_jvm,
&env, NULL) != JNI_OK)
{
LOGE("AttachCurrentThread() failed");
estatus = 0;
return &estatus;
}
while (true) {
//µÈ´ýÐźŴ¦Àíº¯Êý»½ÐÑ
waitForSignal();
//»Øµ÷nativeÒì³£¶ÑÕ»¸øjava²ã
throw_exception(env);
//¸æËßÐźŴ¦Àíº¯ÊýÒѾ´¦ÀíÍêÁË
notifyThrowException();
}
if((*g_jvm)->DetachCurrentThread(g_jvm)
!= JNI_OK)
{
LOGE("DetachCurrentThread() failed");
estatus = 0;
return &estatus;
}
return &estatus;
} |
Áù¡¢ÊÕ¼¯native crashÔÒò
ÐźŴ¦Àíº¯ÊýµÄÈë²ÎÖÐÓзḻµÄ´íÎóÐÅÏ¢£¬ÏÂÃæÎÒÃÇÀ´Ò»Ò»·ÖÎö¡£
/*ÐźŴ¦Àíº¯Êý*/
void (*sa_sigaction)(const int
code,
siginfo_t *const si, void *
const sc)
siginfo_t {
int si_signo; /* Signal number ÐźÅÁ¿ */
int si_errno; /* An errno value */
int si_code; /* Signal code ´íÎóÂë */
} |
1.code
·¢Éúnative crashÖ®ºó£¬logcatÖлá´ò³öÈçÏÂÒ»¾äÐÅÏ¢£º
signal 11 (SIGSEGV), code 0 (SI_USER), fault addr
0x0
¸ù¾ÝcodeÈ¥²é±í£¬Æäʵ¾Í¿ÉÒÔÖªµÀ·¢Éúnative crashµÄ´óÖÂÔÒò£º

´úÂëµÄÒ»²¿·ÖÈçÏ£¬Æäʵ¾ÍÊǸù¾Ý²»Í¬µÄcode£¬Êä³ö²»Í¬ÐÅÏ¢£¬ÕâЩ¶¼Êǹ̶¨µÄ¡£
case
SIGFPE:
switch(code) {
case FPE_INTDIV:
return "Integer divide by zero";
case FPE_INTOVF:
return "Integer overflow";
case FPE_FLTDIV:
return "Floating-point divide by zero";
case FPE_FLTOVF:
return "Floating-point overflow";
case FPE_FLTUND:
return "Floating-point underflow";
case FPE_FLTRES:
return "Floating-point inexact result";
case FPE_FLTINV:
return "Invalid floating-point operation";
case FPE_FLTSUB:
return "Subscript out of range";
default:
return "Floating-point";
}
break;
case SIGSEGV:
switch(code) {
case SEGV_MAPERR:
return "Address not mapped to object";
case SEGV_ACCERR:
return "Invalid permissions for mapped
object";
default:
return "Segmentation violation";
}
break; |
2.pcÖµ
ÐźŴ¦Àíº¯ÊýÖеĵÚÈý¸öÈë²ÎscÊÇuc_mcontextµÄ½á¹¹Ì壬ÊÇcpuÏà¹ØµÄÉÏÏÂÎÄ£¬°üÀ¨µ±Ç°Ï̵߳ļĴæÆ÷ÐÅÏ¢ºÍ±¼À£Ê±µÄpcÖµ¡£Äܹ»ÖªµÀ±ÀÀ£Ê±µÄpc£¬¾ÍÄÜÖªµÀ±ÀÀ£Ê±Ö´ÐеÄÊÇÄÇÌõÖ¸Áî¡£
²»¹ýÕâ¸ö½á¹¹ÌåµÄ¶¨ÒåÊÇÆ½Ì¨Ïà¹Ø£¬²»Í¬Æ½Ì¨¡¢²»Í¬cpu¼Ü¹¹Öе͍Òå¶¼²»Ò»Ñù£º
1.x86-64¼Ü¹¹£ºuc_mcontext.gregs[REG_RIP]
2.arm¼Ü¹¹£ºuc_mcontext.arm_pc
3.¹²Ïí¿âÃû×ÖºÍÏà¶ÔÆ«ÒÆµØÖ·
(1) dladdr()
pcÖµÊdzÌÐò¼ÓÔØµ½ÄÚ´æÖеľø¶ÔµØÖ·£¬ÎÒÃÇÐèÒªÄõ½±¼À£´úÂëÏà¶ÔÓÚ¹²Ïí¿âµÄÏà¶ÔÆ«ÒÆµØÖ·£¬²ÅÄÜʹÓÃaddr2line·ÖÎö³öÊÇÄÄÒ»ÐдúÂ롣ͨ¹ýdladdr()¿ÉÒÔ»ñµÃ¹²Ïí¿â¼ÓÔØµ½ÄÚ´æµÄÆðʼµØÖ·£¬ºÍpcÖµÏà¼õ¾Í¿ÉÒÔ»ñµÃÏà¶ÔÆ«ÒÆµØÖ·£¬²¢ÇÒ¿ÉÒÔ»ñµÃ¹²Ïí¿âµÄÃû×Ö¡£
Dl_info
info;
if (dladdr(addr, &info) != 0 &&
info.dli_
fname != NULL) {
void * const nearest = info.dli_saddr;
//Ïà¶ÔÆ«ÒÆµØÖ·
const uintptr_t addr_relative =
((uintptr_t) addr - (uintptr_t) info.dli_fbase);
...
} |
×÷ΪÓÐ×·ÇóµÄÎÒÃÇ£¬¿Ï¶¨²»Âú×ãÓÚ½ö½öͨ¹ýÒ»¸öº¯Êý¾Í»ñµÃ´ð°¸¡£ÎÒÃdz¢ÊÔÏÂÈçºÎÊÖ¹¤·ÖÎö³öÏà¶ÔµØÖ·¡£Ê×ÏÈÒªÁ˽âϽø³ÌµÄµØÖ·¿Õ¼ä²¼¾Ö¡£
(2) LinuxϽø³ÌµÄµØÖ·¿Õ¼ä²¼¾Ö

ÈκÎÒ»¸ö³ÌÐòͨ³£¶¼°üÀ¨´úÂë¶ÎºÍÊý¾Ý¶Î£¬ÕâЩ´úÂëºÍÊý¾Ý±¾Éí¶¼ÊǾ²Ì¬µÄ¡£³ÌÐòÒªÏëÔËÐУ¬Ê×ÏÈÒªÓɲÙ×÷ϵͳ¸ºÔðΪÆä´´½¨½ø³Ì£¬²¢ÔÚ½ø³ÌµÄÐéÄâµØÖ·¿Õ¼äÖÐΪÆä´úÂë¶ÎºÍÊý¾Ý¶Î½¨Á¢Ó³Éä¡£¹âÓдúÂë¶ÎºÍÊý¾Ý¶ÎÊDz»¹»µÄ£¬½ø³ÌÔÚÔËÐйý³ÌÖл¹ÒªÓÐÆä¶¯Ì¬»·¾³£¬ÆäÖÐ×îÖØÒªµÄ¾ÍÊǶÑÕ»¡£
ÉÏͼÖÐRandom stack offsetºÍRandom mmap offsetµÈËæ»úÖµÒâÔÚ·ÀÖ¹¶ñÒâ³ÌÐò¡£Linuxͨ¹ý¶ÔÕ»¡¢ÄÚ´æÓ³Éä¶Î¡¢¶ÑµÄÆðʼµØÖ·¼ÓÉÏËæ»úÆ«ÒÆÁ¿À´´òÂÒ²¼¾Ö£¬ÒÔÃâ¶ñÒâ³ÌÐòͨ¹ý¼ÆËã·ÃÎÊÕ»¡¢¿âº¯ÊýµÈµØÖ·¡£
Õ»(stack)£¬×÷Ϊ½ø³ÌµÄÁÙʱÊý¾ÝÇø,Ôö³¤·½ÏòÊǴӸߵØÖ·µ½µÍµØÖ·¡£
(3) /proc/self/maps£º¼ì²é¸÷¸öÄ£¿é¼ÓÔØÔÚÄÚ´æµÄµØÖ··¶Î§
ÔÚLinuxϵͳÖУ¬/proc/self/maps±£´æÁ˸÷¸ö³ÌÐò¶ÎÔÚÄÚ´æÖеļÓÔØµØÖ··¶Î§£¬grep³ö¹²Ïí¿âµÄÃû×Ö£¬¾Í¿ÉÒÔÖªµÀ¹²Ïí¿âµÄ¼ÓÔØ»ùÖµÊǶàÉÙ¡£

µÃµ½Ïà¶ÔÆ«ÒÆµØÖ·Ö®ºó£¬Ê¹ÓÃreadelf²é¿´¹²Ïí¿âµÄ·ûºÅ±í£¬¾Í¿ÉÒÔÖªµÀÊÇÄĸöº¯ÊýcrashÁË¡£

Æß¡¢»ñÈ¡¶ÑÕ»
1.ÔÀí
ÔÚǰһ²½£¬ÎÒÃÇ»ñÈ¡Á˱¼À£Ê±µÄpcÖµºÍ¸÷¸ö¼Ä´æÆ÷µÄÄÚÈÝ£¬Í¨¹ýSPºÍFPËùÏÞ¶¨µÄstack
frame£¬¾Í¿ÉÒԵõ½Ä¸º¯ÊýµÄSPºÍFP£¬´Ó¶øµÃµ½Ä¸º¯ÊýµÄstack frame£¨PC£¬LR£¬SP£¬FP»áÔÚº¯Êýµ÷ÓõĵÚһʱ¼äѹջ£©£¬ÒÔ´Ë×·ËÝ£¬¼´¿ÉµÃµ½ËùÓк¯ÊýµÄµ÷ÓÃ˳Ðò¡£

2.ʵÏÖ
ÔÚ4.1.1ÒÔÉÏ£¬5.0ÒÔÏ£ºÊ¹Óð²×¿ÏµÍ³×Ô´øµÄlibcorkscrew.so
5.0ÒÔÉÏ£º°²×¿ÏµÍ³ÖÐûÓÐÁËlibcorkscrew.so£¬Ê¹ÓÃ×Ô¼º±àÒëµÄlibunwind
#ifdef
USE_UNWIND
/* Frame buffer initial position. */
t->frames_size = 0;
/* Skip us and the caller. */
t->frames_skip = 0;
/* ʹÓÃlibcorkscrew½â¶ÑÕ» */
#ifdef USE_CORKSCREW
t->frames_size = backtrace_signal(si, sc,
t->frames, 0,
BACKTRACE_FRAMES_MAX);
#else
/* Unwind frames (equivalent to backtrace())
*/
_Unwind_Backtrace(coffeecatch_unwind_callback,
t);
#endif
/* Èç¹ûÎÞ·¨¼ÓÔØlibcorkscrew£¬ÔòʹÓÃ×Ô¼º±àÒëµÄ
libunwind½â¶ÑÕ» */
#ifdef USE_LIBUNWIND
if (t->frames_size == 0) {
size_t i;
t->frames_size = unwind_signal(si, sc,
t->uframes, 0,BACKTRACE_FRAMES_MAX);
for(i = 0 ; i < t->frames_size ; i++)
{
t->frames[i].absolute_pc = (uintptr_t)
t->uframes[i];
t->frames[i].stack_top = 0;
t->frames[i].stack_size = 0;
__android_log_print(ANDROID_LOG_DEBUG, TAG,
"absolute_pc:%x", t->frames[i].absolute_pc);
}
}
#endif |
libunwindÊÇÒ»¸ö¶ÀÁ¢µÄ¿ªÔ´¿â£¬¸ß°æ±¾µÄ°²×¿Ô´ÂëÖÐҲʹÓÃÁËlibunwind×÷Ϊ½â¶ÑÕ»µÄ¹¤¾ß£¬²¢Õë¶Ô°²×¿×öÁËһЩÊÊÅä¡£ÏÂÃæÊÇʹÓÃlibunwind½â¶ÑÕ»µÄÖ÷Ñ»·£¬Ã¿´ÎÑ»·½âÒ»²ã¶ÑÕ»¡£
static
ALWAYS_INLINE int
slow_backtrace (void **buffer, int size,
unw_context_t *uc)
{
unw_cursor_t cursor;
unw_word_t ip;
int n = 0;
if (unlikely (unw_init_local (&cursor, uc)
< 0))
return 0;
while (unw_step (&cursor) > 0)
{
if (n >= size)
return n;
if (unw_get_reg (&cursor, UNW_REG_IP, &ip)
< 0)
return n;
buffer[n++] = (void *) (uintptr_t) ip;
}
return n;
} |
°Ë¡¢»ñÈ¡º¯Êý·ûºÅ
(1) libcorkscrew
¿ÉÒÔͨ¹ýlibcorkscrewÖеÄget_backtrace_symbolsº¯Êý»ñµÃº¯Êý·ûºÅ¡£
/*
* Describes the symbols associated with a
backtrace frame.
*/
typedef struct {
uintptr_t relative_pc;
uintptr_t relative_symbol_addr;
char* map_name;
char* symbol_name;
char* demangled_name;
} backtrace_symbol_t;
/*
* Gets the symbols for each frame of a backtrace.
* The symbols array must be big enough to
hold one symbol
record per frame.
* The symbols must later be freed using
free_backtrace_symbols.
*/
void get_backtrace_symbols(const
backtrace_frame_t* backtrace,
size_t frames,
backtrace_symbol_t* backtrace_symbols); |
(2) dladdr
¸üͨÓõķ½·¨ÊÇͨ¹ýdladdr»ñµÃº¯ÊýÃû×Ö¡£
int
dladdr(void *addr, Dl_info *info);
typedef struct {
const char *dli_fname; /* Pathname of shared
object that
contains address */
void *dli_fbase; /* Base address at which shared
object is loaded */
const char *dli_sname; /* Name of symbol whose
definition
overlaps addr */
void *dli_saddr; /* Exact address of symbol
named
in dli_sname */
} Dl_info; |
´«Èëÿһ²ã¶ÑÕ»µÄÏà¶ÔÆ«ÒÆµØÖ·£¬¾Í¿ÉÒÔ´Ódli_fnameÖлñµÃº¯ÊýÃû×Ö¡£
¾Å¡¢»ñµÃjava¶ÑÕ»
ÈçºÎ»ñµÃnative crashËù¶ÔÓ¦µÄjava²ã¶ÑÕ»£¬Õâ¸öÎÊÌâÔø¾À§ÈÅÁËÎÒÒ»¶Îʱ¼ä¡£ÕâÀïÓÐÒ»¸öǰÌ᣺ÎÒÃÇÈÏΪcrashÏ߳̾ÍÊDz¶»ñµ½ÐźŵÄỊ̈߳¬ËäÈ»ÕâÔÚSIGABRTϲ»Ò»¶¨¿É¿¿¡£ÓÐÁËÕâ¸öÈÏÖª£¬½ÓÏÂÀ´¾ÍºÃ°ìÁË¡£ÔÚÐźŴ¦Àíº¯ÊýÖлñµÃµ±Ç°Ï̵߳ÄÃû×Ö£¬È»ºó°ÑcrashÏ̵߳ÄÃû×Ö´«¸øjava²ã£¬ÔÚjavaÀïdump³öÕâ¸öÏ̵߳ĶÑÕ»£¬¾ÍÊÇcrashËù¶ÔÓ¦µÄjava²ã¶ÑÕ»ÁË¡£
ÔÚcÖлñµÃÏß³ÌÃû×Ö£º
char*
getThreadName(pid_t tid) {
if (tid <= 1) {
return NULL;
}
char* path = (char *) calloc(1, 80);
char* line = (char *) calloc(1, THREAD_NAME_LENGTH);
snprintf(path, PATH_MAX, "proc/%d/comm",
tid);
FILE* commFile = NULL;
if (commFile = fopen(path, "r")) {
fgets(line, THREAD_NAME_LENGTH, commFile);
fclose(commFile);
}
free(path);
if (line) {
int length = strlen(line);
if (line[length - 1] == '\n') {
line[length - 1] = '\0';
}
}
return line;
} |
È»ºó´«¸øjava²ã£º
/**
* ¸ù¾ÝÏß³ÌÃû»ñµÃÏ̶߳ÔÏó£¬native²ã»áµ÷Óø÷½·¨£¬
²»ÄÜ»ìÏý
* @param threadName
* @return
*/
@Keep
public static Thread getThreadByName(String
threadName) {
if (TextUtils.isEmpty(threadName)) {
return null;
}
Set<Thread> threadSet
= Thread.getAllStackTraces().keySet();
Thread[] threadArray = threadSet.
toArray(new Thread[threadSet.size()]);
Thread theThread = null;
for(Thread thread : threadArray) {
if (thread.getName().equals(threadName)) {
theThread = thread;
}
}
Log.d(TAG, "threadName:
" + threadName
+ ", thread: " + theThread);
return theThread;
} |
Ê®¡¢ ½á¹ûչʾ
¾¹ýÖî¶à̽Ë÷£¬ÖÕÓڵõ½ÁËÍêÃÀµÄ¶ÑÕ»£º
java.lang.Error:
signal 11 (Address not mapped
to object) at address
0x0
at dalvik.system.NativeStart.run(Native Method)
Caused by: java.lang.Error: signal 11 (Address
not
mapped to object)
at address 0x0
at /data/app-lib/com.tencent.moai.crashcatcher.
demo-1/libQMCrashGenerator.so.0xd8e(dangerous
Function:0x5:0)
at /data/app-lib/com.tencent.moai.crashcatcher.demo-1/libQMCrashGenerator.so.0xd95(wrapDangerou
sFunction:0x2:0)
at /data/app-lib/com.tencent.moai.crashcatcher.
demo-1/libQMCrashGenerator.so.0xd9d(nativeInvalid
AddressCrash:0x2:0)
at /system/lib/libdvm.so.0x1ee8c(dvmPlatformI
nvoke:0x70:0)
at /system/lib/libdvm.so.0x503b7(dvmCallJNI
Method(unsigned
int const*, JValue*,
Method const*, Thread*):0x1ee:0)
at /system/lib/libdvm.so.0x28268(Native Method)
at /system/lib/libdvm.so.0x2f738(dvmMterpStd
(Thread*):0x44:0)
at /system/lib/libdvm.so.0x2cda8(dvmInterpret
(Thread*, Method
const*, JValue*):0xb8:0)
at /system/lib/libdvm.so.0x648e3(dvmInvokeMethod
(Object*,
Method const*, ArrayObject*,
ArrayObject*,
ClassObject*,
bool):0x1aa:0)
at /system/lib/libdvm.so.0x6cff9(Native Method)
at /system/lib/libdvm.so.0x28268(Native Method)
at /system/lib/libdvm.so.0x2f738(dvmMterpStd(Thread*)
:0x44:0)
at /system/lib/libdvm.so.0x2cda8(dvmInterpret(Thread*,
Method const*, JValue*):0xb8:0)
at /system/lib/libdvm.so.0x643d9(dvmCallMethodV(Thread*,
Method const*, Object*,
bool, JValue*, std::__va_list):
0x14c:0)
at /system/lib/libdvm.so.0x4bca1(Native Method)
at /system/lib/libandroid_runtime.so.0x50ac3(Native
Method)
at /system/lib/libandroid_runtime.so.0x518e7(android::
AndroidRuntime::start(char
const*, char const*):
0x206:0)
at /system/bin/app_process.0xf33(Native Method)
at /system/lib/libc.so.0xf584(__libc_init:0x64:0)
at /system/bin/app_process.0x107c(Native Method)
Caused by: java.lang.Error: java stack
at com.tencent.crashcatcher.CrashCatcher.nativeInvali
dAddressCrash(Native
Method)
at com.tencent.crashcatcher.CrashCatcher.invalid
AddressCrash
(CrashCatcher.java:33)
at com.tencent.moai.crashcatcher.demo.MainActivity$4.
onClick
(MainActivity.java:56)
at android.view.View.performClick(View.java:4488)
at android.view.View$PerformClick.run(View.java:18860)
at android.os.Handler.handleCallback(Handler.java:808)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loop(Looper.java:222)
at android.app.ActivityThread.main(ActivityThread.
java:5484)
at java.lang.reflect.Method.invokeNative(Native
Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgs
Caller.run
(ZygoteInit.java:860)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.
java:676)
at dalvik.system.NativeStart.main(Native Method) |
ÔÚnative²ã¹¹ÔìÁËÒ»¸öError´«¸øjava£¬ËùÒÔÔÚjava²ã¿ÉÒÔºÜÇáËɵظù¾Ý¶ÑÕ»½øÐÐÒµÎñÉϵĴ¦Àí¡£
public
interface CrashHandleListener {
@Keep
void onCrash(int id, Error e);
} |
ÁíÍâ³õʼ»¯Ê±¾Í½¨Á¢µÈ´ý»Øµ÷Ï̵߳ķ½Ê½£¬ÌṩÁËÎȶ¨µÄ¸øjava²ãµÄ»Øµ÷¡£Ôڻص÷ÖÐÎÒÃÇ´òÓ¡ÁËappµÄ״̬ÐÅÏ¢£¬°üÀ¨activityµÄ¶ÑÕ»¡¢appÊÇ·ñÔÚǰ̨µÈ£¬ÒÔ¼°´òÓ¡crashǰµÄlogcatÈÕÖ¾ºÍ°ÑÓ¦ÓÃÈÕÖ¾flush½øÎļþ¡£Õë¶ÔijЩ¾ßÌåµÄnative
crash»¹×öÁËÒµÎñÉϵĴ¦Àí£¬ÀýÈçÓöµ½ÈȲ¹¶¡¿ò¼ÜÏà¹ØµÄcrashʱ¾Í»Ø¹ö²¹¶¡¡£
ÔÚÓû§»·¾³Öеĺܶànative crashµ¥¿¿¶ÑÕ»Êǽâ¾ö²»Á˵ģ¬logcatÊǷdz£ÖØÒªµÄ²¹³ä¡£ºÃ¼¸Àýwebviewcrash¶¼ÊÇͨ¹ý·¢ÉúcrashʱµÄlogcat¶¨Î»µÄ¡£±ÈÈçÎÒÃÇÔø¾Óöµ½¹ýµÄÒ»¸öµÄwebview
crash£º
#00
pc 00039874 /system/lib/libc.so (tgkill+12)
#01 pc 00013b5d /system/lib/libc.so (pthread_kill+52)
#02 pc 0001477b /system/lib/libc.so (raise+10)
#03 pc 00010ff5 /system/lib/libc.so (__libc_
android_abort+36)
#04 pc 0000f554 /system/lib/libc.so (abort+4)
#05 pc 00239885 /system/lib/libwebviewchromium.so
#06 pc 00219da3 /system/lib/libwebviewchromium.so
#07 pc 00206459 /system/lib/libwebviewchromium.so
#08 pc 001fb6c7 /system/lib/libwebviewchromium.so
#09 pc 001edc97 /system/lib/libwebviewchromium.so
#10 pc 001ec5ad /system/lib/libwebviewchromium.so
#11 pc 001ec617 /system/lib/libwebviewchromium.so
#12 pc 001ec5e5 /system/lib/libwebviewchromium.so
#13 pc 001ec5bf /system/lib/libwebviewchromium.so
#14 pc 0022c941 /system/lib/libwebviewchromium.so
#15 pc 0022c92b /system/lib/libwebviewchromium.so
#16 pc 0022e6a1 /system/lib/libwebviewchromium.so
#17 pc 0022ebcd /system/lib/libwebviewchromium.so
#18 pc 0022ee1d /system/lib/libwebviewchromium.so
#19 pc 0022c511 /system/lib/libwebviewchromium.so
#20 pc 00013347 /system/lib/libc.so (_ZL15__pthread
_startPv+30)
#21 pc 0001135f /system/lib/libc.so (__start_thread+6) |
µ¥Æ¾¶ÑÕ»¸ù±¾¿´²»³öÀ´ÊÇʲôÎÊÌ⣬µ«ÊÇÔÚlogcatÖÐÈ´¿´µ½ÕâÑùÒ»¸öwarning
log£ºNullPointerException£¬ ´«½øÈ¥WebViewÄÚ²¿±ä³ÉÁËnatvie crash£¬ÎÊÌâ½â¾ö¡£
05-21
15:09:28.423 W/System.err(16811): java.lang.
NullPointerException:
Attempt to get length of
null array
05-21 15:09:28.424 W/System.err(16811): at java.io.ByteArrayInputStream.<init>(ByteArray
InputStream.java:60)
05-21 15:09:28.424 W/System.err(16811): at com.tencent.*.InlineImage.fetcher.HttpImageFetcher
.fetchFrom
Network(HttpImageFetcher.java:86)
05-21 15:09:28.424 W/System.err(16811): at com.tencent.*.InlineImage.fetcher.BaseFetcher.fetch
(BaseFetcher.
java:24)
05-21 15:09:28.424 W/System.err(16811): at com.tencent.*.InlineImage.delaystream.DelayInput
Stream.read
(DelayInputStream.java:36)
05-21 15:09:28.424 W/System.err(16811): at com.tencent.*.InlineImage.delaystream.DelayHttpInput
Stream.read
(DelayHttpInputStream.java:12)
05-21 15:09:28.424 W/System.err(16811): at java.io.
InputStream.
read(InputStream.java:181)
05-21 15:09:28.424 W/System.err(16811): at org.chromium.android_webview.InputStreamUtil.read
(InputStream
Util.java:54) |
²é´úÂë·¢ÏÖÊÇÎÒÃÇÔÚWebViewClientµÄshouldInterceptRequest½Ó¿ÚÖеÄÒµÎñ´úÂë·¢ÉúÁËNullPointerException£¬
´«½øÈ¥WebViewÄÚ²¿±ä³ÉÁËnatvie crash£¬ÎÊÌâ½â¾ö¡£ |