2012-05-02 13 views
5

L'analisi del core dump nella build di vendita al dettaglio richiede spesso di correlare lo objdump di qualsiasi modulo specifico e l'origine. Normalmente correlare la discarica di assembly con la sorgente diventa un dolore se la funzione è abbastanza coinvolta. Oggi ho provato a creare un assembly listing di un particolare modulo (con l'opzione di compilazione -S) in attesa di vedere una sorgente di interleaving con assembly o una correlazione. Purtroppo l'elenco non è stato abbastanza gentile di correlare quindi mi chiedevoCorrela origine con elenco assembly di un programma C++

  • Dato un core-discarica da cui è possibile determinare la posizione incidente
  • objdump del modulo non aver Assemblea Inserite da ricompilare il modulo di
  • con Opzione -S.

È possibile eseguire una corrispondenza uno a uno con la fonte?

Come esempio vedo la lista di montaggio come

.LBE7923: 
     .loc 2 4863 0 
     movq %rdi, %r14 
     movl %esi, %r12d 
     movl 696(%rsp), %r15d 
     movq 704(%rsp), %rbp 
.LBB7924: 
     .loc 2 4880 0 
     testq %rdx, %rdx 
     je  .L2680 
.LVL2123: 
     testl %ecx, %ecx 
     jle  .L2680 
     movslq %ecx,%rax 
     .loc 2 4882 0 
     testl %r15d, %r15d 
     .loc 2 4880 0 
     leaq (%rax,%rax,4), %rax 
     leaq -40(%rdx,%rax,8), %rdx 
     movq %rdx, 64(%rsp) 

ma non riuscivo a capire come interpretare le etichette come .LVL2123 e direttive come .loc 2 4863 0

Nota Poiché le risposte raffigurati, attraverso la lettura la fonte dell'assemblaggio e la determinazione intuitiva del modello in base ai simboli (come le chiamate di funzione, i rami, l'istruzione di ritorno) è ciò che generalmente faccio. Non sto negando che non funzioni, ma quando una funzione è abbastanza complicata, leggere le pagine di Assembly Listing è un problema e spesso si finisce con l'elencazione che raramente si combina o perché le funzioni di allineamento o ottimizzazione sono semplicemente sballottate il codice a piacere. Ho la sensazione di vedere quanto efficientemente Valgrind gestisce i binari ottimizzati e come in Windows WinDBG sia possibile gestire i binari ottimizzati, c'è qualcosa che mi manca. Quindi, anche se vorrei iniziare con l'output del compilatore e usarlo per correlare. Se il mio compilatore è responsabile per la manipolazione del file binario sarebbe la persona migliore per dire come correlare con la fonte, ma sfortunatamente è stato meno utile e lo .loc è davvero fuorviante. Sfortunatamente spesso devo leggere i dump non riproducibili su varie piattaforme e il minimo tempo che trascorro è nel debug di Windows Mini-dump attraverso WinDBG e un tempo considerevole nel debug di Linux Coredumps. Per quanto ciò possa essere, non sto facendo le cose correttamente, quindi mi è venuta questa domanda.

+0

Questa non è una risposta alla tua domanda, ma potrebbe essere utile in ogni caso: http://msdn.microsoft.com/en-us/library/aa238730%28v=vs.60%29.aspx –

+1

Il core dump dovrebbe avere indirizzi in esso. Quindi prova il programma 'addr2line' per tradurre in posizioni di origine. Questo ovviamente richiede un eseguibile con simboli di debug (dovrebbe funzionare anche se la tua versione distribuita è stata spogliata, basta confrontare con una versione non ridotta) –

+0

@ edA-qamort-ora-y: Proverò questo e ti faccio sapere dove Finisco con. A proposito, non dovrebbe essere una risposta piuttosto che un commento? – Abhijit

risposta

4

E 'possibile fare una corrispondenza uno-a-uno con la fonte?

A: no, a meno che l'ottimizzazione non sia disabilitata. Il compilatore può emettere inizialmente un gruppo di istruzioni (o cose simili a istruzioni) per linea, ma l'ottimizzatore quindi riordina, divide, fonde e generalmente le cambia completamente.


Se sto smontando il codice di rilascio, osservo le istruzioni che dovrebbero avere una chiara relazione logica con il codice. Ad esempio,

.LBB7924: 
     .loc 2 4880 0 
     testq %rdx, %rdx 
     je  .L2680 

si presenta come un ramo se %rdx è zero, e viene dalla linea 4880. trovare la linea, identificare la variabile in fase di test, fare una nota che è attualmente assegnato a %rdx.

.LVL2123: 
     testl %ecx, %ecx 
     jle  .L2680 

OK, quindi questo test e il ramo ha lo stesso obiettivo, quindi qualunque cosa viene dopo conosce %rdx e %ecx sono entrambi diverso da zero. Il codice originale potrebbe essere strutturato come:

