1// Copyright 2018 Google LLC 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15// Package elf implements access to ELF object files. 16package elf 17 18import ( 19 "bytes" 20 "compress/zlib" 21 "encoding/binary" 22 "errors" 23 "fmt" 24 "io" 25 "os" 26 "strings" 27 28 "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf" 29) 30 31// seekStart, seekCurrent, seekEnd are copies of 32// io.SeekStart, io.SeekCurrent, and io.SeekEnd. 33// We can't use the ones from package io because 34// we want this code to build with Go 1.4 during 35// cmd/dist bootstrap. 36const ( 37 seekStart int = 0 38 seekCurrent int = 1 39 seekEnd int = 2 40) 41 42// TODO: error reporting detail 43 44/* 45 * Internal ELF representation 46 */ 47 48// A FileHeader represents an ELF file header. 49type FileHeader struct { 50 Class Class 51 Data Data 52 Version Version 53 OSABI OSABI 54 ABIVersion uint8 55 ByteOrder binary.ByteOrder 56 Type Type 57 Machine Machine 58 Entry uint64 59} 60 61// A File represents an open ELF file. 62type File struct { 63 FileHeader 64 Sections []*Section 65 Progs []*Prog 66 closer io.Closer 67 gnuNeed []verneed 68 gnuVersym []byte 69} 70 71// A SectionHeader represents a single ELF section header. 72type SectionHeader struct { 73 Name string 74 Type SectionType 75 Flags SectionFlag 76 Addr uint64 77 Offset uint64 78 Size uint64 79 Link uint32 80 Info uint32 81 Addralign uint64 82 Entsize uint64 83 84 // FileSize is the size of this section in the file in bytes. 85 // If a section is compressed, FileSize is the size of the 86 // compressed data, while Size (above) is the size of the 87 // uncompressed data. 88 FileSize uint64 89} 90 91// A Section represents a single section in an ELF file. 92type Section struct { 93 SectionHeader 94 95 // Embed ReaderAt for ReadAt method. 96 // Do not embed SectionReader directly 97 // to avoid having Read and Seek. 98 // If a client wants Read and Seek it must use 99 // Open() to avoid fighting over the seek offset 100 // with other clients. 101 // 102 // ReaderAt may be nil if the section is not easily available 103 // in a random-access form. For example, a compressed section 104 // may have a nil ReaderAt. 105 io.ReaderAt 106 sr *io.SectionReader 107 108 compressionType CompressionType 109 compressionOffset int64 110} 111 112// Data reads and returns the contents of the ELF section. 113// Even if the section is stored compressed in the ELF file, 114// Data returns uncompressed data. 115func (s *Section) Data() ([]byte, error) { 116 dat := make([]byte, s.Size) 117 n, err := io.ReadFull(s.Open(), dat) 118 return dat[0:n], err 119} 120 121// stringTable reads and returns the string table given by the 122// specified link value. 123func (f *File) stringTable(link uint32) ([]byte, error) { 124 if link <= 0 || link >= uint32(len(f.Sections)) { 125 return nil, errors.New("section has invalid string table link") 126 } 127 return f.Sections[link].Data() 128} 129 130// Open returns a new ReadSeeker reading the ELF section. 131// Even if the section is stored compressed in the ELF file, 132// the ReadSeeker reads uncompressed data. 133func (s *Section) Open() io.ReadSeeker { 134 if s.Flags&SHF_COMPRESSED == 0 { 135 return io.NewSectionReader(s.sr, 0, 1<<63-1) 136 } 137 if s.compressionType == COMPRESS_ZLIB { 138 return &readSeekerFromReader{ 139 reset: func() (io.Reader, error) { 140 fr := io.NewSectionReader(s.sr, s.compressionOffset, int64(s.FileSize)-s.compressionOffset) 141 return zlib.NewReader(fr) 142 }, 143 size: int64(s.Size), 144 } 145 } 146 err := &FormatError{int64(s.Offset), "unknown compression type", s.compressionType} 147 return errorReader{err} 148} 149 150// A ProgHeader represents a single ELF program header. 151type ProgHeader struct { 152 Type ProgType 153 Flags ProgFlag 154 Off uint64 155 Vaddr uint64 156 Paddr uint64 157 Filesz uint64 158 Memsz uint64 159 Align uint64 160} 161 162// A Prog represents a single ELF program header in an ELF binary. 163type Prog struct { 164 ProgHeader 165 166 // Embed ReaderAt for ReadAt method. 167 // Do not embed SectionReader directly 168 // to avoid having Read and Seek. 169 // If a client wants Read and Seek it must use 170 // Open() to avoid fighting over the seek offset 171 // with other clients. 172 io.ReaderAt 173 sr *io.SectionReader 174} 175 176// Open returns a new ReadSeeker reading the ELF program body. 177func (p *Prog) Open() io.ReadSeeker { return io.NewSectionReader(p.sr, 0, 1<<63-1) } 178 179// A Symbol represents an entry in an ELF symbol table section. 180type Symbol struct { 181 Name string 182 Info, Other byte 183 Section SectionIndex 184 Value, Size uint64 185} 186 187/* 188 * ELF reader 189 */ 190 191type FormatError struct { 192 off int64 193 msg string 194 val interface{} 195} 196 197func (e *FormatError) Error() string { 198 msg := e.msg 199 if e.val != nil { 200 msg += fmt.Sprintf(" '%v' ", e.val) 201 } 202 msg += fmt.Sprintf("in record at byte %#x", e.off) 203 return msg 204} 205 206// Open opens the named file using os.Open and prepares it for use as an ELF binary. 207func Open(name string) (*File, error) { 208 f, err := os.Open(name) 209 if err != nil { 210 return nil, err 211 } 212 ff, err := NewFile(f) 213 if err != nil { 214 f.Close() 215 return nil, err 216 } 217 ff.closer = f 218 return ff, nil 219} 220 221// Close closes the File. 222// If the File was created using NewFile directly instead of Open, 223// Close has no effect. 224func (f *File) Close() error { 225 var err error 226 if f.closer != nil { 227 err = f.closer.Close() 228 f.closer = nil 229 } 230 return err 231} 232 233// SectionByType returns the first section in f with the 234// given type, or nil if there is no such section. 235func (f *File) SectionByType(typ SectionType) *Section { 236 for _, s := range f.Sections { 237 if s.Type == typ { 238 return s 239 } 240 } 241 return nil 242} 243 244// NewFile creates a new File for accessing an ELF binary in an underlying reader. 245// The ELF binary is expected to start at position 0 in the ReaderAt. 246func NewFile(r io.ReaderAt) (*File, error) { 247 sr := io.NewSectionReader(r, 0, 1<<63-1) 248 // Read and decode ELF identifier 249 var ident [16]uint8 250 if _, err := r.ReadAt(ident[0:], 0); err != nil { 251 return nil, err 252 } 253 if ident[0] != '\x7f' || ident[1] != 'E' || ident[2] != 'L' || ident[3] != 'F' { 254 return nil, &FormatError{0, "bad magic number", ident[0:4]} 255 } 256 257 f := new(File) 258 f.Class = Class(ident[EI_CLASS]) 259 switch f.Class { 260 case ELFCLASS32: 261 case ELFCLASS64: 262 // ok 263 default: 264 return nil, &FormatError{0, "unknown ELF class", f.Class} 265 } 266 267 f.Data = Data(ident[EI_DATA]) 268 switch f.Data { 269 case ELFDATA2LSB: 270 f.ByteOrder = binary.LittleEndian 271 case ELFDATA2MSB: 272 f.ByteOrder = binary.BigEndian 273 default: 274 return nil, &FormatError{0, "unknown ELF data encoding", f.Data} 275 } 276 277 f.Version = Version(ident[EI_VERSION]) 278 if f.Version != EV_CURRENT { 279 return nil, &FormatError{0, "unknown ELF version", f.Version} 280 } 281 282 f.OSABI = OSABI(ident[EI_OSABI]) 283 f.ABIVersion = ident[EI_ABIVERSION] 284 285 // Read ELF file header 286 var phoff int64 287 var phentsize, phnum int 288 var shoff int64 289 var shentsize, shnum, shstrndx int 290 shstrndx = -1 291 switch f.Class { 292 case ELFCLASS32: 293 hdr := new(Header32) 294 sr.Seek(0, seekStart) 295 if err := binary.Read(sr, f.ByteOrder, hdr); err != nil { 296 return nil, err 297 } 298 f.Type = Type(hdr.Type) 299 f.Machine = Machine(hdr.Machine) 300 f.Entry = uint64(hdr.Entry) 301 if v := Version(hdr.Version); v != f.Version { 302 return nil, &FormatError{0, "mismatched ELF version", v} 303 } 304 phoff = int64(hdr.Phoff) 305 phentsize = int(hdr.Phentsize) 306 phnum = int(hdr.Phnum) 307 shoff = int64(hdr.Shoff) 308 shentsize = int(hdr.Shentsize) 309 shnum = int(hdr.Shnum) 310 shstrndx = int(hdr.Shstrndx) 311 case ELFCLASS64: 312 hdr := new(Header64) 313 sr.Seek(0, seekStart) 314 if err := binary.Read(sr, f.ByteOrder, hdr); err != nil { 315 return nil, err 316 } 317 f.Type = Type(hdr.Type) 318 f.Machine = Machine(hdr.Machine) 319 f.Entry = hdr.Entry 320 if v := Version(hdr.Version); v != f.Version { 321 return nil, &FormatError{0, "mismatched ELF version", v} 322 } 323 phoff = int64(hdr.Phoff) 324 phentsize = int(hdr.Phentsize) 325 phnum = int(hdr.Phnum) 326 shoff = int64(hdr.Shoff) 327 shentsize = int(hdr.Shentsize) 328 shnum = int(hdr.Shnum) 329 shstrndx = int(hdr.Shstrndx) 330 } 331 332 if shnum > 0 && shoff > 0 && (shstrndx < 0 || shstrndx >= shnum) { 333 return nil, &FormatError{0, "invalid ELF shstrndx", shstrndx} 334 } 335 336 // Read program headers 337 f.Progs = make([]*Prog, phnum) 338 for i := 0; i < phnum; i++ { 339 off := phoff + int64(i)*int64(phentsize) 340 sr.Seek(off, seekStart) 341 p := new(Prog) 342 switch f.Class { 343 case ELFCLASS32: 344 ph := new(Prog32) 345 if err := binary.Read(sr, f.ByteOrder, ph); err != nil { 346 return nil, err 347 } 348 p.ProgHeader = ProgHeader{ 349 Type: ProgType(ph.Type), 350 Flags: ProgFlag(ph.Flags), 351 Off: uint64(ph.Off), 352 Vaddr: uint64(ph.Vaddr), 353 Paddr: uint64(ph.Paddr), 354 Filesz: uint64(ph.Filesz), 355 Memsz: uint64(ph.Memsz), 356 Align: uint64(ph.Align), 357 } 358 case ELFCLASS64: 359 ph := new(Prog64) 360 if err := binary.Read(sr, f.ByteOrder, ph); err != nil { 361 return nil, err 362 } 363 p.ProgHeader = ProgHeader{ 364 Type: ProgType(ph.Type), 365 Flags: ProgFlag(ph.Flags), 366 Off: ph.Off, 367 Vaddr: ph.Vaddr, 368 Paddr: ph.Paddr, 369 Filesz: ph.Filesz, 370 Memsz: ph.Memsz, 371 Align: ph.Align, 372 } 373 } 374 p.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz)) 375 p.ReaderAt = p.sr 376 f.Progs[i] = p 377 } 378 379 // Read section headers 380 f.Sections = make([]*Section, shnum) 381 names := make([]uint32, shnum) 382 for i := 0; i < shnum; i++ { 383 off := shoff + int64(i)*int64(shentsize) 384 sr.Seek(off, seekStart) 385 s := new(Section) 386 switch f.Class { 387 case ELFCLASS32: 388 sh := new(Section32) 389 if err := binary.Read(sr, f.ByteOrder, sh); err != nil { 390 return nil, err 391 } 392 names[i] = sh.Name 393 s.SectionHeader = SectionHeader{ 394 Type: SectionType(sh.Type), 395 Flags: SectionFlag(sh.Flags), 396 Addr: uint64(sh.Addr), 397 Offset: uint64(sh.Off), 398 FileSize: uint64(sh.Size), 399 Link: sh.Link, 400 Info: sh.Info, 401 Addralign: uint64(sh.Addralign), 402 Entsize: uint64(sh.Entsize), 403 } 404 case ELFCLASS64: 405 sh := new(Section64) 406 if err := binary.Read(sr, f.ByteOrder, sh); err != nil { 407 return nil, err 408 } 409 names[i] = sh.Name 410 s.SectionHeader = SectionHeader{ 411 Type: SectionType(sh.Type), 412 Flags: SectionFlag(sh.Flags), 413 Offset: sh.Off, 414 FileSize: sh.Size, 415 Addr: sh.Addr, 416 Link: sh.Link, 417 Info: sh.Info, 418 Addralign: sh.Addralign, 419 Entsize: sh.Entsize, 420 } 421 } 422 s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.FileSize)) 423 424 if s.Flags&SHF_COMPRESSED == 0 { 425 s.ReaderAt = s.sr 426 s.Size = s.FileSize 427 } else { 428 // Read the compression header. 429 switch f.Class { 430 case ELFCLASS32: 431 ch := new(Chdr32) 432 if err := binary.Read(s.sr, f.ByteOrder, ch); err != nil { 433 return nil, err 434 } 435 s.compressionType = CompressionType(ch.Type) 436 s.Size = uint64(ch.Size) 437 s.Addralign = uint64(ch.Addralign) 438 s.compressionOffset = int64(binary.Size(ch)) 439 case ELFCLASS64: 440 ch := new(Chdr64) 441 if err := binary.Read(s.sr, f.ByteOrder, ch); err != nil { 442 return nil, err 443 } 444 s.compressionType = CompressionType(ch.Type) 445 s.Size = ch.Size 446 s.Addralign = ch.Addralign 447 s.compressionOffset = int64(binary.Size(ch)) 448 } 449 } 450 451 f.Sections[i] = s 452 } 453 454 if len(f.Sections) == 0 { 455 return f, nil 456 } 457 458 // Load section header string table. 459 shstrtab, err := f.Sections[shstrndx].Data() 460 if err != nil { 461 return nil, err 462 } 463 for i, s := range f.Sections { 464 var ok bool 465 s.Name, ok = getString(shstrtab, int(names[i])) 466 if !ok { 467 return nil, &FormatError{shoff + int64(i*shentsize), "bad section name index", names[i]} 468 } 469 } 470 471 return f, nil 472} 473 474// getSymbols returns a slice of Symbols from parsing the symbol table 475// with the given type, along with the associated string table. 476func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, error) { 477 switch f.Class { 478 case ELFCLASS64: 479 return f.getSymbols64(typ) 480 481 case ELFCLASS32: 482 return f.getSymbols32(typ) 483 } 484 485 return nil, nil, errors.New("not implemented") 486} 487 488// ErrNoSymbols is returned by File.Symbols and File.DynamicSymbols 489// if there is no such section in the File. 490var ErrNoSymbols = errors.New("no symbol section") 491 492func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) { 493 symtabSection := f.SectionByType(typ) 494 if symtabSection == nil { 495 return nil, nil, ErrNoSymbols 496 } 497 498 data, err := symtabSection.Data() 499 if err != nil { 500 return nil, nil, errors.New("cannot load symbol section") 501 } 502 symtab := bytes.NewReader(data) 503 if symtab.Len()%Sym32Size != 0 { 504 return nil, nil, errors.New("length of symbol section is not a multiple of SymSize") 505 } 506 507 strdata, err := f.stringTable(symtabSection.Link) 508 if err != nil { 509 return nil, nil, errors.New("cannot load string table section") 510 } 511 512 // The first entry is all zeros. 513 var skip [Sym32Size]byte 514 symtab.Read(skip[:]) 515 516 symbols := make([]Symbol, symtab.Len()/Sym32Size) 517 518 i := 0 519 var sym Sym32 520 for symtab.Len() > 0 { 521 binary.Read(symtab, f.ByteOrder, &sym) 522 str, _ := getString(strdata, int(sym.Name)) 523 symbols[i].Name = str 524 symbols[i].Info = sym.Info 525 symbols[i].Other = sym.Other 526 symbols[i].Section = SectionIndex(sym.Shndx) 527 symbols[i].Value = uint64(sym.Value) 528 symbols[i].Size = uint64(sym.Size) 529 i++ 530 } 531 532 return symbols, strdata, nil 533} 534 535func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) { 536 symtabSection := f.SectionByType(typ) 537 if symtabSection == nil { 538 return nil, nil, ErrNoSymbols 539 } 540 541 data, err := symtabSection.Data() 542 if err != nil { 543 return nil, nil, errors.New("cannot load symbol section") 544 } 545 symtab := bytes.NewReader(data) 546 if symtab.Len()%Sym64Size != 0 { 547 return nil, nil, errors.New("length of symbol section is not a multiple of Sym64Size") 548 } 549 550 strdata, err := f.stringTable(symtabSection.Link) 551 if err != nil { 552 return nil, nil, errors.New("cannot load string table section") 553 } 554 555 // The first entry is all zeros. 556 var skip [Sym64Size]byte 557 symtab.Read(skip[:]) 558 559 symbols := make([]Symbol, symtab.Len()/Sym64Size) 560 561 i := 0 562 var sym Sym64 563 for symtab.Len() > 0 { 564 binary.Read(symtab, f.ByteOrder, &sym) 565 str, _ := getString(strdata, int(sym.Name)) 566 symbols[i].Name = str 567 symbols[i].Info = sym.Info 568 symbols[i].Other = sym.Other 569 symbols[i].Section = SectionIndex(sym.Shndx) 570 symbols[i].Value = sym.Value 571 symbols[i].Size = sym.Size 572 i++ 573 } 574 575 return symbols, strdata, nil 576} 577 578// getString extracts a string from an ELF string table. 579func getString(section []byte, start int) (string, bool) { 580 if start < 0 || start >= len(section) { 581 return "", false 582 } 583 584 for end := start; end < len(section); end++ { 585 if section[end] == 0 { 586 return string(section[start:end]), true 587 } 588 } 589 return "", false 590} 591 592// Section returns a section with the given name, or nil if no such 593// section exists. 594func (f *File) Section(name string) *Section { 595 for _, s := range f.Sections { 596 if s.Name == name { 597 return s 598 } 599 } 600 return nil 601} 602 603// applyRelocations applies relocations to dst. rels is a relocations section 604// in REL or RELA format. 605func (f *File) applyRelocations(dst []byte, rels []byte) error { 606 switch { 607 case f.Class == ELFCLASS64 && f.Machine == EM_X86_64: 608 return f.applyRelocationsAMD64(dst, rels) 609 case f.Class == ELFCLASS32 && f.Machine == EM_386: 610 return f.applyRelocations386(dst, rels) 611 case f.Class == ELFCLASS32 && f.Machine == EM_ARM: 612 return f.applyRelocationsARM(dst, rels) 613 case f.Class == ELFCLASS64 && f.Machine == EM_AARCH64: 614 return f.applyRelocationsARM64(dst, rels) 615 case f.Class == ELFCLASS32 && f.Machine == EM_PPC: 616 return f.applyRelocationsPPC(dst, rels) 617 case f.Class == ELFCLASS64 && f.Machine == EM_PPC64: 618 return f.applyRelocationsPPC64(dst, rels) 619 case f.Class == ELFCLASS32 && f.Machine == EM_MIPS: 620 return f.applyRelocationsMIPS(dst, rels) 621 case f.Class == ELFCLASS64 && f.Machine == EM_MIPS: 622 return f.applyRelocationsMIPS64(dst, rels) 623 case f.Class == ELFCLASS64 && f.Machine == EM_RISCV: 624 return f.applyRelocationsRISCV64(dst, rels) 625 case f.Class == ELFCLASS64 && f.Machine == EM_S390: 626 return f.applyRelocationss390x(dst, rels) 627 case f.Class == ELFCLASS64 && f.Machine == EM_SPARCV9: 628 return f.applyRelocationsSPARC64(dst, rels) 629 default: 630 return errors.New("applyRelocations: not implemented") 631 } 632} 633 634func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error { 635 // 24 is the size of Rela64. 636 if len(rels)%24 != 0 { 637 return errors.New("length of relocation section is not a multiple of 24") 638 } 639 640 symbols, _, err := f.getSymbols(SHT_SYMTAB) 641 if err != nil { 642 return err 643 } 644 645 b := bytes.NewReader(rels) 646 var rela Rela64 647 648 for b.Len() > 0 { 649 binary.Read(b, f.ByteOrder, &rela) 650 symNo := rela.Info >> 32 651 t := R_X86_64(rela.Info & 0xffff) 652 653 if symNo == 0 || symNo > uint64(len(symbols)) { 654 continue 655 } 656 sym := &symbols[symNo-1] 657 if SymType(sym.Info&0xf) != STT_SECTION { 658 // We don't handle non-section relocations for now. 659 continue 660 } 661 662 // There are relocations, so this must be a normal 663 // object file, and we only look at section symbols, 664 // so we assume that the symbol value is 0. 665 666 switch t { 667 case R_X86_64_64: 668 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 669 continue 670 } 671 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend)) 672 case R_X86_64_32: 673 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 674 continue 675 } 676 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)) 677 } 678 } 679 680 return nil 681} 682 683func (f *File) applyRelocations386(dst []byte, rels []byte) error { 684 // 8 is the size of Rel32. 685 if len(rels)%8 != 0 { 686 return errors.New("length of relocation section is not a multiple of 8") 687 } 688 689 symbols, _, err := f.getSymbols(SHT_SYMTAB) 690 if err != nil { 691 return err 692 } 693 694 b := bytes.NewReader(rels) 695 var rel Rel32 696 697 for b.Len() > 0 { 698 binary.Read(b, f.ByteOrder, &rel) 699 symNo := rel.Info >> 8 700 t := R_386(rel.Info & 0xff) 701 702 if symNo == 0 || symNo > uint32(len(symbols)) { 703 continue 704 } 705 sym := &symbols[symNo-1] 706 707 if t == R_386_32 { 708 if rel.Off+4 >= uint32(len(dst)) { 709 continue 710 } 711 val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4]) 712 val += uint32(sym.Value) 713 f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val) 714 } 715 } 716 717 return nil 718} 719 720func (f *File) applyRelocationsARM(dst []byte, rels []byte) error { 721 // 8 is the size of Rel32. 722 if len(rels)%8 != 0 { 723 return errors.New("length of relocation section is not a multiple of 8") 724 } 725 726 symbols, _, err := f.getSymbols(SHT_SYMTAB) 727 if err != nil { 728 return err 729 } 730 731 b := bytes.NewReader(rels) 732 var rel Rel32 733 734 for b.Len() > 0 { 735 binary.Read(b, f.ByteOrder, &rel) 736 symNo := rel.Info >> 8 737 t := R_ARM(rel.Info & 0xff) 738 739 if symNo == 0 || symNo > uint32(len(symbols)) { 740 continue 741 } 742 sym := &symbols[symNo-1] 743 744 switch t { 745 case R_ARM_ABS32: 746 if rel.Off+4 >= uint32(len(dst)) { 747 continue 748 } 749 val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4]) 750 val += uint32(sym.Value) 751 f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val) 752 } 753 } 754 755 return nil 756} 757 758func (f *File) applyRelocationsARM64(dst []byte, rels []byte) error { 759 // 24 is the size of Rela64. 760 if len(rels)%24 != 0 { 761 return errors.New("length of relocation section is not a multiple of 24") 762 } 763 764 symbols, _, err := f.getSymbols(SHT_SYMTAB) 765 if err != nil { 766 return err 767 } 768 769 b := bytes.NewReader(rels) 770 var rela Rela64 771 772 for b.Len() > 0 { 773 binary.Read(b, f.ByteOrder, &rela) 774 symNo := rela.Info >> 32 775 t := R_AARCH64(rela.Info & 0xffff) 776 777 if symNo == 0 || symNo > uint64(len(symbols)) { 778 continue 779 } 780 sym := &symbols[symNo-1] 781 if SymType(sym.Info&0xf) != STT_SECTION { 782 // We don't handle non-section relocations for now. 783 continue 784 } 785 786 // There are relocations, so this must be a normal 787 // object file, and we only look at section symbols, 788 // so we assume that the symbol value is 0. 789 790 switch t { 791 case R_AARCH64_ABS64: 792 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 793 continue 794 } 795 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend)) 796 case R_AARCH64_ABS32: 797 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 798 continue 799 } 800 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)) 801 } 802 } 803 804 return nil 805} 806 807func (f *File) applyRelocationsPPC(dst []byte, rels []byte) error { 808 // 12 is the size of Rela32. 809 if len(rels)%12 != 0 { 810 return errors.New("length of relocation section is not a multiple of 12") 811 } 812 813 symbols, _, err := f.getSymbols(SHT_SYMTAB) 814 if err != nil { 815 return err 816 } 817 818 b := bytes.NewReader(rels) 819 var rela Rela32 820 821 for b.Len() > 0 { 822 binary.Read(b, f.ByteOrder, &rela) 823 symNo := rela.Info >> 8 824 t := R_PPC(rela.Info & 0xff) 825 826 if symNo == 0 || symNo > uint32(len(symbols)) { 827 continue 828 } 829 sym := &symbols[symNo-1] 830 if SymType(sym.Info&0xf) != STT_SECTION { 831 // We don't handle non-section relocations for now. 832 continue 833 } 834 835 switch t { 836 case R_PPC_ADDR32: 837 if rela.Off+4 >= uint32(len(dst)) || rela.Addend < 0 { 838 continue 839 } 840 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)) 841 } 842 } 843 844 return nil 845} 846 847func (f *File) applyRelocationsPPC64(dst []byte, rels []byte) error { 848 // 24 is the size of Rela64. 849 if len(rels)%24 != 0 { 850 return errors.New("length of relocation section is not a multiple of 24") 851 } 852 853 symbols, _, err := f.getSymbols(SHT_SYMTAB) 854 if err != nil { 855 return err 856 } 857 858 b := bytes.NewReader(rels) 859 var rela Rela64 860 861 for b.Len() > 0 { 862 binary.Read(b, f.ByteOrder, &rela) 863 symNo := rela.Info >> 32 864 t := R_PPC64(rela.Info & 0xffff) 865 866 if symNo == 0 || symNo > uint64(len(symbols)) { 867 continue 868 } 869 sym := &symbols[symNo-1] 870 if SymType(sym.Info&0xf) != STT_SECTION { 871 // We don't handle non-section relocations for now. 872 continue 873 } 874 875 switch t { 876 case R_PPC64_ADDR64: 877 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 878 continue 879 } 880 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend)) 881 case R_PPC64_ADDR32: 882 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 883 continue 884 } 885 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)) 886 } 887 } 888 889 return nil 890} 891 892func (f *File) applyRelocationsMIPS(dst []byte, rels []byte) error { 893 // 8 is the size of Rel32. 894 if len(rels)%8 != 0 { 895 return errors.New("length of relocation section is not a multiple of 8") 896 } 897 898 symbols, _, err := f.getSymbols(SHT_SYMTAB) 899 if err != nil { 900 return err 901 } 902 903 b := bytes.NewReader(rels) 904 var rel Rel32 905 906 for b.Len() > 0 { 907 binary.Read(b, f.ByteOrder, &rel) 908 symNo := rel.Info >> 8 909 t := R_MIPS(rel.Info & 0xff) 910 911 if symNo == 0 || symNo > uint32(len(symbols)) { 912 continue 913 } 914 sym := &symbols[symNo-1] 915 916 switch t { 917 case R_MIPS_32: 918 if rel.Off+4 >= uint32(len(dst)) { 919 continue 920 } 921 val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4]) 922 val += uint32(sym.Value) 923 f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val) 924 } 925 } 926 927 return nil 928} 929 930func (f *File) applyRelocationsMIPS64(dst []byte, rels []byte) error { 931 // 24 is the size of Rela64. 932 if len(rels)%24 != 0 { 933 return errors.New("length of relocation section is not a multiple of 24") 934 } 935 936 symbols, _, err := f.getSymbols(SHT_SYMTAB) 937 if err != nil { 938 return err 939 } 940 941 b := bytes.NewReader(rels) 942 var rela Rela64 943 944 for b.Len() > 0 { 945 binary.Read(b, f.ByteOrder, &rela) 946 var symNo uint64 947 var t R_MIPS 948 if f.ByteOrder == binary.BigEndian { 949 symNo = rela.Info >> 32 950 t = R_MIPS(rela.Info & 0xff) 951 } else { 952 symNo = rela.Info & 0xffffffff 953 t = R_MIPS(rela.Info >> 56) 954 } 955 956 if symNo == 0 || symNo > uint64(len(symbols)) { 957 continue 958 } 959 sym := &symbols[symNo-1] 960 if SymType(sym.Info&0xf) != STT_SECTION { 961 // We don't handle non-section relocations for now. 962 continue 963 } 964 965 switch t { 966 case R_MIPS_64: 967 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 968 continue 969 } 970 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend)) 971 case R_MIPS_32: 972 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 973 continue 974 } 975 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)) 976 } 977 } 978 979 return nil 980} 981 982func (f *File) applyRelocationsRISCV64(dst []byte, rels []byte) error { 983 // 24 is the size of Rela64. 984 if len(rels)%24 != 0 { 985 return errors.New("length of relocation section is not a multiple of 24") 986 } 987 988 symbols, _, err := f.getSymbols(SHT_SYMTAB) 989 if err != nil { 990 return err 991 } 992 993 b := bytes.NewReader(rels) 994 var rela Rela64 995 996 for b.Len() > 0 { 997 binary.Read(b, f.ByteOrder, &rela) 998 symNo := rela.Info >> 32 999 t := R_RISCV(rela.Info & 0xffff) 1000 1001 if symNo == 0 || symNo > uint64(len(symbols)) { 1002 continue 1003 } 1004 sym := &symbols[symNo-1] 1005 switch SymType(sym.Info & 0xf) { 1006 case STT_SECTION, STT_NOTYPE: 1007 break 1008 default: 1009 continue 1010 } 1011 1012 switch t { 1013 case R_RISCV_64: 1014 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 1015 continue 1016 } 1017 val := sym.Value + uint64(rela.Addend) 1018 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val) 1019 case R_RISCV_32: 1020 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 1021 continue 1022 } 1023 val := uint32(sym.Value) + uint32(rela.Addend) 1024 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val) 1025 } 1026 } 1027 1028 return nil 1029} 1030 1031func (f *File) applyRelocationss390x(dst []byte, rels []byte) error { 1032 // 24 is the size of Rela64. 1033 if len(rels)%24 != 0 { 1034 return errors.New("length of relocation section is not a multiple of 24") 1035 } 1036 1037 symbols, _, err := f.getSymbols(SHT_SYMTAB) 1038 if err != nil { 1039 return err 1040 } 1041 1042 b := bytes.NewReader(rels) 1043 var rela Rela64 1044 1045 for b.Len() > 0 { 1046 binary.Read(b, f.ByteOrder, &rela) 1047 symNo := rela.Info >> 32 1048 t := R_390(rela.Info & 0xffff) 1049 1050 if symNo == 0 || symNo > uint64(len(symbols)) { 1051 continue 1052 } 1053 sym := &symbols[symNo-1] 1054 switch SymType(sym.Info & 0xf) { 1055 case STT_SECTION, STT_NOTYPE: 1056 break 1057 default: 1058 continue 1059 } 1060 1061 switch t { 1062 case R_390_64: 1063 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 1064 continue 1065 } 1066 val := sym.Value + uint64(rela.Addend) 1067 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val) 1068 case R_390_32: 1069 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 1070 continue 1071 } 1072 val := uint32(sym.Value) + uint32(rela.Addend) 1073 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val) 1074 } 1075 } 1076 1077 return nil 1078} 1079 1080func (f *File) applyRelocationsSPARC64(dst []byte, rels []byte) error { 1081 // 24 is the size of Rela64. 1082 if len(rels)%24 != 0 { 1083 return errors.New("length of relocation section is not a multiple of 24") 1084 } 1085 1086 symbols, _, err := f.getSymbols(SHT_SYMTAB) 1087 if err != nil { 1088 return err 1089 } 1090 1091 b := bytes.NewReader(rels) 1092 var rela Rela64 1093 1094 for b.Len() > 0 { 1095 binary.Read(b, f.ByteOrder, &rela) 1096 symNo := rela.Info >> 32 1097 t := R_SPARC(rela.Info & 0xff) 1098 1099 if symNo == 0 || symNo > uint64(len(symbols)) { 1100 continue 1101 } 1102 sym := &symbols[symNo-1] 1103 if SymType(sym.Info&0xf) != STT_SECTION { 1104 // We don't handle non-section relocations for now. 1105 continue 1106 } 1107 1108 switch t { 1109 case R_SPARC_64, R_SPARC_UA64: 1110 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 1111 continue 1112 } 1113 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend)) 1114 case R_SPARC_32, R_SPARC_UA32: 1115 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 1116 continue 1117 } 1118 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)) 1119 } 1120 } 1121 1122 return nil 1123} 1124 1125func (f *File) DWARF() (*dwarf.Data, error) { 1126 dwarfSuffix := func(s *Section) string { 1127 switch { 1128 case strings.HasPrefix(s.Name, ".debug_"): 1129 return s.Name[7:] 1130 case strings.HasPrefix(s.Name, ".zdebug_"): 1131 return s.Name[8:] 1132 default: 1133 return "" 1134 } 1135 1136 } 1137 // sectionData gets the data for s, checks its size, and 1138 // applies any applicable relations. 1139 sectionData := func(i int, s *Section) ([]byte, error) { 1140 b, err := s.Data() 1141 if err != nil && uint64(len(b)) < s.Size { 1142 return nil, err 1143 } 1144 1145 if len(b) >= 12 && string(b[:4]) == "ZLIB" { 1146 dlen := binary.BigEndian.Uint64(b[4:12]) 1147 dbuf := make([]byte, dlen) 1148 r, err := zlib.NewReader(bytes.NewBuffer(b[12:])) 1149 if err != nil { 1150 return nil, err 1151 } 1152 if _, err := io.ReadFull(r, dbuf); err != nil { 1153 return nil, err 1154 } 1155 if err := r.Close(); err != nil { 1156 return nil, err 1157 } 1158 b = dbuf 1159 } 1160 1161 for _, r := range f.Sections { 1162 if r.Type != SHT_RELA && r.Type != SHT_REL { 1163 continue 1164 } 1165 if int(r.Info) != i { 1166 continue 1167 } 1168 rd, err := r.Data() 1169 if err != nil { 1170 return nil, err 1171 } 1172 err = f.applyRelocations(b, rd) 1173 if err != nil { 1174 return nil, err 1175 } 1176 } 1177 return b, nil 1178 } 1179 1180 // There are many other DWARF sections, but these 1181 // are the ones the debug/dwarf package uses. 1182 // Don't bother loading others. 1183 var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil} 1184 for i, s := range f.Sections { 1185 suffix := dwarfSuffix(s) 1186 if suffix == "" { 1187 continue 1188 } 1189 if _, ok := dat[suffix]; !ok { 1190 continue 1191 } 1192 b, err := sectionData(i, s) 1193 if err != nil { 1194 return nil, err 1195 } 1196 dat[suffix] = b 1197 } 1198 1199 d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, dat["ranges"], dat["str"]) 1200 if err != nil { 1201 return nil, err 1202 } 1203 1204 // Look for DWARF4 .debug_types sections. 1205 for i, s := range f.Sections { 1206 suffix := dwarfSuffix(s) 1207 if suffix != "types" { 1208 continue 1209 } 1210 1211 b, err := sectionData(i, s) 1212 if err != nil { 1213 return nil, err 1214 } 1215 1216 err = d.AddTypes(fmt.Sprintf("types-%d", i), b) 1217 if err != nil { 1218 return nil, err 1219 } 1220 } 1221 1222 return d, nil 1223} 1224 1225// Symbols returns the symbol table for f. The symbols will be listed in the order 1226// they appear in f. 1227// 1228// For compatibility with Go 1.0, Symbols omits the null symbol at index 0. 1229// After retrieving the symbols as symtab, an externally supplied index x 1230// corresponds to symtab[x-1], not symtab[x]. 1231func (f *File) Symbols() ([]Symbol, error) { 1232 sym, _, err := f.getSymbols(SHT_SYMTAB) 1233 return sym, err 1234} 1235 1236// DynamicSymbols returns the dynamic symbol table for f. The symbols 1237// will be listed in the order they appear in f. 1238// 1239// For compatibility with Symbols, DynamicSymbols omits the null symbol at index 0. 1240// After retrieving the symbols as symtab, an externally supplied index x 1241// corresponds to symtab[x-1], not symtab[x]. 1242func (f *File) DynamicSymbols() ([]Symbol, error) { 1243 sym, _, err := f.getSymbols(SHT_DYNSYM) 1244 return sym, err 1245} 1246 1247type ImportedSymbol struct { 1248 Name string 1249 Version string 1250 Library string 1251} 1252 1253// ImportedSymbols returns the names of all symbols 1254// referred to by the binary f that are expected to be 1255// satisfied by other libraries at dynamic load time. 1256// It does not return weak symbols. 1257func (f *File) ImportedSymbols() ([]ImportedSymbol, error) { 1258 sym, str, err := f.getSymbols(SHT_DYNSYM) 1259 if err != nil { 1260 return nil, err 1261 } 1262 f.gnuVersionInit(str) 1263 var all []ImportedSymbol 1264 for i, s := range sym { 1265 if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF { 1266 all = append(all, ImportedSymbol{Name: s.Name}) 1267 f.gnuVersion(i, &all[len(all)-1]) 1268 } 1269 } 1270 return all, nil 1271} 1272 1273type verneed struct { 1274 File string 1275 Name string 1276} 1277 1278// gnuVersionInit parses the GNU version tables 1279// for use by calls to gnuVersion. 1280func (f *File) gnuVersionInit(str []byte) { 1281 // Accumulate verneed information. 1282 vn := f.SectionByType(SHT_GNU_VERNEED) 1283 if vn == nil { 1284 return 1285 } 1286 d, _ := vn.Data() 1287 1288 var need []verneed 1289 i := 0 1290 for { 1291 if i+16 > len(d) { 1292 break 1293 } 1294 vers := f.ByteOrder.Uint16(d[i : i+2]) 1295 if vers != 1 { 1296 break 1297 } 1298 cnt := f.ByteOrder.Uint16(d[i+2 : i+4]) 1299 fileoff := f.ByteOrder.Uint32(d[i+4 : i+8]) 1300 aux := f.ByteOrder.Uint32(d[i+8 : i+12]) 1301 next := f.ByteOrder.Uint32(d[i+12 : i+16]) 1302 file, _ := getString(str, int(fileoff)) 1303 1304 var name string 1305 j := i + int(aux) 1306 for c := 0; c < int(cnt); c++ { 1307 if j+16 > len(d) { 1308 break 1309 } 1310 // hash := f.ByteOrder.Uint32(d[j:j+4]) 1311 // flags := f.ByteOrder.Uint16(d[j+4:j+6]) 1312 other := f.ByteOrder.Uint16(d[j+6 : j+8]) 1313 nameoff := f.ByteOrder.Uint32(d[j+8 : j+12]) 1314 next := f.ByteOrder.Uint32(d[j+12 : j+16]) 1315 name, _ = getString(str, int(nameoff)) 1316 ndx := int(other) 1317 if ndx >= len(need) { 1318 a := make([]verneed, 2*(ndx+1)) 1319 copy(a, need) 1320 need = a 1321 } 1322 1323 need[ndx] = verneed{file, name} 1324 if next == 0 { 1325 break 1326 } 1327 j += int(next) 1328 } 1329 1330 if next == 0 { 1331 break 1332 } 1333 i += int(next) 1334 } 1335 1336 // Versym parallels symbol table, indexing into verneed. 1337 vs := f.SectionByType(SHT_GNU_VERSYM) 1338 if vs == nil { 1339 return 1340 } 1341 d, _ = vs.Data() 1342 1343 f.gnuNeed = need 1344 f.gnuVersym = d 1345} 1346 1347// gnuVersion adds Library and Version information to sym, 1348// which came from offset i of the symbol table. 1349func (f *File) gnuVersion(i int, sym *ImportedSymbol) { 1350 // Each entry is two bytes. 1351 i = (i + 1) * 2 1352 if i >= len(f.gnuVersym) { 1353 return 1354 } 1355 j := int(f.ByteOrder.Uint16(f.gnuVersym[i:])) 1356 if j < 2 || j >= len(f.gnuNeed) { 1357 return 1358 } 1359 n := &f.gnuNeed[j] 1360 sym.Library = n.File 1361 sym.Version = n.Name 1362} 1363 1364// ImportedLibraries returns the names of all libraries 1365// referred to by the binary f that are expected to be 1366// linked with the binary at dynamic link time. 1367func (f *File) ImportedLibraries() ([]string, error) { 1368 return f.DynString(DT_NEEDED) 1369} 1370 1371// DynString returns the strings listed for the given tag in the file's dynamic 1372// section. 1373// 1374// The tag must be one that takes string values: DT_NEEDED, DT_SONAME, DT_RPATH, or 1375// DT_RUNPATH. 1376func (f *File) DynString(tag DynTag) ([]string, error) { 1377 switch tag { 1378 case DT_NEEDED, DT_SONAME, DT_RPATH, DT_RUNPATH: 1379 default: 1380 return nil, fmt.Errorf("non-string-valued tag %v", tag) 1381 } 1382 ds := f.SectionByType(SHT_DYNAMIC) 1383 if ds == nil { 1384 // not dynamic, so no libraries 1385 return nil, nil 1386 } 1387 d, err := ds.Data() 1388 if err != nil { 1389 return nil, err 1390 } 1391 str, err := f.stringTable(ds.Link) 1392 if err != nil { 1393 return nil, err 1394 } 1395 var all []string 1396 for len(d) > 0 { 1397 var t DynTag 1398 var v uint64 1399 switch f.Class { 1400 case ELFCLASS32: 1401 t = DynTag(f.ByteOrder.Uint32(d[0:4])) 1402 v = uint64(f.ByteOrder.Uint32(d[4:8])) 1403 d = d[8:] 1404 case ELFCLASS64: 1405 t = DynTag(f.ByteOrder.Uint64(d[0:8])) 1406 v = f.ByteOrder.Uint64(d[8:16]) 1407 d = d[16:] 1408 } 1409 if t == tag { 1410 s, ok := getString(str, int(v)) 1411 if ok { 1412 all = append(all, s) 1413 } 1414 } 1415 } 1416 return all, nil 1417} 1418