Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
file.go1860 linesDownload Raw Back to elf
1// Copyright 2009 The Go Authors. All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.4 5/*6Package elf implements access to ELF object files.7 8# Security9 10This package is not designed to be hardened against adversarial inputs, and is11outside the scope of https://go.dev/security/policy. In particular, only basic12validation is done when parsing object files. As such, care should be taken when13parsing untrusted inputs, as parsing malformed files may consume significant14resources, or cause panics.15*/16package elf17 18import (19	"bytes"20	"compress/zlib"21	"debug/dwarf"22	"encoding/binary"23	"errors"24	"fmt"25	"internal/saferio"26	"internal/zstd"27	"io"28	"math"29	"os"30	"strings"31	"unsafe"32)33 34// TODO: error reporting detail35 36/*37 * Internal ELF representation38 */39 40// A FileHeader represents an ELF file header.41type FileHeader struct {42	Class      Class43	Data       Data44	Version    Version45	OSABI      OSABI46	ABIVersion uint847	ByteOrder  binary.ByteOrder48	Type       Type49	Machine    Machine50	Entry      uint6451}52 53// A File represents an open ELF file.54type File struct {55	FileHeader56	Sections    []*Section57	Progs       []*Prog58	closer      io.Closer59	dynVers     []DynamicVersion60	dynVerNeeds []DynamicVersionNeed61	gnuVersym   []byte62}63 64// A SectionHeader represents a single ELF section header.65type SectionHeader struct {66	Name      string67	Type      SectionType68	Flags     SectionFlag69	Addr      uint6470	Offset    uint6471	Size      uint6472	Link      uint3273	Info      uint3274	Addralign uint6475	Entsize   uint6476 77	// FileSize is the size of this section in the file in bytes.78	// If a section is compressed, FileSize is the size of the79	// compressed data, while Size (above) is the size of the80	// uncompressed data.81	FileSize uint6482}83 84// A Section represents a single section in an ELF file.85type Section struct {86	SectionHeader87 88	// Embed ReaderAt for ReadAt method.89	// Do not embed SectionReader directly90	// to avoid having Read and Seek.91	// If a client wants Read and Seek it must use92	// Open() to avoid fighting over the seek offset93	// with other clients.94	//95	// ReaderAt may be nil if the section is not easily available96	// in a random-access form. For example, a compressed section97	// may have a nil ReaderAt.98	io.ReaderAt99	sr *io.SectionReader100 101	compressionType   CompressionType102	compressionOffset int64103}104 105// Data reads and returns the contents of the ELF section.106// Even if the section is stored compressed in the ELF file,107// Data returns uncompressed data.108//109// For an [SHT_NOBITS] section, Data always returns a non-nil error.110func (s *Section) Data() ([]byte, error) {111	return saferio.ReadData(s.Open(), s.Size)112}113 114// stringTable reads and returns the string table given by the115// specified link value.116func (f *File) stringTable(link uint32) ([]byte, error) {117	if link <= 0 || link >= uint32(len(f.Sections)) {118		return nil, errors.New("section has invalid string table link")119	}120	return f.Sections[link].Data()121}122 123// Open returns a new ReadSeeker reading the ELF section.124// Even if the section is stored compressed in the ELF file,125// the ReadSeeker reads uncompressed data.126//127// For an [SHT_NOBITS] section, all calls to the opened reader128// will return a non-nil error.129func (s *Section) Open() io.ReadSeeker {130	if s.Type == SHT_NOBITS {131		return io.NewSectionReader(&nobitsSectionReader{}, 0, int64(s.Size))132	}133 134	var zrd func(io.Reader) (io.ReadCloser, error)135	if s.Flags&SHF_COMPRESSED == 0 {136 137		if !strings.HasPrefix(s.Name, ".zdebug") {138			return io.NewSectionReader(s.sr, 0, 1<<63-1)139		}140 141		b := make([]byte, 12)142		n, _ := s.sr.ReadAt(b, 0)143		if n != 12 || string(b[:4]) != "ZLIB" {144			return io.NewSectionReader(s.sr, 0, 1<<63-1)145		}146 147		s.compressionOffset = 12148		s.compressionType = COMPRESS_ZLIB149		s.Size = binary.BigEndian.Uint64(b[4:12])150		zrd = zlib.NewReader151 152	} else if s.Flags&SHF_ALLOC != 0 {153		return errorReader{&FormatError{int64(s.Offset),154			"SHF_COMPRESSED applies only to non-allocable sections", s.compressionType}}155	}156 157	switch s.compressionType {158	case COMPRESS_ZLIB:159		zrd = zlib.NewReader160	case COMPRESS_ZSTD:161		zrd = func(r io.Reader) (io.ReadCloser, error) {162			return io.NopCloser(zstd.NewReader(r)), nil163		}164	}165 166	if zrd == nil {167		return errorReader{&FormatError{int64(s.Offset), "unknown compression type", s.compressionType}}168	}169 170	return &readSeekerFromReader{171		reset: func() (io.Reader, error) {172			fr := io.NewSectionReader(s.sr, s.compressionOffset, int64(s.FileSize)-s.compressionOffset)173			return zrd(fr)174		},175		size: int64(s.Size),176	}177}178 179// A ProgHeader represents a single ELF program header.180type ProgHeader struct {181	Type   ProgType182	Flags  ProgFlag183	Off    uint64184	Vaddr  uint64185	Paddr  uint64186	Filesz uint64187	Memsz  uint64188	Align  uint64189}190 191// A Prog represents a single ELF program header in an ELF binary.192type Prog struct {193	ProgHeader194 195	// Embed ReaderAt for ReadAt method.196	// Do not embed SectionReader directly197	// to avoid having Read and Seek.198	// If a client wants Read and Seek it must use199	// Open() to avoid fighting over the seek offset200	// with other clients.201	io.ReaderAt202	sr *io.SectionReader203}204 205// Open returns a new ReadSeeker reading the ELF program body.206func (p *Prog) Open() io.ReadSeeker { return io.NewSectionReader(p.sr, 0, 1<<63-1) }207 208// A Symbol represents an entry in an ELF symbol table section.209type Symbol struct {210	Name        string211	Info, Other byte212 213	// HasVersion reports whether the symbol has any version information.214	// This will only be true for the dynamic symbol table.215	HasVersion bool216	// VersionIndex is the symbol's version index.217	// Use the methods of the [VersionIndex] type to access it.218	// This field is only meaningful if HasVersion is true.219	VersionIndex VersionIndex220 221	Section     SectionIndex222	Value, Size uint64223 224	// These fields are present only for the dynamic symbol table.225	Version string226	Library string227}228 229/*230 * ELF reader231 */232 233type FormatError struct {234	off int64235	msg string236	val any237}238 239func (e *FormatError) Error() string {240	msg := e.msg241	if e.val != nil {242		msg += fmt.Sprintf(" '%v' ", e.val)243	}244	msg += fmt.Sprintf("in record at byte %#x", e.off)245	return msg246}247 248// Open opens the named file using [os.Open] and prepares it for use as an ELF binary.249func Open(name string) (*File, error) {250	f, err := os.Open(name)251	if err != nil {252		return nil, err253	}254	ff, err := NewFile(f)255	if err != nil {256		f.Close()257		return nil, err258	}259	ff.closer = f260	return ff, nil261}262 263// Close closes the [File].264// If the [File] was created using [NewFile] directly instead of [Open],265// Close has no effect.266func (f *File) Close() error {267	var err error268	if f.closer != nil {269		err = f.closer.Close()270		f.closer = nil271	}272	return err273}274 275// SectionByType returns the first section in f with the276// given type, or nil if there is no such section.277func (f *File) SectionByType(typ SectionType) *Section {278	for _, s := range f.Sections {279		if s.Type == typ {280			return s281		}282	}283	return nil284}285 286// NewFile creates a new [File] for accessing an ELF binary in an underlying reader.287// The ELF binary is expected to start at position 0 in the ReaderAt.288func NewFile(r io.ReaderAt) (*File, error) {289	sr := io.NewSectionReader(r, 0, 1<<63-1)290	// Read and decode ELF identifier291	var ident [16]uint8292	if _, err := r.ReadAt(ident[0:], 0); err != nil {293		return nil, err294	}295	if ident[0] != '\x7f' || ident[1] != 'E' || ident[2] != 'L' || ident[3] != 'F' {296		return nil, &FormatError{0, "bad magic number", ident[0:4]}297	}298 299	f := new(File)300	f.Class = Class(ident[EI_CLASS])301	switch f.Class {302	case ELFCLASS32:303	case ELFCLASS64:304		// ok305	default:306		return nil, &FormatError{0, "unknown ELF class", f.Class}307	}308 309	f.Data = Data(ident[EI_DATA])310	var bo binary.ByteOrder311	switch f.Data {312	case ELFDATA2LSB:313		bo = binary.LittleEndian314	case ELFDATA2MSB:315		bo = binary.BigEndian316	default:317		return nil, &FormatError{0, "unknown ELF data encoding", f.Data}318	}319	f.ByteOrder = bo320 321	f.Version = Version(ident[EI_VERSION])322	if f.Version != EV_CURRENT {323		return nil, &FormatError{0, "unknown ELF version", f.Version}324	}325 326	f.OSABI = OSABI(ident[EI_OSABI])327	f.ABIVersion = ident[EI_ABIVERSION]328 329	// Read ELF file header330	var phoff int64331	var phentsize, phnum int332	var shoff int64333	var shentsize, shnum, shstrndx int334	switch f.Class {335	case ELFCLASS32:336		var hdr Header32337		data := make([]byte, unsafe.Sizeof(hdr))338		if _, err := sr.ReadAt(data, 0); err != nil {339			return nil, err340		}341		f.Type = Type(bo.Uint16(data[unsafe.Offsetof(hdr.Type):]))342		f.Machine = Machine(bo.Uint16(data[unsafe.Offsetof(hdr.Machine):]))343		f.Entry = uint64(bo.Uint32(data[unsafe.Offsetof(hdr.Entry):]))344		if v := Version(bo.Uint32(data[unsafe.Offsetof(hdr.Version):])); v != f.Version {345			return nil, &FormatError{0, "mismatched ELF version", v}346		}347		phoff = int64(bo.Uint32(data[unsafe.Offsetof(hdr.Phoff):]))348		phentsize = int(bo.Uint16(data[unsafe.Offsetof(hdr.Phentsize):]))349		phnum = int(bo.Uint16(data[unsafe.Offsetof(hdr.Phnum):]))350		shoff = int64(bo.Uint32(data[unsafe.Offsetof(hdr.Shoff):]))351		shentsize = int(bo.Uint16(data[unsafe.Offsetof(hdr.Shentsize):]))352		shnum = int(bo.Uint16(data[unsafe.Offsetof(hdr.Shnum):]))353		shstrndx = int(bo.Uint16(data[unsafe.Offsetof(hdr.Shstrndx):]))354	case ELFCLASS64:355		var hdr Header64356		data := make([]byte, unsafe.Sizeof(hdr))357		if _, err := sr.ReadAt(data, 0); err != nil {358			return nil, err359		}360		f.Type = Type(bo.Uint16(data[unsafe.Offsetof(hdr.Type):]))361		f.Machine = Machine(bo.Uint16(data[unsafe.Offsetof(hdr.Machine):]))362		f.Entry = bo.Uint64(data[unsafe.Offsetof(hdr.Entry):])363		if v := Version(bo.Uint32(data[unsafe.Offsetof(hdr.Version):])); v != f.Version {364			return nil, &FormatError{0, "mismatched ELF version", v}365		}366		phoff = int64(bo.Uint64(data[unsafe.Offsetof(hdr.Phoff):]))367		phentsize = int(bo.Uint16(data[unsafe.Offsetof(hdr.Phentsize):]))368		phnum = int(bo.Uint16(data[unsafe.Offsetof(hdr.Phnum):]))369		shoff = int64(bo.Uint64(data[unsafe.Offsetof(hdr.Shoff):]))370		shentsize = int(bo.Uint16(data[unsafe.Offsetof(hdr.Shentsize):]))371		shnum = int(bo.Uint16(data[unsafe.Offsetof(hdr.Shnum):]))372		shstrndx = int(bo.Uint16(data[unsafe.Offsetof(hdr.Shstrndx):]))373	}374 375	if shoff < 0 {376		return nil, &FormatError{0, "invalid shoff", shoff}377	}378	if phoff < 0 {379		return nil, &FormatError{0, "invalid phoff", phoff}380	}381 382	if shoff == 0 && shnum != 0 {383		return nil, &FormatError{0, "invalid ELF shnum for shoff=0", shnum}384	}385 386	if shnum > 0 && shstrndx >= shnum {387		return nil, &FormatError{0, "invalid ELF shstrndx", shstrndx}388	}389 390	var wantPhentsize, wantShentsize int391	switch f.Class {392	case ELFCLASS32:393		wantPhentsize = 8 * 4394		wantShentsize = 10 * 4395	case ELFCLASS64:396		wantPhentsize = 2*4 + 6*8397		wantShentsize = 4*4 + 6*8398	}399	if phnum > 0 && phentsize < wantPhentsize {400		return nil, &FormatError{0, "invalid ELF phentsize", phentsize}401	}402 403	// Read program headers404	f.Progs = make([]*Prog, phnum)405	phdata, err := saferio.ReadDataAt(sr, uint64(phnum)*uint64(phentsize), phoff)406	if err != nil {407		return nil, err408	}409	for i := 0; i < phnum; i++ {410		off := uintptr(i) * uintptr(phentsize)411		p := new(Prog)412		switch f.Class {413		case ELFCLASS32:414			var ph Prog32415			p.ProgHeader = ProgHeader{416				Type:   ProgType(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Type):])),417				Flags:  ProgFlag(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Flags):])),418				Off:    uint64(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Off):])),419				Vaddr:  uint64(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Vaddr):])),420				Paddr:  uint64(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Paddr):])),421				Filesz: uint64(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Filesz):])),422				Memsz:  uint64(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Memsz):])),423				Align:  uint64(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Align):])),424			}425		case ELFCLASS64:426			var ph Prog64427			p.ProgHeader = ProgHeader{428				Type:   ProgType(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Type):])),429				Flags:  ProgFlag(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Flags):])),430				Off:    bo.Uint64(phdata[off+unsafe.Offsetof(ph.Off):]),431				Vaddr:  bo.Uint64(phdata[off+unsafe.Offsetof(ph.Vaddr):]),432				Paddr:  bo.Uint64(phdata[off+unsafe.Offsetof(ph.Paddr):]),433				Filesz: bo.Uint64(phdata[off+unsafe.Offsetof(ph.Filesz):]),434				Memsz:  bo.Uint64(phdata[off+unsafe.Offsetof(ph.Memsz):]),435				Align:  bo.Uint64(phdata[off+unsafe.Offsetof(ph.Align):]),436			}437		}438		if int64(p.Off) < 0 {439			return nil, &FormatError{phoff + int64(off), "invalid program header offset", p.Off}440		}441		if int64(p.Filesz) < 0 {442			return nil, &FormatError{phoff + int64(off), "invalid program header file size", p.Filesz}443		}444		p.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz))445		p.ReaderAt = p.sr446		f.Progs[i] = p447	}448 449	// If the number of sections is greater than or equal to SHN_LORESERVE450	// (0xff00), shnum has the value zero and the actual number of section451	// header table entries is contained in the sh_size field of the section452	// header at index 0.453	if shoff > 0 && shnum == 0 {454		var typ, link uint32455		sr.Seek(shoff, io.SeekStart)456		switch f.Class {457		case ELFCLASS32:458			sh := new(Section32)459			if err := binary.Read(sr, bo, sh); err != nil {460				return nil, err461			}462			shnum = int(sh.Size)463			typ = sh.Type464			link = sh.Link465		case ELFCLASS64:466			sh := new(Section64)467			if err := binary.Read(sr, bo, sh); err != nil {468				return nil, err469			}470			shnum = int(sh.Size)471			typ = sh.Type472			link = sh.Link473		}474		if SectionType(typ) != SHT_NULL {475			return nil, &FormatError{shoff, "invalid type of the initial section", SectionType(typ)}476		}477 478		if shnum < int(SHN_LORESERVE) {479			return nil, &FormatError{shoff, "invalid ELF shnum contained in sh_size", shnum}480		}481 482		// If the section name string table section index is greater than or483		// equal to SHN_LORESERVE (0xff00), this member has the value484		// SHN_XINDEX (0xffff) and the actual index of the section name485		// string table section is contained in the sh_link field of the486		// section header at index 0.487		if shstrndx == int(SHN_XINDEX) {488			shstrndx = int(link)489			if shstrndx < int(SHN_LORESERVE) {490				return nil, &FormatError{shoff, "invalid ELF shstrndx contained in sh_link", shstrndx}491			}492		}493	}494 495	if shnum > 0 && shentsize < wantShentsize {496		return nil, &FormatError{0, "invalid ELF shentsize", shentsize}497	}498 499	// Read section headers500	c := saferio.SliceCap[Section](uint64(shnum))501	if c < 0 {502		return nil, &FormatError{0, "too many sections", shnum}503	}504	if shnum > 0 && ((1<<64)-1)/uint64(shnum) < uint64(shentsize) {505		return nil, &FormatError{0, "section header overflow", shnum}506	}507	f.Sections = make([]*Section, 0, c)508	names := make([]uint32, 0, c)509	shdata, err := saferio.ReadDataAt(sr, uint64(shnum)*uint64(shentsize), shoff)510	if err != nil {511		return nil, err512	}513	for i := 0; i < shnum; i++ {514		off := uintptr(i) * uintptr(shentsize)515		s := new(Section)516		switch f.Class {517		case ELFCLASS32:518			var sh Section32519			names = append(names, bo.Uint32(shdata[off+unsafe.Offsetof(sh.Name):]))520			s.SectionHeader = SectionHeader{521				Type:      SectionType(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Type):])),522				Flags:     SectionFlag(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Flags):])),523				Addr:      uint64(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Addr):])),524				Offset:    uint64(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Off):])),525				FileSize:  uint64(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Size):])),526				Link:      bo.Uint32(shdata[off+unsafe.Offsetof(sh.Link):]),527				Info:      bo.Uint32(shdata[off+unsafe.Offsetof(sh.Info):]),528				Addralign: uint64(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Addralign):])),529				Entsize:   uint64(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Entsize):])),530			}531		case ELFCLASS64:532			var sh Section64533			names = append(names, bo.Uint32(shdata[off+unsafe.Offsetof(sh.Name):]))534			s.SectionHeader = SectionHeader{535				Type:      SectionType(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Type):])),536				Flags:     SectionFlag(bo.Uint64(shdata[off+unsafe.Offsetof(sh.Flags):])),537				Offset:    bo.Uint64(shdata[off+unsafe.Offsetof(sh.Off):]),538				FileSize:  bo.Uint64(shdata[off+unsafe.Offsetof(sh.Size):]),539				Addr:      bo.Uint64(shdata[off+unsafe.Offsetof(sh.Addr):]),540				Link:      bo.Uint32(shdata[off+unsafe.Offsetof(sh.Link):]),541				Info:      bo.Uint32(shdata[off+unsafe.Offsetof(sh.Info):]),542				Addralign: bo.Uint64(shdata[off+unsafe.Offsetof(sh.Addralign):]),543				Entsize:   bo.Uint64(shdata[off+unsafe.Offsetof(sh.Entsize):]),544			}545		}546		if int64(s.Offset) < 0 {547			return nil, &FormatError{shoff + int64(off), "invalid section offset", int64(s.Offset)}548		}549		if int64(s.FileSize) < 0 {550			return nil, &FormatError{shoff + int64(off), "invalid section size", int64(s.FileSize)}551		}552		s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.FileSize))553 554		if s.Flags&SHF_COMPRESSED == 0 {555			s.ReaderAt = s.sr556			s.Size = s.FileSize557		} else {558			// Read the compression header.559			switch f.Class {560			case ELFCLASS32:561				var ch Chdr32562				chdata := make([]byte, unsafe.Sizeof(ch))563				if _, err := s.sr.ReadAt(chdata, 0); err != nil {564					return nil, err565				}566				s.compressionType = CompressionType(bo.Uint32(chdata[unsafe.Offsetof(ch.Type):]))567				s.Size = uint64(bo.Uint32(chdata[unsafe.Offsetof(ch.Size):]))568				s.Addralign = uint64(bo.Uint32(chdata[unsafe.Offsetof(ch.Addralign):]))569				s.compressionOffset = int64(unsafe.Sizeof(ch))570			case ELFCLASS64:571				var ch Chdr64572				chdata := make([]byte, unsafe.Sizeof(ch))573				if _, err := s.sr.ReadAt(chdata, 0); err != nil {574					return nil, err575				}576				s.compressionType = CompressionType(bo.Uint32(chdata[unsafe.Offsetof(ch.Type):]))577				s.Size = bo.Uint64(chdata[unsafe.Offsetof(ch.Size):])578				s.Addralign = bo.Uint64(chdata[unsafe.Offsetof(ch.Addralign):])579				s.compressionOffset = int64(unsafe.Sizeof(ch))580			}581		}582 583		f.Sections = append(f.Sections, s)584	}585 586	if len(f.Sections) == 0 {587		return f, nil588	}589 590	// Load section header string table.591	if shstrndx == 0 {592		// If the file has no section name string table,593		// shstrndx holds the value SHN_UNDEF (0).594		return f, nil595	}596	shstr := f.Sections[shstrndx]597	if shstr.Type != SHT_STRTAB {598		return nil, &FormatError{shoff + int64(shstrndx*shentsize), "invalid ELF section name string table type", shstr.Type}599	}600	shstrtab, err := shstr.Data()601	if err != nil {602		return nil, err603	}604	for i, s := range f.Sections {605		var ok bool606		s.Name, ok = getString(shstrtab, int(names[i]))607		if !ok {608			return nil, &FormatError{shoff + int64(i*shentsize), "bad section name index", names[i]}609		}610	}611 612	return f, nil613}614 615// getSymbols returns a slice of Symbols from parsing the symbol table616// with the given type, along with the associated string table.617func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, error) {618	switch f.Class {619	case ELFCLASS64:620		return f.getSymbols64(typ)621 622	case ELFCLASS32:623		return f.getSymbols32(typ)624	}625 626	return nil, nil, errors.New("not implemented")627}628 629// ErrNoSymbols is returned by [File.Symbols] and [File.DynamicSymbols]630// if there is no such section in the File.631var ErrNoSymbols = errors.New("no symbol section")632 633func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) {634	symtabSection := f.SectionByType(typ)635	if symtabSection == nil {636		return nil, nil, ErrNoSymbols637	}638 639	data, err := symtabSection.Data()640	if err != nil {641		return nil, nil, fmt.Errorf("cannot load symbol section: %w", err)642	}643	if len(data) == 0 {644		return nil, nil, ErrNoSymbols645	}646	if len(data)%Sym32Size != 0 {647		return nil, nil, errors.New("length of symbol section is not a multiple of SymSize")648	}649 650	strdata, err := f.stringTable(symtabSection.Link)651	if err != nil {652		return nil, nil, fmt.Errorf("cannot load string table section: %w", err)653	}654 655	// The first entry is all zeros.656	data = data[Sym32Size:]657 658	symbols := make([]Symbol, len(data)/Sym32Size)659 660	i := 0661	var sym Sym32662	for len(data) > 0 {663		sym.Name = f.ByteOrder.Uint32(data[0:4])664		sym.Value = f.ByteOrder.Uint32(data[4:8])665		sym.Size = f.ByteOrder.Uint32(data[8:12])666		sym.Info = data[12]667		sym.Other = data[13]668		sym.Shndx = f.ByteOrder.Uint16(data[14:16])669		str, _ := getString(strdata, int(sym.Name))670		symbols[i].Name = str671		symbols[i].Info = sym.Info672		symbols[i].Other = sym.Other673		symbols[i].Section = SectionIndex(sym.Shndx)674		symbols[i].Value = uint64(sym.Value)675		symbols[i].Size = uint64(sym.Size)676		i++677		data = data[Sym32Size:]678	}679 680	return symbols, strdata, nil681}682 683func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) {684	symtabSection := f.SectionByType(typ)685	if symtabSection == nil {686		return nil, nil, ErrNoSymbols687	}688 689	data, err := symtabSection.Data()690	if err != nil {691		return nil, nil, fmt.Errorf("cannot load symbol section: %w", err)692	}693	if len(data) == 0 {694		return nil, nil, ErrNoSymbols695	}696	if len(data)%Sym64Size != 0 {697		return nil, nil, errors.New("length of symbol section is not a multiple of Sym64Size")698	}699 700	strdata, err := f.stringTable(symtabSection.Link)701	if err != nil {702		return nil, nil, fmt.Errorf("cannot load string table section: %w", err)703	}704 705	// The first entry is all zeros.706	data = data[Sym64Size:]707 708	symbols := make([]Symbol, len(data)/Sym64Size)709 710	i := 0711	var sym Sym64712	for len(data) > 0 {713		sym.Name = f.ByteOrder.Uint32(data[0:4])714		sym.Info = data[4]715		sym.Other = data[5]716		sym.Shndx = f.ByteOrder.Uint16(data[6:8])717		sym.Value = f.ByteOrder.Uint64(data[8:16])718		sym.Size = f.ByteOrder.Uint64(data[16:24])719		str, _ := getString(strdata, int(sym.Name))720		symbols[i].Name = str721		symbols[i].Info = sym.Info722		symbols[i].Other = sym.Other723		symbols[i].Section = SectionIndex(sym.Shndx)724		symbols[i].Value = sym.Value725		symbols[i].Size = sym.Size726		i++727		data = data[Sym64Size:]728	}729 730	return symbols, strdata, nil731}732 733// getString extracts a string from an ELF string table.734func getString(section []byte, start int) (string, bool) {735	if start < 0 || start >= len(section) {736		return "", false737	}738 739	for end := start; end < len(section); end++ {740		if section[end] == 0 {741			return string(section[start:end]), true742		}743	}744	return "", false745}746 747// Section returns a section with the given name, or nil if no such748// section exists.749func (f *File) Section(name string) *Section {750	for _, s := range f.Sections {751		if s.Name == name {752			return s753		}754	}755	return nil756}757 758// applyRelocations applies relocations to dst. rels is a relocations section759// in REL or RELA format.760func (f *File) applyRelocations(dst []byte, rels []byte) error {761	switch {762	case f.Class == ELFCLASS64 && f.Machine == EM_X86_64:763		return f.applyRelocationsAMD64(dst, rels)764	case f.Class == ELFCLASS32 && f.Machine == EM_386:765		return f.applyRelocations386(dst, rels)766	case f.Class == ELFCLASS32 && f.Machine == EM_ARM:767		return f.applyRelocationsARM(dst, rels)768	case f.Class == ELFCLASS64 && f.Machine == EM_AARCH64:769		return f.applyRelocationsARM64(dst, rels)770	case f.Class == ELFCLASS32 && f.Machine == EM_PPC:771		return f.applyRelocationsPPC(dst, rels)772	case f.Class == ELFCLASS64 && f.Machine == EM_PPC64:773		return f.applyRelocationsPPC64(dst, rels)774	case f.Class == ELFCLASS32 && f.Machine == EM_MIPS:775		return f.applyRelocationsMIPS(dst, rels)776	case f.Class == ELFCLASS64 && f.Machine == EM_MIPS:777		return f.applyRelocationsMIPS64(dst, rels)778	case f.Class == ELFCLASS64 && f.Machine == EM_LOONGARCH:779		return f.applyRelocationsLOONG64(dst, rels)780	case f.Class == ELFCLASS64 && f.Machine == EM_RISCV:781		return f.applyRelocationsRISCV64(dst, rels)782	case f.Class == ELFCLASS64 && f.Machine == EM_S390:783		return f.applyRelocationss390x(dst, rels)784	case f.Class == ELFCLASS64 && f.Machine == EM_SPARCV9:785		return f.applyRelocationsSPARC64(dst, rels)786	default:787		return errors.New("applyRelocations: not implemented")788	}789}790 791// canApplyRelocation reports whether we should try to apply a792// relocation to a DWARF data section, given a pointer to the symbol793// targeted by the relocation.794// Most relocations in DWARF data tend to be section-relative, but795// some target non-section symbols (for example, low_PC attrs on796// subprogram or compilation unit DIEs that target function symbols).797func canApplyRelocation(sym *Symbol) bool {798	return sym.Section != SHN_UNDEF && sym.Section < SHN_LORESERVE799}800 801func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {802	// 24 is the size of Rela64.803	if len(rels)%24 != 0 {804		return errors.New("length of relocation section is not a multiple of 24")805	}806 807	symbols, _, err := f.getSymbols(SHT_SYMTAB)808	if err != nil {809		return err810	}811 812	b := bytes.NewReader(rels)813	var rela Rela64814 815	for b.Len() > 0 {816		binary.Read(b, f.ByteOrder, &rela)817		symNo := rela.Info >> 32818		t := R_X86_64(rela.Info & 0xffff)819 820		if symNo == 0 || symNo > uint64(len(symbols)) {821			continue822		}823		sym := &symbols[symNo-1]824		if !canApplyRelocation(sym) {825			continue826		}827 828		// There are relocations, so this must be a normal829		// object file.  The code below handles only basic relocations830		// of the form S + A (symbol plus addend).831 832		switch t {833		case R_X86_64_64:834			putUint(f.ByteOrder, dst, rela.Off, 8, sym.Value, rela.Addend, false)835		case R_X86_64_32:836			putUint(f.ByteOrder, dst, rela.Off, 4, sym.Value, rela.Addend, false)837		}838	}839 840	return nil841}842 843func (f *File) applyRelocations386(dst []byte, rels []byte) error {844	// 8 is the size of Rel32.845	if len(rels)%8 != 0 {846		return errors.New("length of relocation section is not a multiple of 8")847	}848 849	symbols, _, err := f.getSymbols(SHT_SYMTAB)850	if err != nil {851		return err852	}853 854	b := bytes.NewReader(rels)855	var rel Rel32856 857	for b.Len() > 0 {858		binary.Read(b, f.ByteOrder, &rel)859		symNo := rel.Info >> 8860		t := R_386(rel.Info & 0xff)861 862		if symNo == 0 || symNo > uint32(len(symbols)) {863			continue864		}865		sym := &symbols[symNo-1]866 867		if t == R_386_32 {868			putUint(f.ByteOrder, dst, uint64(rel.Off), 4, sym.Value, 0, true)869		}870	}871 872	return nil873}874 875func (f *File) applyRelocationsARM(dst []byte, rels []byte) error {876	// 8 is the size of Rel32.877	if len(rels)%8 != 0 {878		return errors.New("length of relocation section is not a multiple of 8")879	}880 881	symbols, _, err := f.getSymbols(SHT_SYMTAB)882	if err != nil {883		return err884	}885 886	b := bytes.NewReader(rels)887	var rel Rel32888 889	for b.Len() > 0 {890		binary.Read(b, f.ByteOrder, &rel)891		symNo := rel.Info >> 8892		t := R_ARM(rel.Info & 0xff)893 894		if symNo == 0 || symNo > uint32(len(symbols)) {895			continue896		}897		sym := &symbols[symNo-1]898 899		switch t {900		case R_ARM_ABS32:901			putUint(f.ByteOrder, dst, uint64(rel.Off), 4, sym.Value, 0, true)902		}903	}904 905	return nil906}907 908func (f *File) applyRelocationsARM64(dst []byte, rels []byte) error {909	// 24 is the size of Rela64.910	if len(rels)%24 != 0 {911		return errors.New("length of relocation section is not a multiple of 24")912	}913 914	symbols, _, err := f.getSymbols(SHT_SYMTAB)915	if err != nil {916		return err917	}918 919	b := bytes.NewReader(rels)920	var rela Rela64921 922	for b.Len() > 0 {923		binary.Read(b, f.ByteOrder, &rela)924		symNo := rela.Info >> 32925		t := R_AARCH64(rela.Info & 0xffff)926 927		if symNo == 0 || symNo > uint64(len(symbols)) {928			continue929		}930		sym := &symbols[symNo-1]931		if !canApplyRelocation(sym) {932			continue933		}934 935		// There are relocations, so this must be a normal936		// object file.  The code below handles only basic relocations937		// of the form S + A (symbol plus addend).938 939		switch t {940		case R_AARCH64_ABS64:941			putUint(f.ByteOrder, dst, rela.Off, 8, sym.Value, rela.Addend, false)942		case R_AARCH64_ABS32:943			putUint(f.ByteOrder, dst, rela.Off, 4, sym.Value, rela.Addend, false)944		}945	}946 947	return nil948}949 950func (f *File) applyRelocationsPPC(dst []byte, rels []byte) error {951	// 12 is the size of Rela32.952	if len(rels)%12 != 0 {953		return errors.New("length of relocation section is not a multiple of 12")954	}955 956	symbols, _, err := f.getSymbols(SHT_SYMTAB)957	if err != nil {958		return err959	}960 961	b := bytes.NewReader(rels)962	var rela Rela32963 964	for b.Len() > 0 {965		binary.Read(b, f.ByteOrder, &rela)966		symNo := rela.Info >> 8967		t := R_PPC(rela.Info & 0xff)968 969		if symNo == 0 || symNo > uint32(len(symbols)) {970			continue971		}972		sym := &symbols[symNo-1]973		if !canApplyRelocation(sym) {974			continue975		}976 977		switch t {978		case R_PPC_ADDR32:979			putUint(f.ByteOrder, dst, uint64(rela.Off), 4, sym.Value, 0, false)980		}981	}982 983	return nil984}985 986func (f *File) applyRelocationsPPC64(dst []byte, rels []byte) error {987	// 24 is the size of Rela64.988	if len(rels)%24 != 0 {989		return errors.New("length of relocation section is not a multiple of 24")990	}991 992	symbols, _, err := f.getSymbols(SHT_SYMTAB)993	if err != nil {994		return err995	}996 997	b := bytes.NewReader(rels)998	var rela Rela64999 1000	for b.Len() > 0 {1001		binary.Read(b, f.ByteOrder, &rela)1002		symNo := rela.Info >> 321003		t := R_PPC64(rela.Info & 0xffff)1004 1005		if symNo == 0 || symNo > uint64(len(symbols)) {1006			continue1007		}1008		sym := &symbols[symNo-1]1009		if !canApplyRelocation(sym) {1010			continue1011		}1012 1013		switch t {1014		case R_PPC64_ADDR64:1015			putUint(f.ByteOrder, dst, rela.Off, 8, sym.Value, rela.Addend, false)1016		case R_PPC64_ADDR32:1017			putUint(f.ByteOrder, dst, rela.Off, 4, sym.Value, rela.Addend, false)1018		}1019	}1020 1021	return nil1022}1023 1024func (f *File) applyRelocationsMIPS(dst []byte, rels []byte) error {1025	// 8 is the size of Rel32.1026	if len(rels)%8 != 0 {1027		return errors.New("length of relocation section is not a multiple of 8")1028	}1029 1030	symbols, _, err := f.getSymbols(SHT_SYMTAB)1031	if err != nil {1032		return err1033	}1034 1035	b := bytes.NewReader(rels)1036	var rel Rel321037 1038	for b.Len() > 0 {1039		binary.Read(b, f.ByteOrder, &rel)1040		symNo := rel.Info >> 81041		t := R_MIPS(rel.Info & 0xff)1042 1043		if symNo == 0 || symNo > uint32(len(symbols)) {1044			continue1045		}1046		sym := &symbols[symNo-1]1047 1048		switch t {1049		case R_MIPS_32:1050			putUint(f.ByteOrder, dst, uint64(rel.Off), 4, sym.Value, 0, true)1051		}1052	}1053 1054	return nil1055}1056 1057func (f *File) applyRelocationsMIPS64(dst []byte, rels []byte) error {1058	// 24 is the size of Rela64.1059	if len(rels)%24 != 0 {1060		return errors.New("length of relocation section is not a multiple of 24")1061	}1062 1063	symbols, _, err := f.getSymbols(SHT_SYMTAB)1064	if err != nil {1065		return err1066	}1067 1068	b := bytes.NewReader(rels)1069	var rela Rela641070 1071	for b.Len() > 0 {1072		binary.Read(b, f.ByteOrder, &rela)1073		var symNo uint641074		var t R_MIPS1075		if f.ByteOrder == binary.BigEndian {1076			symNo = rela.Info >> 321077			t = R_MIPS(rela.Info & 0xff)1078		} else {1079			symNo = rela.Info & 0xffffffff1080			t = R_MIPS(rela.Info >> 56)1081		}1082 1083		if symNo == 0 || symNo > uint64(len(symbols)) {1084			continue1085		}1086		sym := &symbols[symNo-1]1087		if !canApplyRelocation(sym) {1088			continue1089		}1090 1091		switch t {1092		case R_MIPS_64:1093			putUint(f.ByteOrder, dst, rela.Off, 8, sym.Value, rela.Addend, false)1094		case R_MIPS_32:1095			putUint(f.ByteOrder, dst, rela.Off, 4, sym.Value, rela.Addend, false)1096		}1097	}1098 1099	return nil1100}1101 1102func (f *File) applyRelocationsLOONG64(dst []byte, rels []byte) error {1103	// 24 is the size of Rela64.1104	if len(rels)%24 != 0 {1105		return errors.New("length of relocation section is not a multiple of 24")1106	}1107 1108	symbols, _, err := f.getSymbols(SHT_SYMTAB)1109	if err != nil {1110		return err1111	}1112 1113	b := bytes.NewReader(rels)1114	var rela Rela641115 1116	for b.Len() > 0 {1117		binary.Read(b, f.ByteOrder, &rela)1118		var symNo uint641119		var t R_LARCH1120		symNo = rela.Info >> 321121		t = R_LARCH(rela.Info & 0xffff)1122 1123		if symNo == 0 || symNo > uint64(len(symbols)) {1124			continue1125		}1126		sym := &symbols[symNo-1]1127		if !canApplyRelocation(sym) {1128			continue1129		}1130 1131		switch t {1132		case R_LARCH_64:1133			putUint(f.ByteOrder, dst, rela.Off, 8, sym.Value, rela.Addend, false)1134		case R_LARCH_32:1135			putUint(f.ByteOrder, dst, rela.Off, 4, sym.Value, rela.Addend, false)1136		}1137	}1138 1139	return nil1140}1141 1142func (f *File) applyRelocationsRISCV64(dst []byte, rels []byte) error {1143	// 24 is the size of Rela64.1144	if len(rels)%24 != 0 {1145		return errors.New("length of relocation section is not a multiple of 24")1146	}1147 1148	symbols, _, err := f.getSymbols(SHT_SYMTAB)1149	if err != nil {1150		return err1151	}1152 1153	b := bytes.NewReader(rels)1154	var rela Rela641155 1156	for b.Len() > 0 {1157		binary.Read(b, f.ByteOrder, &rela)1158		symNo := rela.Info >> 321159		t := R_RISCV(rela.Info & 0xffff)1160 1161		if symNo == 0 || symNo > uint64(len(symbols)) {1162			continue1163		}1164		sym := &symbols[symNo-1]1165		if !canApplyRelocation(sym) {1166			continue1167		}1168 1169		switch t {1170		case R_RISCV_64:1171			putUint(f.ByteOrder, dst, rela.Off, 8, sym.Value, rela.Addend, false)1172		case R_RISCV_32:1173			putUint(f.ByteOrder, dst, rela.Off, 4, sym.Value, rela.Addend, false)1174		}1175	}1176 1177	return nil1178}1179 1180func (f *File) applyRelocationss390x(dst []byte, rels []byte) error {1181	// 24 is the size of Rela64.1182	if len(rels)%24 != 0 {1183		return errors.New("length of relocation section is not a multiple of 24")1184	}1185 1186	symbols, _, err := f.getSymbols(SHT_SYMTAB)1187	if err != nil {1188		return err1189	}1190 1191	b := bytes.NewReader(rels)1192	var rela Rela641193 1194	for b.Len() > 0 {1195		binary.Read(b, f.ByteOrder, &rela)1196		symNo := rela.Info >> 321197		t := R_390(rela.Info & 0xffff)1198 1199		if symNo == 0 || symNo > uint64(len(symbols)) {1200			continue

Showing the first 1,200 of 1860 lines. Download the file for the rest.

codekingpro/portable-devtools · Team Ai