c++filt कमांड गाइड: C++ नेम मैंगलिंग सिंबल डिकोड करें

परिचय: C++ नेम मैंगलिंग की समस्या और समाधान

लिनक्स वातावरण में जब हम संकलित C++ बाइनरी फाइलों का विश्लेषण या डीबगिंग करते हैं, तो अक्सर स्क्रीन पर बेहद अजीब, कूटबद्ध (encrypted) जैसे दिखने वाले सिंबल नाम उभर आते हैं। वास्तव में यह कोई त्रुटि नहीं है, बल्कि C++ कंपाइलर द्वारा फ़ंक्शन ओवरलोडिंग और नेमस्पेस संरचनाओं को बाइनरी स्तर पर विशिष्ट पहचान देने के लिए अपनाई जाने वाली नेम मैंगलिंग (Name Mangling) प्रक्रिया का परिणाम है। इस ट्यूटोरियल में हम विस्तार से समझेंगे कि GNU c++filt टूल की सहायता से इन दुर्बोध सिंबल्स को पुनः उनके मूल मानव-पठनीय फ़ंक्शन प्रारूप में कैसे बदला जाता है और वास्तविक डिबगिंग परिदृश्यों में इसका उपयोग कैसे किया जाए।

c++filt टूलसेट की स्थापना और बुनियादी सिंबल डिमैंगलिंग

सिस्टम पर c++filt उपयोगिता प्राप्त करने हेतु बाइनरी एनालिसिस टूल्स का मुख्य पैकेज इंस्टॉल करने के लिए apt-get update -qq && apt-get install -y binutils कमांड चलाएँ।

apt-get update -qq && apt-get install -y binutils

सफलतापूर्वक कॉन्फ़िगर किए गए टूल का संस्करण और विवरण जांचने के लिए c++filt --version | head -n 2 कमांड निष्पादित करें।
c++filt अनिवार्य रूप से एक रिवर्स-ट्रांसलेटर की तरह कार्य करता है, जो कंपाइलर द्वारा कूटबद्ध (mangled) किए गए सिंबल्स को उनकी मूल C++ क्लास, फ़ंक्शन और पैरामीटर परिभाषाओं में बदल देता है।
⚙️ [महत्वपूर्ण कमांड विकल्प]

-_, --strip-underscore : सिंबल के आरंभ में जुड़े अंडरस्कोर (_) को हटाकर उसे पार्स करता है।
-n, --no-strip-underscore : प्रारंभिक अंडरस्कोर को सुरक्षित रखते हुए डिमैंगलिंग करता है।
-p, --no-params : पैरामीटर सूची को अनदेखा कर केवल मुख्य फ़ंक्शन का नाम प्रदर्शित करता है।
-t, --types : फ़ंक्शन सिंबल्स के साथ-साथ डेटा प्रकारों (data types) को भी डीकोड करता है।
-s, --format : विभिन्न कंपाइलर मानकों (जैसे GNU, Lucent, ARM आदि) के अनुरूप विशिष्ट डिमैंगलिंग प्रारूप सेट करता है।

c++filt –version | head -n 2

एक सामान्य मैंगल्ड स्ट्रिंग के अर्थ को समझने के लिए c++filt _Z1fv कमांड निष्पादित करें।
कमांड के निष्पादन उपरांत आउटपुट में बिना किसी पैरामीटर वाला मूल फ़ंक्शन f() स्पष्ट रूप से प्रदर्शित हो जाता है।

c++filt _Z1fv

नेमस्पेस तथा एकाधिक डेटा प्रकारों से युक्त किसी जटिल सिंबल को डीकोड करने के लिए c++filt _ZN4Math3addEii कमांड चलाएँ।
यहाँ Math नेमस्पेस के अंतर्गत परिभाषित दो पूर्णांक (int) पैरामीटर स्वीकार करने वाले फ़ंक्शन की संरचना स्पष्ट होकर Math::add(int, int) के रूप में सामने आती है।

c++filt _ZN4Math3addEii

C++ सिंबल मैंगलिंग का व्यावहारिक परीक्षण और nm टूल एकीकरण

C++ कोड संकलन के लिए आवश्यक कंपाइलर टूलचेन तैयार करने हेतु टर्मिनल में apt-get update -qq && apt-get install -y build-essential निष्पादित करें।

apt-get update -qq && apt-get install -y build-essential

फ़ंक्शन ओवरलोडिंग और स्कोप रिज़ॉल्यूशन को प्रदर्शित करने वाला एक C++ स्रोत कोड तैयार करने के लिए cat << 'EOF' > /tmp/demo.cpp कमांड का उपयोग करें।

cat « ‘EOF’ > /tmp/demo.cpp
namespace Calculator {
int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; }
}
EOF

तैयार की गई कोड फ़ाइल को असेंबल कर मशीन-स्तरीय ऑब्जेक्ट फ़ाइल में बदलने के लिए g++ -c /tmp/demo.cpp -o /tmp/demo.o कमांड चलाएँ।

g++ -c /tmp/demo.cpp -o /tmp/demo.o

ऑब्जेक्ट बाइनरी फ़ाइल के आंतरिक सिंबल टेबल से add फ़ंक्शन प्रविष्टियों की जाँच करने के लिए nm /tmp/demo.o | grep add चलाएँ।
परिणाम में स्पष्ट दिखाई देता है कि कंपाइलर ने एक ही नाम के दोनों फ़ंक्शंस को अलग-अलग पहचान देने के लिए उनके पैरामीटर प्रकारों के आधार पर _ZN10Calculator3addEii और _ZN10Calculator3addEdd जैसे जटिल सिंबल्स में बदल दिया है।

