2011-12-16 20 views
20

Ho un'applicazione C++ (per OS X) che chiama lua come linguaggio di scripting. Sono in esecuzione un gran numero di queste applicazioni (100s) e possono eseguire per un tempo molto lungo (giorni o settimane).Come posso ottenere la traccia dello stack lua da un file principale usando gdb

A volte un arresto anomalo. E quando si blocca, mi lascia un bel file principale.

Posso aprire questo file core in gdb e trovare dove si blocca l'applicazione. Posso camminare sullo stack delle chiamate e trovare un'istanza di una variabile lua_State. questa volta mi piacerebbe vedere come appare lo stack di chiamate lua a ...

Ricordare che poiché questo è un core, non ho accesso a chiamare le funzioni C, che esclude molti dei soliti metodi di debugging degli script lua.

Id mi piace evitare di aggiungere tracce manuali tramite i bachi di debug perché sono preoccupato per le penalizzazioni delle prestazioni aggiuntive e per la complessità aggiunta.

Come posso attraversare le strutture interne lua per ottenere informazioni sullo stack di chiamata?

+5

Così, forse avete letto questo già, ma non so, in modo da non essere scontroso, si prega;) [Lua stack con C++ debugger] (http://zeuxcg.org/2010/11/07/lua-callstack-with-c-debugger /) –

+0

@macs Questa è una panoramica abbastanza buona. La sezione "Ispezione strutture dati Lua" è la chiave. Avevo elaborato la maggior parte di questo, ma era piuttosto complicato da usare. Probabilmente cercherò di scrivere alcune macro/script GDB per renderlo funzionante. –

+0

Sono felice di darti una mano, c'è anche [StackTracePlus] (https://github.com/ignacio/StackTracePlus) ma dovrai modificare la funzione C chiamante, se sono corretto. Quindi è piuttosto inutile in questo caso particolare. –

risposta

8

Ho creato uno script GDB per fare le cose nella pagina web collegata ai mac. Non è bello, e probabilmente dovrebbe essere avvolto correttamente in una funzione, ecc., Ma qui è per i curiosi.

NOTA: Sembra che la pagina Web sia errata sul nome file per le funzioni lua. Nel caso in cui la stringa provenga da luaL_dofile() il nome file inizia con un simbolo @. Se vengono chiamati da lua_dostring(). In questo caso la variabile $filename è impostata sull'intera stringa passata a lua_dostring() - e l'utente probabilmente è interessato solo a una o due righe di contesto da quel file. Non ero sicuro di come sistemarlo.

set $p = L->base_ci 
while ($p <= L->ci) 
    if ($p->func->value.gc->cl.c.isC == 1) 
    printf "0x%x C FUNCTION", $p 
    output $p->func->value.gc->cl.c.f 
    printf "\n" 
    else 
    if ($p->func.tt==6) 
     set $proto = $p->func->value.gc->cl.l.p 
     set $filename = (char*)(&($proto->source->tsv) + 1) 
     set $lineno = $proto->lineinfo[ $p->savedpc - $proto->code -1 ] 
     printf "0x%x LUA FUNCTION : %d %s\n", $p, $lineno, $filename 
    else 
     printf "0x%x LUA BASE\n", $p 
    end 
    end 
    set $p = $p+1 
end 

Emette qualcosa di simile:

0x1002b0 LUA BASE 
0x1002c8 LUA FUNCTION : 4 @a.lua 
0x1002e0 LUA FUNCTION : 3 @b.lua 
0x100310 C FUNCTION(lua_CFunction) 0x1fda <crash_function(lua_State*)> 

Quando il debug l'incidente da questo codice:

// This is a file designed to crash horribly when run. 
// It should generate a core, and it should crash inside some lua functions 

#include "lua.h" 
#include "lualib.h" 
#include "lauxlib.h" 

#include <iostream> 
#include <signal.h> 

int crash_function(lua_State * L) 
{ 
    raise(SIGABRT); //This should dump core! 
    return 0; 
} 



int main() 
{ 
    lua_State * L = luaL_newstate(); 
    lua_pushcfunction(L, crash_function); 
    lua_setfield(L, LUA_GLOBALSINDEX, "C"); 

    luaopen_base(L); 
    if(1 == luaL_dofile(L, "a.lua")) 
    { 
    std::cout<<"ERROR: "<<lua_tostring(L,-1)<<std::endl; 
    return 1; 
    } 
    if(1 == luaL_dofile(L, "b.lua")) 
    { 
    std::cout<<"ERROR: "<<lua_tostring(L,-1)<<std::endl; 
    return 1; 
    } 

    lua_getfield(L, LUA_GLOBALSINDEX, "A"); 
    lua_pcall(L, 0, 0, NULL); 
} 

Con a.lua

-- a.lua 
-- just calls B, which calls C which should crash 
function A() 
    B() 
end 

e b.lua

-- b.lua 
function B() 
    C() 
end 
4

Sulla base dei commenti sopra, consigliamo il seguente articolo: Lua callstack with C++ debugger. Fornisce una buona panoramica sul debug della combinazione Lua/C++, in particolare la sezione "Ispezionare le strutture dati Lua" è utile, quando si tratta di eseguire il debug dei core dump.

+1

Assegnato questo premio in quanto è quello che mi permette di arrivare alla mia (parziale) soluzione. –

4

È possibile controllare il mio Lua GDB helpers. È una raccolta di macro che consente di ispezionare stack e valori e persino di stampare backtrace. Essenzialmente ciò che l'articolo a cui fa riferimento Macs contiene, in un pacchetto semplice da usare.

Fornisce queste macro:

  • luastack [L] - elenca i valori sulla corrente pila Lua C.

  • luaprint <value> [verbose] - Pretty-prints un TValue passato come argomento. Si aspetta un puntatore a un TValue. Quando verbose è 1, espande le tabelle, i metatables e gli ambienti userdata.

  • luaprinttable <table> - Pretty-stampa un tavolo Lua. Si aspetta un puntatore alla tabella.

  • luavalue <index> [L] - Scarica un singolo valore in un indice.

  • luatraceback [L] - Chiamate debug.traceback(). Non sono sicuro se funzionerà sul file principale ...

+0

Apparentemente, le tue macro usano l'approccio numero 1, chiamando i metodi Lua per ottenere lo stack. Non funzionerà con un core dump. –

+0

Hmmm, sembra che dovrò implementare più funzionalità in puro GDB :) –

