Home | History | Annotate | Download | only in dwarf
      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 	"reflect"
     10 	"testing"
     11 )
     12 
     13 func TestSplit(t *testing.T) {
     14 	// debug/dwarf doesn't (currently) support split DWARF, but
     15 	// the attributes that pointed to the split DWARF used to
     16 	// cause loading the DWARF data to fail entirely (issue
     17 	// #12592). Test that we can at least read the DWARF data.
     18 	d := elfData(t, "testdata/split.elf")
     19 	r := d.Reader()
     20 	e, err := r.Next()
     21 	if err != nil {
     22 		t.Fatal(err)
     23 	}
     24 	if e.Tag != TagCompileUnit {
     25 		t.Fatalf("bad tag: have %s, want %s", e.Tag, TagCompileUnit)
     26 	}
     27 	// Check that we were able to parse the unknown section offset
     28 	// field, even if we can't figure out its DWARF class.
     29 	const AttrGNUAddrBase Attr = 0x2133
     30 	f := e.AttrField(AttrGNUAddrBase)
     31 	if _, ok := f.Val.(int64); !ok {
     32 		t.Fatalf("bad attribute value type: have %T, want int64", f.Val)
     33 	}
     34 	if f.Class != ClassUnknown {
     35 		t.Fatalf("bad class: have %s, want %s", f.Class, ClassUnknown)
     36 	}
     37 }
     38 
     39 // wantRange maps from a PC to the ranges of the compilation unit
     40 // containing that PC.
     41 type wantRange struct {
     42 	pc     uint64
     43 	ranges [][2]uint64
     44 }
     45 
     46 func TestReaderSeek(t *testing.T) {
     47 	want := []wantRange{
     48 		{0x40059d, [][2]uint64{{0x40059d, 0x400601}}},
     49 		{0x400600, [][2]uint64{{0x40059d, 0x400601}}},
     50 		{0x400601, [][2]uint64{{0x400601, 0x400611}}},
     51 		{0x4005f0, [][2]uint64{{0x40059d, 0x400601}}}, // loop test
     52 		{0x10, nil},
     53 		{0x400611, nil},
     54 	}
     55 	testRanges(t, "testdata/line-gcc.elf", want)
     56 }
     57 
     58 func TestRangesSection(t *testing.T) {
     59 	want := []wantRange{
     60 		{0x400500, [][2]uint64{{0x400500, 0x400549}, {0x400400, 0x400408}}},
     61 		{0x400400, [][2]uint64{{0x400500, 0x400549}, {0x400400, 0x400408}}},
     62 		{0x400548, [][2]uint64{{0x400500, 0x400549}, {0x400400, 0x400408}}},
     63 		{0x400407, [][2]uint64{{0x400500, 0x400549}, {0x400400, 0x400408}}},
     64 		{0x400408, nil},
     65 		{0x400449, nil},
     66 		{0x4003ff, nil},
     67 	}
     68 	testRanges(t, "testdata/ranges.elf", want)
     69 }
     70 
     71 func testRanges(t *testing.T, name string, want []wantRange) {
     72 	d := elfData(t, name)
     73 	r := d.Reader()
     74 	for _, w := range want {
     75 		entry, err := r.SeekPC(w.pc)
     76 		if err != nil {
     77 			if w.ranges != nil {
     78 				t.Errorf("%s: missing Entry for %#x", name, w.pc)
     79 			}
     80 			if err != ErrUnknownPC {
     81 				t.Errorf("%s: expected ErrUnknownPC for %#x, got %v", name, w.pc, err)
     82 			}
     83 			continue
     84 		}
     85 
     86 		ranges, err := d.Ranges(entry)
     87 		if err != nil {
     88 			t.Errorf("%s: %v", name, err)
     89 			continue
     90 		}
     91 		if !reflect.DeepEqual(ranges, w.ranges) {
     92 			t.Errorf("%s: for %#x got %x, expected %x", name, w.pc, ranges, w.ranges)
     93 		}
     94 	}
     95 }
     96 
     97 func TestReaderRanges(t *testing.T) {
     98 	d := elfData(t, "testdata/line-gcc.elf")
     99 
    100 	subprograms := []struct {
    101 		name   string
    102 		ranges [][2]uint64
    103 	}{
    104 		{"f1", [][2]uint64{{0x40059d, 0x4005e7}}},
    105 		{"main", [][2]uint64{{0x4005e7, 0x400601}}},
    106 		{"f2", [][2]uint64{{0x400601, 0x400611}}},
    107 	}
    108 
    109 	r := d.Reader()
    110 	i := 0
    111 	for entry, err := r.Next(); entry != nil && err == nil; entry, err = r.Next() {
    112 		if entry.Tag != TagSubprogram {
    113 			continue
    114 		}
    115 
    116 		if i > len(subprograms) {
    117 			t.Fatalf("too many subprograms (expected at most %d)", i)
    118 		}
    119 
    120 		if got := entry.Val(AttrName).(string); got != subprograms[i].name {
    121 			t.Errorf("subprogram %d name is %s, expected %s", i, got, subprograms[i].name)
    122 		}
    123 		ranges, err := d.Ranges(entry)
    124 		if err != nil {
    125 			t.Errorf("subprogram %d: %v", i, err)
    126 			continue
    127 		}
    128 		if !reflect.DeepEqual(ranges, subprograms[i].ranges) {
    129 			t.Errorf("subprogram %d ranges are %x, expected %x", i, ranges, subprograms[i].ranges)
    130 		}
    131 		i++
    132 	}
    133 
    134 	if i < len(subprograms) {
    135 		t.Errorf("saw only %d subprograms, expected %d", i, len(subprograms))
    136 	}
    137 }
    138 
    139 func Test64Bit(t *testing.T) {
    140 	// I don't know how to generate a 64-bit DWARF debug
    141 	// compilation unit except by using XCOFF, so this is
    142 	// hand-written.
    143 	tests := []struct {
    144 		name string
    145 		info []byte
    146 	}{
    147 		{
    148 			"32-bit little",
    149 			[]byte{0x30, 0, 0, 0, // comp unit length
    150 				4, 0, // DWARF version 4
    151 				0, 0, 0, 0, // abbrev offset
    152 				8, // address size
    153 				0,
    154 				0, 0, 0, 0, 0, 0, 0, 0,
    155 				0, 0, 0, 0, 0, 0, 0, 0,
    156 				0, 0, 0, 0, 0, 0, 0, 0,
    157 				0, 0, 0, 0, 0, 0, 0, 0,
    158 				0, 0, 0, 0, 0, 0, 0, 0,
    159 			},
    160 		},
    161 		{
    162 			"64-bit little",
    163 			[]byte{0xff, 0xff, 0xff, 0xff, // 64-bit DWARF
    164 				0x30, 0, 0, 0, 0, 0, 0, 0, // comp unit length
    165 				4, 0, // DWARF version 4
    166 				0, 0, 0, 0, 0, 0, 0, 0, // abbrev offset
    167 				8, // address size
    168 				0, 0, 0, 0, 0,
    169 				0, 0, 0, 0, 0, 0, 0, 0,
    170 				0, 0, 0, 0, 0, 0, 0, 0,
    171 				0, 0, 0, 0, 0, 0, 0, 0,
    172 				0, 0, 0, 0, 0, 0, 0, 0,
    173 			},
    174 		},
    175 		{
    176 			"64-bit big",
    177 			[]byte{0xff, 0xff, 0xff, 0xff, // 64-bit DWARF
    178 				0, 0, 0, 0, 0, 0, 0, 0x30, // comp unit length
    179 				0, 4, // DWARF version 4
    180 				0, 0, 0, 0, 0, 0, 0, 0, // abbrev offset
    181 				8, // address size
    182 				0, 0, 0, 0, 0,
    183 				0, 0, 0, 0, 0, 0, 0, 0,
    184 				0, 0, 0, 0, 0, 0, 0, 0,
    185 				0, 0, 0, 0, 0, 0, 0, 0,
    186 				0, 0, 0, 0, 0, 0, 0, 0,
    187 			},
    188 		},
    189 	}
    190 
    191 	for _, test := range tests {
    192 		_, err := New(nil, nil, nil, test.info, nil, nil, nil, nil)
    193 		if err != nil {
    194 			t.Errorf("%s: %v", test.name, err)
    195 		}
    196 	}
    197 }
    198