2012-07-20 28 views
22

से गलत रेखा संख्या मैं C++ प्रोग्राम में बैकट्रैक में कॉल की सटीक रेखा को खोजने का प्रयास करता हूं। अभी मैं (पश्व-अनुरेखन का आदमी पृष्ठ से) इन पंक्तियों का उपयोग कर रहा ट्रेस पाने के लिए:addr2line

void *bt_buffer[1000]; 
    char **bt_strings; 
    int bt_nptrs = backtrace(bt_buffer, 1000); 
    bt_strings = backtrace_symbols(bt_buffer, bt_nptrs); 

bt_strings मैं प्रपत्र की तर्ज

./prog() [0x402e42] 

अब मैं पता लेने को खोजने में (हेक्स स्ट्रिंग) और addr2line को फ़ीड करें। कभी-कभी स्पष्ट रूप से गलत रेखा संख्याओं में परिणाम मिलता है। इंटरनेट खोज मुझे इस post, जिसमें यह दिखाया गया है कि

readelf -wl ./prog 

इंगित करता है जहां लाइन वास्तव में है, या कहें कि कितने लाइनों प्रतीक वर्तमान लाइन के लिए ले जाया गया है का नेतृत्व किया।

संपादित करें: यह तब होता है जब मैं explicetly अनुकूलन के बिना -g -O0 साथ संकलन है, अर्थात। संकलक gcc 4.6.3 है क्या कोई अन्य कंपाइलर ध्वज है जिसे मैं याद करता हूं?

मेरी समस्या निम्न है: मुझे इसे स्वचालित करने की आवश्यकता है। मुझे बैकट्रैक (पूर्ण) बनाने के लिए अपने प्रोग्राम की आवश्यकता है, फ़ाइल (किया गया) निकालें और लाइन नंबर (असफल) निकालें।

मैं निश्चित रूप से readelf पर कॉल कर सकता हूं और आउटपुट पार्स कर सकता हूं, लेकिन यह वास्तव में उपयुक्त नहीं है, क्योंकि आउटपुट वास्तव में क्या हुआ इसके आधार पर प्रतीक से प्रतीक तक भिन्न होता है। कभी कभी एक प्रतीक का पता एक पंक्ति और लाइन अगली पंक्ति में ऑफसेट के बारे में जानकारी में है ...

सारांश में:

वहाँ एक की सटीक लाइन नंबर प्राप्त करने के लिए एक सुंदर तरीका है रनटाइम के दौरान कार्यक्रम के भीतर से बैकट्रैक में फ़ंक्शन कॉल?

संपादित करें: उदाहरण कोड:

#define UNW_LOCAL_ONLY 
#include <libunwind.h> 
#include <execinfo.h> 
#include <iostream> 
#include <stdlib.h> 

void show_backtrace() 
{ 
    // get current address 
    void* p = __builtin_return_address(0); 
    std::cout << std::hex << p << std::endl; 

    // get callee addresses 
    p = __builtin_return_address(1); 
    std::cout << std::hex << p << std::endl; 

    p = __builtin_return_address(2); 
    std::cout << std::hex << p << std::endl; 
} 

void show_backtrace2() 
{ 
    void *array[10]; 
    size_t size; 
    char **strings; 
    int i; 

    size = backtrace (array, 10); 
    strings = backtrace_symbols ((void *const *)array, size); 

    for (i = 0; i < size; i++) 
    { 
     std::cout << strings[i] << std::endl; 
    } 

    free (strings); 
} 

void show_backtrace3 (void) 
{ 
    char name[256]; 
    unw_cursor_t cursor; unw_context_t uc; 
    unw_word_t ip, sp, offp; 

    unw_getcontext (&uc); 
    unw_init_local (&cursor, &uc); 

    while (unw_step(&cursor) > 0) 
    { 
     char file[256]; 
     int line = 0; 

     name[0] = '\0'; 
     unw_get_proc_name (&cursor, name, 256, &offp); 
     unw_get_reg (&cursor, UNW_REG_IP, &ip); 
     unw_get_reg (&cursor, UNW_REG_SP, &sp); 

     std::cout << std:: hex << name << " ip = " << (long) ip 
       << " , sp = " << (long) sp << std::endl; 
    } 
} 

void dummy_function2() 
{ 
    show_backtrace(); 
    show_backtrace2(); 
    show_backtrace3(); 
} 

void dummy_function1() 
{ 
    dummy_function2(); 
} // line 73 

int main(int argc, char **argv) 
{ 
    dummy_function1(); 
    return 0; 
} 

संकलन और चलाएँ:

