github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/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 "fmt" 13 "strconv" 14 "testing" 15 ) 16 17 var typedefTests = map[string]string{ 18 "t_ptr_volatile_int": "*volatile int", 19 "t_ptr_const_char": "*const char", 20 "t_long": "long int", 21 "t_ushort": "short unsigned int", 22 "t_func_int_of_float_double": "func(float, double) int", 23 "t_ptr_func_int_of_float_double": "*func(float, double) int", 24 "t_ptr_func_int_of_float_complex": "*func(complex float) int", 25 "t_ptr_func_int_of_double_complex": "*func(complex double) int", 26 "t_ptr_func_int_of_long_double_complex": "*func(complex long double) int", 27 "t_func_ptr_int_of_char_schar_uchar": "func(char, signed char, unsigned char) *int", 28 "t_func_void_of_char": "func(char) void", 29 "t_func_void_of_void": "func() void", 30 "t_func_void_of_ptr_char_dots": "func(*char, ...) void", 31 "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}", 32 "t_my_struct1": "struct my_struct1 {zz [1]int@0}", 33 "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}", 34 "t_my_enum": "enum my_enum {e1=1; e2=2; e3=-5; e4=1000000000000000}", 35 "t_my_list": "struct list {val short int@0; next *t_my_list@8}", 36 "t_my_tree": "struct tree {left *struct tree@0; right *struct tree@8; val long long unsigned int@16}", 37 } 38 39 // As Apple converts gcc to a clang-based front end 40 // they keep breaking the DWARF output. This map lists the 41 // conversion from real answer to Apple answer. 42 var machoBug = map[string]string{ 43 "func(*char, ...) void": "func(*char) void", 44 "enum my_enum {e1=1; e2=2; e3=-5; e4=1000000000000000}": "enum my_enum {e1=1; e2=2; e3=-5; e4=-1530494976}", 45 } 46 47 func elfData(t *testing.T, name string) *Data { 48 f, err := elf.Open(name) 49 if err != nil { 50 t.Fatal(err) 51 } 52 53 d, err := f.DWARF() 54 if err != nil { 55 t.Fatal(err) 56 } 57 return d 58 } 59 60 func machoData(t *testing.T, name string) *Data { 61 f, err := macho.Open(name) 62 if err != nil { 63 t.Fatal(err) 64 } 65 66 d, err := f.DWARF() 67 if err != nil { 68 t.Fatal(err) 69 } 70 return d 71 } 72 73 func peData(t *testing.T, name string) *Data { 74 f, err := pe.Open(name) 75 if err != nil { 76 t.Fatal(err) 77 } 78 79 d, err := f.DWARF() 80 if err != nil { 81 t.Fatal(err) 82 } 83 return d 84 } 85 86 func TestTypedefsELF(t *testing.T) { 87 testTypedefs(t, elfData(t, "testdata/typedef.elf"), "elf", typedefTests) 88 } 89 90 func TestTypedefsMachO(t *testing.T) { 91 testTypedefs(t, machoData(t, "testdata/typedef.macho"), "macho", typedefTests) 92 } 93 94 func TestTypedefsELFDwarf4(t *testing.T) { 95 testTypedefs(t, elfData(t, "testdata/typedef.elf4"), "elf", typedefTests) 96 } 97 98 func testTypedefs(t *testing.T, d *Data, kind string, testcases map[string]string) { 99 r := d.Reader() 100 seen := make(map[string]bool) 101 for { 102 e, err := r.Next() 103 if err != nil { 104 t.Fatal("r.Next:", err) 105 } 106 if e == nil { 107 break 108 } 109 if e.Tag == TagTypedef { 110 typ, err := d.Type(e.Offset) 111 if err != nil { 112 t.Fatal("d.Type:", err) 113 } 114 t1 := typ.(*TypedefType) 115 var typstr string 116 if ts, ok := t1.Type.(*StructType); ok { 117 typstr = ts.Defn() 118 } else { 119 typstr = t1.Type.String() 120 } 121 122 if want, ok := testcases[t1.Name]; ok { 123 if seen[t1.Name] { 124 t.Errorf("multiple definitions for %s", t1.Name) 125 } 126 seen[t1.Name] = true 127 if typstr != want && (kind != "macho" || typstr != machoBug[want]) { 128 t.Errorf("%s:\n\thave %s\n\twant %s", t1.Name, typstr, want) 129 } 130 } 131 } 132 if e.Tag != TagCompileUnit { 133 r.SkipChildren() 134 } 135 } 136 137 for k := range testcases { 138 if !seen[k] { 139 t.Errorf("missing %s", k) 140 } 141 } 142 } 143 144 func TestTypedefCycle(t *testing.T) { 145 // See issue #13039: reading a typedef cycle starting from a 146 // different place than the size needed to be computed from 147 // used to crash. 148 // 149 // cycle.elf built with GCC 4.8.4: 150 // gcc -g -c -o cycle.elf cycle.c 151 d := elfData(t, "testdata/cycle.elf") 152 r := d.Reader() 153 offsets := []Offset{} 154 for { 155 e, err := r.Next() 156 if err != nil { 157 t.Fatal("r.Next:", err) 158 } 159 if e == nil { 160 break 161 } 162 switch e.Tag { 163 case TagBaseType, TagTypedef, TagPointerType, TagStructType: 164 offsets = append(offsets, e.Offset) 165 } 166 } 167 168 // Parse each type with a fresh type cache. 169 for _, offset := range offsets { 170 d := elfData(t, "testdata/cycle.elf") 171 _, err := d.Type(offset) 172 if err != nil { 173 t.Fatalf("d.Type(0x%x): %s", offset, err) 174 } 175 } 176 } 177 178 var unsupportedTypeTests = []string{ 179 // varname:typename:string:size 180 "culprit::(unsupported type ReferenceType):8", 181 "pdm::(unsupported type PtrToMemberType):-1", 182 } 183 184 func TestUnsupportedTypes(t *testing.T) { 185 // Issue 29601: 186 // When reading DWARF from C++ load modules, we can encounter 187 // oddball type DIEs. These will be returned as "UnsupportedType" 188 // objects; check to make sure this works properly. 189 d := elfData(t, "testdata/cppunsuptypes.elf") 190 r := d.Reader() 191 seen := make(map[string]bool) 192 for { 193 e, err := r.Next() 194 if err != nil { 195 t.Fatal("r.Next:", err) 196 } 197 if e == nil { 198 break 199 } 200 if e.Tag == TagVariable { 201 vname, _ := e.Val(AttrName).(string) 202 tAttr := e.Val(AttrType) 203 typOff, ok := tAttr.(Offset) 204 if !ok { 205 t.Errorf("variable at offset %v has no type", e.Offset) 206 continue 207 } 208 typ, err := d.Type(typOff) 209 if err != nil { 210 t.Errorf("err in type decode: %v\n", err) 211 continue 212 } 213 unsup, isok := typ.(*UnsupportedType) 214 if !isok { 215 continue 216 } 217 tag := vname + ":" + unsup.Name + ":" + unsup.String() + 218 ":" + strconv.FormatInt(unsup.Size(), 10) 219 seen[tag] = true 220 } 221 } 222 dumpseen := false 223 for _, v := range unsupportedTypeTests { 224 if !seen[v] { 225 t.Errorf("missing %s", v) 226 dumpseen = true 227 } 228 } 229 if dumpseen { 230 for k := range seen { 231 fmt.Printf("seen: %s\n", k) 232 } 233 } 234 } 235 236 var expectedBitOffsets1 = map[string]string{ 237 "x": "S:1 DBO:32", 238 "y": "S:4 DBO:33", 239 } 240 241 var expectedBitOffsets2 = map[string]string{ 242 "x": "S:1 BO:7", 243 "y": "S:4 BO:27", 244 } 245 246 func TestBitOffsetsELF(t *testing.T) { 247 f := "testdata/typedef.elf" 248 testBitOffsets(t, elfData(t, f), f, expectedBitOffsets2) 249 } 250 251 func TestBitOffsetsMachO(t *testing.T) { 252 f := "testdata/typedef.macho" 253 testBitOffsets(t, machoData(t, f), f, expectedBitOffsets2) 254 } 255 256 func TestBitOffsetsMachO4(t *testing.T) { 257 f := "testdata/typedef.macho4" 258 testBitOffsets(t, machoData(t, f), f, expectedBitOffsets1) 259 } 260 261 func TestBitOffsetsELFDwarf4(t *testing.T) { 262 f := "testdata/typedef.elf4" 263 testBitOffsets(t, elfData(t, f), f, expectedBitOffsets1) 264 } 265 266 func TestBitOffsetsELFDwarf5(t *testing.T) { 267 f := "testdata/typedef.elf5" 268 testBitOffsets(t, elfData(t, f), f, expectedBitOffsets1) 269 } 270 271 func testBitOffsets(t *testing.T, d *Data, tag string, expectedBitOffsets map[string]string) { 272 r := d.Reader() 273 for { 274 e, err := r.Next() 275 if err != nil { 276 t.Fatal("r.Next:", err) 277 } 278 if e == nil { 279 break 280 } 281 282 if e.Tag == TagStructType { 283 typ, err := d.Type(e.Offset) 284 if err != nil { 285 t.Fatal("d.Type:", err) 286 } 287 288 t1 := typ.(*StructType) 289 290 bitInfoDump := func(f *StructField) string { 291 res := fmt.Sprintf("S:%d", f.BitSize) 292 if f.BitOffset != 0 { 293 res += fmt.Sprintf(" BO:%d", f.BitOffset) 294 } 295 if f.DataBitOffset != 0 { 296 res += fmt.Sprintf(" DBO:%d", f.DataBitOffset) 297 } 298 return res 299 } 300 301 for _, field := range t1.Field { 302 // We're only testing for bitfields 303 if field.BitSize == 0 { 304 continue 305 } 306 got := bitInfoDump(field) 307 want := expectedBitOffsets[field.Name] 308 if got != want { 309 t.Errorf("%s: field %s in %s: got info %q want %q", tag, field.Name, t1.StructName, got, want) 310 } 311 } 312 } 313 if e.Tag != TagCompileUnit { 314 r.SkipChildren() 315 } 316 } 317 } 318 319 var bitfieldTests = map[string]string{ 320 "t_another_struct": "struct another_struct {quix short unsigned int@0; xyz [0]int@4; x unsigned int@4 : 1@31; array [40]long long int@8}", 321 } 322 323 // TestBitFieldZeroArrayIssue50685 checks to make sure that the DWARF 324 // type reading code doesn't get confused by the presence of a 325 // specifically-sized bitfield member immediately following a field 326 // whose type is a zero-length array. Prior to the fix for issue 327 // 50685, we would get this type for the case in testdata/bitfields.c: 328 // 329 // another_struct {quix short unsigned int@0; xyz [-1]int@4; x unsigned int@4 : 1@31; array [40]long long int@8} 330 // 331 // Note the "-1" for the xyz field, which should be zero. 332 func TestBitFieldZeroArrayIssue50685(t *testing.T) { 333 f := "testdata/bitfields.elf4" 334 testTypedefs(t, elfData(t, f), "elf", bitfieldTests) 335 }