2011-12-16 12 views
20

का उपयोग कर कोर फ़ाइल से लुआ स्टैक ट्रेस कैसे प्राप्त कर सकता हूं मेरे पास एक सी ++ एप्लिकेशन (ओएस एक्स के लिए) है जो लुआ को एक स्क्रिप्टिंग भाषा के रूप में कॉल करता है। मैं इन अनुप्रयोगों (100s) की एक बड़ी संख्या चला रहा हूं और वे बहुत लंबे समय (दिन या सप्ताह) के लिए चला सकते हैं।मैं gdb

कभी-कभी कोई दुर्घटनाग्रस्त हो जाता है। और जब यह दुर्घटनाग्रस्त हो जाता है तो यह मुझे एक सुंदर कोर फ़ाइल छोड़ देता है।

मैं इस कोर फ़ाइल को जीडीबी में खोल सकता हूं और यह पता लगा सकता हूं कि एप्लिकेशन कहां दुर्घटनाग्रस्त हो जाता है। मैं कॉल स्टैक चला सकता हूं और lua_State चर का उदाहरण ढूंढ सकता हूं। मेरे समस्या यह है कि मैं lua कॉल स्टैक इस समय कैसा दिखता देखना चाहते हैं है ...

सी कार्यों बुला लिए ध्यान रखें कि जब से यह है एक कोर मैं पहुँच नहीं है जो लुआ स्क्रिप्ट्स को डिबग करने के सामान्य तरीकों के नियमों का पालन करता है।

आईडी डीबग हुक के माध्यम से मैन्युअल निशान जोड़ने से बचने के लिए पसंद है क्योंकि मैं अतिरिक्त प्रदर्शन दंड के बारे में चिंतित हूं, और जटिलता जोड़ा गया है।

कॉल स्टैक जानकारी प्राप्त करने के लिए मैं लुआ आंतरिक संरचनाओं को कैसे पार कर सकता हूं?

+5

तो, हो सकता है आप यह पहले से ही कृपया पढ़ा है, लेकिन मैं नहीं जानता, इसलिए grumpy मत हो,;) [लुआ callstack साथ सी ++ डीबगर] (http://zeuxcg.org/2010/11/07/lua-callstack-with-c-debugger /) –

+0

@macs यह एक बहुत अच्छा अवलोकन है। "लूआ डेटा संरचनाओं का निरीक्षण करें" खंड कुंजी है। मैं उसमें से अधिकांश काम करता था लेकिन इसका उपयोग करने के लिए यह बहुत ही बोझिल था। मैं इसे व्यावहारिक बनाने के लिए शायद कुछ जीडीबी मैक्रोज़/स्क्रिप्ट लिखना चाहूंगा। –

+0

मैं आपको एक सहायक हाथ देने में प्रसन्न हूं, [स्टैकट्रेसप्लस] (https://github.com/ignacio/StackTracePlus) भी है, लेकिन अगर मैं सही हूं तो आपको कॉलिंग सी फ़ंक्शन को संशोधित करना होगा। तो यह इस विशेष मामले में बेकार है। –

उत्तर

8

मै मैक्स द्वारा लिंक किए गए वेब पेज में सामान करने के लिए एक जीडीबी स्क्रिप्ट बनाई है। यह सुंदर नहीं है, और शायद एक समारोह में ठीक से लपेटा जाना चाहिए, लेकिन यहां यह उत्सुकता के लिए है।

नोट: ऐसा लगता है कि वेब पेज lua कार्यों के लिए फ़ाइल नाम के बारे में गलत है। उस स्थिति में जहां स्ट्रिंग luaL_dofile() से आता है, फ़ाइल नाम @ प्रतीक से शुरू होता है। अगर उन्हें lua_dostring() से बुलाया जाता है। उस स्थिति में $filename चर lua_dostring() पर पारित की गई पूरी स्ट्रिंग पर सेट है - और उपयोगकर्ता शायद उस फ़ाइल से संदर्भ की एक या दो पंक्तियों में रुचि रखते हैं। मुझे यकीन नहीं था कि इसे कैसे ठीक किया जाए।

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 

कुछ इस तरह आउटपुट:

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

मुझे इस कोड से दुर्घटना डिबग:

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

साथ a.lua

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

और b.lua

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

उपर्युक्त टिप्पणियों के आधार पर, मैं निम्नलिखित लेख की सिफारिश करता हूं: Lua callstack with C++ debugger। यह लूआ/सी ++ संयोजन को डीबग करने के बारे में एक अच्छा अवलोकन दे रहा है, विशेष रूप से "लू डेटा संरचनाओं का निरीक्षण करें" अनुभाग उपयोगी है, जब कोर डंप की डीबगिंग की बात आती है।

+1

ने इसे बक्षीस दिया क्योंकि यह मुझे मेरे (आंशिक) समाधान तक पहुंचने देता है। –

4

आप मेरी Lua GDB helpers देख सकते हैं। यह मैक्रोज़ का एक संग्रह है जो आपको ढेर और मूल्यों का निरीक्षण करने देता है, और यहां तक ​​कि बैकट्रैक प्रिंट भी करता है। अनिवार्य रूप से मैक द्वारा संदर्भित लेख में, उपयोग में आसान पैकेज में शामिल है।

यह इन मैक्रो प्रदान करता है:

  • luastack [L] - वर्तमान लुआ सी स्टैक पर मान सूचीबद्ध करता है।

  • luaprint <value> [verbose] - सुंदर टीवी प्रिंट को तर्क के रूप में पारित करता है। एक टीवीएयू के लिए एक सूचक की उम्मीद है। जब वर्बोज़ 1 होता है, टेबल, मेटाटेबल्स और उपयोगकर्ताडेटा वातावरण का विस्तार करता है।

  • luaprinttable <table> - सुंदर-लू टेबल प्रिंट करता है। टेबल के लिए एक सूचक की उम्मीद है।

  • luavalue <index> [L] - एक सूचकांक में एक एकल मूल्य डंप करता है।

  • luatraceback [L] - कॉल debug.traceback()। सुनिश्चित नहीं है कि यह कोर फ़ाइल पर काम करेगा हालांकि ...

+0

स्पष्ट रूप से, आपके मैक्रोज़ दृष्टिकोण संख्या 1 का उपयोग करते हैं, जो स्टैक प्राप्त करने के लिए लुआ विधियों को बुलाते हैं। यह कोर डंप के साथ काम नहीं करेगा। –

+0

हम्म, ऐसा लगता है कि मुझे शुद्ध जीडीबी में अधिक कार्यक्षमता लागू करनी होगी :) –

+0

लुआ स्रोतों पर एक लंबा और पूर्ण रूप से देखने के बाद, मैं जीडीबी में स्टैक ट्रेस को कार्यान्वित करना छोड़ देता हूं, क्योंकि उदाहरण के लिए फ़ंक्शन नाम प्राप्त करने के लिए, [ आपको बाइटकोड का निरीक्षण करना होगा] (http://www.lua.org/source/5.1/ldebug.c.html#symbexec)। मुझे यकीन नहीं है कि ऑफ़लाइन करना वास्तव में संभव है। –

6

यह माइकल एंडरसन की GDB स्क्रिप्ट के लिए एक छोटा सा बदलाव है: मैं क्योंकि मैं उसकी स्क्रिप्ट के साथ Cannot access memory at address 0x656d त्रुटियों हो रही थी, L->base_ci की वजह से मेरी कोर डंप में अमान्य किया जा रहा है इस का उपयोग करने के लिए किया था। यह शीर्ष फ्रेम (L->ci) से शुरू होता है और अमान्य 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