Hata ayıklayıcıda .NET dilinizi doğru şekilde adım adım atma


135

İlk olarak, bu sorunun uzunluğu için özür dilerim.

Ben yazarı değilim IronScheme . Son zamanlarda 'yerli' .NET hata ayıklayıcıyı kullanabilmem için iyi hata ayıklama bilgileri yaymaya çalışıyorum.

Bu kısmen başarılı olsa da, bazı diş çıkarma sorunlarıyla karşılaşıyorum.

İlk sorun adımlama ile ilgilidir.

Şema'nın bir ifade dili olması nedeniyle, ifade (veya satır) tabanlı görünen büyük .NET dillerinin aksine, her şey parantez içine alınma eğilimindedir.

Orijinal kod (Şema) şöyle görünür:

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

Her ifadeyi bir satırsonuna koymuştum.

Yayılan kod C # 'e (ILSpy aracılığıyla) dönüşür:

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

Gördüğünüz gibi oldukça basit.

Not: Kod C # 'da koşullu ifadeye (? :) dönüştürülmüşse, her şey bir hata ayıklama adımı olacaktır, bunu aklınızda bulundurun.

Kaynak ve satır numaraları ile IL çıkışı:

  .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'

Not: Hata ayıklayıcının tüm yöntemi basitçe vurgulamasını önlemek için, yöntem giriş noktasını sadece 1 sütun genişliğinde yapıyorum.

Gördüğünüz gibi, her ifade doğru bir çizgiyle eşleşir.

Şimdi adımlama sorunu (VS2010'da test edildi, ancak VS2008'de aynı / benzer sorun):

Bunlar IgnoreSymbolStoreSequencePointsuygulanmamıştır.

  1. Null arg ile baz deyin, doğru çalışıyor. (null? x) ardından x.
  2. Baz işlevini Cons arg ile arayın, doğru çalışıyor. (null? x) sonra (çift? x) sonra (araba x).
  3. Baz'ı diğer arg ile arayın, başarısız olur. (null? x) sonra (çift? x) sonra (araba x) sonra (onaylama ihlali ...).

Başvururken IgnoreSymbolStoreSequencePoints(önerildiği gibi):

  1. Null arg ile baz deyin, doğru çalışıyor. (null? x) ardından x.
  2. Eks arg ile baz deyin, başarısız olur. (null? x) sonra (pair? x).
  3. Baz'ı diğer arg ile arayın, başarısız olur. (null? x) sonra (çift? x) sonra (araba x) sonra (onaylama ihlali ...).

Ayrıca bu modda bazı satırların (burada gösterilmiyor) yanlış vurgulandığını, 1 ile kapandığını görüyorum.

İşte nedenlerin neler olabileceği hakkında bazı fikirler:

  • Kuyruk çağrıları hata ayıklayıcıyı karıştırır
  • Çakışan konumlar (burada gösterilmemiştir) hata ayıklayıcıyı karıştırır (kesme noktası ayarlarken çok iyi sonuç verir)
  • ????

İkinci ama aynı zamanda ciddi olan sorun, hata ayıklayıcının bazı durumlarda kesme noktalarını kırmaması / vurmamasıdır.

Hata ayıklayıcının doğru (ve tutarlı bir şekilde) kırılmasını sağlayabildiğim tek yer yöntem giriş noktasındadır.

IgnoreSymbolStoreSequencePointsUygulanmadığında durum biraz daha iyileşir .

Sonuç

VS hata ayıklayıcı sadece düz bir hata olabilir :(

Referanslar:

  1. CLR / .NET Dilinde Hata Ayıklanabilir Yapma

Güncelleme 1:

Mdbg 64 bit derlemelerde çalışmaz. Yani bu çıktı. Test etmek için artık 32-bit makinem yok. Güncelleme: Bunun büyük bir sorun olmadığından eminim, birinin düzeltmesi var mı? Düzenleme: Evet, aptal bana, sadece x64 komut istemi altında mdbg başlatın :)

Güncelleme 2:

