github.com/flyinox/gosm@v0.0.0-20171117061539-16768cb62077/src/debug/dwarf/type_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  	"debug/elf"
    10  	"debug/macho"
    11  	"debug/pe"
    12  	"testing"
    13  )
    14  
    15  var typedefTests = map[string]string{
    16  	"t_ptr_volatile_int":                    "*volatile int",
    17  	"t_ptr_const_char":                      "*const char",
    18  	"t_long":                                "long int",
    19  	"t_ushort":                              "short unsigned int",
    20  	"t_func_int_of_float_double":            "func(float, double) int",
    21  	"t_ptr_func_int_of_float_double":        "*func(float, double) int",
    22  	"t_ptr_func_int_of_float_complex":       "*func(complex float) int",
    23  	"t_ptr_func_int_of_double_complex":      "*func(complex double) int",
    24  	"t_ptr_func_int_of_long_double_complex": "*func(complex long double) int",
    25  	"t_func_ptr_int_of_char_schar_uchar":    "func(char, signed char, unsigned char) *int",
    26  	"t_func_void_of_char":                   "func(char) void",
    27  	"t_func_void_of_void":                   "func() void",
    28  	"t_func_void_of_ptr_char_dots":          "func(*char, ...) void",
    29  	"t_my_struct":                           "struct my_struct {vi volatile int@0; x char@4 : 1@7; y int@4 : 4@27; z [0]int@8; array [40]long long int@8; zz [0]int@328}",
    30  	"t_my_struct1":                          "struct my_struct1 {zz [1]int@0}",
    31  	"t_my_union":                            "union my_union {vi volatile int@0; x char@0 : 1@7; y int@0 : 4@28; array [40]long long int@0}",
    32  	"t_my_enum":                             "enum my_enum {e1=1; e2=2; e3=-5; e4=1000000000000000}",
    33  	"t_my_list":                             "struct list {val short int@0; next *t_my_list@8}",
    34  	"t_my_tree":                             "struct tree {left *struct tree@0; right *struct tree@8; val long long unsigned int@16}",
    35  }
    36  
    37  // As Apple converts gcc to a clang-based front end
    38  // they keep breaking the DWARF output. This map lists the
    39  // conversion from real answer to Apple answer.
    40  var machoBug = map[string]string{
    41  	"func(*char, ...) void":                                 "func(*char) void",
    42  	"enum my_enum {e1=1; e2=2; e3=-5; e4=1000000000000000}": "enum my_enum {e1=1; e2=2; e3=-5; e4=-1530494976}",
    43  }
    44  
    45  func elfData(t *testing.T, name string) *Data {
    46  	f, err := elf.Open(name)
    47  	if err != nil {
    48  		t.Fatal(err)
    49  	}
    50  
    51  	d, err := f.DWARF()
    52  	if err != nil {
    53  		t.Fatal(err)
    54  	}
    55  	return d
    56  }
    57  
    58  func machoData(t *testing.T, name string) *Data {
    59  	f, err := macho.Open(name)
    60  	if err != nil {
    61  		t.Fatal(err)
    62  	}
    63  
    64  	d, err := f.DWARF()
    65  	if err != nil {
    66  		t.Fatal(err)
    67  	}
    68  	return d
    69  }
    70  
    71  func peData(t *testing.T, name string) *Data {
    72  	f, err := pe.Open(name)
    73  	if err != nil {
    74  		t.Fatal(err)
    75  	}
    76  
    77  	d, err := f.DWARF()
    78  	if err != nil {
    79  		t.Fatal(err)
    80  	}
    81  	return d
    82  }
    83  
    84  func TestTypedefsELF(t *testing.T) { testTypedefs(t, elfData(t, "testdata/typedef.elf"), "elf") }
    85  
    86  func TestTypedefsMachO(t *testing.T) {
    87  	testTypedefs(t, machoData(t, "testdata/typedef.macho"), "macho")
    88  }
    89  
    90  func TestTypedefsELFDwarf4(t *testing.T) { testTypedefs(t, elfData(t, "testdata/typedef.elf4"), "elf") }
    91  
    92  func testTypedefs(t *testing.T, d *Data, kind string) {
    93  	r := d.Reader()
    94  	seen := make(map[string]bool)
    95  	for {
    96  		e, err := r.Next()
    97  		if err != nil {
    98  			t.Fatal("r.Next:", err)
    99  		}
   100  		if e == nil {
   101  			break
   102  		}
   103  		if e.Tag == TagTypedef {
   104  			typ, err := d.Type(e.Offset)
   105  			if err != nil {
   106  				t.Fatal("d.Type:", err)
   107  			}
   108  			t1 := typ.(*TypedefType)
   109  			var typstr string
   110  			if ts, ok := t1.Type.(*StructType); ok {
   111  				typstr = ts.Defn()
   112  			} else {
   113  				typstr = t1.Type.String()
   114  			}
   115  
   116  			if want, ok := typedefTests[t1.Name]; ok {
   117  				if seen[t1.Name] {
   118  					t.Errorf("multiple definitions for %s", t1.Name)
   119  				}
   120  				seen[t1.Name] = true
   121  				if typstr != want && (kind != "macho" || typstr != machoBug[want]) {
   122  					t.Errorf("%s:\n\thave %s\n\twant %s", t1.Name, typstr, want)
   123  				}
   124  			}
   125  		}
   126  		if e.Tag != TagCompileUnit {
   127  			r.SkipChildren()
   128  		}
   129  	}
   130  
   131  	for k := range typedefTests {
   132  		if !seen[k] {
   133  			t.Errorf("missing %s", k)
   134  		}
   135  	}
   136  }
   137  
   138  func TestTypedefCycle(t *testing.T) {
   139  	// See issue #13039: reading a typedef cycle starting from a
   140  	// different place than the size needed to be computed from
   141  	// used to crash.
   142  	//
   143  	// cycle.elf built with GCC 4.8.4:
   144  	//    gcc -g -c -o cycle.elf cycle.c
   145  	d := elfData(t, "testdata/cycle.elf")
   146  	r := d.Reader()
   147  	offsets := []Offset{}
   148  	for {
   149  		e, err := r.Next()
   150  		if err != nil {
   151  			t.Fatal("r.Next:", err)
   152  		}
   153  		if e == nil {
   154  			break
   155  		}
   156  		switch e.Tag {
   157  		case TagBaseType, TagTypedef, TagPointerType, TagStructType:
   158  			offsets = append(offsets, e.Offset)
   159  		}
   160  	}
   161  
   162  	// Parse each type with a fresh type cache.
   163  	for _, offset := range offsets {
   164  		d := elfData(t, "testdata/cycle.elf")
   165  		_, err := d.Type(offset)
   166  		if err != nil {
   167  			t.Fatalf("d.Type(0x%x): %s", offset, err)
   168  		}
   169  	}
   170  }