Source file src/pkg/debug/elf/file.go
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 elf implements access to ELF object files. 6 package elf 7 8 import ( 9 "bytes" 10 "debug/dwarf" 11 "encoding/binary" 12 "errors" 13 "fmt" 14 "io" 15 "os" 16 ) 17 18 // TODO: error reporting detail 19 20 /* 21 * Internal ELF representation 22 */ 23 24 // A FileHeader represents an ELF file header. 25 type FileHeader struct { 26 Class Class 27 Data Data 28 Version Version 29 OSABI OSABI 30 ABIVersion uint8 31 ByteOrder binary.ByteOrder 32 Type Type 33 Machine Machine 34 } 35 36 // A File represents an open ELF file. 37 type File struct { 38 FileHeader 39 Sections []*Section 40 Progs []*Prog 41 closer io.Closer 42 gnuNeed []verneed 43 gnuVersym []byte 44 } 45 46 // A SectionHeader represents a single ELF section header. 47 type SectionHeader struct { 48 Name string 49 Type SectionType 50 Flags SectionFlag 51 Addr uint64 52 Offset uint64 53 Size uint64 54 Link uint32 55 Info uint32 56 Addralign uint64 57 Entsize uint64 58 } 59 60 // A Section represents a single section in an ELF file. 61 type Section struct { 62 SectionHeader 63 64 // Embed ReaderAt for ReadAt method. 65 // Do not embed SectionReader directly 66 // to avoid having Read and Seek. 67 // If a client wants Read and Seek it must use 68 // Open() to avoid fighting over the seek offset 69 // with other clients. 70 io.ReaderAt 71 sr *io.SectionReader 72 } 73 74 // Data reads and returns the contents of the ELF section. 75 func (s *Section) Data() ([]byte, error) { 76 dat := make([]byte, s.sr.Size()) 77 n, err := s.sr.ReadAt(dat, 0) 78 return dat[0:n], err 79 } 80 81 // stringTable reads and returns the string table given by the 82 // specified link value. 83 func (f *File) stringTable(link uint32) ([]byte, error) { 84 if link <= 0 || link >= uint32(len(f.Sections)) { 85 return nil, errors.New("section has invalid string table link") 86 } 87 return f.Sections[link].Data() 88 } 89 90 // Open returns a new ReadSeeker reading the ELF section. 91 func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) } 92 93 // A ProgHeader represents a single ELF program header. 94 type ProgHeader struct { 95 Type ProgType 96 Flags ProgFlag 97 Off uint64 98 Vaddr uint64 99 Paddr uint64 100 Filesz uint64 101 Memsz uint64 102 Align uint64 103 } 104 105 // A Prog represents a single ELF program header in an ELF binary. 106 type Prog struct { 107 ProgHeader 108 109 // Embed ReaderAt for ReadAt method. 110 // Do not embed SectionReader directly 111 // to avoid having Read and Seek. 112 // If a client wants Read and Seek it must use 113 // Open() to avoid fighting over the seek offset 114 // with other clients. 115 io.ReaderAt 116 sr *io.SectionReader 117 } 118 119 // Open returns a new ReadSeeker reading the ELF program body. 120 func (p *Prog) Open() io.ReadSeeker { return io.NewSectionReader(p.sr, 0, 1<<63-1) } 121 122 // A Symbol represents an entry in an ELF symbol table section. 123 type Symbol struct { 124 Name string 125 Info, Other byte 126 Section SectionIndex 127 Value, Size uint64 128 } 129 130 /* 131 * ELF reader 132 */ 133 134 type FormatError struct { 135 off int64 136 msg string 137 val interface{} 138 } 139 140 func (e *FormatError) Error() string { 141 msg := e.msg 142 if e.val != nil { 143 msg += fmt.Sprintf(" '%v' ", e.val) 144 } 145 msg += fmt.Sprintf("in record at byte %#x", e.off) 146 return msg 147 } 148 149 // Open opens the named file using os.Open and prepares it for use as an ELF binary. 150 func Open(name string) (*File, error) { 151 f, err := os.Open(name) 152 if err != nil { 153 return nil, err 154 } 155 ff, err := NewFile(f) 156 if err != nil { 157 f.Close() 158 return nil, err 159 } 160 ff.closer = f 161 return ff, nil 162 } 163 164 // Close closes the File. 165 // If the File was created using NewFile directly instead of Open, 166 // Close has no effect. 167 func (f *File) Close() error { 168 var err error 169 if f.closer != nil { 170 err = f.closer.Close() 171 f.closer = nil 172 } 173 return err 174 } 175 176 // SectionByType returns the first section in f with the 177 // given type, or nil if there is no such section. 178 func (f *File) SectionByType(typ SectionType) *Section { 179 for _, s := range f.Sections { 180 if s.Type == typ { 181 return s 182 } 183 } 184 return nil 185 } 186 187 // NewFile creates a new File for accessing an ELF binary in an underlying reader. 188 // The ELF binary is expected to start at position 0 in the ReaderAt. 189 func NewFile(r io.ReaderAt) (*File, error) { 190 sr := io.NewSectionReader(r, 0, 1<<63-1) 191 // Read and decode ELF identifier 192 var ident [16]uint8 193 if _, err := r.ReadAt(ident[0:], 0); err != nil { 194 return nil, err 195 } 196 if ident[0] != '\x7f' || ident[1] != 'E' || ident[2] != 'L' || ident[3] != 'F' { 197 return nil, &FormatError{0, "bad magic number", ident[0:4]} 198 } 199 200 f := new(File) 201 f.Class = Class(ident[EI_CLASS]) 202 switch f.Class { 203 case ELFCLASS32: 204 case ELFCLASS64: 205 // ok 206 default: 207 return nil, &FormatError{0, "unknown ELF class", f.Class} 208 } 209 210 f.Data = Data(ident[EI_DATA]) 211 switch f.Data { 212 case ELFDATA2LSB: 213 f.ByteOrder = binary.LittleEndian 214 case ELFDATA2MSB: 215 f.ByteOrder = binary.BigEndian 216 default: 217 return nil, &FormatError{0, "unknown ELF data encoding", f.Data} 218 } 219 220 f.Version = Version(ident[EI_VERSION]) 221 if f.Version != EV_CURRENT { 222 return nil, &FormatError{0, "unknown ELF version", f.Version} 223 } 224 225 f.OSABI = OSABI(ident[EI_OSABI]) 226 f.ABIVersion = ident[EI_ABIVERSION] 227 228 // Read ELF file header 229 var phoff int64 230 var phentsize, phnum int 231 var shoff int64 232 var shentsize, shnum, shstrndx int 233 shstrndx = -1 234 switch f.Class { 235 case ELFCLASS32: 236 hdr := new(Header32) 237 sr.Seek(0, os.SEEK_SET) 238 if err := binary.Read(sr, f.ByteOrder, hdr); err != nil { 239 return nil, err 240 } 241 f.Type = Type(hdr.Type) 242 f.Machine = Machine(hdr.Machine) 243 if v := Version(hdr.Version); v != f.Version { 244 return nil, &FormatError{0, "mismatched ELF version", v} 245 } 246 phoff = int64(hdr.Phoff) 247 phentsize = int(hdr.Phentsize) 248 phnum = int(hdr.Phnum) 249 shoff = int64(hdr.Shoff) 250 shentsize = int(hdr.Shentsize) 251 shnum = int(hdr.Shnum) 252 shstrndx = int(hdr.Shstrndx) 253 case ELFCLASS64: 254 hdr := new(Header64) 255 sr.Seek(0, os.SEEK_SET) 256 if err := binary.Read(sr, f.ByteOrder, hdr); err != nil { 257 return nil, err 258 } 259 f.Type = Type(hdr.Type) 260 f.Machine = Machine(hdr.Machine) 261 if v := Version(hdr.Version); v != f.Version { 262 return nil, &FormatError{0, "mismatched ELF version", v} 263 } 264 phoff = int64(hdr.Phoff) 265 phentsize = int(hdr.Phentsize) 266 phnum = int(hdr.Phnum) 267 shoff = int64(hdr.Shoff) 268 shentsize = int(hdr.Shentsize) 269 shnum = int(hdr.Shnum) 270 shstrndx = int(hdr.Shstrndx) 271 } 272 if shstrndx < 0 || shstrndx >= shnum { 273 return nil, &FormatError{0, "invalid ELF shstrndx", shstrndx} 274 } 275 276 // Read program headers 277 f.Progs = make([]*Prog, phnum) 278 for i := 0; i < phnum; i++ { 279 off := phoff + int64(i)*int64(phentsize) 280 sr.Seek(off, os.SEEK_SET) 281 p := new(Prog) 282 switch f.Class { 283 case ELFCLASS32: 284 ph := new(Prog32) 285 if err := binary.Read(sr, f.ByteOrder, ph); err != nil { 286 return nil, err 287 } 288 p.ProgHeader = ProgHeader{ 289 Type: ProgType(ph.Type), 290 Flags: ProgFlag(ph.Flags), 291 Off: uint64(ph.Off), 292 Vaddr: uint64(ph.Vaddr), 293 Paddr: uint64(ph.Paddr), 294 Filesz: uint64(ph.Filesz), 295 Memsz: uint64(ph.Memsz), 296 Align: uint64(ph.Align), 297 } 298 case ELFCLASS64: 299 ph := new(Prog64) 300 if err := binary.Read(sr, f.ByteOrder, ph); err != nil { 301 return nil, err 302 } 303 p.ProgHeader = ProgHeader{ 304 Type: ProgType(ph.Type), 305 Flags: ProgFlag(ph.Flags), 306 Off: uint64(ph.Off), 307 Vaddr: uint64(ph.Vaddr), 308 Paddr: uint64(ph.Paddr), 309 Filesz: uint64(ph.Filesz), 310 Memsz: uint64(ph.Memsz), 311 Align: uint64(ph.Align), 312 } 313 } 314 p.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz)) 315 p.ReaderAt = p.sr 316 f.Progs[i] = p 317 } 318 319 // Read section headers 320 f.Sections = make([]*Section, shnum) 321 names := make([]uint32, shnum) 322 for i := 0; i < shnum; i++ { 323 off := shoff + int64(i)*int64(shentsize) 324 sr.Seek(off, os.SEEK_SET) 325 s := new(Section) 326 switch f.Class { 327 case ELFCLASS32: 328 sh := new(Section32) 329 if err := binary.Read(sr, f.ByteOrder, sh); err != nil { 330 return nil, err 331 } 332 names[i] = sh.Name 333 s.SectionHeader = SectionHeader{ 334 Type: SectionType(sh.Type), 335 Flags: SectionFlag(sh.Flags), 336 Addr: uint64(sh.Addr), 337 Offset: uint64(sh.Off), 338 Size: uint64(sh.Size), 339 Link: uint32(sh.Link), 340 Info: uint32(sh.Info), 341 Addralign: uint64(sh.Addralign), 342 Entsize: uint64(sh.Entsize), 343 } 344 case ELFCLASS64: 345 sh := new(Section64) 346 if err := binary.Read(sr, f.ByteOrder, sh); err != nil { 347 return nil, err 348 } 349 names[i] = sh.Name 350 s.SectionHeader = SectionHeader{ 351 Type: SectionType(sh.Type), 352 Flags: SectionFlag(sh.Flags), 353 Offset: uint64(sh.Off), 354 Size: uint64(sh.Size), 355 Addr: uint64(sh.Addr), 356 Link: uint32(sh.Link), 357 Info: uint32(sh.Info), 358 Addralign: uint64(sh.Addralign), 359 Entsize: uint64(sh.Entsize), 360 } 361 } 362 s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Size)) 363 s.ReaderAt = s.sr 364 f.Sections[i] = s 365 } 366 367 // Load section header string table. 368 shstrtab, err := f.Sections[shstrndx].Data() 369 if err != nil { 370 return nil, err 371 } 372 for i, s := range f.Sections { 373 var ok bool 374 s.Name, ok = getString(shstrtab, int(names[i])) 375 if !ok { 376 return nil, &FormatError{shoff + int64(i*shentsize), "bad section name index", names[i]} 377 } 378 } 379 380 return f, nil 381 } 382 383 // getSymbols returns a slice of Symbols from parsing the symbol table 384 // with the given type, along with the associated string table. 385 func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, error) { 386 switch f.Class { 387 case ELFCLASS64: 388 return f.getSymbols64(typ) 389 390 case ELFCLASS32: 391 return f.getSymbols32(typ) 392 } 393 394 return nil, nil, errors.New("not implemented") 395 } 396 397 func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) { 398 symtabSection := f.SectionByType(typ) 399 if symtabSection == nil { 400 return nil, nil, errors.New("no symbol section") 401 } 402 403 data, err := symtabSection.Data() 404 if err != nil { 405 return nil, nil, errors.New("cannot load symbol section") 406 } 407 symtab := bytes.NewBuffer(data) 408 if symtab.Len()%Sym32Size != 0 { 409 return nil, nil, errors.New("length of symbol section is not a multiple of SymSize") 410 } 411 412 strdata, err := f.stringTable(symtabSection.Link) 413 if err != nil { 414 return nil, nil, errors.New("cannot load string table section") 415 } 416 417 // The first entry is all zeros. 418 var skip [Sym32Size]byte 419 symtab.Read(skip[0:]) 420 421 symbols := make([]Symbol, symtab.Len()/Sym32Size) 422 423 i := 0 424 var sym Sym32 425 for symtab.Len() > 0 { 426 binary.Read(symtab, f.ByteOrder, &sym) 427 str, _ := getString(strdata, int(sym.Name)) 428 symbols[i].Name = str 429 symbols[i].Info = sym.Info 430 symbols[i].Other = sym.Other 431 symbols[i].Section = SectionIndex(sym.Shndx) 432 symbols[i].Value = uint64(sym.Value) 433 symbols[i].Size = uint64(sym.Size) 434 i++ 435 } 436 437 return symbols, strdata, nil 438 } 439 440 func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) { 441 symtabSection := f.SectionByType(typ) 442 if symtabSection == nil { 443 return nil, nil, errors.New("no symbol section") 444 } 445 446 data, err := symtabSection.Data() 447 if err != nil { 448 return nil, nil, errors.New("cannot load symbol section") 449 } 450 symtab := bytes.NewBuffer(data) 451 if symtab.Len()%Sym64Size != 0 { 452 return nil, nil, errors.New("length of symbol section is not a multiple of Sym64Size") 453 } 454 455 strdata, err := f.stringTable(symtabSection.Link) 456 if err != nil { 457 return nil, nil, errors.New("cannot load string table section") 458 } 459 460 // The first entry is all zeros. 461 var skip [Sym64Size]byte 462 symtab.Read(skip[0:]) 463 464 symbols := make([]Symbol, symtab.Len()/Sym64Size) 465 466 i := 0 467 var sym Sym64 468 for symtab.Len() > 0 { 469 binary.Read(symtab, f.ByteOrder, &sym) 470 str, _ := getString(strdata, int(sym.Name)) 471 symbols[i].Name = str 472 symbols[i].Info = sym.Info 473 symbols[i].Other = sym.Other 474 symbols[i].Section = SectionIndex(sym.Shndx) 475 symbols[i].Value = sym.Value 476 symbols[i].Size = sym.Size 477 i++ 478 } 479 480 return symbols, strdata, nil 481 } 482 483 // getString extracts a string from an ELF string table. 484 func getString(section []byte, start int) (string, bool) { 485 if start < 0 || start >= len(section) { 486 return "", false 487 } 488 489 for end := start; end < len(section); end++ { 490 if section[end] == 0 { 491 return string(section[start:end]), true 492 } 493 } 494 return "", false 495 } 496 497 // Section returns a section with the given name, or nil if no such 498 // section exists. 499 func (f *File) Section(name string) *Section { 500 for _, s := range f.Sections { 501 if s.Name == name { 502 return s 503 } 504 } 505 return nil 506 } 507 508 // applyRelocations applies relocations to dst. rels is a relocations section 509 // in RELA format. 510 func (f *File) applyRelocations(dst []byte, rels []byte) error { 511 if f.Class == ELFCLASS64 && f.Machine == EM_X86_64 { 512 return f.applyRelocationsAMD64(dst, rels) 513 } 514 515 return errors.New("not implemented") 516 } 517 518 func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error { 519 if len(rels)%Sym64Size != 0 { 520 return errors.New("length of relocation section is not a multiple of Sym64Size") 521 } 522 523 symbols, _, err := f.getSymbols(SHT_SYMTAB) 524 if err != nil { 525 return err 526 } 527 528 b := bytes.NewBuffer(rels) 529 var rela Rela64 530 531 for b.Len() > 0 { 532 binary.Read(b, f.ByteOrder, &rela) 533 symNo := rela.Info >> 32 534 t := R_X86_64(rela.Info & 0xffff) 535 536 if symNo >= uint64(len(symbols)) { 537 continue 538 } 539 sym := &symbols[symNo] 540 if SymType(sym.Info&0xf) != STT_SECTION { 541 // We don't handle non-section relocations for now. 542 continue 543 } 544 545 switch t { 546 case R_X86_64_64: 547 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 548 continue 549 } 550 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend)) 551 case R_X86_64_32: 552 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 553 continue 554 } 555 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)) 556 } 557 } 558 559 return nil 560 } 561 562 func (f *File) DWARF() (*dwarf.Data, error) { 563 // There are many other DWARF sections, but these 564 // are the required ones, and the debug/dwarf package 565 // does not use the others, so don't bother loading them. 566 var names = [...]string{"abbrev", "info", "str"} 567 var dat [len(names)][]byte 568 for i, name := range names { 569 name = ".debug_" + name 570 s := f.Section(name) 571 if s == nil { 572 continue 573 } 574 b, err := s.Data() 575 if err != nil && uint64(len(b)) < s.Size { 576 return nil, err 577 } 578 dat[i] = b 579 } 580 581 // If there's a relocation table for .debug_info, we have to process it 582 // now otherwise the data in .debug_info is invalid for x86-64 objects. 583 rela := f.Section(".rela.debug_info") 584 if rela != nil && rela.Type == SHT_RELA && f.Machine == EM_X86_64 { 585 data, err := rela.Data() 586 if err != nil { 587 return nil, err 588 } 589 err = f.applyRelocations(dat[1], data) 590 if err != nil { 591 return nil, err 592 } 593 } 594 595 abbrev, info, str := dat[0], dat[1], dat[2] 596 return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str) 597 } 598 599 // Symbols returns the symbol table for f. 600 func (f *File) Symbols() ([]Symbol, error) { 601 sym, _, err := f.getSymbols(SHT_SYMTAB) 602 return sym, err 603 } 604 605 type ImportedSymbol struct { 606 Name string 607 Version string 608 Library string 609 } 610 611 // ImportedSymbols returns the names of all symbols 612 // referred to by the binary f that are expected to be 613 // satisfied by other libraries at dynamic load time. 614 // It does not return weak symbols. 615 func (f *File) ImportedSymbols() ([]ImportedSymbol, error) { 616 sym, str, err := f.getSymbols(SHT_DYNSYM) 617 if err != nil { 618 return nil, err 619 } 620 f.gnuVersionInit(str) 621 var all []ImportedSymbol 622 for i, s := range sym { 623 if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF { 624 all = append(all, ImportedSymbol{Name: s.Name}) 625 f.gnuVersion(i, &all[len(all)-1]) 626 } 627 } 628 return all, nil 629 } 630 631 type verneed struct { 632 File string 633 Name string 634 } 635 636 // gnuVersionInit parses the GNU version tables 637 // for use by calls to gnuVersion. 638 func (f *File) gnuVersionInit(str []byte) { 639 // Accumulate verneed information. 640 vn := f.SectionByType(SHT_GNU_VERNEED) 641 if vn == nil { 642 return 643 } 644 d, _ := vn.Data() 645 646 var need []verneed 647 i := 0 648 for { 649 if i+16 > len(d) { 650 break 651 } 652 vers := f.ByteOrder.Uint16(d[i : i+2]) 653 if vers != 1 { 654 break 655 } 656 cnt := f.ByteOrder.Uint16(d[i+2 : i+4]) 657 fileoff := f.ByteOrder.Uint32(d[i+4 : i+8]) 658 aux := f.ByteOrder.Uint32(d[i+8 : i+12]) 659 next := f.ByteOrder.Uint32(d[i+12 : i+16]) 660 file, _ := getString(str, int(fileoff)) 661 662 var name string 663 j := i + int(aux) 664 for c := 0; c < int(cnt); c++ { 665 if j+16 > len(d) { 666 break 667 } 668 // hash := f.ByteOrder.Uint32(d[j:j+4]) 669 // flags := f.ByteOrder.Uint16(d[j+4:j+6]) 670 other := f.ByteOrder.Uint16(d[j+6 : j+8]) 671 nameoff := f.ByteOrder.Uint32(d[j+8 : j+12]) 672 next := f.ByteOrder.Uint32(d[j+12 : j+16]) 673 name, _ = getString(str, int(nameoff)) 674 ndx := int(other) 675 if ndx >= len(need) { 676 a := make([]verneed, 2*(ndx+1)) 677 copy(a, need) 678 need = a 679 } 680 681 need[ndx] = verneed{file, name} 682 if next == 0 { 683 break 684 } 685 j += int(next) 686 } 687 688 if next == 0 { 689 break 690 } 691 i += int(next) 692 } 693 694 // Versym parallels symbol table, indexing into verneed. 695 vs := f.SectionByType(SHT_GNU_VERSYM) 696 if vs == nil { 697 return 698 } 699 d, _ = vs.Data() 700 701 f.gnuNeed = need 702 f.gnuVersym = d 703 } 704 705 // gnuVersion adds Library and Version information to sym, 706 // which came from offset i of the symbol table. 707 func (f *File) gnuVersion(i int, sym *ImportedSymbol) { 708 // Each entry is two bytes; skip undef entry at beginning. 709 i = (i + 1) * 2 710 if i >= len(f.gnuVersym) { 711 return 712 } 713 j := int(f.ByteOrder.Uint16(f.gnuVersym[i:])) 714 if j < 2 || j >= len(f.gnuNeed) { 715 return 716 } 717 n := &f.gnuNeed[j] 718 sym.Library = n.File 719 sym.Version = n.Name 720 } 721 722 // ImportedLibraries returns the names of all libraries 723 // referred to by the binary f that are expected to be 724 // linked with the binary at dynamic link time. 725 func (f *File) ImportedLibraries() ([]string, error) { 726 ds := f.SectionByType(SHT_DYNAMIC) 727 if ds == nil { 728 // not dynamic, so no libraries 729 return nil, nil 730 } 731 d, err := ds.Data() 732 if err != nil { 733 return nil, err 734 } 735 str, err := f.stringTable(ds.Link) 736 if err != nil { 737 return nil, err 738 } 739 var all []string 740 for len(d) > 0 { 741 var tag DynTag 742 var value uint64 743 switch f.Class { 744 case ELFCLASS32: 745 tag = DynTag(f.ByteOrder.Uint32(d[0:4])) 746 value = uint64(f.ByteOrder.Uint32(d[4:8])) 747 d = d[8:] 748 case ELFCLASS64: 749 tag = DynTag(f.ByteOrder.Uint64(d[0:8])) 750 value = f.ByteOrder.Uint64(d[8:16]) 751 d = d[16:] 752 } 753 if tag == DT_NEEDED { 754 s, ok := getString(str, int(value)) 755 if ok { 756 all = append(all, s) 757 } 758 } 759 } 760 761 return all, nil 762 }