github.com/geraldss/go/src@v0.0.0-20210511222824-ac7d0ebfc235/debug/macho/file_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 macho 6 7 import ( 8 "bytes" 9 "internal/obscuretestdata" 10 "io" 11 "reflect" 12 "testing" 13 ) 14 15 type fileTest struct { 16 file string 17 hdr FileHeader 18 loads []interface{} 19 sections []*SectionHeader 20 relocations map[string][]Reloc 21 } 22 23 var fileTests = []fileTest{ 24 { 25 "testdata/gcc-386-darwin-exec.base64", 26 FileHeader{0xfeedface, Cpu386, 0x3, 0x2, 0xc, 0x3c0, 0x85}, 27 []interface{}{ 28 &SegmentHeader{LoadCmdSegment, 0x38, "__PAGEZERO", 0x0, 0x1000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, 29 &SegmentHeader{LoadCmdSegment, 0xc0, "__TEXT", 0x1000, 0x1000, 0x0, 0x1000, 0x7, 0x5, 0x2, 0x0}, 30 &SegmentHeader{LoadCmdSegment, 0xc0, "__DATA", 0x2000, 0x1000, 0x1000, 0x1000, 0x7, 0x3, 0x2, 0x0}, 31 &SegmentHeader{LoadCmdSegment, 0x7c, "__IMPORT", 0x3000, 0x1000, 0x2000, 0x1000, 0x7, 0x7, 0x1, 0x0}, 32 &SegmentHeader{LoadCmdSegment, 0x38, "__LINKEDIT", 0x4000, 0x1000, 0x3000, 0x12c, 0x7, 0x1, 0x0, 0x0}, 33 nil, // LC_SYMTAB 34 nil, // LC_DYSYMTAB 35 nil, // LC_LOAD_DYLINKER 36 nil, // LC_UUID 37 nil, // LC_UNIXTHREAD 38 &Dylib{nil, "/usr/lib/libgcc_s.1.dylib", 0x2, 0x10000, 0x10000}, 39 &Dylib{nil, "/usr/lib/libSystem.B.dylib", 0x2, 0x6f0104, 0x10000}, 40 }, 41 []*SectionHeader{ 42 {"__text", "__TEXT", 0x1f68, 0x88, 0xf68, 0x2, 0x0, 0x0, 0x80000400}, 43 {"__cstring", "__TEXT", 0x1ff0, 0xd, 0xff0, 0x0, 0x0, 0x0, 0x2}, 44 {"__data", "__DATA", 0x2000, 0x14, 0x1000, 0x2, 0x0, 0x0, 0x0}, 45 {"__dyld", "__DATA", 0x2014, 0x1c, 0x1014, 0x2, 0x0, 0x0, 0x0}, 46 {"__jump_table", "__IMPORT", 0x3000, 0xa, 0x2000, 0x6, 0x0, 0x0, 0x4000008}, 47 }, 48 nil, 49 }, 50 { 51 "testdata/gcc-amd64-darwin-exec.base64", 52 FileHeader{0xfeedfacf, CpuAmd64, 0x80000003, 0x2, 0xb, 0x568, 0x85}, 53 []interface{}{ 54 &SegmentHeader{LoadCmdSegment64, 0x48, "__PAGEZERO", 0x0, 0x100000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, 55 &SegmentHeader{LoadCmdSegment64, 0x1d8, "__TEXT", 0x100000000, 0x1000, 0x0, 0x1000, 0x7, 0x5, 0x5, 0x0}, 56 &SegmentHeader{LoadCmdSegment64, 0x138, "__DATA", 0x100001000, 0x1000, 0x1000, 0x1000, 0x7, 0x3, 0x3, 0x0}, 57 &SegmentHeader{LoadCmdSegment64, 0x48, "__LINKEDIT", 0x100002000, 0x1000, 0x2000, 0x140, 0x7, 0x1, 0x0, 0x0}, 58 nil, // LC_SYMTAB 59 nil, // LC_DYSYMTAB 60 nil, // LC_LOAD_DYLINKER 61 nil, // LC_UUID 62 nil, // LC_UNIXTHREAD 63 &Dylib{nil, "/usr/lib/libgcc_s.1.dylib", 0x2, 0x10000, 0x10000}, 64 &Dylib{nil, "/usr/lib/libSystem.B.dylib", 0x2, 0x6f0104, 0x10000}, 65 }, 66 []*SectionHeader{ 67 {"__text", "__TEXT", 0x100000f14, 0x6d, 0xf14, 0x2, 0x0, 0x0, 0x80000400}, 68 {"__symbol_stub1", "__TEXT", 0x100000f81, 0xc, 0xf81, 0x0, 0x0, 0x0, 0x80000408}, 69 {"__stub_helper", "__TEXT", 0x100000f90, 0x18, 0xf90, 0x2, 0x0, 0x0, 0x0}, 70 {"__cstring", "__TEXT", 0x100000fa8, 0xd, 0xfa8, 0x0, 0x0, 0x0, 0x2}, 71 {"__eh_frame", "__TEXT", 0x100000fb8, 0x48, 0xfb8, 0x3, 0x0, 0x0, 0x6000000b}, 72 {"__data", "__DATA", 0x100001000, 0x1c, 0x1000, 0x3, 0x0, 0x0, 0x0}, 73 {"__dyld", "__DATA", 0x100001020, 0x38, 0x1020, 0x3, 0x0, 0x0, 0x0}, 74 {"__la_symbol_ptr", "__DATA", 0x100001058, 0x10, 0x1058, 0x2, 0x0, 0x0, 0x7}, 75 }, 76 nil, 77 }, 78 { 79 "testdata/gcc-amd64-darwin-exec-debug.base64", 80 FileHeader{0xfeedfacf, CpuAmd64, 0x80000003, 0xa, 0x4, 0x5a0, 0}, 81 []interface{}{ 82 nil, // LC_UUID 83 &SegmentHeader{LoadCmdSegment64, 0x1d8, "__TEXT", 0x100000000, 0x1000, 0x0, 0x0, 0x7, 0x5, 0x5, 0x0}, 84 &SegmentHeader{LoadCmdSegment64, 0x138, "__DATA", 0x100001000, 0x1000, 0x0, 0x0, 0x7, 0x3, 0x3, 0x0}, 85 &SegmentHeader{LoadCmdSegment64, 0x278, "__DWARF", 0x100002000, 0x1000, 0x1000, 0x1bc, 0x7, 0x3, 0x7, 0x0}, 86 }, 87 []*SectionHeader{ 88 {"__text", "__TEXT", 0x100000f14, 0x0, 0x0, 0x2, 0x0, 0x0, 0x80000400}, 89 {"__symbol_stub1", "__TEXT", 0x100000f81, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80000408}, 90 {"__stub_helper", "__TEXT", 0x100000f90, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0}, 91 {"__cstring", "__TEXT", 0x100000fa8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}, 92 {"__eh_frame", "__TEXT", 0x100000fb8, 0x0, 0x0, 0x3, 0x0, 0x0, 0x6000000b}, 93 {"__data", "__DATA", 0x100001000, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0}, 94 {"__dyld", "__DATA", 0x100001020, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0}, 95 {"__la_symbol_ptr", "__DATA", 0x100001058, 0x0, 0x0, 0x2, 0x0, 0x0, 0x7}, 96 {"__debug_abbrev", "__DWARF", 0x100002000, 0x36, 0x1000, 0x0, 0x0, 0x0, 0x0}, 97 {"__debug_aranges", "__DWARF", 0x100002036, 0x30, 0x1036, 0x0, 0x0, 0x0, 0x0}, 98 {"__debug_frame", "__DWARF", 0x100002066, 0x40, 0x1066, 0x0, 0x0, 0x0, 0x0}, 99 {"__debug_info", "__DWARF", 0x1000020a6, 0x54, 0x10a6, 0x0, 0x0, 0x0, 0x0}, 100 {"__debug_line", "__DWARF", 0x1000020fa, 0x47, 0x10fa, 0x0, 0x0, 0x0, 0x0}, 101 {"__debug_pubnames", "__DWARF", 0x100002141, 0x1b, 0x1141, 0x0, 0x0, 0x0, 0x0}, 102 {"__debug_str", "__DWARF", 0x10000215c, 0x60, 0x115c, 0x0, 0x0, 0x0, 0x0}, 103 }, 104 nil, 105 }, 106 { 107 "testdata/clang-386-darwin-exec-with-rpath.base64", 108 FileHeader{0xfeedface, Cpu386, 0x3, 0x2, 0x10, 0x42c, 0x1200085}, 109 []interface{}{ 110 nil, // LC_SEGMENT 111 nil, // LC_SEGMENT 112 nil, // LC_SEGMENT 113 nil, // LC_SEGMENT 114 nil, // LC_DYLD_INFO_ONLY 115 nil, // LC_SYMTAB 116 nil, // LC_DYSYMTAB 117 nil, // LC_LOAD_DYLINKER 118 nil, // LC_UUID 119 nil, // LC_VERSION_MIN_MACOSX 120 nil, // LC_SOURCE_VERSION 121 nil, // LC_MAIN 122 nil, // LC_LOAD_DYLIB 123 &Rpath{nil, "/my/rpath"}, 124 nil, // LC_FUNCTION_STARTS 125 nil, // LC_DATA_IN_CODE 126 }, 127 nil, 128 nil, 129 }, 130 { 131 "testdata/clang-amd64-darwin-exec-with-rpath.base64", 132 FileHeader{0xfeedfacf, CpuAmd64, 0x80000003, 0x2, 0x10, 0x4c8, 0x200085}, 133 []interface{}{ 134 nil, // LC_SEGMENT 135 nil, // LC_SEGMENT 136 nil, // LC_SEGMENT 137 nil, // LC_SEGMENT 138 nil, // LC_DYLD_INFO_ONLY 139 nil, // LC_SYMTAB 140 nil, // LC_DYSYMTAB 141 nil, // LC_LOAD_DYLINKER 142 nil, // LC_UUID 143 nil, // LC_VERSION_MIN_MACOSX 144 nil, // LC_SOURCE_VERSION 145 nil, // LC_MAIN 146 nil, // LC_LOAD_DYLIB 147 &Rpath{nil, "/my/rpath"}, 148 nil, // LC_FUNCTION_STARTS 149 nil, // LC_DATA_IN_CODE 150 }, 151 nil, 152 nil, 153 }, 154 { 155 "testdata/clang-386-darwin.obj.base64", 156 FileHeader{0xfeedface, Cpu386, 0x3, 0x1, 0x4, 0x138, 0x2000}, 157 nil, 158 nil, 159 map[string][]Reloc{ 160 "__text": { 161 { 162 Addr: 0x1d, 163 Type: uint8(GENERIC_RELOC_VANILLA), 164 Len: 2, 165 Pcrel: true, 166 Extern: true, 167 Value: 1, 168 Scattered: false, 169 }, 170 { 171 Addr: 0xe, 172 Type: uint8(GENERIC_RELOC_LOCAL_SECTDIFF), 173 Len: 2, 174 Pcrel: false, 175 Value: 0x2d, 176 Scattered: true, 177 }, 178 { 179 Addr: 0x0, 180 Type: uint8(GENERIC_RELOC_PAIR), 181 Len: 2, 182 Pcrel: false, 183 Value: 0xb, 184 Scattered: true, 185 }, 186 }, 187 }, 188 }, 189 { 190 "testdata/clang-amd64-darwin.obj.base64", 191 FileHeader{0xfeedfacf, CpuAmd64, 0x3, 0x1, 0x4, 0x200, 0x2000}, 192 nil, 193 nil, 194 map[string][]Reloc{ 195 "__text": { 196 { 197 Addr: 0x19, 198 Type: uint8(X86_64_RELOC_BRANCH), 199 Len: 2, 200 Pcrel: true, 201 Extern: true, 202 Value: 1, 203 }, 204 { 205 Addr: 0xb, 206 Type: uint8(X86_64_RELOC_SIGNED), 207 Len: 2, 208 Pcrel: true, 209 Extern: false, 210 Value: 2, 211 }, 212 }, 213 "__compact_unwind": { 214 { 215 Addr: 0x0, 216 Type: uint8(X86_64_RELOC_UNSIGNED), 217 Len: 3, 218 Pcrel: false, 219 Extern: false, 220 Value: 1, 221 }, 222 }, 223 }, 224 }, 225 } 226 227 func readerAtFromObscured(name string) (io.ReaderAt, error) { 228 b, err := obscuretestdata.ReadFile(name) 229 if err != nil { 230 return nil, err 231 } 232 return bytes.NewReader(b), nil 233 } 234 235 func openObscured(name string) (*File, error) { 236 ra, err := readerAtFromObscured(name) 237 if err != nil { 238 return nil, err 239 } 240 ff, err := NewFile(ra) 241 if err != nil { 242 return nil, err 243 } 244 return ff, nil 245 } 246 247 func openFatObscured(name string) (*FatFile, error) { 248 ra, err := readerAtFromObscured(name) 249 if err != nil { 250 return nil, err 251 } 252 ff, err := NewFatFile(ra) 253 if err != nil { 254 return nil, err 255 } 256 return ff, nil 257 } 258 259 func TestOpen(t *testing.T) { 260 for i := range fileTests { 261 tt := &fileTests[i] 262 263 // Use obscured files to prevent Appleās notarization service from 264 // mistaking them as candidates for notarization and rejecting the entire 265 // toolchain. 266 // See golang.org/issue/34986 267 f, err := openObscured(tt.file) 268 if err != nil { 269 t.Error(err) 270 continue 271 } 272 if !reflect.DeepEqual(f.FileHeader, tt.hdr) { 273 t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr) 274 continue 275 } 276 for i, l := range f.Loads { 277 if len(l.Raw()) < 8 { 278 t.Errorf("open %s, command %d:\n\tload command %T don't have enough data\n", tt.file, i, l) 279 } 280 } 281 if tt.loads != nil { 282 for i, l := range f.Loads { 283 if i >= len(tt.loads) { 284 break 285 } 286 287 want := tt.loads[i] 288 if want == nil { 289 continue 290 } 291 292 switch l := l.(type) { 293 case *Segment: 294 have := &l.SegmentHeader 295 if !reflect.DeepEqual(have, want) { 296 t.Errorf("open %s, command %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want) 297 } 298 case *Dylib: 299 have := l 300 have.LoadBytes = nil 301 if !reflect.DeepEqual(have, want) { 302 t.Errorf("open %s, command %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want) 303 } 304 case *Rpath: 305 have := l 306 have.LoadBytes = nil 307 if !reflect.DeepEqual(have, want) { 308 t.Errorf("open %s, command %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want) 309 } 310 default: 311 t.Errorf("open %s, command %d: unknown load command\n\thave %#v\n\twant %#v\n", tt.file, i, l, want) 312 } 313 } 314 tn := len(tt.loads) 315 fn := len(f.Loads) 316 if tn != fn { 317 t.Errorf("open %s: len(Loads) = %d, want %d", tt.file, fn, tn) 318 } 319 } 320 321 if tt.sections != nil { 322 for i, sh := range f.Sections { 323 if i >= len(tt.sections) { 324 break 325 } 326 have := &sh.SectionHeader 327 want := tt.sections[i] 328 if !reflect.DeepEqual(have, want) { 329 t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want) 330 } 331 } 332 tn := len(tt.sections) 333 fn := len(f.Sections) 334 if tn != fn { 335 t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn) 336 } 337 } 338 339 if tt.relocations != nil { 340 for i, sh := range f.Sections { 341 have := sh.Relocs 342 want := tt.relocations[sh.Name] 343 if !reflect.DeepEqual(have, want) { 344 t.Errorf("open %s, relocations in section %d (%s):\n\thave %#v\n\twant %#v\n", tt.file, i, sh.Name, have, want) 345 } 346 } 347 } 348 } 349 } 350 351 func TestOpenFailure(t *testing.T) { 352 filename := "file.go" // not a Mach-O file 353 _, err := Open(filename) // don't crash 354 if err == nil { 355 t.Errorf("open %s: succeeded unexpectedly", filename) 356 } 357 } 358 359 func TestOpenFat(t *testing.T) { 360 ff, err := openFatObscured("testdata/fat-gcc-386-amd64-darwin-exec.base64") 361 if err != nil { 362 t.Fatal(err) 363 } 364 365 if ff.Magic != MagicFat { 366 t.Errorf("OpenFat: got magic number %#x, want %#x", ff.Magic, MagicFat) 367 } 368 if len(ff.Arches) != 2 { 369 t.Errorf("OpenFat: got %d architectures, want 2", len(ff.Arches)) 370 } 371 372 for i := range ff.Arches { 373 arch := &ff.Arches[i] 374 ftArch := &fileTests[i] 375 376 if arch.Cpu != ftArch.hdr.Cpu || arch.SubCpu != ftArch.hdr.SubCpu { 377 t.Errorf("OpenFat: architecture #%d got cpu=%#x subtype=%#x, expected cpu=%#x, subtype=%#x", i, arch.Cpu, arch.SubCpu, ftArch.hdr.Cpu, ftArch.hdr.SubCpu) 378 } 379 380 if !reflect.DeepEqual(arch.FileHeader, ftArch.hdr) { 381 t.Errorf("OpenFat header:\n\tgot %#v\n\twant %#v\n", arch.FileHeader, ftArch.hdr) 382 } 383 } 384 } 385 386 func TestOpenFatFailure(t *testing.T) { 387 filename := "file.go" // not a Mach-O file 388 if _, err := OpenFat(filename); err == nil { 389 t.Errorf("OpenFat %s: succeeded unexpectedly", filename) 390 } 391 392 filename = "testdata/gcc-386-darwin-exec.base64" // not a fat Mach-O 393 ff, err := openFatObscured(filename) 394 if err != ErrNotFat { 395 t.Errorf("OpenFat %s: got %v, want ErrNotFat", filename, err) 396 } 397 if ff != nil { 398 t.Errorf("OpenFat %s: got %v, want nil", filename, ff) 399 } 400 } 401 402 func TestRelocTypeString(t *testing.T) { 403 if X86_64_RELOC_BRANCH.String() != "X86_64_RELOC_BRANCH" { 404 t.Errorf("got %v, want %v", X86_64_RELOC_BRANCH.String(), "X86_64_RELOC_BRANCH") 405 } 406 if X86_64_RELOC_BRANCH.GoString() != "macho.X86_64_RELOC_BRANCH" { 407 t.Errorf("got %v, want %v", X86_64_RELOC_BRANCH.GoString(), "macho.X86_64_RELOC_BRANCH") 408 } 409 } 410 411 func TestTypeString(t *testing.T) { 412 if TypeExec.String() != "Exec" { 413 t.Errorf("got %v, want %v", TypeExec.String(), "Exec") 414 } 415 if TypeExec.GoString() != "macho.Exec" { 416 t.Errorf("got %v, want %v", TypeExec.GoString(), "macho.Exec") 417 } 418 }