Bir C # uygulaması oluşturdum ve satır bilgisini incelemeye çalıştım.

Bulgularım:

  • Herhangi bir brXXXtalimattan sonra bir sıralama noktasına sahip olmanız gerekir (geçerli değilse '#line gizli', a yayarsınız nop).
  • Herhangi bir brXXXtalimattan önce , '#line hidden' ve a nop.

Ancak bunu uygulamak, sorunları düzeltemez (yalnız mı?).

Ancak aşağıdakileri eklemek istediğiniz sonucu verir :)

  • Sonra ret, '#line hidden' ve a nop.

Bu, IgnoreSymbolStoreSequencePointsuygulanmayan modu kullanıyor . Uygulandığında, bazı adımlar atlanır :(

Yukarıda uygulandığında IL çıktısı:

  .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'

Güncelleme 3:

Yukarıdaki 'yarı düzeltme' ile ilgili sorun. Peverify, nopsonrası nedeniyle tüm yöntemlerle ilgili hataları bildirir ret. Sorunu gerçekten anlamıyorum. Nasıl bir nopmola doğrulamasından sonra a ret. Ölü kod gibidir (kod bile DEĞİLDİR hariç) ... Oh, deneyler devam ediyor.

Güncelleme 4:

Şimdi evde, VS2008 üzerinde çalışan 'doğrulanamayan' kod kaldırıldı ve işler çok daha kötü. Belki de uygun hata ayıklama uğruna doğrulanamayan kod çalıştırmak cevap olabilir. 'Serbest bırakma' modunda, tüm çıktılar hala doğrulanabilir.

Güncelleme 5:

Şimdi yukarıdaki fikrimin tek uygun seçenek olduğuna karar verdim. Oluşturulan kod doğrulanamaz olsa da, henüz herhangi bir bulmak VerificationException's. Bu senaryo ile son kullanıcı üzerindeki etkisinin ne olacağını bilmiyorum.

Bonus olarak, ikinci sayım da çözüldü. :)

İşte sonunda ne ile ilgili biraz screencast . Kesme noktalarına çarpar, uygun adım (giriş / çıkış / üst) vb. Yapar. Sonuç olarak, istenen etki.

Bununla birlikte, bunu hala bunu yapmanın yolu olarak kabul etmiyorum. Bana çok acayip geliyor. Gerçek konuda bir onay olması güzel olurdu.

Güncelleme 6:

VS2010'da kodu test etmek için değişiklik yaptım, bazı problemler var gibi görünüyor:

  1. İlk çağrı artık doğru adım atmıyor. (iddia ihlali ...) vuruldu. Diğer durumlarda iyi çalışıyor. Bazı eski kodlar gereksiz pozisyonlar çıkarmıştır. Kod kaldırıldı, beklendiği gibi çalışıyor. :)
  2. Daha ciddi olarak, kesme noktaları programın ikinci çağrısında başarısız olur (bellek içi derleme kullanarak, dosyaya damping montajı kesme noktalarını tekrar mutlu ediyor gibi görünüyor).

Bu iki durum da VS2008 altında düzgün çalışır. Temel fark VS2010 altında, tüm uygulamanın .NET 4 için derlenmiş olması ve VS2008 altında .NET 2 için derlenmesidir.

Güncelleme 7:

Belirtildiği gibi, 64 bit altında mdbg çalıştıran var. Ne yazık ki, programı yeniden çalıştırırsam kırılamayan kesme noktası sorunu da var (bu yeniden derlendiğini gösteriyor, bu yüzden aynı montajı değil, aynı kaynağı kullanıyor).

Güncelleme 8:

Ben var bir hata açtı kesme noktası konuyla ilgili MS Bağlan sitesinde.

Güncelleme: Sabit

Güncelleme 9:

Uzun bir düşünmeden sonra, hata ayıklayıcıyı mutlu etmenin tek yolu SSA yapmak gibi görünüyor, bu nedenle her adım izole edilebilir ve sıralanabilir. Yine de bu fikri kanıtlayamadım. Ama mantıklı görünüyor. Açıkçası, SSA'dan temper temizliği hata ayıklamayı kıracaktır, ancak bu geçiş yapmak kolaydır ve onları bırakmak çok fazla yüke sahip değildir.


