मैं SIGSEGV (विभाजन दोष) को कैसे पकड़ सकता हूं और Android पर JNI के तहत स्टैक ट्रेस प्राप्त कर सकता हूं?


92

मैं एक प्रोजेक्ट को नए एंड्रॉइड नेटिव डेवलपमेंट किट (यानी JNI) में स्थानांतरित कर रहा हूं और मैं SIGSEGV को पकड़ना चाहता हूं, क्या यह एक अच्छा रिपोर्टिंग रिपोर्टिंग संवाद पेश करने के लिए (संभवतः SIGILL, SIGABRT, SIGFPE) भी होना चाहिए। (या इससे पहले) वर्तमान में क्या होता है: प्रक्रिया की तत्काल असामयिक मृत्यु और संभवतः इसे पुनः आरंभ करने के लिए ओएस द्वारा कुछ प्रयास। ( संपादित करें: JVM / Dalvik VM सिग्नल को पकड़ता है और एक स्टैक ट्रेस और अन्य उपयोगी जानकारी लॉग करता है; मैं बस उपयोगकर्ता को उस जानकारी को वास्तव में मुझे ईमेल करने का विकल्प प्रदान करना चाहता हूं।)

स्थिति यह है: सी कोड का एक बड़ा निकाय, जो मैंने नहीं लिखा था, इस एप्लिकेशन (गेम के सभी तर्क) में अधिकांश काम करता है और यद्यपि यह कई अन्य प्लेटफार्मों पर अच्छी तरह से परीक्षण किया गया है, यह पूरी तरह से संभव है कि मैं, अपने Android में पोर्ट, इसे कचरा खिलाएगा और मूल कोड में क्रैश का कारण होगा, इसलिए मैं क्रैश डंप (मूल और जावा दोनों) चाहता हूं जो वर्तमान में एंड्रॉइड लॉग में दिखाई देता है (मुझे लगता है कि यह एक गैर-एंड्रॉइड स्थिति में stderr होगा)। मैं सी और जावा कोड दोनों को मनमाने ढंग से संशोधित करने के लिए स्वतंत्र हूं, हालांकि कॉलबैक (दोनों जेएनआई से बाहर आ रहे हैं) संख्या लगभग 40 और जाहिर है, छोटे बिंदुओं के लिए बोनस अंक।

मैंने जे 2 एसई, libjsig.so में सिग्नल चाइनिंग लाइब्रेरी के बारे में सुना है, और अगर मैं एंड्रॉइड पर उस तरह से एक सिग्नल हैंडलर को सुरक्षित रूप से स्थापित कर सकता हूं, तो यह मेरे प्रश्न के पकड़ने वाले हिस्से को हल करेगा, लेकिन मुझे एंड्रॉइड / डेल्विक के लिए ऐसी कोई लाइब्रेरी नहीं दिख रही है ।


यदि आप रैपर स्क्रिप्ट के माध्यम से जावा वीएम शुरू कर सकते हैं, तो आप जांच सकते हैं कि क्या ऐप असामान्य रूप से बाहर निकल गया है, और त्रुटि रिपोर्टिंग करता है। यह आपको सभी प्रकार के असामान्य निकासों को आसानी से पकड़ने की अनुमति देगा, वे SIGSEGV, SIGKILL या जो भी हों। हालाँकि, मुझे नहीं लगता कि स्टॉक एंड्रॉइड ऐप के साथ यह संभव है, इसलिए इसे एक टिप्पणी के रूप में पोस्ट किया जाए (उत्तर से परिवर्तित)।
सलेस्के

इसे भी देखें: रैपर स्क्रिप्ट (adb शेल में) के साथ Android ऐप कैसे शुरू करें, इसके लिए Valgrind के साथ एक जावा एंड्रॉइड प्रोग्राम नहीं चला सकते
साल्के जूल

1
उत्तर को अद्यतन करने की आवश्यकता है। स्वीकार किए गए उत्तर में दिए गए स्रोत कोड का उपयोग गैर-एस्सेंट-सिग्नल-सुरक्षित कार्यों के लिए कॉल के कारण अपरिभाषित व्यवहार के परिणामस्वरूप होगा। कृपया यहाँ देखें: stackoverflow.com/questions/34547199/…
user1506104

जवाबों:


82