nm /tmp/demo.o | grep add

कमांड पाइपलाइन का उपयोग करके इन सभी मैंगल्ड सिंबल्स को एक साथ पढ़ने योग्य रूप में बदलने के लिए nm /tmp/demo.o | c++filt | grep add निष्पादित करें।
c++filt से गुजरते ही वे अस्पष्ट सिंबल्स तुरंत Calculator::add(int, int) तथा Calculator::add(double, double) जैसे साफ़-सुथरे फ़ंक्शन प्रोटोटाइप में परिवर्तित हो जाते हैं।

nm /tmp/demo.o | c++filt | grep add

जटिल STL टेम्पलेट्स का विश्लेषण और रियल-टाइम पाइपलाइन प्रोसेसिंग

नेस्टेड टेम्पलेट संरचनाओं और STL कंटेनरों (std::vector, std::string) के व्यवहार को परखने के लिए cat << 'EOF' > /tmp/template_demo.cpp कमांड द्वारा एक टेस्ट फ़ाइल बनाएँ।

cat « ‘EOF’ > /tmp/template_demo.cpp
#include 
#include 
template 
class Storage {
public:
void print(T val) {}
};
template class Storage<std::vectorstd::string>;
EOF

लिखे गए टेम्पलेट कोड को सिंबल एनालिसिस के लिए ऑब्जेक्ट मॉड्यूल में संकलित करने हेतु g++ -c /tmp/template_demo.cpp -o /tmp/template_demo.o चलाएँ।

g++ -c /tmp/template_demo.cpp -o /tmp/template_demo.o

ऑब्जेक्ट फ़ाइल के भीतर मौजूद print मेथड से जुड़े प्रतीकों को फ़िल्टर करने के लिए nm /tmp/template_demo.o | grep print कमांड चलाएँ।
टेम्पलेट टाइप इनहेरिटेंस और STL इंटरनल डेफिनिशन के कारण आउटपुट में एक अत्यंत लंबा और जटिल सिंबल स्ट्रिंग उत्पन्न होता है, जिसे सीधे समझना असंभव सा प्रतीत होता है।

nm /tmp/template_demo.o | grep print

nm के आउटपुट को सीधे c++filt में पाइप करके इस बेहद पेचीदा सिंबल को ऑन-द-फ़्लाई डिकोड करने के लिए nm /tmp/template_demo.o | c++filt | grep print कमांड निष्पादित करें।
यह पाइपलाइन सिंबल के भीतर छिपे सभी टेम्पलेट आर्ग्युमेंट्स को खोलकर अत्यंत व्यवस्थित और स्पष्ट क्लास मेंबर डेफिनिशन के रूप में प्रस्तुत कर देती है।

nm /tmp/template_demo.o | c++filt | grep print

आउटपुट नियंत्रण (-p) और एरर लॉग्स से सिंबल पार्सिंग

डिफ़ॉल्ट सेटिंग्स के साथ सिंबल का पूर्ण विवरण (फ़ंक्शन नाम और पैरामीटर लिस्ट सहित) प्राप्त करने के लिए c++filt _ZN10Calculator3addEii निष्पादित करें।
आउटपुट में नेमस्पेस, क्लास मेंबर तथा उसके दोनों इनपुट तर्कों (int, int) सहित संपूर्ण सिग्नेचर दिखाई देता है।

c++filt _ZN10Calculator3addEii

पैरामीटर्स की लंबी सूची को छोड़कर केवल शुद्ध फ़ंक्शन पथ देखने के लिए -p फ़्लैग जोड़ते हुए c++filt -p _ZN10Calculator3addEii चलाएँ।
इस विकल्प के माध्यम से अतिरिक्त विवरण छंट जाते हैं और केवल संक्षिप्त स्कोप Calculator::add आउटपुट में मिलता है।

c++filt -p _ZN10Calculator3addEii

सिंबल को स्पष्ट रूप से टाइप डिकोडिंग मोड में प्रोसेस करने के लिए c++filt -t _ZN10Calculator3addEii कमांड का उपयोग करें।
यह विकल्प डेटा टाइप संदर्भों की शुद्धता बनाए रखते हुए सटीक रूप से Calculator::add(int, int) प्रस्तुत करता है।

c++filt -t _ZN10Calculator3addEii

क्रैश डंप या रनटाइम एरर लॉग्स में दबे हुए सिंबल्स को बिना किसी मैन्युअल संपादन के बदलने के लिए echo 'Fatal error in _ZN10Calculator3addEii at runtime' | c++filt निष्पादित करें।
c++filt पूरे वाक्य के संदर्भ और स्ट्रक्चर को बदले बिना, केवल उसमें छुपे हुए C++ सिंबल को पहचानकर उसे तुरंत मूल फ़ंक्शन नाम में बदल देता है।

echo ‘Fatal error in _ZN10Calculator3addEii at runtime’ | c++filt

इस प्रकार हमने देखा कि C++ कंपाइलर द्वारा आंतरिक उपयोग के लिए बनाई गई नेम मैंगलिंग प्रणाली किस तरह काम करती है और c++filt कमांड इसे सुलझाने में कितनी प्रभावी है।
भविष्य में लिनक्स पर काम करते समय जब भी लिंकर एरर्स (Undefined Reference) या कोर डंप ट्रेस का सामना हो, तो इस टूल का उपयोग करके आप कुछ ही सेकंड्स में मूल कोड संरचना की पहचान कर सकते हैं।