2011-08-04 17 views
10

मैं अपने (सी ++) प्रोग्राम के निष्पादन के किसी बिंदु पर बैकट्रैक प्राप्त करने का प्रयास कर रहा हूं।स्टैकट्रैक और नामस्थानों में फ़ंक्शंस

इसके लिए मैं बैकट्रैक और बैकट्रैक_सिम्बोल्स का उपयोग कर रहा हूं। इस लाइन के साथ कुछ:

std::string stacktrace(unsigned int frames_to_skip) 
{ 
    std::string str; 

    void* stack_addrs[50]; 
    int trace_size = backtrace(stack_addrs, 50); 
    char** stack_strings = backtrace_symbols(stack_addrs, trace_size); 

    str += "[bt] backtrace:\n"; 
    // skip frames_to_skip stack frames 
    for(int i = frames_to_skip; i < trace_size; ++i) 
    { 
     char tmp[4096]; 
     sprintf(tmp, "[bt] #%d %s\n", i-frames_to_skip, stack_strings[i]); 
     str += tmp; 
    } 

    free(stack_strings); 

    return str; 
} 

यह काम करता है लेकिन कुछ फ़ंक्शन नाम गायब हैं। उदाहरण:

[bt] #0 /path/to/executable() [0x43e1b5] 
[bt] #1 /path/to/executable() [0x43e0cd] 
[bt] #2 /path/to/executable() [0x43df51] 
[bt] #3 /path/to/executable() [0x43dd44] 
[bt] #4 /path/to/executable() [0x43db50] 
[bt] #5 /path/to/executable() [0x43d847] 
[bt] #6 /path/to/executable() [0x43d216] 
[bt] #7 /path/to/executable() [0x43c1e1] 
[bt] #8 /path/to/executable() [0x43b293] 
[bt] #9 /path/to/executable(_Z29SomeRN5other8symbolE+0x2c) [0x43a6ca] 
[bt] #10 /path/to/executable(_Z11SomeIN5_8symbolEPFvRS1_EEvRKT_RKT0_+0x77) [0x441716] 
... 

कार्यों 0 से 8 एक आम बात है: वे सभी एक नाम स्थान में बैठते हैं ...
मैं एक गुमनाम नाम स्थान में (किसी अन्य संशोधन के बिना) समारोह 9 डालने की कोशिश की और इसे से disapears बैकट्रैक ... जो अब इस तरह दिखता है:

[bt] #0 /path/to/executable() [0x43e1b5] 
[bt] #1 /path/to/executable() [0x43e0cd] 
[bt] #2 /path/to/executable() [0x43df51] 
[bt] #3 /path/to/executable() [0x43dd44] 
[bt] #4 /path/to/executable() [0x43db50] 
[bt] #5 /path/to/executable() [0x43d847] 
[bt] #6 /path/to/executable() [0x43d216] 
[bt] #7 /path/to/executable() [0x43c1e1] 
[bt] #8 /path/to/executable() [0x43b293] 
[bt] #9 /path/to/executable() [0x43a6ca] 
[bt] #10 /path/to/executable(_Z11SomeIN5_8symbolEPFvRS1_EEvRKT_RKT0_+0x77) [0x441716] 
... 

क्या इसे ठीक करने का कोई तरीका है?

पुनश्च: ++ जी के संस्करण: जी ++ (जीसीसी) 4.6.0 20,110,530 (रेड हैट 4.6.0-9)

संपादित कोड बंदर टिप्पणी के बाद पश्व-अनुरेखन की अधिकतम गहराई तय
EDIT2 समारोह
edit3 कोड -O0 -g3 साथ संकलित और -rdynamic

उत्तर

6

आपकी समस्या के साथ जुड़े हुए कार्यों का उपयोग कर रहे हो सकता है से भरा कोड गयी। backtrace(.. में) 16 पर सेट है। यह बहुत कम हो सकता है। किसी भी दर पर ...

C++ stack traces with GCC पर यह ब्लॉग पोस्ट बताता है कि आपको स्टैक निशान कैसे करना चाहिए। संक्षेप में,

#include <execinfo.h> 
void print_trace(FILE *out, const char *file, int line) 
{ 
    const size_t max_depth = 100; 
    size_t stack_depth; 
    void *stack_addrs[max_depth]; 
    char **stack_strings; 

    stack_depth = backtrace(stack_addrs, max_depth); 
    stack_strings = backtrace_symbols(stack_addrs, stack_depth); 

    fprintf(out, "Call stack from %s:%d:\n", file, line); 

    for (size_t i = 1; i < stack_depth; i++) { 
     fprintf(out, " %s\n", stack_strings[i]); 
    } 
    free(stack_strings); // malloc()ed by backtrace_symbols 
    fflush(out); 
} 

