अपने .NET लैंग्वेज स्टेप को डिबगर में सही तरीके से बनाना


135

सबसे पहले, मैं इस प्रश्न की लंबाई के लिए माफी माँगता हूँ।

मैं आयरनस्चेम का लेखक हूं । हाल ही में मैं सभ्य डिबग जानकारी का उत्सर्जन करने के लिए कड़ी मेहनत कर रहा हूं, ताकि मैं 'मूल' .NET डीबगर का उपयोग कर सकूं।

हालांकि यह आंशिक रूप से सफल रहा है, मैं कुछ शुरुआती समस्याओं में भाग रहा हूं।

पहली समस्या कदम से संबंधित है।

योजना एक अभिव्यक्ति की भाषा होने के कारण, सब कुछ मुख्य .NET भाषाओं के विपरीत, कोष्ठक में लिपटे रहने की प्रवृत्ति है, जो कि कथन (या पंक्ति) पर आधारित लगता है।

मूल कोड (योजना) इस प्रकार है:

(define (baz x)
  (cond
    [(null? x) 
      x]
    [(pair? x) 
      (car x)]
    [else
      (assertion-violation #f "nooo" x)]))

मैं उद्देश्य पर एक नई लाइन पर प्रत्येक अभिव्यक्ति रखी है।

उत्सर्जित कोड C (# ILSpy के माध्यम से) रूपांतरित होता है:

public static object ::baz(object x)
{
  if (x == null)
  {
    return x;
  }
  if (x is Cons)
  {
    return Builtins.Car(x);
  }
  return #.ironscheme.exceptions::assertion-violation+(
     RuntimeHelpers.False, "nooo", Builtins.List(x));
}

जैसा कि आप देख सकते हैं, बहुत आसान है।

नोट: यदि कोड एक सशर्त अभिव्यक्ति में बदल गया था (? :) C C में, तो पूरी बात सिर्फ एक डिबग कदम होगी, इसे ध्यान में रखें।

यहाँ स्रोत और लाइन नंबरों के साथ IL आउटपुट है:

  .method public static object  '::baz'(object x) cil managed
  {
    // Code size       56 (0x38)
    .maxstack  6
    .line 15,15 : 1,2 ''
//000014: 
//000015: (define (baz x)
    IL_0000:  nop
    .line 17,17 : 6,15 ''
//000016:   (cond
//000017:     [(null? x) 
    IL_0001:  ldarg.0
    IL_0002:  brtrue     IL_0009

    .line 18,18 : 7,8 ''
//000018:       x]
    IL_0007:  ldarg.0
    IL_0008:  ret

    .line 19,19 : 6,15 ''
//000019:     [(pair? x) 
    .line 19,19 : 6,15 ''
    IL_0009:  ldarg.0
    IL_000a:  isinst [IronScheme]IronScheme.Runtime.Cons
    IL_000f:  ldnull
    IL_0010:  cgt.un
    IL_0012:  brfalse    IL_0020

    IL_0017:  ldarg.0
    .line 20,20 : 7,14 ''
//000020:       (car x)]
    IL_0018:  tail.
    IL_001a:  call object [IronScheme]IronScheme.Runtime.Builtins::Car(object)
    IL_001f:  ret

    IL_0020:  ldsfld object 
         [Microsoft.Scripting]Microsoft.Scripting.RuntimeHelpers::False
    IL_0025:  ldstr      "nooo"
    IL_002a:  ldarg.0
    IL_002b:  call object [IronScheme]IronScheme.Runtime.Builtins::List(object)
    .line 22,22 : 7,40 ''
//000021:     [else
//000022:       (assertion-violation #f "nooo" x)]))
    IL_0030:  tail.
    IL_0032:  call object [ironscheme.boot]#::
       'ironscheme.exceptions::assertion-violation+'(object,object,object)
    IL_0037:  ret
  } // end of method 'eval-core(033)'::'::baz'

नोट: डीबगर को पूरी विधि को केवल हाइलाइट करने से रोकने के लिए, मैं विधि प्रविष्टि बिंदु को सिर्फ 1 कॉलम चौड़ा बनाता हूं।

जैसा कि आप देख सकते हैं, प्रत्येक अभिव्यक्ति एक पंक्ति में सही ढंग से मैप करती है।

अब कदम के साथ समस्या (VS2010 पर परीक्षण किया गया, लेकिन VS2008 पर समान / समान मुद्दा):

ये IgnoreSymbolStoreSequencePointsलागू नहीं हैं।

  1. नल आर्ग के साथ बाज को कॉल करें, यह सही ढंग से काम करता है। (null? x) x के बाद।
  2. विपक्ष के साथ कॉल बाज, यह सही ढंग से काम करता है। (नल? x) तब (जोड़ी? x) तब (कार x)।
  3. अन्य आर्ग के साथ बाज को कॉल करें, यह विफल रहता है। (null? x) तब (जोड़ी? x) तब (कार x) फिर (जोर-उल्लंघन ...)।

आवेदन करते समय IgnoreSymbolStoreSequencePoints(अनुशंसित के रूप में):

  1. नल आर्ग के साथ बाज को कॉल करें, यह सही ढंग से काम करता है। (null? x) x के बाद।
  2. विपक्ष के साथ कॉल बाज, यह विफल रहता है। (नल? x) तब (जोड़ी? x)।
  3. अन्य आर्ग के साथ बाज को कॉल करें, यह विफल रहता है। (null? x) तब (जोड़ी? x) तब (कार x) फिर (जोर-उल्लंघन ...)।

मुझे इस विधा में भी पता चलता है कि कुछ लाइनें (यहां नहीं दिखाई गई हैं) गलत तरीके से हाइलाइट की गई हैं, वे 1 से बंद हैं।

यहाँ कुछ विचार दिए गए हैं कि क्या कारण हो सकते हैं:

  • Tailcalls डिबगर को भ्रमित करता है
  • ओवरलैपिंग स्थानों (यहाँ नहीं दिखाया गया है) डिबगर को भ्रमित करता है (ब्रेकपॉइंट सेट करते समय यह बहुत अच्छा करता है)
  • ????

दूसरा, लेकिन गंभीर भी है, समस्या कुछ मामलों में ब्रेकपॉइंट को तोड़ने / हिट करने में विफल डिबगर है।

एकमात्र स्थान जहां मैं डिबगर को सही तरीके से (और लगातार) तोड़ने के लिए प्राप्त कर सकता हूं, विधि प्रविष्टि बिंदु पर है।

IgnoreSymbolStoreSequencePointsलागू नहीं होने पर स्थिति थोड़ी बेहतर हो जाती है।

निष्कर्ष

यह हो सकता है कि वी.एस. डीबगर सिर्फ सादा छोटी गाड़ी है :(

संदर्भ:

  1. एक CLR / .NET भाषा डीबग करने योग्य बनाना

अपडेट 1:

Mdbg 64-बिट असेंबलियों के लिए काम नहीं करता है। तो वह बाहर है। मेरे पास इस पर परीक्षण करने के लिए और अधिक 32-बिट मशीनें नहीं हैं। अद्यतन: मुझे यकीन है कि यह कोई बड़ी समस्या नहीं है, क्या किसी को भी ठीक करना है? संपादित करें: हाँ, मुझे मूर्ख, बस x64 कमांड प्रॉम्प्ट के तहत mdbg शुरू करें :)

अपडेट 2:

मैंने एक C # ऐप बनाया है, और लाइन की जानकारी को अलग करने की कोशिश की है।

मेरे निष्कर्ष:

  • किसी भी brXXXनिर्देश के बाद आपको एक अनुक्रम बिंदु (यदि मान्य aka '#line छिपा हुआ नहीं है, तो उत्सर्जन करें nop)' की आवश्यकता है।
  • किसी भी brXXXनिर्देश से पहले , एक '# छिपी हुई' और ए का उत्सर्जन करें nop

इसे लागू करना, हालांकि मुद्दों (अकेले?) को ठीक नहीं करता है।

लेकिन निम्नलिखित को जोड़ने से वांछित परिणाम मिलता है :)

  • बाद में ret, '# छिपी हुई' और ए का उत्सर्जन करें nop

यह उस मोड का उपयोग कर रहा है जहां IgnoreSymbolStoreSequencePointsलागू नहीं है। जब लागू किया जाता है, तो कुछ कदम अभी भी छोड़ दिए जाते हैं :(

यहाँ IL आउटपुट है जब ऊपर लागू किया गया है:

  .method public static object  '::baz'(object x) cil managed
  {
    // Code size       63 (0x3f)
    .maxstack  6
    .line 15,15 : 1,2 ''
    IL_0000:  nop
    .line 17,17 : 6,15 ''
    IL_0001:  ldarg.0
    .line 16707566,16707566 : 0,0 ''
    IL_0002:  nop
    IL_0003:  brtrue     IL_000c

    .line 16707566,16707566 : 0,0 ''
    IL_0008:  nop
    .line 18,18 : 7,8 ''
    IL_0009:  ldarg.0
    IL_000a:  ret

    .line 16707566,16707566 : 0,0 ''
    IL_000b:  nop
    .line 19,19 : 6,15 ''
    .line 19,19 : 6,15 ''
    IL_000c:  ldarg.0
    IL_000d:  isinst     [IronScheme]IronScheme.Runtime.Cons
    IL_0012:  ldnull
    IL_0013:  cgt.un
    .line 16707566,16707566 : 0,0 ''
    IL_0015:  nop
    IL_0016:  brfalse    IL_0026

    .line 16707566,16707566 : 0,0 ''
    IL_001b:  nop
    IL_001c:  ldarg.0
    .line 20,20 : 7,14 ''
    IL_001d:  tail.
    IL_001f:  call object [IronScheme]IronScheme.Runtime.Builtins::Car(object)
    IL_0024:  ret

    .line 16707566,16707566 : 0,0 ''
    IL_0025:  nop
    IL_0026:  ldsfld object 
      [Microsoft.Scripting]Microsoft.Scripting.RuntimeHelpers::False
    IL_002b:  ldstr      "nooo"
    IL_0030:  ldarg.0
    IL_0031:  call object [IronScheme]IronScheme.Runtime.Builtins::List(object)
    .line 22,22 : 7,40 ''
    IL_0036:  tail.
    IL_0038:  call object [ironscheme.boot]#::
      'ironscheme.exceptions::assertion-violation+'(object,object,object)
    IL_003d:  ret

    .line 16707566,16707566 : 0,0 ''
    IL_003e:  nop
  } // end of method 'eval-core(033)'::'::baz'

अपडेट 3:

ऊपर 'सेमी-फिक्स' के साथ समस्या। nopबाद के कारण सभी तरीकों पर रिपोर्टों की त्रुटियों का लाभ उठाएं ret। मैं वास्तव में समस्या को नहीं समझता। एक के nopबाद एक ब्रेक सत्यापन कैसे हो सकता है ret। यह मृत कोड की तरह है (सिवाय इसके कि यह कोड भी नहीं है) ... ओह ठीक है, प्रयोग जारी है।

अपडेट 4:

घर पर वापस, अब 'अपरिवर्तनीय' कोड को हटा दिया, VS2008 पर चल रहा है और चीजें बहुत खराब हैं। शायद उचित डिबगिंग के लिए अपरिवर्तनीय कोड चलाना उत्तर हो सकता है। 'रिलीज़' मोड में, सभी आउटपुट अभी भी सत्यापन योग्य होंगे।

अपडेट 5:

मैंने अब निर्णय लिया है कि मेरा उपरोक्त विचार अब के लिए एकमात्र व्यवहार्य विकल्प है। यद्यपि उत्पन्न कोड अपरिवर्तनीय है, मुझे अभी तक कोई भी पता नहीं है VerificationException। मुझे नहीं पता कि इस परिदृश्य के साथ अंतिम उपयोगकर्ता पर क्या प्रभाव पड़ेगा।

एक बोनस के रूप में, मेरा दूसरा मुद्दा भी हल हो गया है। :)

यहाँ मैं क्या साथ समाप्त की एक छोटी सी पेंच है। यह ब्रेकपॉइंट्स को हिट करता है, उचित स्टेपिंग (इन / आउट / ओवर), आदि सभी में, वांछित प्रभाव।

हालाँकि, मैं अभी भी इसे करने के तरीके के रूप में स्वीकार नहीं कर रहा हूँ। यह मुझ पर भारी लग रहा है। असली मुद्दे पर पुष्टि होने के बाद अच्छा होगा।

अद्यतन 6:

बस VS2010 पर कोड का परीक्षण करने के लिए परिवर्तन किया गया था, कुछ समस्याएं हैं:

  1. पहला कॉल अब सही तरीके से नहीं होता है। (जोर-आजमाइश ...) हिट है। अन्य मामले ठीक काम करते हैं। कुछ पुराने कोड अनावश्यक पदों का उत्सर्जन करते हैं। कोड को हटा दिया, उम्मीद के मुताबिक काम करता है। :)
  2. अधिक गंभीरता से, ब्रेकपॉइंट प्रोग्राम के दूसरे आह्वान पर विफल होते हैं (इन-मेमोरी संकलन का उपयोग करते हुए, फाइल को असेंबली डंप करना ब्रेकपॉइंट को फिर से खुश करने के लिए लगता है)।

ये दोनों मामले VS2008 के तहत सही तरीके से काम करते हैं। मुख्य अंतर यह है कि VS2010 के तहत, संपूर्ण अनुप्रयोग .NET 4 के लिए और VS2008 के तहत, .NET 2 के लिए संकलित है। दोनों 64-बिट चल रहे हैं।

अपडेट 7:

उल्लेख के अनुसार, मैं 64-बिट के तहत mdbg चला रहा हूं। दुर्भाग्य से, इसका ब्रेकपॉइंट मुद्दा भी है जहां यह टूटने में विफल रहता है अगर मैं कार्यक्रम को फिर से चलाता हूं (इसका मतलब है कि यह फिर से व्यवस्थित हो जाता है, इसलिए एक ही विधानसभा का उपयोग नहीं कर रहा है, लेकिन अभी भी उसी स्रोत का उपयोग कर रहा है)।

अपडेट 8:

मैंने ब्रेक कनेक्ट मुद्दे के बारे में एमएस कनेक्ट साइट पर एक बग दर्ज किया है।

अपडेट: फिक्स्ड

अपडेट 9:

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


किसी भी विचार का स्वागत करते हैं, मैं उन्हें बाहर की कोशिश करेंगे और प्रश्न के परिणामों को जोड़ देंगे। पहले 2 विचार, mdbg आज़माएं और C # में समान कोड लिखें और तुलना करें।
लीपी

6
प्रश्न क्या है?
जॉर्ज स्टॉकर

9
मुझे लगता है कि उनका सवाल "मेरी भाषा सही तरीके से क्यों नहीं चल रही है?"
मैके

1
यदि आप उत्तीर्ण नहीं करते हैं तो आप आंशिक ट्रस्ट स्थितियों में नहीं चल सकते हैं, जैसे कि मैप की गई ड्राइव से या सेटअप की मेजबानी करने वाले कई प्लगइन में। आप अपने आईएल को कैसे पैदा कर रहे हैं, प्रतिबिंब। पाठ या ilasm के माध्यम से। किसी भी मामले में आप हमेशा इनलाइन 16707566,16707566: 0,0 '' डाल सकते हैं, अपने आप को इस तरह से कि आप उन्हें वापसी के बाद एक नाक डाल के बारे में चिंता करने की ज़रूरत नहीं है।
हिप्पीहंटर

@ हिप्पहुंटर: धन्यवाद। दुर्भाग्य से एस के बिना nop, चरणबद्धता विफल हो जाती है (मैं यह सुनिश्चित करने के लिए फिर से सत्यापित करूंगा)। यह एक ऐसा बलिदान है जो मुझे लगता है कि मुझे बनाना होगा। यह ऐसा नहीं है कि वीएस बिना प्रशासक अधिकारों के भी चल सकता है :) रिफ्लेक्शन का उपयोग करके Btw। DLR के माध्यम से स्वीकार करें (एक बहुत जल्दी हैक की गई शाखा)।
17

जवाबों:


26

मैं विजुअल स्टूडियो डीबगर टीम में एक इंजीनियर हूं।

गलत होने पर मुझे सही करें, लेकिन ऐसा लगता है कि केवल एक ही मुद्दा बचा है कि PDBs से .NET 4 डायनामिक कंपाइल सिंबल फॉर्मेट में स्विच करते समय कुछ ब्रेकप्वाइंट छूट रहे हैं।

इस समस्या का सटीक निदान करने के लिए हमें शायद एक रिप्रो की आवश्यकता होगी, हालाँकि यहाँ कुछ नोट हैं जो मदद कर सकते हैं।

  1. वीएस (2008+) एक गैर-व्यवस्थापक के रूप में चल सकता है
  2. क्या कोई भी प्रतीक चारों ओर दूसरी बार लोड होता है? आप (अपवाद या कॉल के माध्यम से परीक्षण कर सकते हैं। System.Diagnostic.Debugger.Break ()
  3. मान लें कि प्रतीकों को लोड किया गया है, तो क्या आप हमें भेज सकते हैं?
  4. संभावित अंतर यह है कि डायनेमिक-संकलित कोड के लिए प्रतीक प्रारूप .NET 2 (PDB स्ट्रीम) और .NET 4 (IL DB के बीच 100% भिन्न है) मुझे लगता है कि वे इसे कहते हैं?)
  5. सही के बारे में 'एनओपी की आवाज। नीचे दिए गए निहितार्थ अंक बनाने के लिए नियम देखें।
  6. आपको वास्तव में अलग-अलग लाइनों पर चीजों का उत्सर्जन करने की आवश्यकता नहीं है। डिफ़ॉल्ट रूप से, VS 'सिम्बल-स्टेटमेंट्स' को स्टेप करेगा, जहाँ संकलक लेखक के रूप में आपको परिभाषित करना है कि 'सिंबल-स्टेटमेंट' का क्या अर्थ है। इसलिए यदि आप चाहते हैं कि प्रत्येक अभिव्यक्ति प्रतीक फ़ाइल में एक अलग चीज हो, तो यह ठीक काम करेगा।

JIT निम्नलिखित नियमों के आधार पर एक अंतर्निहित अनुक्रम बिंदु बनाता है: 1. IL nop निर्देश 2. IL स्टैक खाली अंक 3. IL निर्देश तुरंत कॉल निर्देश का पालन करता है

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

अपडेट करें:

हम अन्य उपयोगकर्ताओं को http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=27543 से Dev11 के डेवलपर पूर्वावलोकन को आज़माने के लिए इस समस्या का सामना करने के लिए प्रोत्साहित कर रहे हैं और किसी भी प्रतिक्रिया के साथ टिप्पणी कर सकते हैं। (लक्ष्य ४.५)

अपडेट 2:

लेप्पी ने उसके लिए काम करने के लिए फिक्स को सत्यापित किया है कि Dev11 के बीटा संस्करण पर उपलब्ध है http://www.microsoft.com/visualstudio/11/en-us/downloads जो कनेक्ट बग https://connect.microsoft में उल्लेखित है । com / VisualStudio / प्रतिक्रिया / विवरण / 684089 /

धन्यवाद,

ल्यूक


बहुत बहुत धन्यवाद। जरूरत पड़ने पर मैं रेप्रो बनाने की कोशिश करूंगा।
लीपी

पुष्टिकरण के लिए, हाँ आप सही हैं, लेकिन मैं अभी भी सत्यता को तोड़े बिना कदमों को हल करना पसंद करूंगा। लेकिन जैसा कि कहा गया है, मैं बलिदान करने को तैयार हूं कि अगर मैं संभवत: यह साबित कर सकूं कि यह एक रनटाइम नहीं होगा VerificationException
लीपी

बिंदु 6 के लिए, मैंने बस इस प्रश्न के लिए इसे 'लाइन-आधारित' बनाया। डीबगर वास्तव में / बाहर / ओवर एक्सप्रेशंस में सही तरीके से कदम रखता है जैसे कि मैं इसे काम करने का इरादा रखता हूं :) दृष्टिकोण के साथ एकमात्र समस्या 'इनर' भावों पर ब्रेकप्वाइंट सेट कर रही है अगर कोई 'बाहरी' अभिव्यक्ति इसे कवर करता है; डीएस में डीबगर सबसे बाहरी अभिव्यक्ति को ब्रेकपॉइंट के रूप में बनाना चाहते हैं।
लीपी

मुझे लगता है कि मैंने विराम बिंदु को अलग कर दिया है। CLR2 के तहत चलने के दौरान, कोड को फिर से चलाते समय ब्रेकपॉइंट का पुनर्मूल्यांकन किया जाता है, भले ही नया कोड हो। CLR4 पर, ब्रेकपॉइंट्स केवल मूल कोड को 'स्टिक' करते हैं। मैंने CLR4 व्यवहार का एक छोटा सा स्क्रैन्कास्ट बनाया है @ screencast.com/t/eiSilNzL5Nr । ध्यान दें कि प्रकार नाम चालान के बीच बदलता है।
लीपी

मैंने कनेक्ट पर एक बग दर्ज किया है।
रेप्रो

3

मैं SharpDevelop डीबगर टीम पर एक इंजीनियर हूँ :-)

