Ottieni lo stack di chiamate in codice con un sovraccarico minore?
Domanda
Ho intenzione di implementare un profiler interno per la memoria su Linux. Voglio salvare lo stack per ogni malloc / free / realloc. Sto cercando di utilizzare " pstack " per ottenere la traccia dello stack ogni volta. Ma il sovraccarico è troppo alto. Esiste un approccio lightweigt per ottenere lo stack di chiamate nel codice C?
So che ci sono alcuni strumenti come " valgrind, google profiler " ;, ma non so come ricordino le pile per ogni azione.
Ogni commento è apprezzato.
Grazie.
Soluzione
È possibile creare la propria funzione per ottenere il chiamante:
static inline void *get_caller(void) {
unsigned long *ebp;
/* WARNING: This is working only with frame pointers */
asm ("movl %%ebp, %0" : "=r" (ebp) : );
ebp = (unsigned long*)*ebp;
ebp = (unsigned long*)*(ebp+1);
return ebp;
}
void *malloc(void) {
void *caller = get_caller();
...
}
" ebp = (unsigned long *) * ebp;
" ti farà passare attraverso lo stack (se hai bisogno di più di quella traccia dello stack).
Altri suggerimenti
Esiste una funzione GNU backtrace ()
che è relativamente veloce - restituisce solo array di indirizzi.
Per risolvere questi indirizzi in nomi di funzioni è necessario utilizzare backtrace_symbols ()
che è molto più pesante, ma speriamo che non sia necessario eseguirlo troppo spesso.
Per ottenere backtrace_symbols ()
per risolvere effettivamente i nomi devi usare le opzioni del linker -rdynamic
.
Vedi man backtrace
per i dettagli.
Fai attenzione alle ricorsioni con backtrace_symbols (), che chiama malloc stesso.
Nota anche che al primo utilizzo di backtrace () e degli amici il linker dinamico proverà a caricare libgcc, che invocherà ancora una volta malloc.
Gilad
Ora ho riscontrato un problema a 64 bit.
Su 64 bit, RBP non è rigorosamente mantenuto. Ad esempio, gcc -O3 utilizzerà RBP come un normale registro salvato del chiamante. Quindi, in questo caso, ottenere stack di chiamate dai puntatori di frame non funziona. :(
Qualche commento?