2011-08-04 33 views
10

Tôi đang cố gắng để có được một backtrace tại một số điểm của việc thực hiện của tôi (c + +) chương trình.stacktrace và chức năng trong không gian tên

cho rằng tôi đang sử dụng backtrace và backtrace_symbols. Một cái gì đó dọc theo dòng này:

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; 
} 

Nó hoạt động nhưng một số tên hàm bị thiếu. Ví dụ:

[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] 
... 

chức năng 0-8 có một điểm chung: họ đều ngồi trong một không gian tên ...
Tôi đã thử đưa chức năng 9 trong một không gian tên vô danh (không có bất kỳ thay đổi khác) và nó disapears từ backtrace ... trông giống như sau:

[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] 
... 

Có cách nào khắc phục điều đó không?

ps: phiên bản của g ++: g ++ (GCC) 4.6.0 20.110.530 (Red Hat 4.6.0-9)

chỉnh sửa cố định chiều sâu tối đa của vết lùi sau Mã Khỉ xét
edit2 thêm mã đầy đủ các chức năng
EDIT3 mã được biên dịch với -O0 -g3 và liên kết với -rdynamic

Trả lời

6

vấn đề của bạn có thể là chức năng bạn đang sử dụng. max_depth của bạn ở backtrace(..) được đặt thành 16. Điều đó có thể quá thấp. Ở bất kỳ giá nào ...

Bài đăng trên blog này trên C++ stack traces with GCC giải thích cách bạn nên thực hiện theo dõi ngăn xếp. Tóm lại,

#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); 
} 

GCC cũng cung cấp truy cập vào cáC++ tên C (de) Mangler. Có một số chi tiết khá lông để tìm hiểu về quyền sở hữu trí nhớ, và interfacing với stack trace đầu ra đòi hỏi một chút của chuỗi phân tích cú pháp, nhưng nó nắm để thay thế các vòng lặp bên trên với điều này:

#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); 
} 

Có thêm thông tin trên trang web đó (tôi không muốn sao chép nguyên văn) nhưng nhìn vào mã này và trang web ở trên sẽ giúp bạn đi đúng hướng.

+0

xin chào, cảm ơn câu trả lời của bạn.bạn đúng về độ sâu tối đa, phần cuối của backtrace bị thiếu, nhưng đó không phải là vấn đề vì những cuộc gọi bị thiếu đó là từ khung kiểm tra mà tôi đang sử dụng. Tuy nhiên, vấn đề vẫn còn và tôi đang làm giống như bài đăng trên blog nói. Tuy nhiên, một thực tế thú vị là khung công tác có các hàm trong các không gian tên và chúng có thể nhìn thấy trong stacktrace, các chức năng của tôi không ... Tôi đã thực hiện lại kiểm tra (đặt một hàm trong một không gian tên). không còn nhìn thấy trong backtrace ... – foke

1

backtrace liệt kê các khung hình cuộc gọi, tương ứng với mã máy call hướng dẫn, không nguồn gọi hàm cấp.

Sự khác biệt là với nội tuyến, trình biên dịch tối ưu hóa thường có thể tránh sử dụng lệnh call cho mọi lệnh gọi hàm logic trong mã nguồn.

+0

Trong trường hợp đó chúng sẽ không xuất hiện ở tất cả trong bt. Dù sao không có tối ưu hóa ở đây, nó được biên dịch với '-O0 -g3' Hơn nữa, nếu tôi phá vỡ chức năng mà xây dựng backtrace, và đi đến địa chỉ dưới một không có biểu tượng, trong xem tháo gỡ (tôi đang sử dụng nhật thực), tôi kết thúc ngay sau khi một 'call' hướng dẫn mà được hiển thị chính xác (còn gọi là tên của hàm/phương thức mà nó sẽ nhảy vào). – foke

Các vấn đề liên quan