2013-05-28 3 views
8

Ho costruito un frontend di targeting LLVM che produce alcuni IR. Successivamente e del tutto prevedibile, l'output IR non è corretto in alcuni casi (come in, sembra corretto, ma il programma risultante si blocca quando viene eseguito). Tuttavia, non ho trovato molti strumenti utili per affrontare questo.Debug LLVM IR

Ho provato a utilizzare lli, ma l'output del messaggio di errore è incredibilmente inutile (quando si suppone che un interprete possa fornire dettagli di errore molto precisi).

Ho esaminato la conversione del codice IR in C e quindi il debugging con Visual Studio, ma sembra che questa funzionalità sia stata rimossa da LLVM.

Ho anche esaminato GDB. Tuttavia, il formato di informazioni di debug di DWARF è abbastanza specifico per alcuni linguaggi esistenti, e inoltre, la fonte che sto traducendo con il mio frontend è corretta, è l'IR prodotto che è sbagliato, quindi i simboli di debug per la fonte originale non sarebbero essere troppo utile, ad esempio, avrei bisogno di vedere i valori di un gruppo di valori di registro intermedi che non corrispondono a nessuna variabile sorgente o punto di interruzione nelle funzioni generate dal compilatore.

Quali strumenti e tecniche esistono per eseguire il debug dell'output LLVM IR?

risposta

3

Non sono sicuro di aver compreso completamente il problema. Stai dicendo che il tuo compilatore (dalla lingua X a LLVM IR) sta producendo output non corretto (IR LLVM errato) e non sei sicuro di come eseguirne il debug? In altre parole, ci sono due possibilità:

  1. L'IR prodotto dal compilatore non è corretto - è possibile indicare alcune istruzioni e dire - questo non è ciò che intendevo generare.
  2. L'IR sembra corretto ma non produce i risultati che mi aspettavo che producesse.

Penso che sia (1) si sta parlando (perché questo è ciò che la questione stava dicendo, prima dell'aggiornamento esso)

Questo non sarebbe un problema LLVM-specifica, quindi. Supponi di scrivere un compilatore dalla lingua X al codice nativo. Il codice nativo prodotto non è corretto: come si esegue il debug del problema? Bene, esegui il debug del tuo compilatore, ovviamente. Cerchi di trovare l'ultimo posto in cui la comprensione dell'input del compilatore era corretta, o il primo posto in cui è diventato errato. Il modo in cui lo fai dipende enormemente dall'architettura del tuo compilatore. Tuttavia, qualcosa che aiuta molto è avere una rappresentazione stampabile di altri livelli intermedi nel compilatore.

Per esempio, Clang (che produce LLVM IR da C, C++ e Objective C) può scaricare il suo pieno AST. Quindi, guardare l'AST per il codice errato può dimezzare il compilatore, aiutando a determinare se il problema è nel front-end (sorgente C -> AST) o codice gen (AST -> LLVM IR). Il backend LLVM (compila l'LLVM IR al codice nativo) ha anche alcuni strati intermedi (in particolare SelectionDAG e MI), che possono essere esaminati per il debugging. Questi sono solo esempi di altri compilatori esistenti, YMMV con i tuoi.

+1

Er, in realtà, è # 2. Posso prendere il numero 1 senza troppi problemi adesso. Il programma è molto piccolo, ho ispezionato visivamente molte parti dell'IR e sembrano perfettamente corrette, ma il programma si blocca in fase di esecuzione. Ho anche verificato che il programma sorgente sia corretto. – Puppy

+0

@DeadMG: quindi devi fare una domanda diversa. "Ecco questo piccolo pezzo di LLVM IR e non funziona" e vedere se qualcuno può aiutare. Oltre a questo, presumo che si blocca con 'lli'? Hai provato a compilarlo con 'llc' e vedere cosa viene fuori? Eseguendolo tramite 'opt' con la verifica del modulo? –

+0

'lli' ha effettivamente esito negativo (ovviamente con un messaggio di errore incredibilmente inutile). Ho compilato con 'llc' e ho verificato sia le funzioni che il modulo nel suo complesso. – Puppy

1

Will Diez ha descritto come ha implementato che:
https://groups.google.com/d/msg/llvm-dev/O4Dj9FW1gtM/ovnm6dqoJJsJ

Ciao a tutti,

per i miei scopi, ho scritto un passaggio che fa esattamente quello che tutti voi siete descrive: aggiungere metadati di debug a LLVM IR.

Come un passaggio, doveva affrontare il problema della "Questo file deve esistere su disco da qualche parte in modo gdb possono trovare", che ho risolto il mio dumping su/tmp/da qualche parte. Non è una soluzione eccezionale (chi li elimina?) Ma ha funzionato abbastanza bene.

Un altro aspetto interessante è il modo di coesistere con qualsiasi di debug metadati esistenti, che può essere utile per il debug contemporaneamente un IR trasformerà in linea con il sorgente C per la strumentazione in stile passa come SAFECode, Asan/tsan.

Esempio rapida:

(gdb) break main 
Breakpoint 1 at 0x4010b1: file 
/home/wdietz2/magic/test/unit/test_loop.c, line 9. 
(gdb) r 
Starting program: 
/home/wdietz2/llvm/32-obj-make/projects/magic/test/Output/test_loop 

Breakpoint 1, main (argc=<value optimized out>, argv=<value optimized 
out>) at /home/wdietz2/magic/test/unit/test_loop.c:9 
9   unsigned k = 0; 
Missing separate debuginfos, use: debuginfo-install 
glibc-2.12-1.80.el6_3.5.x86_64 libgcc-4.4.6-4.el6.x86_64 
libstdc++-4.4.6-4.el6.x86_64 
(gdb) n 
10  source(argc != 0, &k); 
(gdb) n 
14  %and.i.i.i.i104 = and i64 %4, 70368744177660 
(gdb) n 
15  %5 = load i8** @global, align 8 
(gdb) n 
18  store i32 16843009, i32* %6, align 1 
(gdb) n 
19  store i8 1, i8* getelementptr inbounds ([1 x i8]* @array, 
i64 0, i64 0), align 1 
(gdb) n 
20  call coldcc void @runtime_func() nounwind 
(gdb) n 
11  while(i-- > argc) 
(gdb) n 
23  %and.i.i.i.i85 = and i64 %7, 70368744177660 
(gdb) n 
14   while(j++ < i) k += j; 
(gdb) n 
11  while(i-- > argc) 
(gdb) n 
14   while(j++ < i) k += j; 
(gdb) n 
102  %77 = load i8** @global, align 8 
(gdb) n 
105  %79 = load i32* %78, align 4 
(gdb) n 
106  %cmp7.i.i.i = icmp ne i32 %79, 0 
(gdb) n 
108  call void @llvm.memset.p0i8.i64(i8* %add.ptr.i.i.i.i86, i8 
%conv8.i.i.i, i64 4, i32 1, i1 false) nounwind 
(gdb) n 
14   while(j++ < i) k += j; 
(gdb) n 
15   while(j-- > 0) k *= k + j; 
(gdb) n 
95  %69 = load i8** @global, align 8 
(gdb) n 
98  %71 = load i32* %70, align 4 
(gdb) 

Il passo stesso è piuttosto semplice - il problema difficile risolve è emettitori IR disco e ragionamento su ciò Instruction * è in quale linea, che in realtà shouldn' t essere un problema se fatto correttamente in LLVM. Se lo si desidera posso certamente rendere il codice disponibile su richiesta.

In breve, sembrava funzionare bene per me e averlo fatto correttamente in LLVM stesso sarebbe fantastico!

Sfortunatamente, sembra che il codice non sia disponibile.