if (a && b) { 

o forse era:

if (!a || !b) { 

e l'ottimizzatore riordinato i due rami ...

Ora hai qualche struttura è possibile si spera che corrisponda al codice originale, è anche possibile capire i compiti del registro. Ad esempio, se si sa che la cosa testata è il membro dati di una certa struttura, leggere all'indietro per vedere dove è stato caricato %rdx dalla memoria: è stato caricato da un offset fisso in qualche altro registro? Se è così, quel registro è probabilmente l'indirizzo dell'oggetto.

Buona fortuna!

+0

+1 per il tutorial dettagliato. È davvero meraviglioso. Ma sfortunatamente questo e soprattutto quello che @Chris ha menzionato è quello che faccio per leggere attraverso la discarica. Ma sei d'accordo, leggere le pagine di discariche a volte può diventare un vero dolore e soprattutto quando la funzione diventa in-linea. Ad esempio, oggi passo quasi un'ora a leggere quasi 1000 linee di assemblaggio. Ho avuto l'impressione che ci dovrebbe essere qualcosa che mi manca considerando quanto sia efficiente e quasi prevedibile che 'Valgrind' mappa un binario completamente ottimizzato con l'elenco sorgente se si compila con l'opzione' -g' (con i simboli). – Abhijit

+0

Bene, l'etichetta '.loc' può mappare un gruppo di istruzioni a una linea di codice, e presumibilmente valgrind può usarlo per attribuire il costo approssimativo dell'istruzione a una linea sorgente. Tuttavia, ciò non equivale a capire perché un programma si è arrestato in modo anomalo: si sta tentando di ricostruire lo stato del programma _logical_ che l'ottimizzatore ha trasformato e scartato. È più difficile e non è richiesto per la contabilità valgrind. – Useless

4

La direttiva .loc è ciò che stai cercando. Questi indicano la riga 4863, 4880, ecc. Non esiste una mappatura perfetta tra sorgente e assemblatore ottimizzato (motivo per cui si vede 4880 più di una volta). Ma .loc è come sapere dove si trova nel file. La sintassi è:

.loc <file> <line> <column> 
+0

Qui posso dire di più? Ad esempio il '.loc' ha altri due numeri come' 2' e '0'. Cosa sono questi? E quali sono queste etichette '.LVL2123' e' .LBE7923'? – Abhijit

+1

Questi sono in genere obiettivi "goto" emessi dal compilatore. Ad esempio hai 'je .L2680', quindi dovrebbe esserci una riga che inizia' .L2680: 'da qualche parte. – Useless

1

Se non si collega staticamente alle librerie di sistema, anche senza i simboli di debug ci saranno nomi simbolici nel binario, quello delle funzioni della libreria di sistema collegate.

Questi possono spesso aiutare a restringere il punto in cui ci si trova nel codice. Per esempio, se vedi che nella funzione foo() chiama open() e poi ioctl() e poi si blocca proprio prima di chiamare read(), puoi probabilmente trovare quel punto nella sorgente di foo abbastanza facilmente. (In questo caso potresti anche non aver bisogno del dump - on linux puoi ottenere il record di occorrenza di crash relativo alle funzioni di libreria e di sistema usando ltrace o strace)

Nota che in alcuni formati binari, tuttavia, potrebbe esserci un riferimento indiretto alle funzioni di libreria tramite piccoli wrapper in altre parti del binario. Spesso un dump avrà ancora informazioni sul nome simbolico rilevanti all'indirizzo dell'invocazione nel flusso del programma. Ma anche se no, puoi riconoscere quei wrapper di linkage esterni dal loro range di indirizzi nel binario, e quando ne vedi uno puoi andare a trovare il suo codice e capire a quale funzione esterna si collega.

Ma, come altri hanno detto, se hai il codice sorgente e il sistema in cui si blocca una frequenza tale da essere utile, la soluzione più veloce di solito è di ricostruire con i simboli di debug, o inserire l'output di registrazione e ottenere un crash più utile disco.

+0

Purtroppo devo spesso eseguire il debug di dump non riproducibili su vari sistemi e quello che hai menzionato è il mio modo di lavorare e funziona, ma devo investire molto tempo e impegno. Ho stimato che il debugging di un minidump di Windows richiede molto meno tempo (tramite WinDBG) rispetto al debug di un coredump di Linux. Anche doloroso è il debug di dump Solaris/AIX/HP-UX. Vedendo con quanta efficienza Valgrind mappa un binario ottimizzato con la fonte, sono diventato davvero ambizioso e ottimista nel determinare qualcosa di più efficiente. @ edA-qa mort-ora-y ha un suggerimento che devo ancora provare e farti sapere dove finisco :-) – Abhijit

Problemi correlati