From fdd49d2be02fa62ecbf547e4224663b562077425 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 6 Mar 2015 13:26:04 -0500 Subject: [PATCH] debug/dwarf: add unit tests for line table reader This adds simple ELF test binaries generated by gcc and clang and compares the line tables returned by the line table reader against tables based on the output of readelf. The binaries were generated with # gcc --version | head -n1 gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2 # gcc -g -o line-gcc.elf line*.c # clang --version | head -n1 Ubuntu clang version 3.4-1ubuntu3 (tags/RELEASE_34/final) (based on LLVM 3.4) # clang -g -o line-clang.elf line*.c Change-Id: Id210fdc1d007ac9719e8f5dc845f2b94eed12234 Reviewed-on: https://go-review.googlesource.com/7070 Reviewed-by: Nigel Tao Reviewed-by: Rob Pike --- src/debug/dwarf/line_test.go | 229 ++++++++++++++++++++++++ src/debug/dwarf/testdata/line-clang.elf | Bin 0 -> 10271 bytes src/debug/dwarf/testdata/line-gcc.elf | Bin 0 -> 10113 bytes src/debug/dwarf/testdata/line1.c | 9 + src/debug/dwarf/testdata/line1.h | 7 + src/debug/dwarf/testdata/line2.c | 6 + 6 files changed, 251 insertions(+) create mode 100644 src/debug/dwarf/line_test.go create mode 100755 src/debug/dwarf/testdata/line-clang.elf create mode 100755 src/debug/dwarf/testdata/line-gcc.elf create mode 100644 src/debug/dwarf/testdata/line1.c create mode 100644 src/debug/dwarf/testdata/line1.h create mode 100644 src/debug/dwarf/testdata/line2.c diff --git a/src/debug/dwarf/line_test.go b/src/debug/dwarf/line_test.go new file mode 100644 index 0000000000..4104b5d49b --- /dev/null +++ b/src/debug/dwarf/line_test.go @@ -0,0 +1,229 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package dwarf_test + +import ( + . "debug/dwarf" + "io" + "testing" +) + +var ( + file1C = &LineFile{Name: "/home/austin/go.dev/src/debug/dwarf/testdata/line1.c"} + file1H = &LineFile{Name: "/home/austin/go.dev/src/debug/dwarf/testdata/line1.h"} + file2C = &LineFile{Name: "/home/austin/go.dev/src/debug/dwarf/testdata/line2.c"} +) + +func TestLineELFGCC(t *testing.T) { + // Generated by: + // # gcc --version | head -n1 + // gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2 + // # gcc -g -o line-gcc.elf line*.c + + // Line table based on readelf --debug-dump=rawline,decodedline + want := []LineEntry{ + {Address: 0x40059d, File: file1H, Line: 2, IsStmt: true}, + {Address: 0x4005a5, File: file1H, Line: 2, IsStmt: true}, + {Address: 0x4005b4, File: file1H, Line: 5, IsStmt: true}, + {Address: 0x4005bd, File: file1H, Line: 6, IsStmt: true, Discriminator: 2}, + {Address: 0x4005c7, File: file1H, Line: 5, IsStmt: true, Discriminator: 2}, + {Address: 0x4005cb, File: file1H, Line: 5, IsStmt: false, Discriminator: 1}, + {Address: 0x4005d1, File: file1H, Line: 7, IsStmt: true}, + {Address: 0x4005e7, File: file1C, Line: 6, IsStmt: true}, + {Address: 0x4005eb, File: file1C, Line: 7, IsStmt: true}, + {Address: 0x4005f5, File: file1C, Line: 8, IsStmt: true}, + {Address: 0x4005ff, File: file1C, Line: 9, IsStmt: true}, + {Address: 0x400601, EndSequence: true}, + + {Address: 0x400601, File: file2C, Line: 4, IsStmt: true}, + {Address: 0x400605, File: file2C, Line: 5, IsStmt: true}, + {Address: 0x40060f, File: file2C, Line: 6, IsStmt: true}, + {Address: 0x400611, EndSequence: true}, + } + + testLineTable(t, want, elfData(t, "testdata/line-gcc.elf")) +} + +func TestLineELFClang(t *testing.T) { + // Generated by: + // # clang --version | head -n1 + // Ubuntu clang version 3.4-1ubuntu3 (tags/RELEASE_34/final) (based on LLVM 3.4) + // # clang -g -o line-clang.elf line*. + + want := []LineEntry{ + {Address: 0x400530, File: file1C, Line: 6, IsStmt: true}, + {Address: 0x400534, File: file1C, Line: 7, IsStmt: true, PrologueEnd: true}, + {Address: 0x400539, File: file1C, Line: 8, IsStmt: true}, + {Address: 0x400545, File: file1C, Line: 9, IsStmt: true}, + {Address: 0x400550, File: file1H, Line: 2, IsStmt: true}, + {Address: 0x400554, File: file1H, Line: 5, IsStmt: true, PrologueEnd: true}, + {Address: 0x400568, File: file1H, Line: 6, IsStmt: true}, + {Address: 0x400571, File: file1H, Line: 5, IsStmt: true}, + {Address: 0x400581, File: file1H, Line: 7, IsStmt: true}, + {Address: 0x400583, EndSequence: true}, + + {Address: 0x400590, File: file2C, Line: 4, IsStmt: true}, + {Address: 0x4005a0, File: file2C, Line: 5, IsStmt: true, PrologueEnd: true}, + {Address: 0x4005a7, File: file2C, Line: 6, IsStmt: true}, + {Address: 0x4005b0, EndSequence: true}, + } + + testLineTable(t, want, elfData(t, "testdata/line-clang.elf")) +} + +func TestLineSeek(t *testing.T) { + d := elfData(t, "testdata/line-gcc.elf") + + // Get the line table for the first CU. + cu, err := d.Reader().Next() + if err != nil { + t.Fatal("d.Reader().Next:", err) + } + lr, err := d.LineReader(cu) + if err != nil { + t.Fatal("d.LineReader:", err) + } + + // Read entries forward. + var line LineEntry + var posTable []LineReaderPos + var table []LineEntry + for { + posTable = append(posTable, lr.Tell()) + + err := lr.Next(&line) + if err != nil { + if err == io.EOF { + break + } + t.Fatal("lr.Next:", err) + } + table = append(table, line) + } + + // Test that Reset returns to the first line. + lr.Reset() + if err := lr.Next(&line); err != nil { + t.Fatal("lr.Next after Reset failed:", err) + } else if line != table[0] { + t.Fatal("lr.Next after Reset returned", line, "instead of", table[0]) + } + + // Check that entries match when seeking backward. + for i := len(posTable) - 1; i >= 0; i-- { + lr.Seek(posTable[i]) + err := lr.Next(&line) + if i == len(posTable)-1 { + if err != io.EOF { + t.Fatal("expected io.EOF after seek to end, got", err) + } + } else if err != nil { + t.Fatal("lr.Next after seek to", posTable[i], "failed:", err) + } else if line != table[i] { + t.Fatal("lr.Next after seek to", posTable[i], "returned", line, "instead of", table[i]) + } + } + + // Check that seeking to a PC returns the right line. + if err := lr.SeekPC(table[0].Address-1, &line); err != ErrUnknownPC { + t.Fatalf("lr.SeekPC to %#x returned %v instead of ErrUnknownPC", table[0].Address-1, err) + } + for i, testLine := range table { + if testLine.EndSequence { + if err := lr.SeekPC(testLine.Address, &line); err != ErrUnknownPC { + t.Fatalf("lr.SeekPC to %#x returned %v instead of ErrUnknownPC", testLine.Address, err) + } + continue + } + + nextPC := table[i+1].Address + for pc := testLine.Address; pc < nextPC; pc++ { + if err := lr.SeekPC(pc, &line); err != nil { + t.Fatalf("lr.SeekPC to %#x failed: %v", pc, err) + } else if line != testLine { + t.Fatalf("lr.SeekPC to %#x returned %v instead of %v", pc, line, testLine) + } + } + } +} + +func testLineTable(t *testing.T, want []LineEntry, d *Data) { + // Get line table from d. + var got []LineEntry + dr := d.Reader() + for { + ent, err := dr.Next() + if err != nil { + t.Fatal("dr.Next:", err) + } else if ent == nil { + break + } + + if ent.Tag != TagCompileUnit { + dr.SkipChildren() + continue + } + + // Decode CU's line table. + lr, err := d.LineReader(ent) + if err != nil { + t.Fatal("d.LineReader:", err) + } else if lr == nil { + continue + } + + for { + var line LineEntry + err := lr.Next(&line) + if err != nil { + if err == io.EOF { + break + } + t.Fatal("lr.Next:", err) + } + got = append(got, line) + } + } + + // Compare line tables. + if !compareLines(got, want) { + t.Log("Line tables do not match. Got:") + dumpLines(t, got) + t.Log("Want:") + dumpLines(t, want) + t.FailNow() + } +} + +func compareLines(a, b []LineEntry) bool { + if len(a) != len(b) { + return false + } + + for i := range a { + al, bl := a[i], b[i] + // If both are EndSequence, then the only other valid + // field is Address. Otherwise, test equality of all + // fields. + if al.EndSequence && bl.EndSequence && al.Address == bl.Address { + continue + } + if al.File.Name != bl.File.Name { + return false + } + al.File = nil + bl.File = nil + if al != bl { + return false + } + } + return true +} + +func dumpLines(t *testing.T, lines []LineEntry) { + for _, l := range lines { + t.Logf(" %+v File:%+v", l, l.File) + } +} diff --git a/src/debug/dwarf/testdata/line-clang.elf b/src/debug/dwarf/testdata/line-clang.elf new file mode 100755 index 0000000000000000000000000000000000000000..b63cc781c410a53840c001af944e6292935ce3ff GIT binary patch literal 10271 zcmeHNZ)_Y#6`$R`vz<6OpPjUE8fdP?Zk>Y9PV5G^Nt-=8m)xaxnkG(~in{Bw?`$8O z@2vZiCPjde(}LBee*lR9AE+vj_<%%&Du{~ICb()o6r>b^R9cX%s6k2Ef}tUb3a$CQ z*?D(+duOE|%C|gg=gs@`d-G;?ZgzIo-w5~b&^1jk>Ed2NlIby}$}WX?_68{`U5{8M zOwlTC6*bU!ahcLW+^#XdszNibQ+@`x2Um}7D|&QOR+xXrRtx5wA#rN2M5e0R{KZ;Z zWG+NNDhNlp`h8LaAC?v7oy9zCJL5=AxHg4rQ#j^lRbtG!f7Ca+236ca-GoH4Nla{) zWr>q7(Vp}9IMugOqmr9td@0-mz$u9IzgFQ_4trI5OO4Bd>K}6@ijGurWOH{%D&C$- zrVEGL5BF?t-`pL{WrCYzzbQWX?%cg!w#4Ju42k-;8W+t0vLAl=g>U`+cy2uU<8uwa zKXEwv@_VU0gyjp>PfYdjY^vf-x@!6s=mS;!1^PEi-PtUrvdMIQOjs7FtXw{p&0CYP zWEz_B$xK>lEU~jc+S_Ms3T_JCNda~IQ6K0J^Nv)Y!cEC#Wb3j;akXJs*67~RcrZ2l zhh>$fGvS#64!xRM($wbAJL5!V-m8l|>0P-ZAR>>S%6l(tfqP`;)w(%5;^Lh;OpC1^ zlnv`m)JUEn!(R~k|g#&ebs<}WcIg_)0ehIw6l>nt`-1(i5w%3{{i60>}xjuoWf7v^APeCg~t6r zUidl^8G6mT11jxAhFOF5 zPKXP8z$9vD4xKv+Ng&nP^Jl^fRQ=}H7M6oG99xSrG8$fZZM*l1_GEa$OQSg(Uby%c zr874cWH8zxJnor4a%^jBH%1c8BtKqUoDKgMH_bmZ7kV%>yBInUoxKv;AD#VEXt4iS zYosm!+_84z`}#MW-}rXq^hXBW`3oO?w73{~{QdmR+(iHErT*C~+Yw`N^^hn5>8!M&s0p^LELu$%sn7b2+R4Rk6Y3qzFCb~j%^i?$U6u1Y; zJ`8>t{6+B9=;9y22f;6c=fPK_|L=f53{L9+k@nbLp&j;X>sHj(J*(CFNl$D4^N4!~ zIVh^`FGLIM?%RsvC|@==PnW3|NZe| zhUDYANv!zJ*R0y(=k-b5B(tEM7ST4F33?A8YPOkhyuM0JagU7cB@sVkBT_2uOK5LH zB=-v7$5s2RpH?#G&Fx{6FNtM5#$|tol|QyWQr48;f|3s^yHfw(8NbK68@f^5|JxMb z?3xekzq7CJ?m*lAkwQ9O2y_Q~f}7em-c^v|#tpVYDC=k{mL3lrN@R1%OghjN>~7y^ zJ9Y)y^0Dz;$KG&%IJ7Tpb#-@)CDXCghCtg$ESHD};NIVVV1O_i#23)CeYffaMsbne zFo^cava+!Ke*}Z=|E%&4RJuyd%_!~ogt-lueA(ND%GgE}Le3>!kk!OR9%GwO2=RSf z9$BlC_jQHXEu~U%09Abkh34%;$+_=TIcW!sZ$s_%c%C9hZI9B=6z$$;$Y4xU`P?Dz zapE2dr9U?%Y6w;PT@=fNL99lrqj(;#*h)-HqU6+mh&mI!qs!D@Kt(fnh)xun6RaVCe2toa%{m;0=s{ul?ylcbA6>O=ZKKwtnfM7BEl}QDUyom(C#czWwt2gY03EJ1 znigG!Y;O_KRUPoJBWQj7z4XIfy0KDI;sH47;`8LL{l~Wwr98&Mz-vK)*Y|W{V{jB! zRh_Vxu4Oup`I_bTJ@gxoZXEgf@`1X0p1G{+2+<>h(iEr&D&uUjLt=n+9;6$Ve^Ahu z!T-~p=G=jfiOgi8BUZ@elj)A}Ofa4})RD`McEl4Sh4GH~qp|E*M?R6u$7A`JJyUU7 zK{IuvFeXMPVp)+aW{zpPUUm?LoWC@2$erem^d$qGbd{zzX+$u0WHKKc0ncY`KEXA> z6WJ*dOlR_mV5m3Rj-RrU#?yu1NFj+cqGVhINt%e|CPXlPB#n4B&u49mS{BL#3$|<` z6(fMEO{MZ8m`o>8<`aieVxdUFmXX~LCMK-0Y-}=NO~ip^$wpYQY&LepMsWShqi{p? z*kp1PO=l1gMNqb4M;yuJL~t}SIhnvPVem2N0AnFbKyQmvg%JcO$;tFshHbHtk!<1+ zOLR}Uj`8Cv0_2ZOA;70V^qi%&$6mqceAR?hI%nnQtW=_q>l6#%pTkv)i}8cH38{3B z8IV$`u$Q}%Oe>@lpVv)k%&UMcQYsa0{C1eG;91D+AJ?~HF&dRheyT#V=aMl&fvyuYxe%JF*y270zLo}cFj6`tGU z{MnEBSAeIz0?WK#7*_azYPbg6nZHtt$55d$W&E^ZO4GE$b3eI#&WH6!U3lK_99Q^= zjArl0R-o?2KMft_MfnlUtM=y=p7(vW)y|dc#Ak6i@xo)0y69+1p;Yj>D)aBbouQj*Jds9INQ5=*07WwncS__jT;A!m=oyS9l)(&KgtNIu)Mgrjy+GpTS7&Gk&YW z^Y?)5PB7|j{I6X2X@#Fw?RUHS&-ahRoWW(o>& z`@7{g;X^5M`*adZ6!?VrzrvTg%6Q)2^7kA5PNRmSm=Di`zX9uPpU>y7Ql~)fd|77x zE_|GL;U6Yg@dH4oEfq_~F~1Cp6W^)uohm`jlLIi0xj3m zwk7!`$YF5fN#?c7;U><~o*Gm~n*&e_uFbf3KJxR2*4Jw7zu5`{Xs0Wv` z^5VIK6J%f~G+)&pPi{}O_$!Ow{mbL{1V0DM^$mibZ{>PFzF$|1-zfNbRPNtYe9n~X zR|$T8l2T%jaGs2`8ZYRI=amlC2O0+mXszokO2LE{nsq-DR1Xm6+C zE0lYj>0D12E5(#+{sfi&d6zz<^z$zLgED?;JSh*NFD2*GZ3^ zDX&+&?|BP)8lMwtJ|tAkOVInpS`l%@`G@j1UGw>h@^_B|PL*W*P8A<_NK!5I0abUh zb=PCXrzY7W z!akFU7bYi<0OF7=I?5??XhX$g3 z@N!t>zw8KWXaD`Zp?>TB9Xs}g2d%+SZ-1D=$^YsZ%@t(YbdqaD2M4UuFbxj$(I5@R zMp6kuheGy0{0J){Pl#-o{Xasc>HHs{ihme#o1MYR|CI>in#))dv2+}5TG9K_WIUO+ z3OEdRW=wrV9%(35A1$0$sk;3yO1lnOd)58!OT}_I+-%E2mv}U(uYC8*dMXD{{10>u B2^9bU literal 0 HcmV?d00001 diff --git a/src/debug/dwarf/testdata/line-gcc.elf b/src/debug/dwarf/testdata/line-gcc.elf new file mode 100755 index 0000000000000000000000000000000000000000..50500a8eecd95ee18ac78e130e12eef10c4aaf55 GIT binary patch literal 10113 zcmeHNZ)_aJ6`$QZ+ZRmEP8^CuD7io)1yrBy#0e%*V9$S&bK)d!un82L_4#gXUpe1d zcY7fLK?8;eH-tiqP)b2WEuwq?DIZYlR+UKVDghO#p=u?nrmclYNdibgq> zcel4bt9)p`R2gaK&HK%JZ{EC}+nIg0-|6h$tZSO!qKn%FamW0Igq&K4v1=r&uvW1^ z7~&=o5|uzIa2c|PsMBIPqf9dmC^;XfA6KjH0Ij+q8%(cvV8N6*2r5cip%Se+yxeKTJ!==fEyX{BE zKM6z+RlHFh6457)+ZE@wK_fc;o4}N#IlJ!1=$c*i3hJ8W23o|AQ0MvSS(H^T5Kpe1 zKP~z16HhLkKQ8(25>Kw2KL)<})2@m4_CzN>h>m}Fv8T7|)bVF34G}$cA|%PFk17mt z?&lD^G*q*^Lx{y7&#nsL_AKgy=DA1UNdL)- zzXH-epQ8Ck$2YwefPj5N!G$G#Z-wwwf&A?0{__t(rDnM}p93Wu2yjy(ddRl zD&^&cSc!g;4?(_%WP`PvgY{c$svig(5O-X+@s_nKZzPyx5Js^M{%s{760AL_w=b;J zJ2A4;p8#y4|2lVnpX`?Uj|0C4{qkAB`rDj-vi%CKyU}lvep|5idwOTE{%K!lFm%}8 z8C?BTMKsuSureBK9k1FRG*ZFVNU$jqT-_E7wFT=T-xdtWxO@Wj1F++M9+1f^KIXsuM#Po zZE@VA!h4>>70(HD)}V5&L&UTipYgX9&wlfGIGoGEJhoM5K1v?P5y@*x?xNzKRQ(G6 zpA&wM^$xUG-PePPKCkGjihAX@w6|{vt?nDlr|o>GCEOZb)6jfdUb4+MJAn8Gl$n*}TyXthTX}_j*)e&B?LUh$N;@4KWQdC#p4oirFYT~X1!s3plz95mK_ELDZk6 z>LpZK<<`m(zaH4V?d6wsym)K3LR=R&pe}EIO}Jo_qk7FYM->^3P`k6@Lk**LK5cCp zw$fHM83!B7#z!_exsp)BaHwHOW)B+1vKiZo+nH>^;au`T%icd`37JA@9LbDYjj?>r zPNo}&GvS1_w=tKEHzusX{BUF9fmn8^(YA7SB4)=#Dw7@#<6kIMU~ z1W}Q!yW9kZ_Ab`%)eUfzmy|?=98##A=V^fz&1kyyZQYQaw$fiIxnkwj??BgO>~%c; z5#5l&M-;&RbB@<}@=Fm}?LbX?JL^yC1~@tgNFw$*MCNR1?yO(0@Vh{LxLBXh6HNr7 z-0hG;?Tz0a^w8eT`n+F1sr30A!v3=y)BB-MX94Dq_zXGL5vAWGIVb1r_Fuu`K{P0) ztpB#se_QGEJb8TY{2%w|Pb>Xtr9XgvDx^AcSYDZB zRvcCO9RH)0hU`14^!ffv5S3T|HDEM8>%Xq_Ip5#Gii&#mf9BD@sPr$Y@moCe=ljQI zkE20v(gTF)9JwE5nXJ}F=UVoWq`Y~kO`a-=w$fP{_TFHp3upZM(=yU70 zD*aaFAp6NCSdaOCqCptXpVHM-qDs*#ufic^sG7w^SQ9a>!ul&+7&Td+DIHn4?G{a` z@dw96$|_psuodGu!&IV1dn2U66l-#m~0r22D+o)7Ng)!(G_z46S%fDSlPqy}uN%F6@7$_|<~mVh#3J1Pa`@uHbKb4w6Lp3BODVnt&*K3%B-=h@QTTc5?(~VT34V^2;&`3p=cB8` zhpY@g_gpa6~KC0 ztSmo7t>K?={{BJ1ViJvV^EwWk{O31kPLxc|BR^k!ehYaG>oXKE&?=Tcp;<0&BvH;`z)7CZ@9aXYlJ~~pdL{48r>y`UVr3Uy z2b}!(+KJ2~f3LJ(=6N2^+BrLqf2ia5kYj86F0;Gq&R)|L2`g(2Cv!-EnD(d{N4^AE zfijS3CNk!5Dl-^MnF(Zga%L>QPavx>ma=Rs5ng}Wt!rSpjF3tB4JTV+A_I}#FP!{F zB0oC1A1W@+q_jwhsFMSW3uHMt!DE`6cSW{$nw>j3;J-5&ZkOmMgxPV=j>z_|c1XE; zJ#j#s*WC zpahHaMU4E6#xVG+82T2*v}FFpG35QgrYPFNgBHKFDRxRbrfV3_S2&1xE@O_w(g}ED zcI|{SiDcT$=Pb;=I2W2d{7C~;vp10yQf=q!o~?V$U1}w?r((GrmVs$vvK(iM0 + +void f2() +{ + printf("hello\n"); +} -- 2.48.1