c++ lua gdb

c++ - ¿Cómo puedo obtener el seguimiento de la pila lua desde un archivo central utilizando gdb?



(4)

Tengo una aplicación C ++ (para OS X) que llama a lua como un lenguaje de scripting. Estoy ejecutando una gran cantidad de estas aplicaciones (100s) y pueden funcionar durante mucho tiempo (días o semanas).

A veces uno se cuelga. Y cuando se bloquea, me deja un precioso archivo central.

Puedo abrir este archivo core en gdb y encontrar dónde falla la aplicación. Puedo recorrer la pila de llamadas y encontrar una instancia de una variable lua_State. Mi problema es que me gustaría ver cómo es la pila de llamadas de lua en este momento ...

Tenga en cuenta que, dado que se trata de un núcleo, no tengo acceso a las funciones C de llamada, lo que excluye varias de las formas habituales de depurar scripts de lua.

Me gustaría evitar agregar rastros manuales a través de los anzuelos de depuración ya que estoy preocupado por las penalizaciones de rendimiento adicionales y la complejidad añadida.

¿Cómo puedo atravesar las estructuras internas de lua para obtener información sobre la pila de llamadas?


Creé un script GDB para hacer las cosas en la página web vinculada por macs. No es hermoso, y probablemente debería estar adecuadamente envuelto en una función, etc., pero aquí está para los curiosos.

NOTA: parece que la página web está equivocada con respecto al nombre de archivo de las funciones lua. En el caso en que la cadena proviene de luaL_dofile() el nombre del archivo comienza con un símbolo @ . Si se llaman desde lua_dostring() . En ese caso, la variable $filename se establece en la totalidad de la cadena que se pasa a lua_dostring() , y es probable que el usuario solo esté interesado en una o dos líneas de contexto de ese archivo. No estaba seguro de cómo arreglarlo.

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

Esto produce algo como:

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

Cuando depuro el bloqueo de este código:

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

y b.lua

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


En base a los comentarios anteriores, recomendaría el siguiente artículo: Lua callstack con C ++ depurador . Está dando una buena visión general sobre la depuración de la combinación Lua / C ++, especialmente la sección "Inspeccionar estructuras de datos Lua" es útil, cuando se trata de la depuración de los volcados centrales.


Esta es una pequeña variación del guión GDB de Michael Anderson: tuve que usar esto porque Cannot access memory at address 0x656d errores de la Cannot access memory at address 0x656d con su script, debido a que L->base_ci no es válido en mi volcado del núcleo. Esto comienza desde el cuadro superior ( L->ci ) y baja, en la dirección opuesta, evitando el puntero inválido L->base_ci .

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


Podrías echarle un vistazo a mis ayudantes Lua GDB . Es una colección de macros que le permite inspeccionar la pila y los valores, e incluso imprimir trazados retrospectivos. Esencialmente lo que contiene el artículo al que hacen referencia los Mac, en un paquete fácil de usar.

Proporciona estas macros:

  • luastack [L] - enumera los valores en la pila Lua C actual.

  • luaprint < value > [verbose] - Pretty imprime un TValue pasado como argumento. Espera un puntero a un TValue. Cuando verbose es 1, expande tablas, metatablas y entornos de datos de usuario.

  • luaprinttable < table > - Pretty-prints a Lua Table. Espera un puntero a la Tabla.

  • luavalue < index > [L] - Vuelca un único valor en un índice.

  • luatraceback [L] - Llama a debug.traceback() . No estoy seguro de si funcionará en el archivo principal aunque ...