How can I get the lua stack trace from a core file using gdb

后端 未结 4 947
北海茫月
北海茫月 2021-02-01 18:07

I have a C++ application (for OS X) that calls lua as a scripting language. I\'m running a large number of these applications (100s) and they can run for a very long time (days

相关标签:
4条回答
  • 2021-02-01 18:15

    You could check out my Lua GDB helpers. It is a collection of macros that let you inspect the stack and values, and even print backtrace. Essentially what the article referenced by macs contains, in a simple-to-use package.

    It provides these macros:

    • luastack [L] - lists the values on the current Lua C stack.

    • luaprint < value > [verbose] - Pretty-prints a TValue passed as argument. Expects a pointer to a TValue. When verbose is 1, expands tables, metatables and userdata environments.

    • luaprinttable < table > - Pretty-prints a Lua Table. Expects a pointer to Table.

    • luavalue < index > [L] - Dumps a single value at an index.

    • luatraceback [L] - Calls debug.traceback(). Not sure if it will work on core file though...

    0 讨论(0)
  • 2021-02-01 18:16

    Based on the comments above, I'd recommend the following article: Lua callstack with C++ debugger. It's giving a good overview about debugging the Lua / C++ combination, especially the section "Inspect Lua data structures" is helpful, when it comes to debugging of core dumps.

    0 讨论(0)
  • 2021-02-01 18:17

    This is a small variation to Michael Anderson's GDB script: I had to use this because I was getting Cannot access memory at address 0x656d errors with his script, due to L->base_ci being invalid in my core dump. This starts from the top frame (L->ci) and goes down, in the opposite direction, avoiding the invalid L->base_ci pointer.

    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
    
    0 讨论(0)
  • 2021-02-01 18:36

    I've created a GDB script to do the stuff in the web page linked to by macs. Its not beautiful, and should probably be properly wrapped into a function etc, but here it is for the curious.

    NOTE: It seems that the web page is wrong about the filename for lua functions. In the case where the string comes from luaL_dofile() the filename starts with a @ symbol. If they're called from lua_dostring(). In that case the $filename variable is set to the whole of the string passed to lua_dostring() - and the user is probably only interested in one or two lines of context from that file. I wasn't sure how to fix that up.

    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
    

    This outputs something like:

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

    When I debug the crash from this code:

    // 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);
    }
    

    With a.lua

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

    and b.lua

    -- b.lua
    function B()
      C()
    end
    
    0 讨论(0)
提交回复
热议问题