İkili bir formatta nasıl hata ayıklarsınız?


11

İkili bir inşaatçı inşa ederken hata ayıklamak istiyorum. Şu anda temel olarak ikili ayrıştırıcıya giriş verilerini yazdırıyorum ve sonra kodun derinliklerine gidiyorum ve girdinin çıktıya eşlenmesini yazdırıyorum, sonra çıktı eşlemesini (tamsayılar) alıp karşılık gelen tamsayıyı bulmak için kullanıyorum ikili. Oldukça hantal ve giriş ve çıkış arasındaki eşleme almak için kaynak kodunu derinden değiştirmenizi gerektirir.

İkili farklı varyantlarda görebiliyormuşsunuz gibi görünüyor (benim durumumda, 8 bitlik parçalar halinde ondalık sayı olarak görmek istiyorum, çünkü bu girişe oldukça yakın). Aslında, bazı sayılar 16 bit, bazı 8, bazı 32 vb. Olabilir. Bu nedenle, belki de bu farklı sayıların her birini bir şekilde bellekte vurgulanmış olarak ikili ile görüntülemenin bir yolu olabilir.

Olabildiğimi görebilmemin tek yolu, gerçek ikili biçime / düzene özel bir görselleştirici oluşturuyorsanız. Yani 32 bit sayıların nerede olması gerektiğini ve 8 bit sayıların nerede olması gerektiğini vb. Bilir. Bu, bazı durumlarda çok fazla iş ve biraz zor. Bunu yapmak için genel bir yol olup olmadığını merak ediyorum.

Ayrıca şu anda bu tür bir şeyi hata ayıklamanın genel yolunun ne olduğunu merak ediyorum, bu yüzden belki ondan ne denemek için bazı fikirler alabilirim.


75
"Hexdump'ı doğrudan kullanın ve bunu ve ek olarak yapın" diyen bir yanıt aldınız - ve bu cevap çok fazla oy aldı. Ve 5 saat sonra ikinci bir cevap (!). Sonra ikincisini birincinin lehine kabul ettin mi? Ciddi anlamda?
Doc Brown

4
İkili biçim kullanmak için iyi bir nedeniniz olsa da, bunun yerine JSON gibi varolan bir metin biçimini kullanıp kullanamayacağınızı düşünün. İnsanların okunabilirliği çok önemlidir ve makineler ve ağlar günümüzde boyutu küçültmek için özel bir biçim kullanmak gereksizdir.
jpmc26

4
@ jpmc26 İkili biçimler için hala çok fazla kullanım vardır ve her zaman olacaktır. İnsanların okunabilirliği genellikle performans, depolama gereksinimleri ve ağ performansına ikincildir. Özellikle ağ performansının düşük ve depolama alanının sınırlı olduğu birçok alan var. Ayrıca, eski sistemlerle (hem donanım hem de yazılım) arabirim kurmak ve veri formatlarını desteklemek zorunda olan tüm sistemleri unutmayın.
jwenting

4
@jwenting Hayır, aslında geliştirici süresi genellikle bir uygulamanın en pahalı parçasıdır. Elbette, Google veya Facebook'ta çalışıyorsanız durum böyle olmayabilir, ancak çoğu uygulama bu ölçekte çalışmaz. Ve geliştiricilerin bir şeyler için zaman harcamak en pahalı kaynak olduğunda, insanların okunabilirliği, programın ayrıştırması için fazladan 100 milisaniyeden fazladır.
jpmc26

3
@ jpmc26 Soruda OP'nin formatı tanımlayan olduğunu gösteren hiçbir şey görmüyorum.
JimmyJames

Yanıtlar:


76

Geçici kontroller için standart bir hexdump kullanın ve göz küresi yapmayı öğrenin.

Düzgün bir soruşturma için araç oluşturmak istiyorsanız, genellikle Python gibi bir şeye ayrı bir kod çözücü yazarım - ideal olarak bu doğrudan bir mesaj spesifikasyon belgesinden veya IDL'den sürülecek ve mümkün olduğunca otomatik olacaktır (bu yüzden manuel olarak giriş şansı yoktur. her iki kod çözücüde de aynı hata).

Son olarak, bilinen doğru konserve girişini kullanarak kod çözücünüz için birim testleri yazmanız gerektiğini unutmayın.


2
"sadece standart bir hexdump kullanın ve onu göz küresi öğrenin." Evet. Deneyimlerime göre, 200 bit'e kadar herhangi bir şeyin birden çok bölümü, gruplandırılmış karşılaştırma için bir beyaz tahtaya yazılabilir, bu da bazen bu tür şeylerin başlamasına yardımcı olur.
Mast