संपादित करें: जेली बीन से आपको स्टैक ट्रेस नहीं मिल सकता है, क्योंकि READ_LOGSचले गए । :-(

मुझे वास्तव में एक सिग्नल हैंडलर बिना कुछ भी विदेशी काम करने के लिए मिला है, और इसका उपयोग करके कोड जारी किया है, जिसे आप जीथब पर देख सकते हैं (संपादित करें: ऐतिहासिक रिलीज से लिंक करना; मैंने तब से क्रैश हैंडलर हटा दिया है)। ऐसे:

  1. sigaction()संकेतों को पकड़ने और पुराने हैंडलर को स्टोर करने के लिए उपयोग करें । ( Android.c: 570 )
  2. समय गुजरता है, एक segfault होता है।
  3. सिग्नल हैंडलर में, अंतिम बार जेएनआई को कॉल करें और फिर पुराने हैंडलर को कॉल करें। ( Android.c: 528 )
  4. उस JNI कॉल में, किसी भी उपयोगी डिबगिंग जानकारी को लॉग इन करें, और startActivity()एक ऐसी गतिविधि पर कॉल करें, जिसे स्वयं की प्रक्रिया में होना चाहिए। ( एसजीटीपीपीस.जावा : 962 , एंड्रॉइड मैनफेस्ट.एक्सएमएल : 28 )
  5. जब आप जावा से वापस आते हैं और उस पुराने हैंडलर को कॉल करते हैं, तो एंड्रॉइड फ्रेमवर्क आपके debuggerdलिए एक अच्छा देशी ट्रेस लॉग करने के लिए कनेक्ट होगा , और फिर प्रक्रिया मर जाएगी। ( debugger.c , debuggerd.c )
  6. इस बीच, आपकी क्रैश-हैंडलिंग गतिविधि शुरू हो रही है। वास्तव में आपको इसे पीआईडी ​​पास करना चाहिए ताकि यह चरण 5 के पूरा होने की प्रतीक्षा कर सके; मैं ऐसा नहीं करता। यहां आप उपयोगकर्ता से माफी मांगते हैं और पूछते हैं कि क्या आप लॉग भेज सकते हैं। यदि ऐसा है, तो आउटपुट को इकट्ठा करें logcat -d -v threadtimeऔर ACTION_SENDप्राप्तकर्ता, विषय और बॉडी के साथ लॉन्च करें। उपयोगकर्ता को सेंड को दबाना होगा। ( CrashHandler.java , SGTPuzzles.java:462 , strings.xml: 41
  7. logcatअसफल होने या कुछ सेकंड से अधिक लेने के लिए बाहर देखें । मुझे एक डिवाइस, टी-मोबाइल पल्स / हुआवेई यू 8220 का सामना करना पड़ा है, जहां लॉगकैट तुरंत T(ट्रेस) स्थिति में चला जाता है और लटका रहता है। ( क्रैशहैंडलर.जावा : 70 , स्ट्रिंग्स.एक्सएमएल : 51 )

एक गैर-एंड्रॉइड स्थिति में, इसमें से कुछ अलग होगा। आपको अपने स्वयं के मूल ट्रेस को इकट्ठा करने की आवश्यकता होगी, यह अन्य प्रश्न देखें , कि आपके पास किस प्रकार का परिवाद है। आपको अपना अलग क्रैश-हैंडलर प्रक्रिया शुरू करने, और अपने प्लेटफ़ॉर्म के लिए कुछ उपयुक्त तरीकों से ईमेल भेजने के लिए ट्रेसिंग को संभालने की आवश्यकता होगी, लेकिन मुझे लगता है कि सामान्य दृष्टिकोण अभी भी काम करना चाहिए।


2
आदर्श रूप से आप यह देखना चाहेंगे कि आपके पुस्तकालय में दुर्घटना हुई है या नहीं। यदि यह कहीं और हुआ (जैसे, वीएम के अंदर), आपके जेएनआई सिग्नल हैंडलर से कॉल करते हैं, तो चीजों को बुरी तरह से भ्रमित कर सकते हैं। यह दुनिया का अंत नहीं है, क्योंकि आप वैसे भी मध्य दुर्घटना हैं, लेकिन यह एक VM दुर्घटना का निदान अधिक कठिन बना सकता है (या एक विचित्र वीएम दुर्घटना का कारण बन सकता है जो एक एंड्रॉइड बग रिपोर्ट में समाप्त होता है और सभी को चकरा देता है)।
fadden

आप इस पर अपनी शोध परियोजना को साझा करने के लिए अद्भुत @Chris हैं!
ओलफुरे

धन्यवाद, यह खोजने में उपयोगी था कि मेरा जेएनआई कहां जा रहा था। इसके अलावा, एक डीसीएस पूर्व छात्र से नमस्ते!
निक

3
एक सेवा से एक नई प्रक्रिया में एक गतिविधि शुरू करने के लिए भी निम्नलिखित कोड की आवश्यकता होती है:newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ग्रीम

1
क्या यह समाधान जेली बीन के तहत अभी भी मान्य है? चरण 6 कुछ debuggerdआउटपुट लॉग करने में विफल नहीं होगा ?
जोश

14

मुझे थोड़ी देर हो गई है, लेकिन मुझे ठीक वैसी ही ज़रूरत थी, और मैंने जेएनआई कोड के अंदर आम क्रैश ( SEGVऔर SIBGUS, आदि) को पकड़कर , उन्हें नियमित अपवादों से बदलकर , इसे संबोधित करने के लिए एक छोटी सी लाइब्रेरी विकसित की java.lang.Error है । बोनस, अगर क्लाइंट एंड्रॉइड> = पर चल रहा है 4.1.1, तो स्टैक ट्रेस दुर्घटना के हल किए गए बैकट्रेस (एक छद्म ट्रेस जिसमें पूर्ण देशी स्टैक ट्रेस होता है) को एम्बेड करता है । आप शातिर दुर्घटनाओं से उबर नहीं पाएंगे (यानी यदि आप आवंटनकर्ता को भ्रष्ट करते हैं, उदाहरण के लिए), लेकिन कम से कम यह आपको उनमें से अधिकांश से उबरने की अनुमति देता है। (कृपया सफलताओं और विफलताओं की रिपोर्ट करें, कोड बिल्कुल नया है)

Https://github.com/xroche/coffeecatch पर अधिक जानकारी (कोड BSD 2-Clauses लाइसेंस है )


6

FWIW, Google ब्रेकपैड Android पर ठीक काम करता है। मैंने पोर्टिंग का काम किया, और हम इसे फ़ायरफ़ॉक्स मोबाइल के हिस्से के रूप में शिपिंग कर रहे हैं। इसके लिए एक छोटे से सेटअप की आवश्यकता होती है, क्योंकि यह आपको क्लाइंट-साइड पर स्टैक के निशान नहीं देता है, लेकिन आपको कच्ची स्टैक मेमोरी भेजता है और स्टैक वॉकिंग सर्वर-साइड करता है (इसलिए आपको अपने ऐप के साथ डिबग प्रतीकों को शिप करने की आवश्यकता नहीं है )।


1
ब्रेकडैप को कॉन्फ़िगर करना लगभग असंभव है, बिल्कुल लापता प्रलेखन पर विचार करना
shader

यह वास्तव में कठिन नहीं है, और परियोजना विकि पर बहुत सारे दस्तावेज हैं। वास्तव में, एंड्रॉइड के लिए अब एक NDK बिल्ड मेकफिल है और इसका उपयोग करना आसान होना चाहिए: code.google.com/p/google-breakpad/source/browse/trunk/…
Ted Mielczarek

आपको मॉड्यूल को संकलित करने की भी आवश्यकता है जो एंड्रॉइड के लिए डिबग प्रतीक फ़ाइलों को प्रीप्रोसेस करता है और आप केवल लिनक्स पर ही इसे संकलित कर सकते हैं। जब आप Mac पर संकलित करते हैं - यह केवल Mac / iOS dSym प्रीप्रोसेसर बनाता है।
shader

5

मेरे सीमित अनुभव (गैर-एंड्रॉइड) में, JNI कोड में SIGSEGV आमतौर पर आपके जावा कोड पर नियंत्रण वापस आने से पहले JVM को क्रैश कर देगा। मैं अस्पष्ट रूप से कुछ गैर-सूर्य JVM के बारे में सुनकर याद करता हूं जो आपको SIGSEGV को पकड़ने की अनुमति देता है, लेकिन AFAICR आप ऐसा करने में सक्षम होने की उम्मीद नहीं कर सकते।

आप उन्हें सी (सिगनेचर (2) देखें) में पकड़ने की कोशिश कर सकते हैं, हालांकि आप एक SIGSEGV (या SIGFPE या SIGILL) हैंडलर के बाद बहुत कम कर सकते हैं क्योंकि प्रक्रिया का चलन व्यवहार आधिकारिक रूप से अपरिभाषित है।


खैर, व्यवहार "अज्ञान [आईएनजी] एक सिगफिक, साइली, या एसआईईजीएसवीवी सिग्नल के बाद अपरिभाषित है जो कि मार (2) या बढ़ा (3)" द्वारा उत्पन्न नहीं हुआ था, लेकिन जरूरी नहीं कि इस तरह के सिग्नल को पकड़ने के दौरान। वर्तमान योजना एक सी सिग्नल हैंडलर की कोशिश है जो जावा को वापस बुलाती है और किसी तरह, प्रक्रिया को समाप्त किए बिना थ्रेड को समाप्त कर देती है। यह संभव हो सकता है या नहीं भी हो सकता है। :-)
क्रिस बोयले

1
सी बैकट्रेस निर्देश: stackoverflow.com/questions/76822/…
क्रिस बॉयल

1
... सिवाय इसके कि मैं बैकट्रेस () का उपयोग नहीं कर सकता, क्योंकि एंड्रॉइड ग्लिबक का उपयोग नहीं करता है, यह बायोनिक का उपयोग करता है। :-( से जुड़ी कोई भी _Unwind_Backtraceसे unwind.hबजाय की आवश्यकता होगी।
क्रिस बॉयल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.