addr2line कमांड से सेकंडों में खोजें गड़बड़ कोड लाइन

परिचय

जब कोई एप्लिकेशन अप्रत्याशित रूप से बंद हो जाती है (Segmentation Fault) या सिस्टम कोर डंप फाइल तैयार करता है, तो स्क्रीन पर दिखने वाले हेक्साडेसिमल मेमोरी एड्रेस डेवलपर्स के लिए किसी पहेली जैसे लगते हैं। यह हैंड्स-ऑन गाइड सिखाती है कि कैसे addr2line यूटिलिटी की मदद से इन जटिल मेमोरी एड्रेस को सीधे सोर्स कोड की संबंधित फाइल और सटीक लाइन नंबर में बदला जाता है। इस ट्यूटोरियल में हम डीबग सिंबल (-g) के साथ बाइनरी तैयार करने से लेकर, C++ फंक्शन नामों को डिमैंगल करने (-C) और इनलाइन फंक्शन्स को गहराई से ट्रेस करने (-i) तक की व्यावहारिक डीबगिंग तकनीकों को विस्तार से समझेंगे।

1. जरूरी टूल्स (binutils और gcc) इंस्टॉल करना व वर्जन जांचना

addr2line टूल GNU बाइनरी यूटिलिटीज का हिस्सा है। इस प्रैक्टिकल गाइड के लिए कम्पाइलर और आवश्यक टूल्स सेटअप करने के लिए टर्मिनल में sudo apt-get update -qq && sudo apt-get install -y binutils gcc चलाएं।

binutils और gcc पैकेज स्थापित करें

टूल सही तरीके से सिस्टम में उपलब्ध है या नहीं, यह परखने के लिए addr2line -v रन करके इसका वर्जन चेक करें।
सरल शब्दों में कहें तो addr2line रनटाइम क्रैश या एरर के वक्त मिले निष्पादन पते (execution addresses) को आपके मूल कोड के संदर्भ (फाइल नाम व लाइन संख्या) में अनुवादित करता है।
⚙️ [उपयोगी फ्लैग्स की सूची]

-e : जिस एग्जीक्यूटेबल फाइल का विश्लेषण करना है उसका पाथ सेट करता है।
-f : लाइन नंबर के साथ-साथ उस फंक्शन का नाम भी प्रदर्शित करता है जहां एरर आया।
-C : कम्पाइलर द्वारा कोड किए गए जटिल C++ सिंबल्स को सामान्य पठनीय नाम में बदलता है (Demangling)।
-p : फाइल, लाइन नंबर और फंक्शन की जानकारी को एक ही साफ-सुथरी लाइन में प्रिंट करता है (Pretty-print)।
-a : आउटपुट में परिणाम के साथ मूल मेमोरी एड्रेस भी सामने दिखाता है।
-i : इनलाइन फंक्शन कॉल्स की पूरी चेन को पीछे की ओर ट्रैक करता है।

addr2line वर्जन चेक

2. डीबग सिंबल (-g) सहित सैंपल प्रोग्राम बनाना और कम्पाइल करना

प्रयोग को व्यवस्थित रखने के लिए एक समर्पित डायरेक्टरी तैयार करें और उसमें प्रवेश करें: mkdir -p ~/addr2line_lab && cd ~/addr2line_lab।

प्रैक्टिकल डायरेक्टरी बनाएं और उसमें जाएं

परीक्षण के लिए एक डमी C प्रोग्राम तैयार करते हैं, जिसमें faulty_function नाम का रूटीन शामिल होगा। इसके लिए test_crash.c फाइल बनाएं:

C सोर्स कोड फाइल बनाएं

addr2line केवल तभी सटीक सोर्स लाइन बता पाता है जब बाइनरी में डीबग मेटाडेटा मौजूद हो। इसलिए किसी भी ऑप्टिमाइज़ेशन को रोकते हुए -g फ्लैग के साथ कम्पाइल करें: gcc -g -O0 test_crash.c -o test_crash।

डीबग सिंबल्स के साथ C प्रोग्राम कम्पाइल करें

