Pertama, saya mohon maaf atas panjangnya pertanyaan ini.
Saya adalah penulis IronScheme . Baru-baru ini saya telah bekerja keras untuk memancarkan info debug yang layak, sehingga saya dapat menggunakan debugger .NET 'asli'.
Meskipun ini sebagian berhasil, saya mengalami beberapa masalah gigi.
Masalah pertama terkait dengan melangkah.
Karena Skema menjadi bahasa ekspresi, semuanya cenderung dibungkus dalam tanda kurung, tidak seperti bahasa .NET utama yang tampaknya berbasis pernyataan (atau baris).
Kode asli (Skema) terlihat seperti:
(define (baz x)
(cond
[(null? x)
x]
[(pair? x)
(car x)]
[else
(assertion-violation #f "nooo" x)]))
Saya sengaja meletakkan setiap ekspresi di baris baru.
Kode yang dipancarkan berubah menjadi C # (melalui ILSpy) terlihat seperti:
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));
}
Seperti yang Anda lihat, sangat sederhana.
Catatan: Jika kode diubah menjadi ekspresi kondisional (? :) di C #, semuanya hanya akan menjadi satu langkah debug, ingatlah itu.
Berikut adalah keluaran IL dengan sumber dan nomor baris:
.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'
Catatan: Untuk mencegah debugger hanya menyorot seluruh metode, saya membuat titik masuk metode hanya selebar 1 kolom.
Seperti yang Anda lihat, setiap ekspresi dipetakan dengan benar ke sebuah garis.
Sekarang masalah dengan menginjak (diuji pada VS2010, tetapi masalah yang sama / serupa pada VS2008):
Ini dengan IgnoreSymbolStoreSequencePoints
tidak diterapkan.
- Panggil baz dengan null arg, ini berfungsi dengan benar. (null? x) diikuti oleh x.
- Panggil baz dengan Cons arg, ini berfungsi dengan benar. (null? x) lalu (pair? x) lalu (car x).
- Panggil baz dengan arg lain, gagal. (null? x) lalu (pair? x) lalu (mobil x) lalu (pelanggaran pernyataan ...).
Saat melamar IgnoreSymbolStoreSequencePoints
(seperti yang disarankan):
- Panggil baz dengan null arg, ini berfungsi dengan benar. (null? x) diikuti oleh x.
- Panggil baz dengan Cons arg, gagal. (null? x) lalu (pair? x).
- Panggil baz dengan arg lain, gagal. (null? x) lalu (pair? x) lalu (mobil x) lalu (pelanggaran pernyataan ...).
Saya juga menemukan dalam mode ini bahwa beberapa baris (tidak diperlihatkan di sini) salah disorot, mereka mati dengan 1.
Berikut beberapa ide yang mungkin menjadi penyebabnya:
- Tailcall membingungkan debugger
- Lokasi yang tumpang tindih (tidak ditampilkan di sini) membingungkan debugger (melakukannya dengan sangat baik saat menyetel breakpoint)
- ????
Masalah kedua, tetapi juga serius, adalah debugger gagal untuk merusak / mencapai breakpoint dalam beberapa kasus.
Satu-satunya tempat di mana saya bisa mendapatkan debugger untuk istirahat dengan benar (dan secara konsisten), adalah di titik masuk metode.
Situasi menjadi sedikit lebih baik jika IgnoreSymbolStoreSequencePoints
tidak diterapkan.
Kesimpulan
Mungkin debugger VS hanya berisi bug :(
Referensi:
Pembaruan 1:
Mdbg tidak berfungsi untuk rakitan 64-bit. Jadi itu sudah keluar. Saya tidak memiliki mesin 32-bit lagi untuk mengujinya. Pembaruan: Saya yakin ini bukan masalah besar, apakah ada yang punya perbaikan? Sunting: Ya, konyol saya, mulai saja mdbg di bawah prompt perintah x64 :)
Perbarui 2:
Saya telah membuat aplikasi C #, dan mencoba membedah info baris.
Temuan saya:
- Setelah
brXXX
instruksi apa pun, Anda harus memiliki titik urutan (jika tidak valid alias '#line hidden', keluarkan anop
). - Sebelum
brXXX
instruksi apa pun , keluarkan '#line hidden' dan anop
.
Menerapkan ini, bagaimanapun, tidak memperbaiki masalah (sendiri?).
Tetapi menambahkan yang berikut ini, memberikan hasil yang diinginkan :)
- Setelah itu
ret
, keluarkan '#line hidden' dan anop
.
Ini menggunakan mode di mana IgnoreSymbolStoreSequencePoints
tidak diterapkan. Saat diterapkan, beberapa langkah masih dilewati :(
Berikut adalah keluaran IL ketika di atas telah diterapkan:
.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'
Perbarui 3:
Masalah dengan 'semi-fix' di atas. Peverify melaporkan kesalahan pada semua metode karena nop
setelahnya ret
. Saya benar-benar tidak mengerti masalahnya. Bagaimana bisa nop
verifikasi istirahat setelah ret
. Ini seperti kode mati (kecuali bahwa ini BUKAN kode) ... Oh well, eksperimen terus berlanjut.
Pembaruan 4:
Kembali ke rumah sekarang, hapus kode 'tidak dapat diverifikasi', berjalan di VS2008 dan segalanya menjadi jauh lebih buruk. Mungkin menjalankan kode yang tidak dapat diverifikasi demi debugging yang tepat mungkin jawabannya. Dalam mode 'rilis', semua keluaran masih dapat diverifikasi.
Perbarui 5:
Sekarang saya telah memutuskan bahwa ide saya di atas adalah satu-satunya pilihan yang layak untuk saat ini. Meskipun kode yang dihasilkan tidak dapat diverifikasi, saya belum menemukan kode apa pun VerificationException
. Saya tidak tahu apa dampaknya pada pengguna akhir dengan skenario ini.
Sebagai bonus, masalah kedua saya juga telah diselesaikan. :)
Ini sedikit screencast dari hasil akhir saya. Ini mengenai breakpoint, melakukan langkah yang tepat (masuk / keluar / atas), dll. Secara keseluruhan, efek yang diinginkan.
Saya, bagaimanapun, masih belum menerima ini sebagai cara untuk melakukannya. Rasanya terlalu hacky bagi saya. Memiliki konfirmasi tentang masalah sebenarnya akan menyenangkan.
Pembaruan 6:
Baru saja perubahan untuk menguji kode pada VS2010, sepertinya ada beberapa masalah:
Panggilan pertama sekarang tidak berjalan dengan benar. (pelanggaran-pernyataan ...) dipukul. Kasus lain berfungsi dengan baik.Beberapa kode lama mengeluarkan posisi yang tidak perlu. Kode dihapus, berfungsi seperti yang diharapkan. :)- Lebih serius lagi, breakpoint gagal pada pemanggilan kedua program (menggunakan kompilasi dalam memori, membuang assembly ke file tampaknya membuat breakpoint senang lagi).
Kedua kasus ini bekerja dengan benar di bawah VS2008. Perbedaan utamanya adalah bahwa di bawah VS2010, seluruh aplikasi dikompilasi untuk .NET 4 dan di bawah VS2008, dikompilasi ke .NET 2. Keduanya menjalankan 64-bit.
Pembaruan 7:
Seperti disebutkan, saya menjalankan mdbg di bawah 64-bit. Sayangnya, ia juga memiliki masalah breakpoint di mana ia gagal rusak jika saya menjalankan ulang program (ini berarti ia akan dikompilasi ulang, jadi tidak menggunakan rakitan yang sama, tetapi masih menggunakan sumber yang sama).
Perbarui 8:
Saya telah mengajukan bug di situs MS Connect terkait masalah breakpoint.
Pembaruan: Diperbaiki
Pembaruan 9:
Setelah berpikir panjang, satu-satunya cara untuk membuat debugger senang adalah dengan melakukan SSA, sehingga setiap langkah dapat diisolasi dan berurutan. Saya belum membuktikan gagasan ini. Tapi sepertinya logis. Jelas, membersihkan temps dari SSA akan menghentikan debugging, tetapi itu mudah untuk diubah, dan membiarkannya tidak memiliki banyak overhead.