|
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417 |
- // Copyright 2018 Google LLC
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
-
- // Package elf implements access to ELF object files.
- package elf
-
- import (
- "bytes"
- "compress/zlib"
- "encoding/binary"
- "errors"
- "fmt"
- "io"
- "os"
- "strings"
-
- "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf"
- )
-
- // seekStart, seekCurrent, seekEnd are copies of
- // io.SeekStart, io.SeekCurrent, and io.SeekEnd.
- // We can't use the ones from package io because
- // we want this code to build with Go 1.4 during
- // cmd/dist bootstrap.
- const (
- seekStart int = 0
- seekCurrent int = 1
- seekEnd int = 2
- )
-
- // TODO: error reporting detail
-
- /*
- * Internal ELF representation
- */
-
- // A FileHeader represents an ELF file header.
- type FileHeader struct {
- Class Class
- Data Data
- Version Version
- OSABI OSABI
- ABIVersion uint8
- ByteOrder binary.ByteOrder
- Type Type
- Machine Machine
- Entry uint64
- }
-
- // A File represents an open ELF file.
- type File struct {
- FileHeader
- Sections []*Section
- Progs []*Prog
- closer io.Closer
- gnuNeed []verneed
- gnuVersym []byte
- }
-
- // A SectionHeader represents a single ELF section header.
- type SectionHeader struct {
- Name string
- Type SectionType
- Flags SectionFlag
- Addr uint64
- Offset uint64
- Size uint64
- Link uint32
- Info uint32
- Addralign uint64
- Entsize uint64
-
- // FileSize is the size of this section in the file in bytes.
- // If a section is compressed, FileSize is the size of the
- // compressed data, while Size (above) is the size of the
- // uncompressed data.
- FileSize uint64
- }
-
- // A Section represents a single section in an ELF file.
- type Section struct {
- SectionHeader
-
- // Embed ReaderAt for ReadAt method.
- // Do not embed SectionReader directly
- // to avoid having Read and Seek.
- // If a client wants Read and Seek it must use
- // Open() to avoid fighting over the seek offset
- // with other clients.
- //
- // ReaderAt may be nil if the section is not easily available
- // in a random-access form. For example, a compressed section
- // may have a nil ReaderAt.
- io.ReaderAt
- sr *io.SectionReader
-
- compressionType CompressionType
- compressionOffset int64
- }
-
- // Data reads and returns the contents of the ELF section.
- // Even if the section is stored compressed in the ELF file,
- // Data returns uncompressed data.
- func (s *Section) Data() ([]byte, error) {
- dat := make([]byte, s.Size)
- n, err := io.ReadFull(s.Open(), dat)
- return dat[0:n], err
- }
-
- // stringTable reads and returns the string table given by the
- // specified link value.
- func (f *File) stringTable(link uint32) ([]byte, error) {
- if link <= 0 || link >= uint32(len(f.Sections)) {
- return nil, errors.New("section has invalid string table link")
- }
- return f.Sections[link].Data()
- }
-
- // Open returns a new ReadSeeker reading the ELF section.
- // Even if the section is stored compressed in the ELF file,
- // the ReadSeeker reads uncompressed data.
- func (s *Section) Open() io.ReadSeeker {
- if s.Flags&SHF_COMPRESSED == 0 {
- return io.NewSectionReader(s.sr, 0, 1<<63-1)
- }
- if s.compressionType == COMPRESS_ZLIB {
- return &readSeekerFromReader{
- reset: func() (io.Reader, error) {
- fr := io.NewSectionReader(s.sr, s.compressionOffset, int64(s.FileSize)-s.compressionOffset)
- return zlib.NewReader(fr)
- },
- size: int64(s.Size),
- }
- }
- err := &FormatError{int64(s.Offset), "unknown compression type", s.compressionType}
- return errorReader{err}
- }
-
- // A ProgHeader represents a single ELF program header.
- type ProgHeader struct {
- Type ProgType
- Flags ProgFlag
- Off uint64
- Vaddr uint64
- Paddr uint64
- Filesz uint64
- Memsz uint64
- Align uint64
- }
-
- // A Prog represents a single ELF program header in an ELF binary.
- type Prog struct {
- ProgHeader
-
- // Embed ReaderAt for ReadAt method.
- // Do not embed SectionReader directly
- // to avoid having Read and Seek.
- // If a client wants Read and Seek it must use
- // Open() to avoid fighting over the seek offset
- // with other clients.
- io.ReaderAt
- sr *io.SectionReader
- }
-
- // Open returns a new ReadSeeker reading the ELF program body.
- func (p *Prog) Open() io.ReadSeeker { return io.NewSectionReader(p.sr, 0, 1<<63-1) }
-
- // A Symbol represents an entry in an ELF symbol table section.
- type Symbol struct {
- Name string
- Info, Other byte
- Section SectionIndex
- Value, Size uint64
- }
-
- /*
- * ELF reader
- */
-
- type FormatError struct {
- off int64
- msg string
- val interface{}
- }
-
- func (e *FormatError) Error() string {
- msg := e.msg
- if e.val != nil {
- msg += fmt.Sprintf(" '%v' ", e.val)
- }
- msg += fmt.Sprintf("in record at byte %#x", e.off)
- return msg
- }
-
- // Open opens the named file using os.Open and prepares it for use as an ELF binary.
- func Open(name string) (*File, error) {
- f, err := os.Open(name)
- if err != nil {
- return nil, err
- }
- ff, err := NewFile(f)
- if err != nil {
- f.Close()
- return nil, err
- }
- ff.closer = f
- return ff, nil
- }
-
- // Close closes the File.
- // If the File was created using NewFile directly instead of Open,
- // Close has no effect.
- func (f *File) Close() error {
- var err error
- if f.closer != nil {
- err = f.closer.Close()
- f.closer = nil
- }
- return err
- }
-
- // SectionByType returns the first section in f with the
- // given type, or nil if there is no such section.
- func (f *File) SectionByType(typ SectionType) *Section {
- for _, s := range f.Sections {
- if s.Type == typ {
- return s
- }
- }
- return nil
- }
-
- // NewFile creates a new File for accessing an ELF binary in an underlying reader.
- // The ELF binary is expected to start at position 0 in the ReaderAt.
- func NewFile(r io.ReaderAt) (*File, error) {
- sr := io.NewSectionReader(r, 0, 1<<63-1)
- // Read and decode ELF identifier
- var ident [16]uint8
- if _, err := r.ReadAt(ident[0:], 0); err != nil {
- return nil, err
- }
- if ident[0] != '\x7f' || ident[1] != 'E' || ident[2] != 'L' || ident[3] != 'F' {
- return nil, &FormatError{0, "bad magic number", ident[0:4]}
- }
-
- f := new(File)
- f.Class = Class(ident[EI_CLASS])
- switch f.Class {
- case ELFCLASS32:
- case ELFCLASS64:
- // ok
- default:
- return nil, &FormatError{0, "unknown ELF class", f.Class}
- }
-
- f.Data = Data(ident[EI_DATA])
- switch f.Data {
- case ELFDATA2LSB:
- f.ByteOrder = binary.LittleEndian
- case ELFDATA2MSB:
- f.ByteOrder = binary.BigEndian
- default:
- return nil, &FormatError{0, "unknown ELF data encoding", f.Data}
- }
-
- f.Version = Version(ident[EI_VERSION])
- if f.Version != EV_CURRENT {
- return nil, &FormatError{0, "unknown ELF version", f.Version}
- }
-
- f.OSABI = OSABI(ident[EI_OSABI])
- f.ABIVersion = ident[EI_ABIVERSION]
-
- // Read ELF file header
- var phoff int64
- var phentsize, phnum int
- var shoff int64
- var shentsize, shnum, shstrndx int
- shstrndx = -1
- switch f.Class {
- case ELFCLASS32:
- hdr := new(Header32)
- sr.Seek(0, seekStart)
- if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
- return nil, err
- }
- f.Type = Type(hdr.Type)
- f.Machine = Machine(hdr.Machine)
- f.Entry = uint64(hdr.Entry)
- if v := Version(hdr.Version); v != f.Version {
- return nil, &FormatError{0, "mismatched ELF version", v}
- }
- phoff = int64(hdr.Phoff)
- phentsize = int(hdr.Phentsize)
- phnum = int(hdr.Phnum)
- shoff = int64(hdr.Shoff)
- shentsize = int(hdr.Shentsize)
- shnum = int(hdr.Shnum)
- shstrndx = int(hdr.Shstrndx)
- case ELFCLASS64:
- hdr := new(Header64)
- sr.Seek(0, seekStart)
- if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
- return nil, err
- }
- f.Type = Type(hdr.Type)
- f.Machine = Machine(hdr.Machine)
- f.Entry = hdr.Entry
- if v := Version(hdr.Version); v != f.Version {
- return nil, &FormatError{0, "mismatched ELF version", v}
- }
- phoff = int64(hdr.Phoff)
- phentsize = int(hdr.Phentsize)
- phnum = int(hdr.Phnum)
- shoff = int64(hdr.Shoff)
- shentsize = int(hdr.Shentsize)
- shnum = int(hdr.Shnum)
- shstrndx = int(hdr.Shstrndx)
- }
-
- if shnum > 0 && shoff > 0 && (shstrndx < 0 || shstrndx >= shnum) {
- return nil, &FormatError{0, "invalid ELF shstrndx", shstrndx}
- }
-
- // Read program headers
- f.Progs = make([]*Prog, phnum)
- for i := 0; i < phnum; i++ {
- off := phoff + int64(i)*int64(phentsize)
- sr.Seek(off, seekStart)
- p := new(Prog)
- switch f.Class {
- case ELFCLASS32:
- ph := new(Prog32)
- if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
- return nil, err
- }
- p.ProgHeader = ProgHeader{
- Type: ProgType(ph.Type),
- Flags: ProgFlag(ph.Flags),
- Off: uint64(ph.Off),
- Vaddr: uint64(ph.Vaddr),
- Paddr: uint64(ph.Paddr),
- Filesz: uint64(ph.Filesz),
- Memsz: uint64(ph.Memsz),
- Align: uint64(ph.Align),
- }
- case ELFCLASS64:
- ph := new(Prog64)
- if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
- return nil, err
- }
- p.ProgHeader = ProgHeader{
- Type: ProgType(ph.Type),
- Flags: ProgFlag(ph.Flags),
- Off: ph.Off,
- Vaddr: ph.Vaddr,
- Paddr: ph.Paddr,
- Filesz: ph.Filesz,
- Memsz: ph.Memsz,
- Align: ph.Align,
- }
- }
- p.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz))
- p.ReaderAt = p.sr
- f.Progs[i] = p
- }
-
- // Read section headers
- f.Sections = make([]*Section, shnum)
- names := make([]uint32, shnum)
- for i := 0; i < shnum; i++ {
- off := shoff + int64(i)*int64(shentsize)
- sr.Seek(off, seekStart)
- s := new(Section)
- switch f.Class {
- case ELFCLASS32:
- sh := new(Section32)
- if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
- return nil, err
- }
- names[i] = sh.Name
- s.SectionHeader = SectionHeader{
- Type: SectionType(sh.Type),
- Flags: SectionFlag(sh.Flags),
- Addr: uint64(sh.Addr),
- Offset: uint64(sh.Off),
- FileSize: uint64(sh.Size),
- Link: sh.Link,
- Info: sh.Info,
- Addralign: uint64(sh.Addralign),
- Entsize: uint64(sh.Entsize),
- }
- case ELFCLASS64:
- sh := new(Section64)
- if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
- return nil, err
- }
- names[i] = sh.Name
- s.SectionHeader = SectionHeader{
- Type: SectionType(sh.Type),
- Flags: SectionFlag(sh.Flags),
- Offset: sh.Off,
- FileSize: sh.Size,
- Addr: sh.Addr,
- Link: sh.Link,
- Info: sh.Info,
- Addralign: sh.Addralign,
- Entsize: sh.Entsize,
- }
- }
- s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.FileSize))
-
- if s.Flags&SHF_COMPRESSED == 0 {
- s.ReaderAt = s.sr
- s.Size = s.FileSize
- } else {
- // Read the compression header.
- switch f.Class {
- case ELFCLASS32:
- ch := new(Chdr32)
- if err := binary.Read(s.sr, f.ByteOrder, ch); err != nil {
- return nil, err
- }
- s.compressionType = CompressionType(ch.Type)
- s.Size = uint64(ch.Size)
- s.Addralign = uint64(ch.Addralign)
- s.compressionOffset = int64(binary.Size(ch))
- case ELFCLASS64:
- ch := new(Chdr64)
- if err := binary.Read(s.sr, f.ByteOrder, ch); err != nil {
- return nil, err
- }
- s.compressionType = CompressionType(ch.Type)
- s.Size = ch.Size
- s.Addralign = ch.Addralign
- s.compressionOffset = int64(binary.Size(ch))
- }
- }
-
- f.Sections[i] = s
- }
-
- if len(f.Sections) == 0 {
- return f, nil
- }
-
- // Load section header string table.
- shstrtab, err := f.Sections[shstrndx].Data()
- if err != nil {
- return nil, err
- }
- for i, s := range f.Sections {
- var ok bool
- s.Name, ok = getString(shstrtab, int(names[i]))
- if !ok {
- return nil, &FormatError{shoff + int64(i*shentsize), "bad section name index", names[i]}
- }
- }
-
- return f, nil
- }
-
- // getSymbols returns a slice of Symbols from parsing the symbol table
- // with the given type, along with the associated string table.
- func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, error) {
- switch f.Class {
- case ELFCLASS64:
- return f.getSymbols64(typ)
-
- case ELFCLASS32:
- return f.getSymbols32(typ)
- }
-
- return nil, nil, errors.New("not implemented")
- }
-
- // ErrNoSymbols is returned by File.Symbols and File.DynamicSymbols
- // if there is no such section in the File.
- var ErrNoSymbols = errors.New("no symbol section")
-
- func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) {
- symtabSection := f.SectionByType(typ)
- if symtabSection == nil {
- return nil, nil, ErrNoSymbols
- }
-
- data, err := symtabSection.Data()
- if err != nil {
- return nil, nil, errors.New("cannot load symbol section")
- }
- symtab := bytes.NewReader(data)
- if symtab.Len()%Sym32Size != 0 {
- return nil, nil, errors.New("length of symbol section is not a multiple of SymSize")
- }
-
- strdata, err := f.stringTable(symtabSection.Link)
- if err != nil {
- return nil, nil, errors.New("cannot load string table section")
- }
-
- // The first entry is all zeros.
- var skip [Sym32Size]byte
- symtab.Read(skip[:])
-
- symbols := make([]Symbol, symtab.Len()/Sym32Size)
-
- i := 0
- var sym Sym32
- for symtab.Len() > 0 {
- binary.Read(symtab, f.ByteOrder, &sym)
- str, _ := getString(strdata, int(sym.Name))
- symbols[i].Name = str
- symbols[i].Info = sym.Info
- symbols[i].Other = sym.Other
- symbols[i].Section = SectionIndex(sym.Shndx)
- symbols[i].Value = uint64(sym.Value)
- symbols[i].Size = uint64(sym.Size)
- i++
- }
-
- return symbols, strdata, nil
- }
-
- func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) {
- symtabSection := f.SectionByType(typ)
- if symtabSection == nil {
- return nil, nil, ErrNoSymbols
- }
-
- data, err := symtabSection.Data()
- if err != nil {
- return nil, nil, errors.New("cannot load symbol section")
- }
- symtab := bytes.NewReader(data)
- if symtab.Len()%Sym64Size != 0 {
- return nil, nil, errors.New("length of symbol section is not a multiple of Sym64Size")
- }
-
- strdata, err := f.stringTable(symtabSection.Link)
- if err != nil {
- return nil, nil, errors.New("cannot load string table section")
- }
-
- // The first entry is all zeros.
- var skip [Sym64Size]byte
- symtab.Read(skip[:])
-
- symbols := make([]Symbol, symtab.Len()/Sym64Size)
-
- i := 0
- var sym Sym64
- for symtab.Len() > 0 {
- binary.Read(symtab, f.ByteOrder, &sym)
- str, _ := getString(strdata, int(sym.Name))
- symbols[i].Name = str
- symbols[i].Info = sym.Info
- symbols[i].Other = sym.Other
- symbols[i].Section = SectionIndex(sym.Shndx)
- symbols[i].Value = sym.Value
- symbols[i].Size = sym.Size
- i++
- }
-
- return symbols, strdata, nil
- }
-
- // getString extracts a string from an ELF string table.
- func getString(section []byte, start int) (string, bool) {
- if start < 0 || start >= len(section) {
- return "", false
- }
-
- for end := start; end < len(section); end++ {
- if section[end] == 0 {
- return string(section[start:end]), true
- }
- }
- return "", false
- }
-
- // Section returns a section with the given name, or nil if no such
- // section exists.
- func (f *File) Section(name string) *Section {
- for _, s := range f.Sections {
- if s.Name == name {
- return s
- }
- }
- return nil
- }
-
- // applyRelocations applies relocations to dst. rels is a relocations section
- // in REL or RELA format.
- func (f *File) applyRelocations(dst []byte, rels []byte) error {
- switch {
- case f.Class == ELFCLASS64 && f.Machine == EM_X86_64:
- return f.applyRelocationsAMD64(dst, rels)
- case f.Class == ELFCLASS32 && f.Machine == EM_386:
- return f.applyRelocations386(dst, rels)
- case f.Class == ELFCLASS32 && f.Machine == EM_ARM:
- return f.applyRelocationsARM(dst, rels)
- case f.Class == ELFCLASS64 && f.Machine == EM_AARCH64:
- return f.applyRelocationsARM64(dst, rels)
- case f.Class == ELFCLASS32 && f.Machine == EM_PPC:
- return f.applyRelocationsPPC(dst, rels)
- case f.Class == ELFCLASS64 && f.Machine == EM_PPC64:
- return f.applyRelocationsPPC64(dst, rels)
- case f.Class == ELFCLASS32 && f.Machine == EM_MIPS:
- return f.applyRelocationsMIPS(dst, rels)
- case f.Class == ELFCLASS64 && f.Machine == EM_MIPS:
- return f.applyRelocationsMIPS64(dst, rels)
- case f.Class == ELFCLASS64 && f.Machine == EM_RISCV:
- return f.applyRelocationsRISCV64(dst, rels)
- case f.Class == ELFCLASS64 && f.Machine == EM_S390:
- return f.applyRelocationss390x(dst, rels)
- case f.Class == ELFCLASS64 && f.Machine == EM_SPARCV9:
- return f.applyRelocationsSPARC64(dst, rels)
- default:
- return errors.New("applyRelocations: not implemented")
- }
- }
-
- func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
- // 24 is the size of Rela64.
- if len(rels)%24 != 0 {
- return errors.New("length of relocation section is not a multiple of 24")
- }
-
- symbols, _, err := f.getSymbols(SHT_SYMTAB)
- if err != nil {
- return err
- }
-
- b := bytes.NewReader(rels)
- var rela Rela64
-
- for b.Len() > 0 {
- binary.Read(b, f.ByteOrder, &rela)
- symNo := rela.Info >> 32
- t := R_X86_64(rela.Info & 0xffff)
-
- if symNo == 0 || symNo > uint64(len(symbols)) {
- continue
- }
- sym := &symbols[symNo-1]
- if SymType(sym.Info&0xf) != STT_SECTION {
- // We don't handle non-section relocations for now.
- continue
- }
-
- // There are relocations, so this must be a normal
- // object file, and we only look at section symbols,
- // so we assume that the symbol value is 0.
-
- switch t {
- case R_X86_64_64:
- if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
- continue
- }
- f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
- case R_X86_64_32:
- if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
- continue
- }
- f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
- }
- }
-
- return nil
- }
-
- func (f *File) applyRelocations386(dst []byte, rels []byte) error {
- // 8 is the size of Rel32.
- if len(rels)%8 != 0 {
- return errors.New("length of relocation section is not a multiple of 8")
- }
-
- symbols, _, err := f.getSymbols(SHT_SYMTAB)
- if err != nil {
- return err
- }
-
- b := bytes.NewReader(rels)
- var rel Rel32
-
- for b.Len() > 0 {
- binary.Read(b, f.ByteOrder, &rel)
- symNo := rel.Info >> 8
- t := R_386(rel.Info & 0xff)
-
- if symNo == 0 || symNo > uint32(len(symbols)) {
- continue
- }
- sym := &symbols[symNo-1]
-
- if t == R_386_32 {
- if rel.Off+4 >= uint32(len(dst)) {
- continue
- }
- val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
- val += uint32(sym.Value)
- f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
- }
- }
-
- return nil
- }
-
- func (f *File) applyRelocationsARM(dst []byte, rels []byte) error {
- // 8 is the size of Rel32.
- if len(rels)%8 != 0 {
- return errors.New("length of relocation section is not a multiple of 8")
- }
-
- symbols, _, err := f.getSymbols(SHT_SYMTAB)
- if err != nil {
- return err
- }
-
- b := bytes.NewReader(rels)
- var rel Rel32
-
- for b.Len() > 0 {
- binary.Read(b, f.ByteOrder, &rel)
- symNo := rel.Info >> 8
- t := R_ARM(rel.Info & 0xff)
-
- if symNo == 0 || symNo > uint32(len(symbols)) {
- continue
- }
- sym := &symbols[symNo-1]
-
- switch t {
- case R_ARM_ABS32:
- if rel.Off+4 >= uint32(len(dst)) {
- continue
- }
- val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
- val += uint32(sym.Value)
- f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
- }
- }
-
- return nil
- }
-
- func (f *File) applyRelocationsARM64(dst []byte, rels []byte) error {
- // 24 is the size of Rela64.
- if len(rels)%24 != 0 {
- return errors.New("length of relocation section is not a multiple of 24")
- }
-
- symbols, _, err := f.getSymbols(SHT_SYMTAB)
- if err != nil {
- return err
- }
-
- b := bytes.NewReader(rels)
- var rela Rela64
-
- for b.Len() > 0 {
- binary.Read(b, f.ByteOrder, &rela)
- symNo := rela.Info >> 32
- t := R_AARCH64(rela.Info & 0xffff)
-
- if symNo == 0 || symNo > uint64(len(symbols)) {
- continue
- }
- sym := &symbols[symNo-1]
- if SymType(sym.Info&0xf) != STT_SECTION {
- // We don't handle non-section relocations for now.
- continue
- }
-
- // There are relocations, so this must be a normal
- // object file, and we only look at section symbols,
- // so we assume that the symbol value is 0.
-
- switch t {
- case R_AARCH64_ABS64:
- if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
- continue
- }
- f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
- case R_AARCH64_ABS32:
- if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
- continue
- }
- f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
- }
- }
-
- return nil
- }
-
- func (f *File) applyRelocationsPPC(dst []byte, rels []byte) error {
- // 12 is the size of Rela32.
- if len(rels)%12 != 0 {
- return errors.New("length of relocation section is not a multiple of 12")
- }
-
- symbols, _, err := f.getSymbols(SHT_SYMTAB)
- if err != nil {
- return err
- }
-
- b := bytes.NewReader(rels)
- var rela Rela32
-
- for b.Len() > 0 {
- binary.Read(b, f.ByteOrder, &rela)
- symNo := rela.Info >> 8
- t := R_PPC(rela.Info & 0xff)
-
- if symNo == 0 || symNo > uint32(len(symbols)) {
- continue
- }
- sym := &symbols[symNo-1]
- if SymType(sym.Info&0xf) != STT_SECTION {
- // We don't handle non-section relocations for now.
- continue
- }
-
- switch t {
- case R_PPC_ADDR32:
- if rela.Off+4 >= uint32(len(dst)) || rela.Addend < 0 {
- continue
- }
- f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
- }
- }
-
- return nil
- }
-
- func (f *File) applyRelocationsPPC64(dst []byte, rels []byte) error {
- // 24 is the size of Rela64.
- if len(rels)%24 != 0 {
- return errors.New("length of relocation section is not a multiple of 24")
- }
-
- symbols, _, err := f.getSymbols(SHT_SYMTAB)
- if err != nil {
- return err
- }
-
- b := bytes.NewReader(rels)
- var rela Rela64
-
- for b.Len() > 0 {
- binary.Read(b, f.ByteOrder, &rela)
- symNo := rela.Info >> 32
- t := R_PPC64(rela.Info & 0xffff)
-
- if symNo == 0 || symNo > uint64(len(symbols)) {
- continue
- }
- sym := &symbols[symNo-1]
- if SymType(sym.Info&0xf) != STT_SECTION {
- // We don't handle non-section relocations for now.
- continue
- }
-
- switch t {
- case R_PPC64_ADDR64:
- if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
- continue
- }
- f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
- case R_PPC64_ADDR32:
- if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
- continue
- }
- f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
- }
- }
-
- return nil
- }
-
- func (f *File) applyRelocationsMIPS(dst []byte, rels []byte) error {
- // 8 is the size of Rel32.
- if len(rels)%8 != 0 {
- return errors.New("length of relocation section is not a multiple of 8")
- }
-
- symbols, _, err := f.getSymbols(SHT_SYMTAB)
- if err != nil {
- return err
- }
-
- b := bytes.NewReader(rels)
- var rel Rel32
-
- for b.Len() > 0 {
- binary.Read(b, f.ByteOrder, &rel)
- symNo := rel.Info >> 8
- t := R_MIPS(rel.Info & 0xff)
-
- if symNo == 0 || symNo > uint32(len(symbols)) {
- continue
- }
- sym := &symbols[symNo-1]
-
- switch t {
- case R_MIPS_32:
- if rel.Off+4 >= uint32(len(dst)) {
- continue
- }
- val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
- val += uint32(sym.Value)
- f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
- }
- }
-
- return nil
- }
-
- func (f *File) applyRelocationsMIPS64(dst []byte, rels []byte) error {
- // 24 is the size of Rela64.
- if len(rels)%24 != 0 {
- return errors.New("length of relocation section is not a multiple of 24")
- }
-
- symbols, _, err := f.getSymbols(SHT_SYMTAB)
- if err != nil {
- return err
- }
-
- b := bytes.NewReader(rels)
- var rela Rela64
-
- for b.Len() > 0 {
- binary.Read(b, f.ByteOrder, &rela)
- var symNo uint64
- var t R_MIPS
- if f.ByteOrder == binary.BigEndian {
- symNo = rela.Info >> 32
- t = R_MIPS(rela.Info & 0xff)
- } else {
- symNo = rela.Info & 0xffffffff
- t = R_MIPS(rela.Info >> 56)
- }
-
- if symNo == 0 || symNo > uint64(len(symbols)) {
- continue
- }
- sym := &symbols[symNo-1]
- if SymType(sym.Info&0xf) != STT_SECTION {
- // We don't handle non-section relocations for now.
- continue
- }
-
- switch t {
- case R_MIPS_64:
- if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
- continue
- }
- f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
- case R_MIPS_32:
- if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
- continue
- }
- f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
- }
- }
-
- return nil
- }
-
- func (f *File) applyRelocationsRISCV64(dst []byte, rels []byte) error {
- // 24 is the size of Rela64.
- if len(rels)%24 != 0 {
- return errors.New("length of relocation section is not a multiple of 24")
- }
-
- symbols, _, err := f.getSymbols(SHT_SYMTAB)
- if err != nil {
- return err
- }
-
- b := bytes.NewReader(rels)
- var rela Rela64
-
- for b.Len() > 0 {
- binary.Read(b, f.ByteOrder, &rela)
- symNo := rela.Info >> 32
- t := R_RISCV(rela.Info & 0xffff)
-
- if symNo == 0 || symNo > uint64(len(symbols)) {
- continue
- }
- sym := &symbols[symNo-1]
- switch SymType(sym.Info & 0xf) {
- case STT_SECTION, STT_NOTYPE:
- break
- default:
- continue
- }
-
- switch t {
- case R_RISCV_64:
- if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
- continue
- }
- val := sym.Value + uint64(rela.Addend)
- f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val)
- case R_RISCV_32:
- if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
- continue
- }
- val := uint32(sym.Value) + uint32(rela.Addend)
- f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val)
- }
- }
-
- return nil
- }
-
- func (f *File) applyRelocationss390x(dst []byte, rels []byte) error {
- // 24 is the size of Rela64.
- if len(rels)%24 != 0 {
- return errors.New("length of relocation section is not a multiple of 24")
- }
-
- symbols, _, err := f.getSymbols(SHT_SYMTAB)
- if err != nil {
- return err
- }
-
- b := bytes.NewReader(rels)
- var rela Rela64
-
- for b.Len() > 0 {
- binary.Read(b, f.ByteOrder, &rela)
- symNo := rela.Info >> 32
- t := R_390(rela.Info & 0xffff)
-
- if symNo == 0 || symNo > uint64(len(symbols)) {
- continue
- }
- sym := &symbols[symNo-1]
- switch SymType(sym.Info & 0xf) {
- case STT_SECTION, STT_NOTYPE:
- break
- default:
- continue
- }
-
- switch t {
- case R_390_64:
- if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
- continue
- }
- val := sym.Value + uint64(rela.Addend)
- f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val)
- case R_390_32:
- if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
- continue
- }
- val := uint32(sym.Value) + uint32(rela.Addend)
- f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val)
- }
- }
-
- return nil
- }
-
- func (f *File) applyRelocationsSPARC64(dst []byte, rels []byte) error {
- // 24 is the size of Rela64.
- if len(rels)%24 != 0 {
- return errors.New("length of relocation section is not a multiple of 24")
- }
-
- symbols, _, err := f.getSymbols(SHT_SYMTAB)
- if err != nil {
- return err
- }
-
- b := bytes.NewReader(rels)
- var rela Rela64
-
- for b.Len() > 0 {
- binary.Read(b, f.ByteOrder, &rela)
- symNo := rela.Info >> 32
- t := R_SPARC(rela.Info & 0xff)
-
- if symNo == 0 || symNo > uint64(len(symbols)) {
- continue
- }
- sym := &symbols[symNo-1]
- if SymType(sym.Info&0xf) != STT_SECTION {
- // We don't handle non-section relocations for now.
- continue
- }
-
- switch t {
- case R_SPARC_64, R_SPARC_UA64:
- if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
- continue
- }
- f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
- case R_SPARC_32, R_SPARC_UA32:
- if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
- continue
- }
- f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
- }
- }
-
- return nil
- }
-
- func (f *File) DWARF() (*dwarf.Data, error) {
- dwarfSuffix := func(s *Section) string {
- switch {
- case strings.HasPrefix(s.Name, ".debug_"):
- return s.Name[7:]
- case strings.HasPrefix(s.Name, ".zdebug_"):
- return s.Name[8:]
- default:
- return ""
- }
-
- }
- // sectionData gets the data for s, checks its size, and
- // applies any applicable relations.
- sectionData := func(i int, s *Section) ([]byte, error) {
- b, err := s.Data()
- if err != nil && uint64(len(b)) < s.Size {
- return nil, err
- }
-
- if len(b) >= 12 && string(b[:4]) == "ZLIB" {
- dlen := binary.BigEndian.Uint64(b[4:12])
- dbuf := make([]byte, dlen)
- r, err := zlib.NewReader(bytes.NewBuffer(b[12:]))
- if err != nil {
- return nil, err
- }
- if _, err := io.ReadFull(r, dbuf); err != nil {
- return nil, err
- }
- if err := r.Close(); err != nil {
- return nil, err
- }
- b = dbuf
- }
-
- for _, r := range f.Sections {
- if r.Type != SHT_RELA && r.Type != SHT_REL {
- continue
- }
- if int(r.Info) != i {
- continue
- }
- rd, err := r.Data()
- if err != nil {
- return nil, err
- }
- err = f.applyRelocations(b, rd)
- if err != nil {
- return nil, err
- }
- }
- return b, nil
- }
-
- // There are many other DWARF sections, but these
- // are the ones the debug/dwarf package uses.
- // Don't bother loading others.
- var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil}
- for i, s := range f.Sections {
- suffix := dwarfSuffix(s)
- if suffix == "" {
- continue
- }
- if _, ok := dat[suffix]; !ok {
- continue
- }
- b, err := sectionData(i, s)
- if err != nil {
- return nil, err
- }
- dat[suffix] = b
- }
-
- d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, dat["ranges"], dat["str"])
- if err != nil {
- return nil, err
- }
-
- // Look for DWARF4 .debug_types sections.
- for i, s := range f.Sections {
- suffix := dwarfSuffix(s)
- if suffix != "types" {
- continue
- }
-
- b, err := sectionData(i, s)
- if err != nil {
- return nil, err
- }
-
- err = d.AddTypes(fmt.Sprintf("types-%d", i), b)
- if err != nil {
- return nil, err
- }
- }
-
- return d, nil
- }
-
- // Symbols returns the symbol table for f. The symbols will be listed in the order
- // they appear in f.
- //
- // For compatibility with Go 1.0, Symbols omits the null symbol at index 0.
- // After retrieving the symbols as symtab, an externally supplied index x
- // corresponds to symtab[x-1], not symtab[x].
- func (f *File) Symbols() ([]Symbol, error) {
- sym, _, err := f.getSymbols(SHT_SYMTAB)
- return sym, err
- }
-
- // DynamicSymbols returns the dynamic symbol table for f. The symbols
- // will be listed in the order they appear in f.
- //
- // For compatibility with Symbols, DynamicSymbols omits the null symbol at index 0.
- // After retrieving the symbols as symtab, an externally supplied index x
- // corresponds to symtab[x-1], not symtab[x].
- func (f *File) DynamicSymbols() ([]Symbol, error) {
- sym, _, err := f.getSymbols(SHT_DYNSYM)
- return sym, err
- }
-
- type ImportedSymbol struct {
- Name string
- Version string
- Library string
- }
-
- // ImportedSymbols returns the names of all symbols
- // referred to by the binary f that are expected to be
- // satisfied by other libraries at dynamic load time.
- // It does not return weak symbols.
- func (f *File) ImportedSymbols() ([]ImportedSymbol, error) {
- sym, str, err := f.getSymbols(SHT_DYNSYM)
- if err != nil {
- return nil, err
- }
- f.gnuVersionInit(str)
- var all []ImportedSymbol
- for i, s := range sym {
- if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF {
- all = append(all, ImportedSymbol{Name: s.Name})
- f.gnuVersion(i, &all[len(all)-1])
- }
- }
- return all, nil
- }
-
- type verneed struct {
- File string
- Name string
- }
-
- // gnuVersionInit parses the GNU version tables
- // for use by calls to gnuVersion.
- func (f *File) gnuVersionInit(str []byte) {
- // Accumulate verneed information.
- vn := f.SectionByType(SHT_GNU_VERNEED)
- if vn == nil {
- return
- }
- d, _ := vn.Data()
-
- var need []verneed
- i := 0
- for {
- if i+16 > len(d) {
- break
- }
- vers := f.ByteOrder.Uint16(d[i : i+2])
- if vers != 1 {
- break
- }
- cnt := f.ByteOrder.Uint16(d[i+2 : i+4])
- fileoff := f.ByteOrder.Uint32(d[i+4 : i+8])
- aux := f.ByteOrder.Uint32(d[i+8 : i+12])
- next := f.ByteOrder.Uint32(d[i+12 : i+16])
- file, _ := getString(str, int(fileoff))
-
- var name string
- j := i + int(aux)
- for c := 0; c < int(cnt); c++ {
- if j+16 > len(d) {
- break
- }
- // hash := f.ByteOrder.Uint32(d[j:j+4])
- // flags := f.ByteOrder.Uint16(d[j+4:j+6])
- other := f.ByteOrder.Uint16(d[j+6 : j+8])
- nameoff := f.ByteOrder.Uint32(d[j+8 : j+12])
- next := f.ByteOrder.Uint32(d[j+12 : j+16])
- name, _ = getString(str, int(nameoff))
- ndx := int(other)
- if ndx >= len(need) {
- a := make([]verneed, 2*(ndx+1))
- copy(a, need)
- need = a
- }
-
- need[ndx] = verneed{file, name}
- if next == 0 {
- break
- }
- j += int(next)
- }
-
- if next == 0 {
- break
- }
- i += int(next)
- }
-
- // Versym parallels symbol table, indexing into verneed.
- vs := f.SectionByType(SHT_GNU_VERSYM)
- if vs == nil {
- return
- }
- d, _ = vs.Data()
-
- f.gnuNeed = need
- f.gnuVersym = d
- }
-
- // gnuVersion adds Library and Version information to sym,
- // which came from offset i of the symbol table.
- func (f *File) gnuVersion(i int, sym *ImportedSymbol) {
- // Each entry is two bytes.
- i = (i + 1) * 2
- if i >= len(f.gnuVersym) {
- return
- }
- j := int(f.ByteOrder.Uint16(f.gnuVersym[i:]))
- if j < 2 || j >= len(f.gnuNeed) {
- return
- }
- n := &f.gnuNeed[j]
- sym.Library = n.File
- sym.Version = n.Name
- }
-
- // ImportedLibraries returns the names of all libraries
- // referred to by the binary f that are expected to be
- // linked with the binary at dynamic link time.
- func (f *File) ImportedLibraries() ([]string, error) {
- return f.DynString(DT_NEEDED)
- }
-
- // DynString returns the strings listed for the given tag in the file's dynamic
- // section.
- //
- // The tag must be one that takes string values: DT_NEEDED, DT_SONAME, DT_RPATH, or
- // DT_RUNPATH.
- func (f *File) DynString(tag DynTag) ([]string, error) {
- switch tag {
- case DT_NEEDED, DT_SONAME, DT_RPATH, DT_RUNPATH:
- default:
- return nil, fmt.Errorf("non-string-valued tag %v", tag)
- }
- ds := f.SectionByType(SHT_DYNAMIC)
- if ds == nil {
- // not dynamic, so no libraries
- return nil, nil
- }
- d, err := ds.Data()
- if err != nil {
- return nil, err
- }
- str, err := f.stringTable(ds.Link)
- if err != nil {
- return nil, err
- }
- var all []string
- for len(d) > 0 {
- var t DynTag
- var v uint64
- switch f.Class {
- case ELFCLASS32:
- t = DynTag(f.ByteOrder.Uint32(d[0:4]))
- v = uint64(f.ByteOrder.Uint32(d[4:8]))
- d = d[8:]
- case ELFCLASS64:
- t = DynTag(f.ByteOrder.Uint64(d[0:8]))
- v = f.ByteOrder.Uint64(d[8:16])
- d = d[16:]
- }
- if t == tag {
- s, ok := getString(str, int(v))
- if ok {
- all = append(all, s)
- }
- }
- }
- return all, nil
- }
|