क्या आपने समस्या का समाधान किया?

क्या आपने इसे SharpDevelop में डीबग करने का प्रयास किया था? यदि .NET में बग है, तो मुझे आश्चर्य होता है कि क्या हमें कुछ वर्कअराउंड लागू करने की आवश्यकता है। मुझे इस मुद्दे की जानकारी नहीं है।

क्या आपने इसे ILSpy में डीबग करने का प्रयास किया था? विशेष रूप से डिबग प्रतीकों के बिना। यह C # कोड को डिबग करेगा, लेकिन यह हमें बताएगा कि IL निर्देश अच्छी तरह से डिबग करने योग्य है या नहीं। (दिमाग है कि ILSpy डिबगर हालांकि बीटा है)

मूल आईएल कोड पर त्वरित नोट्स:

  • .line 19,19: 6,15 '' दो बार होता है?
  • .line 20,20: 7,14 '' निहित अनुक्रम बिंदु पर शुरू नहीं होता है (स्टैक खाली नहीं है)। मैं चिंतित हूँ
  • .line 20,20: 7,14 '' में "कार x" (अच्छा) के साथ-साथ "#f nooo x" (बुरा?) का कोड शामिल है
  • रिट के बाद एनओपी के बारे में। Stloc, ldloc, ret के बारे में क्या? मुझे लगता है कि C # इस ट्रिक का उपयोग रिटेन को एक अलग अनुक्रम बिंदु बनाने के लिए करता है।