Herhangi bir fikir hoş geldiniz, onları deneyeceğim ve sonuçları soruya ekleyeceğim. İlk 2 fikir, mdbg deneyin ve aynı kodu C # yazın ve karşılaştırın.
leppie

6
Soru nedir?
George Stocker

9
Bence onun sorusu "dilim neden doğru adım atılamıyor?"
McKay

1
Peverify'i geçmezseniz, eşlenmiş bir sürücü veya birçok eklenti barındırma kurulumunda olduğu gibi kısmi güven durumlarında çalışamazsınız. IL, yansıma formunuzu nasıl üretiyorsunuz? Her iki durumda da .line 16707566,16707566: 0,0 '' kendinizi her zaman koyabilirsiniz, böylece dönüşten sonra bir nop koyarak endişelenmenize gerek kalmaz.
Hippiehunter

@Hippiehunter: Teşekkürler. Ne yazık ki nops olmadan, adım başarısız olur (emin olmak için bunu tekrar doğrulayacağım). Sanırım yapmak zorunda olduğum bir fedakarlık. VS'nin yönetici hakları olmadan bile çalışabileceği gibi değil :) Reflection kullanarak BTW.
leppie

Yanıtlar:


26

Visual Studio Hata Ayıklayıcı ekibinde mühendisim.

Yanılıyorsam beni düzeltin, ancak kalan tek sorun PDB'lerden .NET 4 dinamik derleme sembol biçimine geçerken bazı kesme noktalarının kaçırıldığı gibi geliyor.

Sorunu tam olarak teşhis etmek için muhtemelen bir reproya ihtiyacımız olacak, ancak burada yardımcı olabilecek bazı notlar var.

  1. VS (2008+) yönetici olmayan olarak çalışabilir
  2. İkinci kez yüklenen semboller var mı? İçeri girerek test edebilirsiniz (istisna yoluyla veya System.Diagnostic.Debugger.Break () öğesini çağırın)
  3. Sembollerin yüklendiğini varsayarsak, bize gönderebileceğiniz bir repro var mı?
  4. Muhtemel fark, dinamik derlenmiş kodun sembol formatının .NET 2 (PDB akışı) ve .NET 4 (IL DB Sanırım dedikleri gibi) arasında% 100 farklı olmasıdır.
  5. 'Nop'un sesi doğru. Aşağıdaki örtük dizi noktaları oluşturmak için kurallara bakın.
  6. Aslında farklı satırlarda bir şeyler yayınlamanıza gerek yok. Varsayılan olarak, VS 'sembol-deyimleri' adım atacak, burada derleyici yazarı olarak 'sembol-deyimi' ne anlama gelir. Yani her ifadenin sembol dosyasında ayrı bir şey olmasını istiyorsanız, bu işe yarayacaktır.

JIT, aşağıdaki kurallara göre örtük bir sıralama noktası oluşturur: 1. IL nop talimatları 2. IL yığın boş noktaları 3. Bir çağrı talimatını izleyen IL talimatı

Görünüyorsa, sorununuzu çözmek için bir reproya ihtiyacımız var, bir bağlantı hatası gönderebilir ve bu ortam aracılığıyla dosyaları güvenli bir şekilde yükleyebilirsiniz.

Güncelleme:

Bu sorunu yaşayan diğer kullanıcıları http://www.microsoft.com/download/en/details.aspx?displaylang=tr&id=27543 adresinden Dev11'in Geliştirici Önizlemesini denemeye ve geri bildirimlerle yorum yapmaya teşvik ediyoruz . (4.5 hedef olmalı)

Güncelleme 2:

Leppie, http://www.microsoft.com/visualstudio/11/en-us/downloads adresindeki Dev11'in Beta sürümünde https://connect.microsoft bağlantı hatalarında belirtildiği gibi onun için çalışmanın düzeltmesini doğruladı . com.tr / VisualStudio / feedback / details / 684089 / .