बिल्ड की गई बाइनरी की सिंबल टेबल जांचकर देखें कि faulty_function मेमोरी में किस वर्चुअल एड्रेस पर स्थित है: nm test_crash | grep faulty_function।
कमांड के आउटपुट में स्पष्ट दिखेगा कि यह फंक्शन 0000000000001149 जैसे किसी निश्चित मेमोरी लोकेशन पर मैप हुआ है।

nm कमांड से फंक्शन का मेमोरी एड्रेस देखें

3. मेमोरी एड्रेस से फाइल का नाम और लाइन नंबर ढूंढना (-e, -f विकल्प)

बार-बार हेक्साडेसिमल एड्रेस टाइप करने से बचने के लिए, उस पते को शेल वेरिएबल में स्टोर कर लेते हैं: FUNC_ADDR=$(nm test_crash | grep faulty_function | awk '{print $1}')।

फंक्शन का एड्रेस एनवायरनमेंट वेरिएबल में असाइन करें

अब -e फ्लैग के जरिए अपनी बाइनरी फाइल निर्दिष्ट करें और वेरिएबल में मौजूद एड्रेस पास करें। टूल तुरंत सोर्स फाइल और सटीक लाइन दिखा देगा (test_crash.c:3):

addr2line द्वारा सोर्स लाइन ट्रैक करना

यदि आप फाइल और लाइन के साथ उस फंक्शन का नाम भी प्रिंट कराना चाहते हैं, तो -f विकल्प जोड़ें (परिणाम में faulty_function साफ दिखाई देगा):

फंक्शन नाम सहित सोर्स कोड लाइन देखना

4. C++ सिंबल डिमैंगलिंग (-C) और इनलाइन फंक्शन ट्रेसिंग (-i, -p विकल्प)

C++ कोड में नाम कई आंतरिक अक्षरों के साथ मैंगल (Name Mangling) हो जाते हैं। इसके परीक्षण के लिए पहले C++ कम्पाइलर इंस्टॉल करें: sudo apt-get install -y g++।

g++ कम्पाइलर इंस्टॉल करें

एक C++ कोड फाइल test_cpp.cpp तैयार करें जिसमें नेस्टेड इनलाइन फंक्शन कॉल शामिल हो:

इनलाइन फंक्शन वाली C++ फाइल बनाएं

कम्पाइलर को इनलाइन फंक्शन्स को ऑप्टिमाइज़ और एक्सपैंड करने की अनुमति देने के लिए -O2 और डीबग सिंबल -g के साथ बिल्ड करें: g++ -g -O2 test_cpp.cpp -o test_cpp।

C++ कोड को ऑप्टिमाइज़ेशन और डीबग फ्लैग के साथ बिल्ड करें

बाइनरी की सिंबल टेबल से main फंक्शन का एंट्री एड्रेस निकालकर वेरिएबल में सुरक्षित करें:

![main फंक्शन का एड्रेस निकालें](captures/s04_c04_MAIN_ADDR___nm test_cpp___grep__main____head_-n_1.png)

सिंबल्स को इंसानों के पढ़ने योग्य बनाने के लिए -C लगाएं, और इनलाइन कॉल्स को सिंगल लाइन फॉर्मेट में देखने के लिए -i व -p का इस्तेमाल करें।
यदि आउटपुट में ??:0 जैसा परिणाम दिखाई दे, तो इसका मतलब है कि कम्पाइलर ऑप्टिमाइज़ेशन या पोजीशन इंडिपेंडेंट एग्जीक्यूटेबल (PIE) एड्रेसिंग की वजह से उस खास पते का डायरेक्ट सोर्स मैपिंग उपलब्ध नहीं हो पाया।

C++ सिंबल्स डिमैंगल और इनलाइन ट्रेसिंग

इस प्रकार, लिनक्स एनवायरनमेंट में मेमोरी क्रैश या सेगफॉल्ट का सामना होने पर addr2line की मदद से महज कुछ पलों में समस्याग्रस्त कोड तक पहुंचा जा सकता है।
अस्पष्ट एरर लॉग्स और उलझे हुए मेमोरी एड्रेस देखकर परेशान होने के बजाय, इस शक्तिशाली टूल को अपनी डीबगिंग वर्कफ्लो में शामिल करें और अपने समय की बचत करें।