2008-11-14 6 views
6

J'essaie de trouver comment stocker puis imprimer la pile actuelle dans mes applications C++ sur Mac OS X. Le problème principal semble être que dladdr renvoie le bon symbole quand donné une adresse dans l'exécutable principal. Je soupçonne que la question est en fait une option de compilation, mais je ne suis pas sûr.Obtention de la trace de la pile actuelle sous Mac OS X

J'ai essayé le code de traçage de Darwin/Leopard mais il appelle dladdr et a le même problème que mon propre code appelant dladdr.

Original post: Actuellement, je suis capturer la pile avec ce code:

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

qui semble bien fonctionner. Ensuite, pour imprimer la pile je regarde en utilisant dladdr comme ceci:

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

Ce qui fonctionne presque, une sortie par exemple:

/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] 

Il devient juste le nom de la méthode de l'objet partagé, mais pas pour l'application principale. Ceux-ci se contentent de "piquer" (ou de "commencer" moins le premier caractère).

Idéalement, j'aimerais connaître les numéros de ligne ainsi que le nom de la méthode à ce moment-là. Mais je vais me contenter du bon nom de fonction/méthode pour les débutants. Peut-être tirer pour les numéros de ligne après cela, sur Linux, j'entends que vous devez écrire votre propre analyseur pour un bloc ELF privé qui a son propre jeu d'instructions. Ça fait peur.

De toute façon, quelqu'un peut-il trier ce code afin qu'il obtienne le nom de la méthode?

Répondre

12

Quelles sont les versions d'OS X que vous ciblez? Si vous utilisez Mac OS X 10.5 et supérieur, vous pouvez simplement utiliser les appels backrace() et backtrace_symbols() libraray. Ils sont définis dans execinfo.h, et il y a un manpage avec un exemple de code.

Edit:

Vous avez mentionné dans les commentaires que vous avez besoin sur Tiger. Vous pouvez probablement inclure l'implémentation de Libc dans votre application. La source est disponible sur le site opensource d'Apple. Voici un lien vers le lien file.

+0

Je cible actuellement les versions actuelles et précédentes, à savoir Leopard et Tiger. Aussi j'ai actuellement Tiger sur mon Macbook. Donc, jusqu'à ce que Snow Leopard sorte, mon code devra compiler/fonctionner sur Tiger. – user33847

+0

Eh bien, le code source de ces fonctions est opensource, donc vous pouvez probablement inclure l'implémentation dans votre application. Je suis en train d'éditer ma réponse avec les informations pertinentes. –

+0

J'ai jeté un oeil sur le code que vous avez posté des liens et il utilise finalement dladdr exactement le même que mon code. Ce qui donne les mêmes mauvais résultats, en ce que tout ce qui se trouve dans mon exécutable (c'est-à-dire, pas un objet partagé) porte le symbole "tarte". – user33847

Questions connexes