Получение текущей трассировки стека в Mac OS X - PullRequest
6 голосов
/ 14 ноября 2008

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

Я пробовал код обратной трассировки от 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]

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

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

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

1 Ответ

12 голосов
/ 14 ноября 2008

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

Edit:

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

...