2011-12-16 31 views
20

Tôi có ứng dụng C++ (dành cho OS X) gọi lua là ngôn ngữ kịch bản. Tôi đang chạy một số lượng lớn các ứng dụng này (100) và chúng có thể chạy trong một thời gian rất dài (ngày hoặc vài tuần).Tôi có thể lấy dấu vết ngăn xếp lua từ một tệp lõi bằng cách sử dụng gdb

Đôi khi một sự cố. Và khi nó bị treo, nó để lại cho tôi một tập tin cốt lõi đáng yêu.

Tôi có thể mở tệp lõi này trong gdb và tìm nơi ứng dụng gặp sự cố. Tôi có thể đi bộ ngăn xếp cuộc gọi và tìm một phiên bản của biến lua_State. Vấn đề của tôi là tôi muốn xem những gì các lua gọi stack trông giống như tại thời gian này ...

Hãy nhớ rằng vì đây là một lõi tôi không có quyền truy cập để gọi C chức năng, mà quy tắc ra một số cách thông thường để gỡ lỗi các script lua.

Id muốn tránh thêm dấu vết thủ công thông qua các móc gỡ lỗi vì tôi lo lắng về các hình phạt hiệu suất bổ sung và độ phức tạp được thêm vào.

Làm cách nào tôi có thể duyệt qua cấu trúc nội bộ lua để nhận thông tin ngăn xếp cuộc gọi?

+5

Vì vậy, có thể bạn đã đọc điều này, nhưng tôi không biết, vì vậy đừng lo lắng, vui lòng;) [Lua callstack with C++ debugger] (http://zeuxcg.org/2010/11/07/lua-callstack-với-c-debugger /) –

+0

@macs Đó là một tổng quan khá tuyệt vời. Phần "Kiểm tra cấu trúc dữ liệu Lua" là chìa khóa. Tôi đã làm việc ra hầu hết nhưng nó khá cồng kềnh để sử dụng. Tôi có lẽ sẽ xem xét để viết một số macro/script GDB để làm cho nó hoàn toàn khả thi. –

+0

Tôi rất vui khi đưa cho bạn một bàn tay giúp đỡ, đó cũng là [StackTracePlus] (https://github.com/ignacio/StackTracePlus) nhưng bạn sẽ phải sửa đổi chức năng gọi C, nếu tôi đúng. Vì vậy, nó khá vô ích trong trường hợp cụ thể này. –

Trả lời

8

tôi đã tạo ra một kịch bản GDB để làm những thứ trong trang web liên quan đến bằng Mac. Nó không đẹp, và có lẽ nên được bao bọc đúng cách vào một chức năng vv, nhưng ở đây nó là cho tò mò.

LƯU Ý: Dường như trang web không đúng về tên tệp cho các hàm lua. Trong trường hợp chuỗi xuất phát từ luaL_dofile(), tên tệp bắt đầu bằng ký hiệu @. Nếu chúng được gọi từ lua_dostring(). Trong trường hợp đó biến số $filename được đặt thành toàn bộ chuỗi được chuyển đến lua_dostring() - và người dùng có lẽ chỉ quan tâm đến một hoặc hai dòng ngữ cảnh từ tệp đó. Tôi không chắc cách sửa lỗi đó.

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 

này kết quả đầu ra một cái gì đó như:

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

Khi tôi gỡ lỗi các vụ tai nạn từ mã này:

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

Với a.lua

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

và b.lua

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

Dựa trên các nhận xét ở trên, tôi khuyên bạn nên sử dụng bài viết sau: Lua callstack with C++ debugger. Nó đưa ra một tổng quan tốt về việc gỡ lỗi kết hợp Lua/C++, đặc biệt là phần "Kiểm tra cấu trúc dữ liệu Lua" là hữu ích, khi nói đến gỡ lỗi các bãi lõi.

+1

Được trao giải thưởng tiền thưởng này vì nó là những gì cho phép tôi nhận được giải pháp (một phần) của tôi. –

4

Bạn có thể xem Lua GDB helpers của mình. Nó là một tập hợp các macro cho phép bạn kiểm tra stack và các giá trị, và thậm chí in backtrace. Về cơ bản, bài viết được tham chiếu bởi các mac chứa trong một gói đơn giản để sử dụng.

Nó cung cấp các macro:

  • luastack [L] - liệt kê các giá trị trên hiện chồng Lua C.

  • luaprint <value> [verbose] - In đẹp một TValue được chuyển làm đối số. Mong đợi một con trỏ đến một TValue. Khi tiết là 1, mở rộng các bảng, các siêu dữ liệu và môi trường userdata.

  • luaprinttable <table> - In đẹp một bảng Lua. Mong một con trỏ đến Bảng.

  • luavalue <index> [L] - Dumps một giá trị duy nhất tại chỉ mục.

  • luatraceback [L] - Cuộc gọi debug.traceback(). Không chắc chắn nếu nó sẽ làm việc trên tập tin lõi dù ...

+0

Rõ ràng, các macro của bạn sử dụng phương pháp tiếp cận số 1, gọi phương thức Lua để có được ngăn xếp. Nó sẽ không làm việc với một bãi chứa lõi. –

+0

Hmmm, có vẻ như tôi sẽ phải thực hiện nhiều chức năng hơn trong GDB thuần túy :) –

+0

Sau khi xem xét kỹ lưỡng các nguồn Lua, tôi từ bỏ việc triển khai dấu vết ngăn xếp trong GDB, vì ví dụ để lấy tên hàm, [ bạn phải kiểm tra bytecode] (http://www.lua.org/source/5.1/ldebug.c.html#symbexec). Tôi không chắc chắn nó thực sự có thể làm ngoại tuyến. –

6

Đây là một biến thể nhỏ đối với tập lệnh GDB của Michael Anderson: Tôi phải sử dụng điều này vì tôi gặp phải lỗi Cannot access memory at address 0x656d với tập lệnh của mình do L->base_ci không hợp lệ trong kết xuất cốt lõi của tôi. Điều này bắt đầu từ khung trên cùng (L->ci) và đi xuống theo hướng ngược lại, tránh con trỏ L->base_ci không hợp lệ.

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 
Các vấn đề liên quan