1
İkili veriler uygulamada (veya genel olarak sistemde) önemli bir rol oynarsa, çabaya değer ayrı bir kod çözücü buluyorum. Bu özellikle veri formatı değişkense doğrudur: sabit mizanpajlardaki veriler küçük bir uygulama ile bir hexdump içinde tespit edilebilir, ancak bir uygulanabilirlik duvarına hızlı bir şekilde vurur. USB ve CAN trafiğini ticari paket kod çözücüleriyle hata ayıkladık ve bir PROFIBus kod çözücü yazdım (değişkenlerin baytlara yayıldığı, altıgen bir dökümünde tamamen okunamayan) ve üçünü de son derece yararlı buldum.
Peter - Monica'yı

10

Bunu yapmanın ilk adımı, verilerin bir yapısını, yani bir şemayı tanımlayan bir dilbilgisi bulmanın veya tanımlamanın bir yoluna ihtiyacınız olmasıdır.

Bunun bir örneği COBOL'un gayri resmi olarak copybook olarak bilinen bir dil özelliğidir. COBOL programlarında bellekteki verilerin yapısını tanımlarsınız. Bu yapı, doğrudan baytların depolanma biçimiyle eşlenmiştir. Bu, fiziksel bellek düzeninin geliştiriciden ayrılan bir uygulama sorunu olduğu, yaygın çağdaş dillerin aksine o dönemin dilleri için ortaktır.

Google'da ikili veri şeması dili araması, bir dizi aracı açar. Apache DFDL buna bir örnektir . Bunun için zaten UI olabilir.


2
Bu özellik 'eski' çağ dillerine ayrılmamıştır. C ve C ++ yapıları ve birlikleri bellekle hizalanabilir. C # ikili veri iletmek için kullandığım StructLayoutAttribute vardır.
Kasper van den Berg

1
@KaspervandenBerg C ve C ++ 'nın son zamanlarda bunları eklediğini söylemedikçe, aynı dönemi düşünürüm. Mesele şu ki, bu formatlar sadece veri aktarımı için değil, bunlar için kullanılmış olsalar da, kodun bellekteki ve diskteki verilerle nasıl çalıştığını doğrudan eşleştirdiler. Genel olarak, bu tür özelliklere sahip olmalarına rağmen, daha yeni diller çalışma eğilimi bu değildir.
JimmyJames

@KaspervandenBerg C ++ düşündüğünüz kadar yapmaz. Dolguyu hizalamak ve ortadan kaldırmak için uygulamaya özel araç kullanmak mümkündür (ve itiraf etmek gerekirse, standart bu tür şeyler için özellikler ekliyor) ve üye sırası belirleyicidir (ancak bellekte olduğu gibi değil!).
Yörüngedeki Hafiflik Yarışları

6

ASN.1 , Özet Sözdizimi Notation One, bir ikili biçim belirtmenin bir yolunu sunar.

  • DDT - Örnek veriler ve birim testleri kullanarak geliştirin.
  • Metin dökümü yardımcı olabilir. XML'de ise, alt hiyerarşileri daraltabilir / genişletebilirsiniz.
  • ASN.1 gerçekten gerekli değildir, ancak dilbilgisi tabanlı, daha bildirimsel bir dosya belirtimi daha kolaydır.

6
ASN.1 ayrıştırıcılarında hiç bitmeyen bir güvenlik açığı geçit töreni herhangi bir gösterge ise, bunu benimsemek kesinlikle ikili biçimlerde hata ayıklamada iyi bir egzersiz sağlayacaktır.
Mark

1
@ Birçok küçük bayt dizisini (ve değişen hiyerarşi ağaçlarında) genellikle C'de (örneğin istisnalar kullanmadan) doğru (güvenli) olarak işlemez. Örneğin, java'daki C. ASN.1'in düşük seviyeli, doğal güvensizliğini asla hafife almayın - bu sorunu ortaya çıkarmaz. ASN.1 dilbilgisi yönelimli ayrıştırma güvenli bir şekilde yapılabildiğinden, C bile küçük ve güvenli bir kod tabanıyla yapılabilir. Bu güvenlik açıklarının bir kısmı ikili biçimin kendisinde bulunmaktadır: biçimin dilbilgisinin korkunç anlambilimine sahip "yasal" yapılarından yararlanabilir.
Joop Eggen

3

Diğer cevaplar, onaltılık dökümü görüntülemeyi veya JSON'da nesne yapılarını yazmayı açıkladı. Her ikisini de birleştirmenin çok faydalı olduğunu düşünüyorum.