डेविड


+1 प्रतिक्रिया के लिए धन्यवाद, पहले बिंदु के रूप में, कोड जनरेटर से दुर्भाग्यपूर्ण साइड-इफेक्ट, लेकिन हानिरहित लगता है। दूसरा बिंदु, यह वही है जो मुझे चाहिए, लेकिन मैं आपकी बात देखता हूं, इस पर गौर करूंगा। निश्चित नहीं कि आपको अंतिम बिंदु से क्या मतलब है।
लेप्पी

तीसरा बिंदु यह था कि .line 22,22: 7,40 '' IL_0020 से पहले होना चाहिए। या IL_0020 से पहले कुछ होना चाहिए, अन्यथा कोड अभी भी .line 20,20: 7,14 'के रूप में गिना जाता है। चौथा बिंदु "रिट, एनओपी" को "स्लोक, .line, ldloc, रिट" से बदला जा सकता है। मैंने पहले पैटर्न देखा है, शायद यह बेमानी था, लेकिन शायद इसका एक कारण था।
dsrbecky

मैं रिटेल से पहले स्टालोक, एलडॉक नहीं कर सकता, क्योंकि मैं पूंछ कॉल को ढीला कर दूंगा। आह मैं तुम्हें, तुम मूल उत्पादन की बात कर रहे थे?
लेप्पी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.