g++ test_unwind.cc -g -O0 -lunwind && ./a.out 

उत्पादन:

0x400edb 
0x400ef0 
0x400f06 
./a.out() [0x400cfb] 
./a.out() [0x400ee0] 
./a.out() [0x400ef0] 
./a.out() [0x400f06] 
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed) [0x7f2f044ae76d] 
./a.out() [0x400b79] 
_Z15dummy_function2v ip = 400ee5 , sp = 7fffdb564580 
_Z15dummy_function1v ip = 400ef0 , sp = 7fffdb564590 
main ip = 400f06 , sp = 7fffdb5645a0 
__libc_start_main ip = 7f2f044ae76d , sp = 7fffdb5645c0 
_start ip = 400b79 , sp = 7fffdb564680 

परीक्षण उदा addr2line पैदावार

/path/to/code/test_unwind.cc:73 

जो सही फ़ाइल है, लेकिन गलत लाइन संख्या के साथ 0x400ef0। वास्तविक जीवन अनुप्रयोगों में लाइन संख्या कई पंक्तियों, आगे और पीछे से भिन्न हो सकती है।

संपादित करें:-S साथ संकलन से पता चलता है कि प्रासंगिक हिस्सा है: के रूप में call के बाद लाइन में दिखाया गया

.LCFI34: 
    .cfi_def_cfa_register 6 
    .loc 2 72 0 
    call _Z15dummy_function2v 
    .loc 2 73 0 
    popq %rbp 

क्या addr2line द्वारा प्रदर्शित और एक जैसे है, वापसी पता है। मैं "एंट्री" लाइन प्राप्त करना चाहता हूं, यानी पहले क्या दिखाया गया है!

+0

क्या ऑप्टिमाइज़ेशन के बिना संकलित होने पर यह गलत हो जाता है? – Flexo

+0

हां इसका उल्लेख करना भूल गया ... मैं – steffen

+1

पोस्ट संपादित करूँगा निष्पादन योग्य 'gdb'' का प्रयास करें और 'l * 0x

' का उपयोग करें। क्या यह सही पता देता है, या यह 'addr2line' के समान भी देता है? – Shahbaz

उत्तर

3

आप निश्चित रूप से कर सकते हैं!मुझे एक उदाहरण कार्यान्वयन पता है जो libunwind का उपयोग करता है। http://blog.bigpixel.ro/2010/09/stack-unwinding-stack-trace-with-gcc/

यह कोड के इस टुकड़े (शाब्दिक लेख से नकल) करने के लिए नीचे आता है: इस ब्लॉग पोस्ट देखें

void show_backtrace (void) 
{ 
    char name[256]; 
    unw_cursor_t cursor; unw_context_t uc; 
    unw_word_t ip, sp, offp; 

    unw_getcontext(&uc); 
    unw_init_local(&cursor, &uc); 

    while (unw_step(&cursor) > 0) 
    { 
     char file[256]; 
     int line = 0; 

     name[0] = '\0'; 
     unw_get_proc_name(&cursor, name, 256, &offp); 
     unw_get_reg(&cursor, UNW_REG_IP, &ip); 
     unw_get_reg(&cursor, UNW_REG_SP, &sp); 

     //printf ("%s ip = %lx, sp = %lx\n", name, (long) ip, (long) sp); 
     getFileAndLine((long)ip, file, 256, &line); 
     printf("%s in file %s line %d\n", name, file, line); 
    } 
} 
+0

जैसे ही मैं कार्यालय जाता हूं, मैं कोशिश करने के लिए उत्साहित हूं! – steffen

+2

मैंने कोशिश की और पाया कि 'getFileAndLine' में वे 'popr' कॉल' addr2line' पर भी उपयोग करते हैं। libunwind दिलचस्प है (इसके लिए +1) लेकिन बैकट्रैक के समान कार्यक्षमता है। नतीजा एक ही ऑफसेट लाइन नंबर है। – steffen

+1

आपके प्रश्न में आपने कहा है कि आप '-g' के साथ संकलित कर रहे हैं, शायद आपको' -ggdb' का उपयोग करना चाहिए? – Bart

0

आप

__LINE__ 

की कोशिश की यह एक पूर्वप्रक्रमक प्रतीक है है, लेकिन आप इसे संकलित कर सकते हैं।

+0

मैंने '__FILE__' और' __LINE__' के बारे में भी सोचा है, लेकिन मैं 'foo() 'कॉल से' foo()' की जानकारी प्राप्त करना चाहता हूं। और मैं नहीं बदल सकता कि कैसे 'foo() 'कहा जाता है। – steffen