2011-02-14 17 views
6

मैं विंडोज निष्पादन योग्य में कॉल स्टैक प्राप्त करने के लिए संघर्ष कर रहा हूं। मैंने कॉल स्टैक प्राप्त करने के कई अलग-अलग तरीकों की कोशिश की है। निम्नलिखित कुछ उदाहरण हैं। ध्यान दें कि मैंने उन्हें थोड़ा सा संशोधित किया है और उन्हें समझने में आसान बनाने के लिए त्रुटि प्रबंधन को हटा दिया है, इसलिए वे संकलित नहीं हो सकते हैं। मुझे लगता है आपको बात समझ में आ गयी है।रिलीज में कॉल स्टैक प्राप्त करने में समस्याएं

आसान तरीका:

const int max_entries = 10; 
void *entries[max_entries]; 
return CaptureStackBackTrace(0, max_entries, entries, 0); 

निम्न स्तर रास्ता:

const int max_entries = 10; 
void *entries[max_entries]; 

void **frame = 0; 
__asm { mov frame, ebp } 
unsigned int i = 0; 
while(frame && i < max_entries) { 
    entries[i++] = frame[1]; 
    frame = (void **)frame[0]; 
} 

संगत तरीका:

void *entries[max_entries]; 
CONTEXT context; 
RtlCaptureContext(&context); 
STACKFRAME64 stack_frame; 
ZeroMemory(&stack_frame, sizeof(STACKFRAME64)); 
stack_frame.AddrPC.Offset = context.Eip; 
stack_frame.AddrPC.Mode  = AddrModeFlat; 
stack_frame.AddrFrame.Offset = context.Ebp; 
stack_frame.AddrFrame.Mode = AddrModeFlat; 
stack_frame.AddrStack.Offset = context.Esp; 
stack_frame.AddrStack.Mode = AddrModeFlat; 

unsigned int num_frames = 0; 
while (true) { 
    if (!StackWalk64(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), 
     GetCurrentThread(), &stack_frame, &context, NULL, 
     SymFunctionTableAccess64, SymGetModuleBase64, NULL)) 
     break; 

    if (stack_frame.AddrPC.Offset == 0) 
     break; 

    entries[num_frames++] = reinterpret_cast<void *>(stack_frame.AddrPC.Offset); 
} 

मेरे समस्या यह है कि वे एक unoptimized निर्माण में काम है, लेकिन पूर्ण अनुकूलन के साथ नहीं। क्या होता है कि मुझे एक टूटी हुई प्रविष्टि मिलती है और फिर वे अपने लूप से बाहर निकलते हैं। डीबग में मुझे पूर्ण कॉल स्टैक मिलता है और जब मैं बाद में प्रतीकों को देखता हूं, तो यह सब सही है।

मुझे समझ में नहीं आता कि यह काम सभी कार्यों में कैसे करना मुश्किल हो सकता है जब डीबगर इसे हर समय करता है। मैं विशेष रूप से कह सकता हूं कि फ्रेम पॉइंटर्स कोड पीढ़ी में छोड़े नहीं जाते हैं। मैं पहले डीबग के लिए निर्माण करता हूं और फिर केवल ऑप्टिमाइज़ेशन को पूर्ण ऑप्टिमाइज़ेशन में बदलता हूं और कॉल स्टैक विफलता को पुन: पेश करने के लिए पुनर्निर्माण करता हूं।

किसी समाधान के लिए किसी भी संकेत की सराहना की जाएगी।

/जोनास

+0

आप फ्रेम सूचक अनुकूलन के साथ संकलित नहीं कर रहे हैं, है ना? –

+0

फ़्रेम पॉइंटर्स कोड जनरेशन में छोड़े नहीं जाते हैं, यदि आपका यही मतलब है। –

उत्तर

2

मैं अब "संगत रास्ता" का उपयोग इस काम के मिला है। मैं संदर्भ को प्रारंभ करने के लिए निम्न कोड का उपयोग करता हूं:

#define GET_CURRENT_CONTEXT(c, contextFlags) \ 
    do { \ 
     memset(&c, 0, sizeof(CONTEXT)); \ 
     c.ContextFlags = contextFlags; \ 
     __asm call x \ 
     __asm x: pop eax \ 
     __asm mov c.Eip, eax \ 
     __asm mov c.Ebp, ebp \ 
     __asm mov c.Esp, esp \ 
    } while(0); 

CONTEXT context; 
GET_CURRENT_CONTEXT(context, CONTEXT_FULL); 

और फिर पहले के रूप में StackWalk64 का उपयोग करके स्टैक लाने के लिए जारी रखें।

void *entries[max_entries]; 
STACKFRAME64 stack_frame; 
ZeroMemory(&stack_frame, sizeof(STACKFRAME64)); 
stack_frame.AddrPC.Offset = context.Eip; 
stack_frame.AddrPC.Mode  = AddrModeFlat; 
stack_frame.AddrFrame.Offset = context.Ebp; 
stack_frame.AddrFrame.Mode = AddrModeFlat; 
stack_frame.AddrStack.Offset = context.Esp; 
stack_frame.AddrStack.Mode = AddrModeFlat; 

unsigned int num_frames = 0; 
while (true) { 
    if (!StackWalk64(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), 
     GetCurrentThread(), &stack_frame, &context, NULL, 
     SymFunctionTableAccess64, SymGetModuleBase64, NULL)) 
     break; 

    if (stack_frame.AddrPC.Offset == 0) 
     break; 

    entries[num_frames++] = reinterpret_cast<void *>(stack_frame.AddrPC.Offset); 
} 

मैंने देखा है कि मैं इसे RtlCaptureContext को भेजने से पहले संदर्भ संरचना स्पष्ट करने के लिए भूल गया तो मैं इस तरह यह करने के लिए (क्योंकि मैं RtlCaptureContext फ़ंक्शन का उपयोग करना पसंद करेंगे) की कोशिश की।

CONTEXT context; 
memset(&context, 0, sizeof(CONTEXT)); 
context.ContextFlags = CONTEXT_FULL; 
RtlCaptureContext(&context); 

अब RtlCaptureContext दुर्घटनाओं, तो मैं GET_CURRENT_CONTEXT मैक्रो का उपयोग करने के लिए वापस चला गया।

मैं RtlCaptureContext अंदर लेकिन केवल 32-बिट पर डीबग बनाता है और नहीं पर 32-बिट रिलीज छिटपुट दुर्घटनाओं दिखाई दे रही है:

+0

हाय जोनास, अनुकूलित बिल्डों में वास्तविक फ़ंक्शन नामों पर पुनर्प्राप्त प्रविष्टियों [] को मानचित्र करना संभव है? मुझे गलत परिणाम मिलता है। क्या आपके पास कोई उदाहरण है? –

0

यह एक जवाब है, लेकिन सिर्फ एक "मुझे भी" रिपोर्ट विशिष्ट संस्करणों स्पष्ट करने के लिए नहीं है बनाता है, और डीबग या रिलीज 64-बिट बिल्ड पर नहीं। मैं VS2008 SP1 का उपयोग कर रहा हूं dbghelp.dll फ़ाइल संस्करण 6.12.2.633 विंडोज़ के लिए डिबगिंग टूल्स से 25 अप्रैल, 2011 को डाउनलोड किया गया था, और dbghelp.dll ने उसी एक्सचेंज में मेरे एक्सई के रूप में उसी निर्देशिका में कॉपी किया था।

यह उसी विंडोज एक्सपी 64-बिट एसपी 2 मशीन पर वीएस -2008 एसपी 1 कंपाइलर की सटीक उसी रिलीज का उपयोग करके संकलित करने के साथ है (32-बिट और 64-बिट देशी ऐप्स दोनों को संकलित करता है, कोई भी .NET प्रबंधित कोड बिल्कुल नहीं है मिश्रण)।

ऊपर की कुंजी यह स्पोरैडिक प्रकृति है। मैंने उन स्थितियों को निर्धारित नहीं किया है जिनके द्वारा यह दुर्घटनाग्रस्त हो जाता है।

संबंधित मुद्दे