2008-11-14 1 views
6

Я пытаюсь определить, как хранить и затем печатать текущий стек в моих приложениях на C++ в Mac OS X. Основная проблема заключается в том, чтобы заставить dladdr вернуть правильный символ когда задан адрес внутри основного исполняемого файла. Я подозреваю, что проблема на самом деле является компилятором, но я не уверен.Получение текущей трассировки стека в Mac OS X

Я пробовал код backtrace от Darwin/Leopard, но он вызывает dladdr и имеет ту же проблему, что и мой собственный код, вызывающий dladdr.

Оригинальное сообщение: В настоящее время я захватывая стек с этим кодом:

int BackTrace(Addr *buffer, int max_frames) 
{ 
    void **frame = (void **)__builtin_frame_address(0); 
    void **bp = (void **)(*frame); 
    void *ip = frame[1]; 
    int i; 

    for (i = 0; bp && ip && i < max_frames; i++) 
    { 
     *(buffer++) = ip; 
     ip = bp[1]; 
     bp = (void**)(bp[0]); 
    } 

    return i; 
} 

который, кажется, работает нормально. Затем, чтобы напечатать стек я ищу на использование dladdr так:

Dl_info dli; 
if (dladdr(Ip, &dli)) 
{ 
    ptrdiff_t  offset; 
    int c = 0; 

    if (dli.dli_fname && dli.dli_fbase) 
    { 
     offset = (ptrdiff_t)Ip - (ptrdiff_t)dli.dli_fbase; 
     c = snprintf(buf, buflen, "%s+0x%x", dli.dli_fname, offset); 
    } 
    if (dli.dli_sname && dli.dli_saddr) 
    { 
     offset = (ptrdiff_t)Ip - (ptrdiff_t)dli.dli_saddr; 
     c += snprintf(buf+c, buflen-c, "(%s+0x%x)", dli.dli_sname, offset); 
    } 

    if (c > 0) 
     snprintf(buf+c, buflen-c, " [%p]", Ip); 

который почти работает, некоторый пример вывода:

/Users/matthew/Library/Frameworks/Lgi.framework/Versions/A/Lgi+0x2473d(LgiStackTrace+0x5d) [0x102c73d] 
/Users/matthew/Code/Lgi/LgiRes/build/Debug/LgiRes.app/Contents/MacOS/LgiRes+0x2a006(tart+0x28e72) [0x2b006] 
/Users/matthew/Code/Lgi/LgiRes/build/Debug/LgiRes.app/Contents/MacOS/LgiRes+0x2f438(tart+0x2e2a4) [0x30438] 
/Users/matthew/Code/Lgi/LgiRes/build/Debug/LgiRes.app/Contents/MacOS/LgiRes+0x35e9c(tart+0x34d08) [0x36e9c] 
/Users/matthew/Code/Lgi/LgiRes/build/Debug/LgiRes.app/Contents/MacOS/LgiRes+0x1296(tart+0x102) [0x2296] 
/Users/matthew/Code/Lgi/LgiRes/build/Debug/LgiRes.app/Contents/MacOS/LgiRes+0x11bd(tart+0x29) [0x21bd] 

Это становится имя метода право для общего объекта, но не для основное приложение. Они просто отображают «tart» (или «start» минус первый символ).

В идеале мне бы хотелось указать номера строк, а также имя метода в этой точке. Но я соглашусь на правильное имя функции/метода для стартеров. Возможно, стреляйте по номерам строк после этого, в Linux я слышал, что вам нужно написать собственный синтаксический анализатор для частного блока ELF, у которого есть собственный набор команд. Звучит страшно.

В любом случае, может ли кто-нибудь отсортировать этот код, чтобы он правильно получил имена методов?

ответ

12

Какие версии ОС X вы нацеливаете. Если вы работаете в Mac OS X 10.5 и выше, вы можете просто использовать вызовы backtrace() и backtrace_symbols() libraray. Они определены в execinfo.h, и есть manpage с некоторым примером кода.

Edit:

Вы упоминали в комментариях, что вы должны работать на тигра. Вероятно, вы можете просто включить реализацию из Libc в ваше приложение. Источник доступен на веб-сайте Apple с открытым исходным кодом. Вот ссылка на релевантный file.

+0

В настоящее время я нацелен на текущие и предыдущие версии, то есть Leopard и Tiger. Также у меня есть Tiger на моем Macbook. Поэтому до тех пор, пока не появится снежный барс, мне нужно будет скомпилировать/запустить Tiger. – user33847 2008-11-14 21:50:02