نظرة عامة
كثيرًا ما يُفاجأ مطورو النظم ومهندسو عكس البرمجيات في بيئات لينكس بظهور سلاسل نصية مبهمة وغامضة عند تتبع وتصحيح الملفات التنفيذية المكتوبة بلغة C++. هذه المعرفات المعقدة ليست شفرات عشوائية، بل هي نتاج آلية تُعرف بتشويه الأسماء (Name Mangling)، والتي يعتمد عليها المترجم لتمييز فضاءات التسمية (Namespaces) والدوال المحملة بشكل زائد (Function Overloading). في هذا المقال، نوضح كيفية تسخير أداة c++filt لتحويل هذه الرموز الملتوية وإعادتها فورًا إلى بنيتها البرمجية الواضحة والأصلية.
تجهيز بيئة العمل والبدء في استعادة المعرفات البسيطة
للحصول على حزمة أدوات معالجة الملفات الثنائية التي تتضمن برنامج c++filt، يكفي تحديث مستودعات النظام وتثبيت الحزمة عبر تنفيذ الأمر التالي:

للتحقق من نجاح التثبيت ومعاينة رقم الإصدار قيد التشغيل، يمكن الاستعلام باستخدام الأمر c++filt --version | head -n 2.
تعمل هذه الأداة كأداة ترجمة عكسية للمعرفات (Demangler)، حيث تفك ترميز الرموز المجمعة وتسترجع التواقيع البرمجية الصريحة للدوال والأصناف التي يمكن للبشر قراءتها بسلاسة.
⚙️ [أهم الخيارات والوسائط التشغيلية]
-_, --strip-underscore : يتجاهل الشرطة السفلية (_) الواقعة في بداية المعرف ويبدأ فك الترميز مباشرة.-n, --no-strip-underscore : يُبقي على الشرطة السفلية البادئة دون اقتطاع أثناء المعالجة.-p, --no-params : يقتصر الإخراج على اسم الدالة ومسارها فقط مع استبعاد معلمات الدخل (Arguments).-t, --types : يتيح فك تشفير وتفسير أسماء الأنواع البيانية (Types) وليس الدوال فحسب.-s, --format : يحدد التنسيق القياسي للمترجم المستهدف (ABI) لضمان دقة التفسير.

لتجربة استرجاع دالة أولية بدون معلمات، يتم تمرير الرمز المبهم عبر الأمر c++filt _Z1fv.
تُعيد الأداة بناء التوقيع الرياضي للدالة بدقة ليتضح أنها الدالة المجردة f().

عند مواجهة رمز ينتمي إلى نطاق تسمية محدد ويستقبل معلمات رقمية، يمكن تنفيذ الأمر c++filt _ZN4Math3addEii.
تقوم الأداة بتفكيك النطاق المتداخل وتحديد المعاملين، لتظهر النتيجة بوضوح بالشكل المألوف: Math::add(int, int).

استكشاف آلية التشويه عمليًا وربطها بأداة nm
لتجربة هذه الآلية من البداية وبناء ملفات كائنية لاختبارها، نقوم بتجهيز أدوات البناء الأساسية في النظام عبر تنفيذ apt-get update -qq && apt-get install -y build-essential.

سنقوم الآن بصياغة ملف C++ تجريبي يحتوي على دالة مكررة الاسم مع اختلاف نوع المعلمات (Overloading) داخل فضاء تسمية عبر الأمر cat << 'EOF' > /tmp/demo.cpp.

يتم تحويل هذا الكود البرمجي إلى ملف كائن ثنائي غير مربوط (Object File) باستعمال المترجم: g++ -c /tmp/demo.cpp -o /tmp/demo.o.

لعرض جدول الرموز البرمجية المضمنة واستخراج أسماء الدوال الناتجة عن التجميع، ننفذ الأمر nm /tmp/demo.o | grep add.
تُظهر المخرجات كيف قام المترجم بتحوير الدالتين لتصبحا _ZN10Calculator3addEii و_ZN10Calculator3addEdd بهدف التفريق الحاسم بينهما داخل الجدول الثنائي.

يمكننا توجيه خرج أداة nm مباشرة عبر أنبوب المعالجة (Pipeline) لمعالجة الرموز دفعة واحدة بالصيغة: nm /tmp/demo.o | c++filt | grep add.
تتولى c++filt قراءة التدفق النصي وترجمة التواقيع المشفرة لحظيًا إلى صيغتها الصريحة المقروءة: Calculator::add(int, int) وCalculator::add(double, double).

التعامل مع القوالب المركبة وفك التشفير عبر خطوط الأنابيب
يزداد تعقيد الرموز المشوهة عند التعامل مع مكتبة القوالب القياسية (STL). سنقوم بتوليد نموذج يعتمد على فئات متداخلة مثل std::vector وstd::string باستخدام الأمر cat << 'EOF' > /tmp/template_demo.cpp.

نقوم بتجميع هذا النموذج لإنتاج ملف ثنائي تحليلي عبر تنفيذ الأمر g++ -c /tmp/template_demo.cpp -o /tmp/template_demo.o.

عند استخراج الرمز الخاص بتابع الطباعة print بواسطة nm /tmp/template_demo.o | grep print، تظهر سلسلة شديدة الطول وغير قابلة للفهم بالعين المجردة نتيجة تشفير تفاصيل القالب ومعاملاته النوعية.

لحل هذه المعضلة في سياق العمل المباشر، نربط المخرجات فورًا بأداة فك التشويه عبر الأمر nm /tmp/template_demo.o | c++filt | grep print.
ينتج عن هذا الإجراء إظهار البنية الهيكلية الكاملة للقالب بوضوح تام، بما يشمل أسماء الأصناف والحاويات والوسائط المرتبطة بالدالة.

تخصيص مظهر الدوال ومعالجة ملفات السجلات أثناء التشخيص
في الوضع الاعتيادي، يعرض الأمر c++filt _ZN10Calculator3addEii التوقيع التفصيلي متضمنًا مسارات الفئات وقائمة الأنواع المُمررة بين القوسين.

إذا أردنا التركيز على معرف الدالة ومسارها فقط مع استبعاد أنواع المعاملات لتقليل الضوضاء البصرية، نمرر الخيار -p عبر الأمر c++filt -p _ZN10Calculator3addEii.
يعمل هذا التبديل على تقليص المخرج بدقة ليقتصر على اسم النطاق واسم الدالة: Calculator::add.

لتفعيل نمط فحص وتفسير الأنواع المجردة بدقة، يمكن تزويد الأداة بالمعامل -t كما في c++filt -t _ZN10Calculator3addEii.
يحافظ هذا الخيار على سلامة التفسير ويعيد البنية الكاملة Calculator::add(int, int) دون أي تشويه لمعلومات الأنواع.

تكمن القوة الحقيقية لـ c++filt في قدرتها على تنقيح سجلات الأخطاء البرمجية تلقائيًا؛ فبتمرير رسالة خطأ تتضمن رمزًا مدمجًا عبر echo 'Fatal error in _ZN10Calculator3addEii at runtime' | c++filt، تلتقط الأداة الرمز المشوه وتستبدله في موقعه الدقيق مع الحفاظ التام على سياق الجملة المحيطة.

بهذا يتضح كيف ترفع آلية تشويه الأسماء (Name Mangling) من كفاءة الربط الثنائي في مترجمات C++، وكيف توفر أداة c++filt وسيلة مرنة لفك طلاسم هذه الرموز. يساعد دمج هذه الأداة في سير عملك على تسريع تتبع مشكلات الربط (Linker Errors) وتشريح تقارير الانهيار في بيئات لينكس بكل سهولة.