Onaltılık dökümü üzerine JSON oluşturabilir bir araç kullanmak gerçekten yararlı; DotNetBytes adlı .NET ikili dosyalarını ayrıştıran açık kaynaklı bir araç yazdım , işte örnek bir DLL görünümü .

dotNetBytes Örneği


1

Tam olarak anladığımdan emin değilim, ancak bu ikili biçim için bir ayrıştırıcıya sahip olduğunuz ve bunun kodunu kontrol ettiğiniz gibi görünüyor. Yani bu cevap bu varsayım üzerine kuruludur.

Ayrıştırıcı bir şekilde yapıları, sınıfları veya dilinizin sahip olduğu veri yapısını doldurur. ToStringAyrıştırılan her şey için bir uygularsanız , o zaman ikili verileri okunabilir bir formatta görüntülemek için kullanımı çok kolay ve bakımı kolay bir yöntemle sonuçlanırsınız.

Temelde:

byte[] arrayOfBytes; // initialized somehow
Object obj = Parser.parse(arrayOfBytes);
Logger.log(obj.ToString());

Ve bu, onu kullanmak açısından. Tabii ki bu ToString, Objectsınıfınız / struct / whatınız için fonksiyonu uygulamanızı / geçersiz kılmanızı gerektirir ve bunu ayrıca iç içe sınıflar / struct / whatevers için de yapmanız gerekir.

Ayrıca ToString, hata ayıklama modunun dışında günlüğe kaydedilmeyecek bir şey için zaman kaybetmemeniz için, işlevin sürüm kodunda çağrılmasını önlemek için koşullu bir deyim kullanabilirsiniz .

Sizin ToStringböyle kudreti bakış:

return String.Format("%d,%d,%d,%d", int32var, int16var, int8var, int32var2);

// OR

return String.Format("%s:%d,%s:%d,%s:%d,%s:%d", varName1, int32var, varName2, int16var, varName3, int8var, varName4, int32var2);

Orijinal sorunuz, bunu yapmaya çalıştığınız gibi geliyor ve bu yöntemin külfetli olduğunu düşünüyorsunuz, ancak bir noktada ikili bir format ayrıştırma uyguladınız ve bu verileri depolamak için değişkenler oluşturdunuz. Tek yapmanız gereken mevcut değişkenleri uygun soyutlama seviyesinde (değişkenin bulunduğu sınıf / yapı) yazdırmaktır.

Bu, yalnızca bir kez yapmanız gereken bir şeydir ve ayrıştırıcıyı oluştururken yapabilirsiniz. Ve sadece ikili biçim değiştiğinde değişecektir (bu zaten ayrıştırıcıda zaten bir değişiklik isteyecektir).

Benzer bir şekilde: bazı diller sınıfları XML veya JSON'a dönüştürmek için güçlü özelliklere sahiptir. C # bu konuda özellikle iyidir. İkili biçiminizden vazgeçmek zorunda değilsiniz, XML veya JSON'u bir hata ayıklama günlüğü deyiminde yaparsınız ve sürüm kodunuzu yalnız bırakırsınız.

Kişisel olarak onaltılık döküm yoluna gitmemenizi tavsiye ederim, çünkü hatalara yatkın (sağ baytta başladınız mı, soldan sağa doğru okurken doğru endianlığı vb. Gördüğünüzden emin misiniz) .

Örnek: ToStringsTükürük değişkenlerinizi söyleyin a,b,c,d,e,f,g,h. Programınızı çalıştırırsınız ve bir hata fark edersiniz g, ancak sorun gerçekten başladı c(ancak hata ayıklama yapıyorsunuz, bu yüzden henüz çözemediniz). Giriş değerlerini biliyorsanız (ve yapmalısınız) anında csorunların başladığı yeri göreceksiniz .

Size söyleyen bir altıgen dökümü ile karşılaştırıldığında 338E 8455 0000 FF76 0000 E444 ....; alanlarınız boyut olarak değişirse, nerede cbaşlar ve değer nedir - bir hex editörü size söyleyecektir, ancak benim açımdan bu hataya eğilimli ve zaman alıcıdır. Sadece bu da değil, bir hex görüntüleyici aracılığıyla testi kolayca / hızlı bir şekilde otomatik hale getiremezsiniz. Verileri ayrıştırdıktan sonra bir dize yazdırmak, programınızın tam olarak ne düşündüğünü söyleyecektir ve otomatik test yolunda bir adım olacaktır.

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.