+0

Dopo aver dato un'occhiata lunga e approfondita ai sorgenti Lua, rinuncio all'implementazione della traccia dello stack in GDB, perché ad esempio per ottenere il nome della funzione, [ devi ispezionare il bytecode] (http://www.lua.org/source/5.1/ldebug.c.html#symbexec). Non sono sicuro che sia davvero possibile fare offline. –

6

Questa è una piccola variazione allo script GDB di Michael Anderson: ho dovuto usare questo perché mi stavo Cannot access memory at address 0x656d errori con la sua sceneggiatura, a causa di L->base_ci essere valida nel mio core dump. Questo inizia dal frame superiore (L->ci) e scende, nella direzione opposta, evitando il puntatore L->base_ci non valido.

set $p = L->ci 
while ($p > L->base_ci) 
    if ($p->func->value.gc->cl.c.isC == 1) 
    printf "0x%x C FUNCTION ", $p 
    output $p->func->value.gc->cl.c.f 
    printf "\n" 
    else 
    if ($p->func.tt==6) 
     set $proto = $p->func->value.gc->cl.l.p 
     set $filename = (char*)(&($proto->source->tsv) + 1) 
     set $lineno = $proto->lineinfo[ $p->savedpc - $proto->code -1 ] 
     printf "0x%x LUA FUNCTION : %d %s\n", $p, $lineno, $filename 
    else 
     printf "0x%x LUA BASE\n", $p 
    end 
    end 
    set $p = $p - 1 
end 
Problemi correlati