github.com/guyezi/gofrontend@v0.0.0-20200228202240-7a62a49e62c0/libgo/go/debug/xcoff/file.go (about) 1 // Copyright 2017 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 xcoff implements access to XCOFF (Extended Common Object File Format) files. 6 package xcoff 7 8 import ( 9 "debug/dwarf" 10 "encoding/binary" 11 "fmt" 12 "io" 13 "os" 14 "strings" 15 ) 16 17 // Information we store about an XCOFF section header. 18 type SectionHeader struct { 19 Name string 20 VirtualAddress uint64 21 Size uint64 22 Type uint32 23 } 24 type Section struct { 25 SectionHeader 26 io.ReaderAt 27 sr *io.SectionReader 28 } 29 30 // Information we store about an XCOFF symbol. 31 type AuxiliaryCSect struct { 32 Length int64 33 StorageMappingClass int 34 SymbolType int 35 } 36 type Symbol struct { 37 Name string 38 Value uint64 39 SectionNumber int 40 StorageClass int 41 AuxCSect AuxiliaryCSect 42 } 43 44 // Information we store about an imported XCOFF symbol. 45 type ImportedSymbol struct { 46 Name string 47 Library string 48 } 49 50 // A File represents an open XCOFF file. 51 type FileHeader struct { 52 TargetMachine uint16 53 } 54 type File struct { 55 FileHeader 56 Sections []*Section 57 Symbols []*Symbol 58 StringTable []byte 59 LibraryPaths []string 60 61 closer io.Closer 62 } 63 64 // Open opens the named file using os.Open and prepares it for use as an XCOFF binary. 65 func Open(name string) (*File, error) { 66 f, err := os.Open(name) 67 if err != nil { 68 return nil, err 69 } 70 ff, err := NewFile(f) 71 if err != nil { 72 f.Close() 73 return nil, err 74 } 75 ff.closer = f 76 return ff, nil 77 } 78 79 // Close closes the File. 80 // If the File was created using NewFile directly instead of Open, 81 // Close has no effect. 82 func (f *File) Close() error { 83 var err error 84 if f.closer != nil { 85 err = f.closer.Close() 86 f.closer = nil 87 } 88 return err 89 } 90 91 // SectionByType returns the first section in f with the 92 // given type, or nil if there is no such section. 93 func (f *File) SectionByType(typ uint32) *Section { 94 for _, s := range f.Sections { 95 if s.Type == typ { 96 return s 97 } 98 } 99 return nil 100 } 101 102 // cstring converts ASCII byte sequence b to string. 103 // It stops once it finds 0 or reaches end of b. 104 func cstring(b []byte) string { 105 var i int 106 for i = 0; i < len(b) && b[i] != 0; i++ { 107 } 108 return string(b[:i]) 109 } 110 111 // getString extracts a string from an XCOFF string table. 112 func getString(st []byte, offset uint32) (string, bool) { 113 if offset < 4 || int(offset) >= len(st) { 114 return "", false 115 } 116 return cstring(st[offset:]), true 117 } 118 119 // NewFile creates a new File for accessing an XCOFF binary in an underlying reader. 120 func NewFile(r io.ReaderAt) (*File, error) { 121 sr := io.NewSectionReader(r, 0, 1<<63-1) 122 // Read XCOFF target machine 123 var magic uint16 124 if err := binary.Read(sr, binary.BigEndian, &magic); err != nil { 125 return nil, err 126 } 127 if magic != U802TOCMAGIC && magic != U64_TOCMAGIC { 128 return nil, fmt.Errorf("unrecognised XCOFF magic", magic) 129 } 130 131 f := new(File) 132 f.TargetMachine = magic 133 134 // Read XCOFF file header 135 sr.Seek(0, io.SeekStart) 136 var nscns uint16 137 var symptr uint64 138 var nsyms int32 139 var opthdr uint16 140 var hdrsz int 141 switch f.TargetMachine { 142 case U802TOCMAGIC: 143 fhdr := new(FileHeader32) 144 if err := binary.Read(sr, binary.BigEndian, fhdr); err != nil { 145 return nil, err 146 } 147 nscns = fhdr.Fnscns 148 symptr = uint64(fhdr.Fsymptr) 149 nsyms = fhdr.Fnsyms 150 opthdr = fhdr.Fopthdr 151 hdrsz = FILHSZ_32 152 case U64_TOCMAGIC: 153 fhdr := new(FileHeader64) 154 if err := binary.Read(sr, binary.BigEndian, fhdr); err != nil { 155 return nil, err 156 } 157 nscns = fhdr.Fnscns 158 symptr = fhdr.Fsymptr 159 nsyms = fhdr.Fnsyms 160 opthdr = fhdr.Fopthdr 161 hdrsz = FILHSZ_64 162 } 163 164 if symptr == 0 || nsyms <= 0 { 165 return nil, fmt.Errorf("no symbol table") 166 } 167 168 // Read string table (located right after symbol table). 169 offset := symptr + uint64(nsyms)*SYMESZ 170 sr.Seek(int64(offset), io.SeekStart) 171 // The first 4 bytes contain the length (in bytes). 172 var l uint32 173 binary.Read(sr, binary.BigEndian, &l) 174 if l > 4 { 175 sr.Seek(int64(offset), io.SeekStart) 176 f.StringTable = make([]byte, l) 177 io.ReadFull(sr, f.StringTable) 178 } 179 180 // Read section headers 181 sr.Seek(int64(hdrsz)+int64(opthdr), io.SeekStart) 182 f.Sections = make([]*Section, nscns) 183 for i := 0; i < int(nscns); i++ { 184 var scnptr uint64 185 s := new(Section) 186 switch f.TargetMachine { 187 case U802TOCMAGIC: 188 shdr := new(SectionHeader32) 189 if err := binary.Read(sr, binary.BigEndian, shdr); err != nil { 190 return nil, err 191 } 192 s.Name = cstring(shdr.Sname[:]) 193 s.VirtualAddress = uint64(shdr.Svaddr) 194 s.Size = uint64(shdr.Ssize) 195 scnptr = uint64(shdr.Sscnptr) 196 s.Type = shdr.Sflags 197 case U64_TOCMAGIC: 198 shdr := new(SectionHeader64) 199 if err := binary.Read(sr, binary.BigEndian, shdr); err != nil { 200 return nil, err 201 } 202 s.Name = cstring(shdr.Sname[:]) 203 s.VirtualAddress = shdr.Svaddr 204 s.Size = shdr.Ssize 205 scnptr = shdr.Sscnptr 206 s.Type = shdr.Sflags 207 } 208 r2 := r 209 if scnptr == 0 { // .bss must have all 0s 210 r2 = zeroReaderAt{} 211 } 212 s.sr = io.NewSectionReader(r2, int64(scnptr), int64(s.Size)) 213 s.ReaderAt = s.sr 214 f.Sections[i] = s 215 } 216 217 // Read symbol table 218 sr.Seek(int64(symptr), io.SeekStart) 219 f.Symbols = make([]*Symbol, 0) 220 for i := 0; i < int(nsyms); i++ { 221 var numaux int 222 var ok bool 223 sym := new(Symbol) 224 switch f.TargetMachine { 225 case U802TOCMAGIC: 226 se := new(SymEnt32) 227 if err := binary.Read(sr, binary.BigEndian, se); err != nil { 228 return nil, err 229 } 230 numaux = int(se.Nnumaux) 231 sym.SectionNumber = int(se.Nscnum) 232 sym.StorageClass = int(se.Nsclass) 233 sym.Value = uint64(se.Nvalue) 234 zeroes := binary.BigEndian.Uint32(se.Nname[:4]) 235 if zeroes != 0 { 236 sym.Name = cstring(se.Nname[:]) 237 } else { 238 offset := binary.BigEndian.Uint32(se.Nname[4:]) 239 sym.Name, ok = getString(f.StringTable, offset) 240 if !ok { 241 goto skip 242 } 243 } 244 case U64_TOCMAGIC: 245 se := new(SymEnt64) 246 if err := binary.Read(sr, binary.BigEndian, se); err != nil { 247 return nil, err 248 } 249 numaux = int(se.Nnumaux) 250 sym.SectionNumber = int(se.Nscnum) 251 sym.StorageClass = int(se.Nsclass) 252 sym.Value = se.Nvalue 253 sym.Name, ok = getString(f.StringTable, se.Noffset) 254 if !ok { 255 goto skip 256 } 257 } 258 if sym.StorageClass != C_EXT && sym.StorageClass != C_WEAKEXT && sym.StorageClass != C_HIDEXT { 259 goto skip 260 } 261 // Must have at least one csect auxiliary entry. 262 if numaux < 1 || i+numaux >= int(nsyms) { 263 goto skip 264 } 265 if sym.SectionNumber < 1 || sym.SectionNumber > int(nscns) { 266 goto skip 267 } 268 sym.Value -= f.Sections[sym.SectionNumber-1].VirtualAddress 269 270 // Read csect auxiliary entry (by convention, it is the last). 271 sr.Seek(int64((numaux-1)*SYMESZ), io.SeekCurrent) 272 i += numaux 273 numaux = 0 274 switch f.TargetMachine { 275 case U802TOCMAGIC: 276 aux := new(AuxCSect32) 277 if err := binary.Read(sr, binary.BigEndian, aux); err != nil { 278 return nil, err 279 } 280 sym.AuxCSect.SymbolType = int(aux.Xsmtyp & 0x7) 281 sym.AuxCSect.StorageMappingClass = int(aux.Xsmclas) 282 sym.AuxCSect.Length = int64(aux.Xscnlen) 283 case U64_TOCMAGIC: 284 aux := new(AuxCSect64) 285 if err := binary.Read(sr, binary.BigEndian, aux); err != nil { 286 return nil, err 287 } 288 sym.AuxCSect.SymbolType = int(aux.Xsmtyp & 0x7) 289 sym.AuxCSect.StorageMappingClass = int(aux.Xsmclas) 290 sym.AuxCSect.Length = int64(aux.Xscnlenhi)<<32 | int64(aux.Xscnlenlo) 291 } 292 293 f.Symbols = append(f.Symbols, sym) 294 skip: 295 i += numaux // Skip auxiliary entries 296 sr.Seek(int64(numaux)*SYMESZ, io.SeekCurrent) 297 } 298 299 return f, nil 300 } 301 302 // zeroReaderAt is ReaderAt that reads 0s. 303 type zeroReaderAt struct{} 304 305 // ReadAt writes len(p) 0s into p. 306 func (w zeroReaderAt) ReadAt(p []byte, off int64) (n int, err error) { 307 for i := range p { 308 p[i] = 0 309 } 310 return len(p), nil 311 } 312 313 // Data reads and returns the contents of the XCOFF section s. 314 func (s *Section) Data() ([]byte, error) { 315 dat := make([]byte, s.sr.Size()) 316 n, err := s.sr.ReadAt(dat, 0) 317 if n == len(dat) { 318 err = nil 319 } 320 return dat[0:n], err 321 } 322 323 // CSect reads and returns the contents of a csect. 324 func (f *File) CSect(name string) []byte { 325 for _, sym := range f.Symbols { 326 if sym.Name == name && sym.AuxCSect.SymbolType == XTY_SD { 327 if i := sym.SectionNumber - 1; 0 <= i && i < len(f.Sections) { 328 s := f.Sections[i] 329 if sym.Value+uint64(sym.AuxCSect.Length) <= s.Size { 330 dat := make([]byte, sym.AuxCSect.Length) 331 _, err := s.sr.ReadAt(dat, int64(sym.Value)) 332 if err != nil { 333 return nil 334 } 335 return dat 336 } 337 } 338 break 339 } 340 } 341 return nil 342 } 343 344 func (f *File) DWARF() (*dwarf.Data, error) { 345 // There are many other DWARF sections, but these 346 // are the ones the debug/dwarf package uses. 347 // Don't bother loading others. 348 var subtypes = [...]uint32{SSUBTYP_DWABREV, SSUBTYP_DWINFO, SSUBTYP_DWLINE, SSUBTYP_DWARNGE, SSUBTYP_DWSTR} 349 var dat [len(subtypes)][]byte 350 for i, subtype := range subtypes { 351 s := f.SectionByType(STYP_DWARF | subtype) 352 if s != nil { 353 b, err := s.Data() 354 if err != nil && uint64(len(b)) < s.Size { 355 return nil, err 356 } 357 dat[i] = b 358 } 359 } 360 361 abbrev, info, line, ranges, str := dat[0], dat[1], dat[2], dat[3], dat[4] 362 return dwarf.New(abbrev, nil, nil, info, line, nil, ranges, str) 363 } 364 365 // Read a loader section import file IDs. 366 func (f *File) readImportIDs(s *Section) ([]string, error) { 367 // Read loader header 368 s.sr.Seek(0, io.SeekStart) 369 var istlen uint32 370 var nimpid int32 371 var impoff uint64 372 switch f.TargetMachine { 373 case U802TOCMAGIC: 374 lhdr := new(LoaderHeader32) 375 if err := binary.Read(s.sr, binary.BigEndian, lhdr); err != nil { 376 return nil, err 377 } 378 istlen = lhdr.Listlen 379 nimpid = lhdr.Lnimpid 380 impoff = uint64(lhdr.Limpoff) 381 case U64_TOCMAGIC: 382 lhdr := new(LoaderHeader64) 383 if err := binary.Read(s.sr, binary.BigEndian, lhdr); err != nil { 384 return nil, err 385 } 386 istlen = lhdr.Listlen 387 nimpid = lhdr.Lnimpid 388 impoff = lhdr.Limpoff 389 } 390 391 // Read loader import file ID table 392 s.sr.Seek(int64(impoff), io.SeekStart) 393 table := make([]byte, istlen) 394 io.ReadFull(s.sr, table) 395 396 offset := 0 397 // First import file ID is the default LIBPATH value 398 libpath := cstring(table[offset:]) 399 f.LibraryPaths = strings.Split(libpath, ":") 400 offset += len(libpath) + 3 // 3 null bytes 401 all := make([]string, 0) 402 for i := 1; i < int(nimpid); i++ { 403 impidpath := cstring(table[offset:]) 404 offset += len(impidpath) + 1 405 impidbase := cstring(table[offset:]) 406 offset += len(impidbase) + 1 407 impidmem := cstring(table[offset:]) 408 offset += len(impidmem) + 1 409 var path string 410 if len(impidpath) > 0 { 411 path = impidpath + "/" + impidbase 412 } else { 413 path = impidbase 414 } 415 all = append(all, path) 416 } 417 418 return all, nil 419 } 420 421 // ImportedSymbols returns the names of all symbols 422 // referred to by the binary f that are expected to be 423 // satisfied by other libraries at dynamic load time. 424 // It does not return weak symbols. 425 func (f *File) ImportedSymbols() ([]ImportedSymbol, error) { 426 s := f.SectionByType(STYP_LOADER) 427 if s == nil { 428 return nil, nil 429 } 430 // Read loader header 431 s.sr.Seek(0, io.SeekStart) 432 var stlen uint32 433 var stoff uint64 434 var nsyms int32 435 var symoff uint64 436 switch f.TargetMachine { 437 case U802TOCMAGIC: 438 lhdr := new(LoaderHeader32) 439 if err := binary.Read(s.sr, binary.BigEndian, lhdr); err != nil { 440 return nil, err 441 } 442 stlen = lhdr.Lstlen 443 stoff = uint64(lhdr.Lstoff) 444 nsyms = lhdr.Lnsyms 445 symoff = LDHDRSZ_32 446 case U64_TOCMAGIC: 447 lhdr := new(LoaderHeader64) 448 if err := binary.Read(s.sr, binary.BigEndian, lhdr); err != nil { 449 return nil, err 450 } 451 stlen = lhdr.Lstlen 452 stoff = lhdr.Lstoff 453 nsyms = lhdr.Lnsyms 454 symoff = lhdr.Lsymoff 455 } 456 457 // Read loader section string table 458 s.sr.Seek(int64(stoff), io.SeekStart) 459 st := make([]byte, stlen) 460 io.ReadFull(s.sr, st) 461 462 // Read imported libraries 463 libs, err := f.readImportIDs(s) 464 if err != nil { 465 return nil, err 466 } 467 468 // Read loader symbol table 469 s.sr.Seek(int64(symoff), io.SeekStart) 470 all := make([]ImportedSymbol, 0) 471 for i := 0; i < int(nsyms); i++ { 472 var name string 473 var ifile int32 474 var ok bool 475 switch f.TargetMachine { 476 case U802TOCMAGIC: 477 ldsym := new(LoaderSymbol32) 478 if err := binary.Read(s.sr, binary.BigEndian, ldsym); err != nil { 479 return nil, err 480 } 481 if ldsym.Lsmtype&0x40 == 0 { 482 continue // Imported symbols only 483 } 484 zeroes := binary.BigEndian.Uint32(ldsym.Lname[:4]) 485 if zeroes != 0 { 486 name = cstring(ldsym.Lname[:]) 487 } else { 488 offset := binary.BigEndian.Uint32(ldsym.Lname[4:]) 489 name, ok = getString(st, offset) 490 if !ok { 491 continue 492 } 493 } 494 ifile = ldsym.Lifile 495 case U64_TOCMAGIC: 496 ldsym := new(LoaderSymbol64) 497 if err := binary.Read(s.sr, binary.BigEndian, ldsym); err != nil { 498 return nil, err 499 } 500 if ldsym.Lsmtype&0x40 == 0 { 501 continue // Imported symbols only 502 } 503 name, ok = getString(st, ldsym.Loffset) 504 if !ok { 505 continue 506 } 507 ifile = ldsym.Lifile 508 } 509 var sym ImportedSymbol 510 sym.Name = name 511 if ifile >= 1 && int(ifile) <= len(libs) { 512 sym.Library = libs[ifile-1] 513 } 514 all = append(all, sym) 515 } 516 517 return all, nil 518 } 519 520 // ImportedLibraries returns the names of all libraries 521 // referred to by the binary f that are expected to be 522 // linked with the binary at dynamic link time. 523 func (f *File) ImportedLibraries() ([]string, error) { 524 s := f.SectionByType(STYP_LOADER) 525 if s == nil { 526 return nil, nil 527 } 528 all, err := f.readImportIDs(s) 529 return all, err 530 } 531 532 // FormatError is unused. 533 // The type is retained for compatibility. 534 type FormatError struct { 535 } 536 537 func (e *FormatError) Error() string { 538 return "unknown error" 539 }