Teşekkürler,

Luke


Çok teşekkürler. Gerekirse repro yapmaya çalışacağım.
leppie

Onaylama konusunda, evet haklısınız, ancak yine de doğrulama sorunlarını bozmadan adım sorunlarını çözmeyi tercih ederim. Ama dediğim gibi, eğer muhtemelen bir çalışma zamanı atmayacağını kanıtlayabilirsem feda etmeye hazırım VerificationException.
leppie

6. noktaya gelince, bu soru için 'çizgi tabanlı' yaptım. Hata ayıklayıcı aslında çalışmayı düşündüğüm gibi ifadeler içeri / dışarı / üzerine doğru adım atmaktadır :) Yaklaşımdaki tek sorun, bir 'dış' ifadeyi kapsıyorsa 'iç' ifadeler üzerinde kesme noktaları belirlemektir; VS'deki hata ayıklayıcı, kesme noktası olarak en dış ifadeyi yapma eğilimindedir.
leppie

Sanırım kesme noktası sorununu izole ettim. CLR2 altında çalışırken, yeni kod da olsa, kodu tekrar çalıştırırken kesme noktaları yeniden değerlendirilmiş gibi görünüyor. CLR4'te kesme noktaları sadece orijinal koda yapışır. CLR4 davranışının küçük bir ekran görüntüsünü @ screencast.com/t/eiSilNzL5Nr yaptım . Tür adının çağrılar arasında değiştiğine dikkat edin.
leppie

Connect ile ilgili bir hata bildirdim. Repro oldukça kolaydır :) connect.microsoft.com/VisualStudio/feedback/details/684089
leppie

3

SharpDevelop Hata Ayıklayıcı ekibinde mühendisim :-)

Sorunu çözdün mü?

SharpDevelop'da hata ayıklamaya çalıştınız mı? .NET'te bir hata varsa, bazı geçici çözüm uygulamaları gerekip gerekmediğini merak ediyorum. Bu sorunun farkında değilim.

ILSpy'da hata ayıklamaya çalıştınız mı? Özellikle hata ayıklama sembolleri olmadan. C # kodunda hata ayıklayacaktır, ancak IL talimatlarının güzel bir şekilde hata ayıklanabilir olup olmadığını söyleyecektir. (ILSpy hata ayıklayıcının beta olduğunu unutmayın)

Orijinal IL koduyla ilgili kısa notlar:

  • .line 19,19: 6,15 '' iki kez meydana geliyor mu?
  • .line 20,20: 7,14 '' örtük dizi noktasında başlamıyor (yığın boş değil). endişeliyim
  • .line 20,20: 7,14 '', "araba x" (iyi) ve "#f nooo x" (kötü?)
  • ret sonrası nop ile ilgili. Stloc, ldloc, ret ne olacak? Ben C # ret farklı bir dizi noktası yapmak için bu hile kullanır düşünüyorum.

David


+1 Geri bildirim için teşekkürler, ilk nokta olarak kod üreticisinin talihsiz yan etkisi, ancak zararsız görünüyor. İkinci nokta, tam da ihtiyacım olan şey bu, ama anladığım kadarıyla, ona bakacağım. Son noktada ne demek istediğinden emin değilim.
leppie

Üçüncü nokta .line 22,22: 7,40 '' IL_0020'den önce olması gerektiğiydi. Veya IL_0020'den önce bir şey olmalı, aksi takdirde kod hala .line 20,20: 7,14 '' olarak sayılır. Dördüncü nokta "ret, nop", "sloc, .line, ldloc, ret" ile değiştirilebilir. Deseni daha önce görmüştüm, belki gereksizdi, ama belki bir nedeni vardı.
dsrbecky

Ben kuyruk çağrısı kaybedecek gibi stloc, ret önce ldloc yapamam. Ah seni alıyorum, orijinal çıktıdan bahsediyor muydun?
leppie
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.