github.com/geraldss/go/src@v0.0.0-20210511222824-ac7d0ebfc235/debug/dwarf/entry_test.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package dwarf_test
     6  
     7  import (
     8  	. "debug/dwarf"
     9  	"encoding/binary"
    10  	"path/filepath"
    11  	"reflect"
    12  	"testing"
    13  )
    14  
    15  func TestSplit(t *testing.T) {
    16  	// debug/dwarf doesn't (currently) support split DWARF, but
    17  	// the attributes that pointed to the split DWARF used to
    18  	// cause loading the DWARF data to fail entirely (issue
    19  	// #12592). Test that we can at least read the DWARF data.
    20  	d := elfData(t, "testdata/split.elf")
    21  	r := d.Reader()
    22  	e, err := r.Next()
    23  	if err != nil {
    24  		t.Fatal(err)
    25  	}
    26  	if e.Tag != TagCompileUnit {
    27  		t.Fatalf("bad tag: have %s, want %s", e.Tag, TagCompileUnit)
    28  	}
    29  	// Check that we were able to parse the unknown section offset
    30  	// field, even if we can't figure out its DWARF class.
    31  	const AttrGNUAddrBase Attr = 0x2133
    32  	f := e.AttrField(AttrGNUAddrBase)
    33  	if _, ok := f.Val.(int64); !ok {
    34  		t.Fatalf("bad attribute value type: have %T, want int64", f.Val)
    35  	}
    36  	if f.Class != ClassUnknown {
    37  		t.Fatalf("bad class: have %s, want %s", f.Class, ClassUnknown)
    38  	}
    39  }
    40  
    41  // wantRange maps from a PC to the ranges of the compilation unit
    42  // containing that PC.
    43  type wantRange struct {
    44  	pc     uint64
    45  	ranges [][2]uint64
    46  }
    47  
    48  func TestReaderSeek(t *testing.T) {
    49  	want := []wantRange{
    50  		{0x40059d, [][2]uint64{{0x40059d, 0x400601}}},
    51  		{0x400600, [][2]uint64{{0x40059d, 0x400601}}},
    52  		{0x400601, [][2]uint64{{0x400601, 0x400611}}},
    53  		{0x4005f0, [][2]uint64{{0x40059d, 0x400601}}}, // loop test
    54  		{0x10, nil},
    55  		{0x400611, nil},
    56  	}
    57  	testRanges(t, "testdata/line-gcc.elf", want)
    58  
    59  	want = []wantRange{
    60  		{0x401122, [][2]uint64{{0x401122, 0x401166}}},
    61  		{0x401165, [][2]uint64{{0x401122, 0x401166}}},
    62  		{0x401166, [][2]uint64{{0x401166, 0x401179}}},
    63  	}
    64  	testRanges(t, "testdata/line-gcc-dwarf5.elf", want)
    65  
    66  	want = []wantRange{
    67  		{0x401130, [][2]uint64{{0x401130, 0x40117e}}},
    68  		{0x40117d, [][2]uint64{{0x401130, 0x40117e}}},
    69  		{0x40117e, nil},
    70  	}
    71  	testRanges(t, "testdata/line-clang-dwarf5.elf", want)
    72  }
    73  
    74  func TestRangesSection(t *testing.T) {
    75  	want := []wantRange{
    76  		{0x400500, [][2]uint64{{0x400500, 0x400549}, {0x400400, 0x400408}}},
    77  		{0x400400, [][2]uint64{{0x400500, 0x400549}, {0x400400, 0x400408}}},
    78  		{0x400548, [][2]uint64{{0x400500, 0x400549}, {0x400400, 0x400408}}},
    79  		{0x400407, [][2]uint64{{0x400500, 0x400549}, {0x400400, 0x400408}}},
    80  		{0x400408, nil},
    81  		{0x400449, nil},
    82  		{0x4003ff, nil},
    83  	}
    84  	testRanges(t, "testdata/ranges.elf", want)
    85  }
    86  
    87  func testRanges(t *testing.T, name string, want []wantRange) {
    88  	d := elfData(t, name)
    89  	r := d.Reader()
    90  	for _, w := range want {
    91  		entry, err := r.SeekPC(w.pc)
    92  		if err != nil {
    93  			if w.ranges != nil {
    94  				t.Errorf("%s: missing Entry for %#x", name, w.pc)
    95  			}
    96  			if err != ErrUnknownPC {
    97  				t.Errorf("%s: expected ErrUnknownPC for %#x, got %v", name, w.pc, err)
    98  			}
    99  			continue
   100  		}
   101  
   102  		ranges, err := d.Ranges(entry)
   103  		if err != nil {
   104  			t.Errorf("%s: %v", name, err)
   105  			continue
   106  		}
   107  		if !reflect.DeepEqual(ranges, w.ranges) {
   108  			t.Errorf("%s: for %#x got %x, expected %x", name, w.pc, ranges, w.ranges)
   109  		}
   110  	}
   111  }
   112  
   113  func TestReaderRanges(t *testing.T) {
   114  	type subprograms []struct {
   115  		name   string
   116  		ranges [][2]uint64
   117  	}
   118  	tests := []struct {
   119  		filename    string
   120  		subprograms subprograms
   121  	}{
   122  		{
   123  			"testdata/line-gcc.elf",
   124  			subprograms{
   125  				{"f1", [][2]uint64{{0x40059d, 0x4005e7}}},
   126  				{"main", [][2]uint64{{0x4005e7, 0x400601}}},
   127  				{"f2", [][2]uint64{{0x400601, 0x400611}}},
   128  			},
   129  		},
   130  		{
   131  			"testdata/line-gcc-dwarf5.elf",
   132  			subprograms{
   133  				{"main", [][2]uint64{{0x401147, 0x401166}}},
   134  				{"f1", [][2]uint64{{0x401122, 0x401147}}},
   135  				{"f2", [][2]uint64{{0x401166, 0x401179}}},
   136  			},
   137  		},
   138  		{
   139  			"testdata/line-clang-dwarf5.elf",
   140  			subprograms{
   141  				{"main", [][2]uint64{{0x401130, 0x401144}}},
   142  				{"f1", [][2]uint64{{0x401150, 0x40117e}}},
   143  				{"f2", [][2]uint64{{0x401180, 0x401197}}},
   144  			},
   145  		},
   146  	}
   147  
   148  	for _, test := range tests {
   149  		d := elfData(t, test.filename)
   150  		subprograms := test.subprograms
   151  
   152  		r := d.Reader()
   153  		i := 0
   154  		for entry, err := r.Next(); entry != nil && err == nil; entry, err = r.Next() {
   155  			if entry.Tag != TagSubprogram {
   156  				continue
   157  			}
   158  
   159  			if i > len(subprograms) {
   160  				t.Fatalf("%s: too many subprograms (expected at most %d)", test.filename, i)
   161  			}
   162  
   163  			if got := entry.Val(AttrName).(string); got != subprograms[i].name {
   164  				t.Errorf("%s: subprogram %d name is %s, expected %s", test.filename, i, got, subprograms[i].name)
   165  			}
   166  			ranges, err := d.Ranges(entry)
   167  			if err != nil {
   168  				t.Errorf("%s: subprogram %d: %v", test.filename, i, err)
   169  				continue
   170  			}
   171  			if !reflect.DeepEqual(ranges, subprograms[i].ranges) {
   172  				t.Errorf("%s: subprogram %d ranges are %x, expected %x", test.filename, i, ranges, subprograms[i].ranges)
   173  			}
   174  			i++
   175  		}
   176  
   177  		if i < len(subprograms) {
   178  			t.Errorf("%s: saw only %d subprograms, expected %d", test.filename, i, len(subprograms))
   179  		}
   180  	}
   181  }
   182  
   183  func Test64Bit(t *testing.T) {
   184  	// I don't know how to generate a 64-bit DWARF debug
   185  	// compilation unit except by using XCOFF, so this is
   186  	// hand-written.
   187  	tests := []struct {
   188  		name      string
   189  		info      []byte
   190  		addrSize  int
   191  		byteOrder binary.ByteOrder
   192  	}{
   193  		{
   194  			"32-bit little",
   195  			[]byte{0x30, 0, 0, 0, // comp unit length
   196  				4, 0, // DWARF version 4
   197  				0, 0, 0, 0, // abbrev offset
   198  				8, // address size
   199  				0,
   200  				0, 0, 0, 0, 0, 0, 0, 0,
   201  				0, 0, 0, 0, 0, 0, 0, 0,
   202  				0, 0, 0, 0, 0, 0, 0, 0,
   203  				0, 0, 0, 0, 0, 0, 0, 0,
   204  				0, 0, 0, 0, 0, 0, 0, 0,
   205  			},
   206  			8, binary.LittleEndian,
   207  		},
   208  		{
   209  			"64-bit little",
   210  			[]byte{0xff, 0xff, 0xff, 0xff, // 64-bit DWARF
   211  				0x30, 0, 0, 0, 0, 0, 0, 0, // comp unit length
   212  				4, 0, // DWARF version 4
   213  				0, 0, 0, 0, 0, 0, 0, 0, // abbrev offset
   214  				8, // address size
   215  				0, 0, 0, 0, 0,
   216  				0, 0, 0, 0, 0, 0, 0, 0,
   217  				0, 0, 0, 0, 0, 0, 0, 0,
   218  				0, 0, 0, 0, 0, 0, 0, 0,
   219  				0, 0, 0, 0, 0, 0, 0, 0,
   220  			},
   221  			8, binary.LittleEndian,
   222  		},
   223  		{
   224  			"64-bit big",
   225  			[]byte{0xff, 0xff, 0xff, 0xff, // 64-bit DWARF
   226  				0, 0, 0, 0, 0, 0, 0, 0x30, // comp unit length
   227  				0, 4, // DWARF version 4
   228  				0, 0, 0, 0, 0, 0, 0, 0, // abbrev offset
   229  				8, // address size
   230  				0, 0, 0, 0, 0,
   231  				0, 0, 0, 0, 0, 0, 0, 0,
   232  				0, 0, 0, 0, 0, 0, 0, 0,
   233  				0, 0, 0, 0, 0, 0, 0, 0,
   234  				0, 0, 0, 0, 0, 0, 0, 0,
   235  			},
   236  			8, binary.BigEndian,
   237  		},
   238  	}
   239  
   240  	for _, test := range tests {
   241  		data, err := New(nil, nil, nil, test.info, nil, nil, nil, nil)
   242  		if err != nil {
   243  			t.Errorf("%s: %v", test.name, err)
   244  		}
   245  
   246  		r := data.Reader()
   247  		if r.AddressSize() != test.addrSize {
   248  			t.Errorf("%s: got address size %d, want %d", test.name, r.AddressSize(), test.addrSize)
   249  		}
   250  		if r.ByteOrder() != test.byteOrder {
   251  			t.Errorf("%s: got byte order %s, want %s", test.name, r.ByteOrder(), test.byteOrder)
   252  		}
   253  	}
   254  }
   255  
   256  func TestUnitIteration(t *testing.T) {
   257  	// Iterate over all ELF test files we have and ensure that
   258  	// we get the same set of compilation units skipping (method 0)
   259  	// and not skipping (method 1) CU children.
   260  	files, err := filepath.Glob(filepath.Join("testdata", "*.elf"))
   261  	if err != nil {
   262  		t.Fatal(err)
   263  	}
   264  	for _, file := range files {
   265  		t.Run(file, func(t *testing.T) {
   266  			d := elfData(t, file)
   267  			var units [2][]interface{}
   268  			for method := range units {
   269  				for r := d.Reader(); ; {
   270  					ent, err := r.Next()
   271  					if err != nil {
   272  						t.Fatal(err)
   273  					}
   274  					if ent == nil {
   275  						break
   276  					}
   277  					if ent.Tag == TagCompileUnit {
   278  						units[method] = append(units[method], ent.Val(AttrName))
   279  					}
   280  					if method == 0 {
   281  						if ent.Tag != TagCompileUnit {
   282  							t.Fatalf("found unexpected tag %v on top level", ent.Tag)
   283  						}
   284  						r.SkipChildren()
   285  					}
   286  				}
   287  			}
   288  			t.Logf("skipping CUs:     %v", units[0])
   289  			t.Logf("not-skipping CUs: %v", units[1])
   290  			if !reflect.DeepEqual(units[0], units[1]) {
   291  				t.Fatal("set of CUs differ")
   292  			}
   293  		})
   294  	}
   295  }