هل هناك طريقة أرخص للعثور على عمق مكدس المكالمات من استخدام BackTrace ()؟

StackOverflow https://stackoverflow.com/questions/582673

  •  06-09-2019
  •  | 
  •  

سؤال

يستخدم رمز التسجيل الخاص بي قيمة الإرجاع Backtrace () لتحديد عمق المكدس الحالي (لأغراض الطباعة الجميلة)، ولكن يمكنني أن أرى من التنميط أن هذه مكالمة باهظة الثمن.

لا أفترض أن هناك طريقة أرخص للقيام بذلك؟ لاحظ أنه لا يهمني عناوين الإطار، فقط كم منهم هناك.

تحرير: يتم استخدام وظائف التسجيل هذه في جميع أنحاء قاعدة رمز كبيرة، لذا فإن تتبع عمق المكدس يدويا ليس خيارا حقا.

هل كانت مفيدة؟

المحلول

المشي كومة نفسك سريع جدا - معظم البطء في backtrace() هو من البحث عن أسماء الرموز. على X86، يمكنك القيام بما يلي:

inline uint32_t get_ebp(void)
{
    __asm__ __volatile__("mov %%ebp, %%eax");
}

int get_stack_depth(void)
{
    uint32_t ebp = get_ebp();
    int stack_depth = 0;
    while(ebp != 0)
    {
        ebp = *(uint32_t *)ebp;
        stack_depth++;
    }
    return stack_depth;
}

هذا سوف يمشي سلسلة ebp مؤشرات. ضع في اعتبارك أن هذا غير محمول للغاية. لاحظ أيضا أن هذا لن يحسب أي وظائف تم إنطاؤها أو الذيل مكالمة محسنة (بالطبع، backtrace() لديه نفس المشكلة).

قضية مهمة أخرى هي حالة الإنهاء - بمجرد التراجع main(), في كثير من الأحيان لا تضمن حول ما ستجده في المكدس. لذلك، إذا لم تضع LIBC مؤشر إطارا فارغا، فستحتمل على المرجح جدا Segfault. يمكنك الحصول على قيمة الإنهاء من خلال النظر إليها في بداية main().

نصائح أخرى

إذا كانت وظائف الطباعة الجميلة تحتوي على معقولة، فستمر في المسافة البادئة (أو حجم المسافة البادئة) كمعلمة، وزيادة ذلك فقط عند استدعاء وظائف العرض الأخرى.

لا يمكنك فقط تحمل TLS. متغير حولك تسمى "العمق" وزيادة ذلك / إنهاء كل وظيفة؟ بينما يمكنك كتابة التعليمات البرمجية الخاصة بك في المشي بشكل أسرع، ما زال الأمر أبطأ من مجرد حمل المتغير معك.

لبنية الذراع:

register unsigned long *rfp asm("fp");
unsigned long *fp = rfp;
unsigned long depth = 0;

while(fp)
{
    fp = (unsigned long *)(*(fp -3));
    depth++;
}

return depth;
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top