जीसीसी भी सी ++ नाम (डी) mangler तक पहुँच प्रदान करता। वहाँ कुछ सुंदर बालों स्मृति स्वामित्व के बारे में जानने के लिए जानकारी दी जा रही है, और इंटरफ़ेस स्टैक ट्रेस उत्पादन के साथ स्ट्रिंग पार्स का एक सा की आवश्यकता है, लेकिन यह इस के साथ ऊपर भीतरी पाश की जगह करने पर निर्भर करता:

#include <cxxabi.h> 
... 
for (size_t i = 1; i < stack.depth; i++) { 
    size_t sz = 200; // just a guess, template names will go much wider 
    char *function = static_cast(malloc(sz)); 
    char *begin = 0, *end = 0; 
    // find the parentheses and address offset surrounding the mangled name 
    for (char *j = stack.strings[i]; *j; ++j) { 
     if (*j == '(') { 
      begin = j; 
     } 
     else if (*j == '+') { 
      end = j; 
     } 
    } 
    if (begin && end) { 
     *begin++ = ''; 
     *end = ''; 
     // found our mangled name, now in [begin, end) 

     int status; 
     char *ret = abi::__cxa_demangle(begin, function, &sz, &status); 
     if (ret) { 
      // return value may be a realloc() of the input 
      function = ret; 
     } 
     else { 
      // demangling failed, just pretend it's a C function with no args 
      std::strncpy(function, begin, sz); 
      std::strncat(function, "()", sz); 
      function[sz-1] = ''; 
     } 
     fprintf(out, " %s:%s\n", stack.strings[i], function); 
    } 
    else 
    { 
     // didn't find the mangled name, just print the whole line 
     fprintf(out, " %s\n", stack.strings[i]); 
    } 
    free(function); 
} 

उस साइट पर अधिक जानकारी है (मैं verbatim कॉपी नहीं करना चाहता था) लेकिन इस कोड को देखकर और उपर्युक्त साइट आपको सही रास्ते पर लेनी चाहिए।

+0

हैलो, आपके उत्तर के लिए धन्यवाद।आप अधिकतम गहराई के बारे में सही हैं, बैकट्रैस का अंत गुम था, लेकिन यह कोई समस्या नहीं है क्योंकि उन लापता कॉल परीक्षण फ्रेमवर्क से हैं जो मैं उपयोग कर रहा हूं। फिर भी, समस्या बनी हुई है और मैं ब्लॉग पोस्ट के समान ही कर रहा हूं। एक दिलचस्प तथ्य हालांकि, टेस्ट फ्रेमवर्क में नेमस्पेस में फ़ंक्शन हैं और वे स्टैकट्रैस में दिखाई दे रहे हैं, मेरे फ़ंक्शन नहीं हैं ... मैंने फिर से टेस्ट किया था (एक नामस्थान में फ़ंक्शन डालना), और फिर से वही काम किया गया (फ़ंक्शन बैकट्रैक में अब दिखाई नहीं दे रहा है ... – foke

1

backtrace सूचियों कॉल फ्रेम, जो मशीन कोड को call निर्देश, स्रोत स्तर फ़ंक्शन कॉल नहीं अनुरूप हैं।

अंतर यह है कि इनलाइनिंग के साथ, एक अनुकूलन कंपाइलर अक्सर स्रोत कोड में प्रत्येक लॉजिकल फ़ंक्शन कॉल के लिए call निर्देश का उपयोग करने से बच सकता है।

+0

पर कोई प्रतीक नहीं है, उस स्थिति में वे बीटी में बिल्कुल दिखाई नहीं देंगे। वैसे भी यहां कोई अनुकूलन नहीं है, यह '-O0' के साथ संकलित है -g3'। इसके अलावा यदि मैं बैकट्रैस बनाने वाले फ़ंक्शन में तोड़ता हूं, और बिना किसी प्रतीक के पते के पते पर जाता हूं, तो डिस्सेप्लोर व्यू (मैं ग्रहण का उपयोग कर रहा हूं) में, मैं 'कॉल' निर्देश के ठीक बाद समाप्त होता हूं सही ढंग से प्रदर्शित होता है (उर्फ उस समारोह/विधि का नाम दिखाता है जिसमें यह कूदने जा रहा है)। – foke

संबंधित मुद्दे