src/debug/elf/file.go GO 1,889 lines View on github.com → Search inside
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.45/*6Package elf implements access to ELF object files.78# Security910This 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 elf1718import (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)3334// TODO: error reporting detail3536/*37 * Internal ELF representation38 */3940// 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}5253// 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}6364// 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   uint647677	// 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}8384// A Section represents a single section in an ELF file.85type Section struct {86	SectionHeader8788	// 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.SectionReader100101	compressionType   CompressionType102	compressionOffset int64103}104105// 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}113114// 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}122123// 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	}133134	var zrd func(io.Reader) (io.ReadCloser, error)135	if s.Flags&SHF_COMPRESSED == 0 {136137		if !strings.HasPrefix(s.Name, ".zdebug") {138			return io.NewSectionReader(s.sr, 0, 1<<63-1)139		}140141		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		}146147		s.compressionOffset = 12148		s.compressionType = COMPRESS_ZLIB149		s.Size = binary.BigEndian.Uint64(b[4:12])150		zrd = zlib.NewReader151152	} 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	}156157	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	}165166	if zrd == nil {167		return errorReader{&FormatError{int64(s.Offset), "unknown compression type", s.compressionType}}168	}169170	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}178179// 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}190191// A Prog represents a single ELF program header in an ELF binary.192type Prog struct {193	ProgHeader194195	// 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}204205// 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) }207208// A Symbol represents an entry in an ELF symbol table section.209type Symbol struct {210	Name        string211	Info, Other byte212213	// 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 VersionIndex220221	Section     SectionIndex222	Value, Size uint64223224	// These fields are present only for the dynamic symbol table.225	Version string226	Library string227}228229/*230 * ELF reader231 */232233type FormatError struct {234	off int64235	msg string236	val any237}238239func (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}247248// 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}262263// 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}274275// 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}285286// 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, &FormatError{0, "cannot read ELF identifier", err}294	}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	}298299	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	}308309	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 = bo320321	f.Version = Version(ident[EI_VERSION])322	if f.Version != EV_CURRENT {323		return nil, &FormatError{0, "unknown ELF version", f.Version}324	}325326	f.OSABI = OSABI(ident[EI_OSABI])327	f.ABIVersion = ident[EI_ABIVERSION]328329	// 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	}374375	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	}381382	if shoff == 0 && shnum != 0 {383		return nil, &FormatError{0, "invalid ELF shnum for shoff=0", shnum}384	}385386	if shnum > 0 && shstrndx >= shnum {387		return nil, &FormatError{0, "invalid ELF shstrndx", shstrndx}388	}389390	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	}402403	// If the number of sections is greater than or equal to SHN_LORESERVE404	// (0xff00), shnum has the value zero and the actual number of section405	// header table entries is contained in the sh_size field of the section406	// header at index 0.407	//408	// If the number of segments is greater than or equal to 0xffff,409	// phnum has the value 0xffff, and the actual number of segments410	// is contained in the sh_info field of the section header at411	// index 0.412	const pnXnum = 0xffff413	if shoff > 0 && (shnum == 0 || phnum == pnXnum) {414		var typ, link, info uint32415		var size uint64416		sr.Seek(shoff, io.SeekStart)417		switch f.Class {418		case ELFCLASS32:419			sh := new(Section32)420			if err := binary.Read(sr, bo, sh); err != nil {421				return nil, err422			}423			size = uint64(sh.Size)424			typ = sh.Type425			link = sh.Link426			info = sh.Info427		case ELFCLASS64:428			sh := new(Section64)429			if err := binary.Read(sr, bo, sh); err != nil {430				return nil, err431			}432			size = sh.Size433			typ = sh.Type434			link = sh.Link435			info = sh.Info436		}437438		if SectionType(typ) != SHT_NULL {439			return nil, &FormatError{shoff, "invalid type of the initial section", SectionType(typ)}440		}441442		if shnum == 0 {443			if size < uint64(SHN_LORESERVE) {444				return nil, &FormatError{shoff, "invalid ELF shnum contained in sh_size", shnum}445			}446			shnum = int(size)447		}448449		if phnum == pnXnum {450			if info < 0xffff {451				return nil, &FormatError{shoff, "invalid ELF phnum contained in sh_info", info}452			}453			phnum = int(info)454		}455456		// If the section name string table section index is greater than or457		// equal to SHN_LORESERVE (0xff00), this member has the value458		// SHN_XINDEX (0xffff) and the actual index of the section name459		// string table section is contained in the sh_link field of the460		// section header at index 0.461		if shstrndx == int(SHN_XINDEX) {462			shstrndx = int(link)463			if shstrndx < int(SHN_LORESERVE) || shstrndx >= shnum {464				return nil, &FormatError{shoff, "invalid ELF shstrndx contained in sh_link", shstrndx}465			}466		}467	}468469	// Read program headers470	c := saferio.SliceCap[*Prog](uint64(phnum))471	if c < 0 {472		return nil, &FormatError{0, "too many segments", phnum}473	}474	if phnum > 0 && ((1<<64)-1)/uint64(phnum) < uint64(phentsize) {475		return nil, &FormatError{0, "segment header overflow", phnum}476	}477	f.Progs = make([]*Prog, 0, c)478	phdata, err := saferio.ReadDataAt(sr, uint64(phnum)*uint64(phentsize), phoff)479	if err != nil {480		return nil, err481	}482	for i := 0; i < phnum; i++ {483		off := uintptr(i) * uintptr(phentsize)484		p := new(Prog)485		switch f.Class {486		case ELFCLASS32:487			var ph Prog32488			p.ProgHeader = ProgHeader{489				Type:   ProgType(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Type):])),490				Flags:  ProgFlag(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Flags):])),491				Off:    uint64(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Off):])),492				Vaddr:  uint64(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Vaddr):])),493				Paddr:  uint64(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Paddr):])),494				Filesz: uint64(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Filesz):])),495				Memsz:  uint64(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Memsz):])),496				Align:  uint64(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Align):])),497			}498		case ELFCLASS64:499			var ph Prog64500			p.ProgHeader = ProgHeader{501				Type:   ProgType(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Type):])),502				Flags:  ProgFlag(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Flags):])),503				Off:    bo.Uint64(phdata[off+unsafe.Offsetof(ph.Off):]),504				Vaddr:  bo.Uint64(phdata[off+unsafe.Offsetof(ph.Vaddr):]),505				Paddr:  bo.Uint64(phdata[off+unsafe.Offsetof(ph.Paddr):]),506				Filesz: bo.Uint64(phdata[off+unsafe.Offsetof(ph.Filesz):]),507				Memsz:  bo.Uint64(phdata[off+unsafe.Offsetof(ph.Memsz):]),508				Align:  bo.Uint64(phdata[off+unsafe.Offsetof(ph.Align):]),509			}510		}511		if int64(p.Off) < 0 {512			return nil, &FormatError{phoff + int64(off), "invalid program header offset", p.Off}513		}514		if int64(p.Filesz) < 0 {515			return nil, &FormatError{phoff + int64(off), "invalid program header file size", p.Filesz}516		}517		p.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz))518		p.ReaderAt = p.sr519		f.Progs = append(f.Progs, p)520	}521522	if shnum > 0 && shentsize < wantShentsize {523		return nil, &FormatError{0, "invalid ELF shentsize", shentsize}524	}525526	// Read section headers527	c = saferio.SliceCap[Section](uint64(shnum))528	if c < 0 {529		return nil, &FormatError{0, "too many sections", shnum}530	}531	if shnum > 0 && ((1<<64)-1)/uint64(shnum) < uint64(shentsize) {532		return nil, &FormatError{0, "section header overflow", shnum}533	}534	f.Sections = make([]*Section, 0, c)535	names := make([]uint32, 0, c)536	shdata, err := saferio.ReadDataAt(sr, uint64(shnum)*uint64(shentsize), shoff)537	if err != nil {538		return nil, err539	}540	for i := 0; i < shnum; i++ {541		off := uintptr(i) * uintptr(shentsize)542		s := new(Section)543		switch f.Class {544		case ELFCLASS32:545			var sh Section32546			names = append(names, bo.Uint32(shdata[off+unsafe.Offsetof(sh.Name):]))547			s.SectionHeader = SectionHeader{548				Type:      SectionType(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Type):])),549				Flags:     SectionFlag(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Flags):])),550				Addr:      uint64(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Addr):])),551				Offset:    uint64(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Off):])),552				FileSize:  uint64(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Size):])),553				Link:      bo.Uint32(shdata[off+unsafe.Offsetof(sh.Link):]),554				Info:      bo.Uint32(shdata[off+unsafe.Offsetof(sh.Info):]),555				Addralign: uint64(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Addralign):])),556				Entsize:   uint64(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Entsize):])),557			}558		case ELFCLASS64:559			var sh Section64560			names = append(names, bo.Uint32(shdata[off+unsafe.Offsetof(sh.Name):]))561			s.SectionHeader = SectionHeader{562				Type:      SectionType(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Type):])),563				Flags:     SectionFlag(bo.Uint64(shdata[off+unsafe.Offsetof(sh.Flags):])),564				Offset:    bo.Uint64(shdata[off+unsafe.Offsetof(sh.Off):]),565				FileSize:  bo.Uint64(shdata[off+unsafe.Offsetof(sh.Size):]),566				Addr:      bo.Uint64(shdata[off+unsafe.Offsetof(sh.Addr):]),567				Link:      bo.Uint32(shdata[off+unsafe.Offsetof(sh.Link):]),568				Info:      bo.Uint32(shdata[off+unsafe.Offsetof(sh.Info):]),569				Addralign: bo.Uint64(shdata[off+unsafe.Offsetof(sh.Addralign):]),570				Entsize:   bo.Uint64(shdata[off+unsafe.Offsetof(sh.Entsize):]),571			}572		}573		if int64(s.Offset) < 0 {574			return nil, &FormatError{shoff + int64(off), "invalid section offset", int64(s.Offset)}575		}576		if int64(s.FileSize) < 0 {577			return nil, &FormatError{shoff + int64(off), "invalid section size", int64(s.FileSize)}578		}579		s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.FileSize))580581		if s.Flags&SHF_COMPRESSED == 0 {582			s.ReaderAt = s.sr583			s.Size = s.FileSize584		} else {585			// Read the compression header.586			switch f.Class {587			case ELFCLASS32:588				var ch Chdr32589				chdata := make([]byte, unsafe.Sizeof(ch))590				if _, err := s.sr.ReadAt(chdata, 0); err != nil {591					return nil, err592				}593				s.compressionType = CompressionType(bo.Uint32(chdata[unsafe.Offsetof(ch.Type):]))594				s.Size = uint64(bo.Uint32(chdata[unsafe.Offsetof(ch.Size):]))595				s.Addralign = uint64(bo.Uint32(chdata[unsafe.Offsetof(ch.Addralign):]))596				s.compressionOffset = int64(unsafe.Sizeof(ch))597			case ELFCLASS64:598				var ch Chdr64599				chdata := make([]byte, unsafe.Sizeof(ch))600				if _, err := s.sr.ReadAt(chdata, 0); err != nil {601					return nil, err602				}603				s.compressionType = CompressionType(bo.Uint32(chdata[unsafe.Offsetof(ch.Type):]))604				s.Size = bo.Uint64(chdata[unsafe.Offsetof(ch.Size):])605				s.Addralign = bo.Uint64(chdata[unsafe.Offsetof(ch.Addralign):])606				s.compressionOffset = int64(unsafe.Sizeof(ch))607			}608		}609610		f.Sections = append(f.Sections, s)611	}612613	if len(f.Sections) == 0 {614		return f, nil615	}616617	// Load section header string table.618	if shstrndx == 0 {619		// If the file has no section name string table,620		// shstrndx holds the value SHN_UNDEF (0).621		return f, nil622	}623	shstr := f.Sections[shstrndx]624	if shstr.Type != SHT_STRTAB {625		return nil, &FormatError{shoff + int64(shstrndx*shentsize), "invalid ELF section name string table type", shstr.Type}626	}627	shstrtab, err := shstr.Data()628	if err != nil {629		return nil, err630	}631	for i, s := range f.Sections {632		var ok bool633		s.Name, ok = getString(shstrtab, int(names[i]))634		if !ok {635			return nil, &FormatError{shoff + int64(i*shentsize), "bad section name index", names[i]}636		}637	}638639	return f, nil640}641642// getSymbols returns a slice of Symbols from parsing the symbol table643// with the given type, along with the associated string table.644func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, error) {645	switch f.Class {646	case ELFCLASS64:647		return f.getSymbols64(typ)648649	case ELFCLASS32:650		return f.getSymbols32(typ)651	}652653	return nil, nil, errors.New("not implemented")654}655656// ErrNoSymbols is returned by [File.Symbols] and [File.DynamicSymbols]657// if there is no such section in the File.658var ErrNoSymbols = errors.New("no symbol section")659660func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) {661	symtabSection := f.SectionByType(typ)662	if symtabSection == nil {663		return nil, nil, ErrNoSymbols664	}665666	data, err := symtabSection.Data()667	if err != nil {668		return nil, nil, fmt.Errorf("cannot load symbol section: %w", err)669	}670	if len(data) == 0 {671		return nil, nil, ErrNoSymbols672	}673	if len(data)%Sym32Size != 0 {674		return nil, nil, errors.New("length of symbol section is not a multiple of SymSize")675	}676677	strdata, err := f.stringTable(symtabSection.Link)678	if err != nil {679		return nil, nil, fmt.Errorf("cannot load string table section: %w", err)680	}681682	// The first entry is all zeros.683	data = data[Sym32Size:]684685	symbols := make([]Symbol, len(data)/Sym32Size)686687	i := 0688	var sym Sym32689	for len(data) > 0 {690		sym.Name = f.ByteOrder.Uint32(data[0:4])691		sym.Value = f.ByteOrder.Uint32(data[4:8])692		sym.Size = f.ByteOrder.Uint32(data[8:12])693		sym.Info = data[12]694		sym.Other = data[13]695		sym.Shndx = f.ByteOrder.Uint16(data[14:16])696		str, _ := getString(strdata, int(sym.Name))697		symbols[i].Name = str698		symbols[i].Info = sym.Info699		symbols[i].Other = sym.Other700		symbols[i].Section = SectionIndex(sym.Shndx)701		symbols[i].Value = uint64(sym.Value)702		symbols[i].Size = uint64(sym.Size)703		i++704		data = data[Sym32Size:]705	}706707	return symbols, strdata, nil708}709710func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) {711	symtabSection := f.SectionByType(typ)712	if symtabSection == nil {713		return nil, nil, ErrNoSymbols714	}715716	data, err := symtabSection.Data()717	if err != nil {718		return nil, nil, fmt.Errorf("cannot load symbol section: %w", err)719	}720	if len(data) == 0 {721		return nil, nil, ErrNoSymbols722	}723	if len(data)%Sym64Size != 0 {724		return nil, nil, errors.New("length of symbol section is not a multiple of Sym64Size")725	}726727	strdata, err := f.stringTable(symtabSection.Link)728	if err != nil {729		return nil, nil, fmt.Errorf("cannot load string table section: %w", err)730	}731732	// The first entry is all zeros.733	data = data[Sym64Size:]734735	symbols := make([]Symbol, len(data)/Sym64Size)736737	i := 0738	var sym Sym64739	for len(data) > 0 {740		sym.Name = f.ByteOrder.Uint32(data[0:4])741		sym.Info = data[4]742		sym.Other = data[5]743		sym.Shndx = f.ByteOrder.Uint16(data[6:8])744		sym.Value = f.ByteOrder.Uint64(data[8:16])745		sym.Size = f.ByteOrder.Uint64(data[16:24])746		str, _ := getString(strdata, int(sym.Name))747		symbols[i].Name = str748		symbols[i].Info = sym.Info749		symbols[i].Other = sym.Other750		symbols[i].Section = SectionIndex(sym.Shndx)751		symbols[i].Value = sym.Value752		symbols[i].Size = sym.Size753		i++754		data = data[Sym64Size:]755	}756757	return symbols, strdata, nil758}759760// getString extracts a string from an ELF string table.761func getString(section []byte, start int) (string, bool) {762	if start < 0 || start >= len(section) {763		return "", false764	}765766	end := bytes.IndexByte(section[start:], 0)767	if end < 0 {768		return "", false769	}770	return string(section[start : start+end]), true771}772773// Section returns a section with the given name, or nil if no such774// section exists.775func (f *File) Section(name string) *Section {776	for _, s := range f.Sections {777		if s.Name == name {778			return s779		}780	}781	return nil782}783784// applyRelocations applies relocations to dst. rels is a relocations section785// in REL or RELA format.786func (f *File) applyRelocations(dst []byte, rels []byte) error {787	switch {788	case f.Class == ELFCLASS64 && f.Machine == EM_X86_64:789		return f.applyRelocationsAMD64(dst, rels)790	case f.Class == ELFCLASS32 && f.Machine == EM_386:791		return f.applyRelocations386(dst, rels)792	case f.Class == ELFCLASS32 && f.Machine == EM_ARM:793		return f.applyRelocationsARM(dst, rels)794	case f.Class == ELFCLASS64 && f.Machine == EM_AARCH64:795		return f.applyRelocationsARM64(dst, rels)796	case f.Class == ELFCLASS32 && f.Machine == EM_PPC:797		return f.applyRelocationsPPC(dst, rels)798	case f.Class == ELFCLASS64 && f.Machine == EM_PPC64:799		return f.applyRelocationsPPC64(dst, rels)800	case f.Class == ELFCLASS32 && f.Machine == EM_MIPS:801		return f.applyRelocationsMIPS(dst, rels)802	case f.Class == ELFCLASS64 && f.Machine == EM_MIPS:803		return f.applyRelocationsMIPS64(dst, rels)804	case f.Class == ELFCLASS64 && f.Machine == EM_LOONGARCH:805		return f.applyRelocationsLOONG64(dst, rels)806	case f.Class == ELFCLASS64 && f.Machine == EM_RISCV:807		return f.applyRelocationsRISCV64(dst, rels)808	case f.Class == ELFCLASS64 && f.Machine == EM_S390:809		return f.applyRelocationss390x(dst, rels)810	case f.Class == ELFCLASS64 && f.Machine == EM_SPARCV9:811		return f.applyRelocationsSPARC64(dst, rels)812	default:813		return errors.New("applyRelocations: not implemented")814	}815}816817// canApplyRelocation reports whether we should try to apply a818// relocation to a DWARF data section, given a pointer to the symbol819// targeted by the relocation.820// Most relocations in DWARF data tend to be section-relative, but821// some target non-section symbols (for example, low_PC attrs on822// subprogram or compilation unit DIEs that target function symbols).823func canApplyRelocation(sym *Symbol) bool {824	return sym.Section != SHN_UNDEF && sym.Section < SHN_LORESERVE825}826827func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {828	// 24 is the size of Rela64.829	if len(rels)%24 != 0 {830		return errors.New("length of relocation section is not a multiple of 24")831	}832833	symbols, _, err := f.getSymbols(SHT_SYMTAB)834	if err != nil {835		return err836	}837838	b := bytes.NewReader(rels)839	var rela Rela64840841	for b.Len() > 0 {842		binary.Read(b, f.ByteOrder, &rela)843		symNo := rela.Info >> 32844		t := R_X86_64(rela.Info & 0xffff)845846		if symNo == 0 || symNo > uint64(len(symbols)) {847			continue848		}849		sym := &symbols[symNo-1]850		if !canApplyRelocation(sym) {851			continue852		}853854		// There are relocations, so this must be a normal855		// object file.  The code below handles only basic relocations856		// of the form S + A (symbol plus addend).857858		switch t {859		case R_X86_64_64:860			putUint(f.ByteOrder, dst, rela.Off, 8, sym.Value, rela.Addend, false)861		case R_X86_64_32:862			putUint(f.ByteOrder, dst, rela.Off, 4, sym.Value, rela.Addend, false)863		}864	}865866	return nil867}868869func (f *File) applyRelocations386(dst []byte, rels []byte) error {870	// 8 is the size of Rel32.871	if len(rels)%8 != 0 {872		return errors.New("length of relocation section is not a multiple of 8")873	}874875	symbols, _, err := f.getSymbols(SHT_SYMTAB)876	if err != nil {877		return err878	}879880	b := bytes.NewReader(rels)881	var rel Rel32882883	for b.Len() > 0 {884		binary.Read(b, f.ByteOrder, &rel)885		symNo := rel.Info >> 8886		t := R_386(rel.Info & 0xff)887888		if symNo == 0 || symNo > uint32(len(symbols)) {889			continue890		}891		sym := &symbols[symNo-1]892893		if t == R_386_32 {894			putUint(f.ByteOrder, dst, uint64(rel.Off), 4, sym.Value, 0, true)895		}896	}897898	return nil899}900901func (f *File) applyRelocationsARM(dst []byte, rels []byte) error {902	// 8 is the size of Rel32.903	if len(rels)%8 != 0 {904		return errors.New("length of relocation section is not a multiple of 8")905	}906907	symbols, _, err := f.getSymbols(SHT_SYMTAB)908	if err != nil {909		return err910	}911912	b := bytes.NewReader(rels)913	var rel Rel32914915	for b.Len() > 0 {916		binary.Read(b, f.ByteOrder, &rel)917		symNo := rel.Info >> 8918		t := R_ARM(rel.Info & 0xff)919920		if symNo == 0 || symNo > uint32(len(symbols)) {921			continue922		}923		sym := &symbols[symNo-1]924925		switch t {926		case R_ARM_ABS32:927			putUint(f.ByteOrder, dst, uint64(rel.Off), 4, sym.Value, 0, true)928		}929	}930931	return nil932}933934func (f *File) applyRelocationsARM64(dst []byte, rels []byte) error {935	// 24 is the size of Rela64.936	if len(rels)%24 != 0 {937		return errors.New("length of relocation section is not a multiple of 24")938	}939940	symbols, _, err := f.getSymbols(SHT_SYMTAB)941	if err != nil {942		return err943	}944945	b := bytes.NewReader(rels)946	var rela Rela64947948	for b.Len() > 0 {949		binary.Read(b, f.ByteOrder, &rela)950		symNo := rela.Info >> 32951		t := R_AARCH64(rela.Info & 0xffff)952953		if symNo == 0 || symNo > uint64(len(symbols)) {954			continue955		}956		sym := &symbols[symNo-1]957		if !canApplyRelocation(sym) {958			continue959		}960961		// There are relocations, so this must be a normal962		// object file.  The code below handles only basic relocations963		// of the form S + A (symbol plus addend).964965		switch t {966		case R_AARCH64_ABS64:967			putUint(f.ByteOrder, dst, rela.Off, 8, sym.Value, rela.Addend, false)968		case R_AARCH64_ABS32:969			putUint(f.ByteOrder, dst, rela.Off, 4, sym.Value, rela.Addend, false)970		}971	}972973	return nil974}975976func (f *File) applyRelocationsPPC(dst []byte, rels []byte) error {977	// 12 is the size of Rela32.978	if len(rels)%12 != 0 {979		return errors.New("length of relocation section is not a multiple of 12")980	}981982	symbols, _, err := f.getSymbols(SHT_SYMTAB)983	if err != nil {984		return err985	}986987	b := bytes.NewReader(rels)988	var rela Rela32989990	for b.Len() > 0 {991		binary.Read(b, f.ByteOrder, &rela)992		symNo := rela.Info >> 8993		t := R_PPC(rela.Info & 0xff)994995		if symNo == 0 || symNo > uint32(len(symbols)) {996			continue997		}998		sym := &symbols[symNo-1]999		if !canApplyRelocation(sym) {1000			continue1001		}10021003		switch t {1004		case R_PPC_ADDR32:1005			putUint(f.ByteOrder, dst, uint64(rela.Off), 4, sym.Value, 0, false)1006		}1007	}10081009	return nil1010}10111012func (f *File) applyRelocationsPPC64(dst []byte, rels []byte) error {1013	// 24 is the size of Rela64.1014	if len(rels)%24 != 0 {1015		return errors.New("length of relocation section is not a multiple of 24")1016	}10171018	symbols, _, err := f.getSymbols(SHT_SYMTAB)1019	if err != nil {1020		return err1021	}10221023	b := bytes.NewReader(rels)1024	var rela Rela6410251026	for b.Len() > 0 {1027		binary.Read(b, f.ByteOrder, &rela)1028		symNo := rela.Info >> 321029		t := R_PPC64(rela.Info & 0xffff)10301031		if symNo == 0 || symNo > uint64(len(symbols)) {1032			continue1033		}1034		sym := &symbols[symNo-1]1035		if !canApplyRelocation(sym) {1036			continue1037		}10381039		switch t {1040		case R_PPC64_ADDR64:1041			putUint(f.ByteOrder, dst, rela.Off, 8, sym.Value, rela.Addend, false)1042		case R_PPC64_ADDR32:1043			putUint(f.ByteOrder, dst, rela.Off, 4, sym.Value, rela.Addend, false)1044		}1045	}10461047	return nil1048}10491050func (f *File) applyRelocationsMIPS(dst []byte, rels []byte) error {1051	// 8 is the size of Rel32.1052	if len(rels)%8 != 0 {1053		return errors.New("length of relocation section is not a multiple of 8")1054	}10551056	symbols, _, err := f.getSymbols(SHT_SYMTAB)1057	if err != nil {1058		return err1059	}10601061	b := bytes.NewReader(rels)1062	var rel Rel3210631064	for b.Len() > 0 {1065		binary.Read(b, f.ByteOrder, &rel)1066		symNo := rel.Info >> 81067		t := R_MIPS(rel.Info & 0xff)10681069		if symNo == 0 || symNo > uint32(len(symbols)) {1070			continue1071		}1072		sym := &symbols[symNo-1]10731074		switch t {1075		case R_MIPS_32:1076			putUint(f.ByteOrder, dst, uint64(rel.Off), 4, sym.Value, 0, true)1077		}1078	}10791080	return nil1081}10821083func (f *File) applyRelocationsMIPS64(dst []byte, rels []byte) error {1084	// 24 is the size of Rela64.1085	if len(rels)%24 != 0 {1086		return errors.New("length of relocation section is not a multiple of 24")1087	}10881089	symbols, _, err := f.getSymbols(SHT_SYMTAB)1090	if err != nil {1091		return err1092	}10931094	b := bytes.NewReader(rels)1095	var rela Rela6410961097	for b.Len() > 0 {1098		binary.Read(b, f.ByteOrder, &rela)1099		var symNo uint641100		var t R_MIPS1101		if f.ByteOrder == binary.BigEndian {1102			symNo = rela.Info >> 321103			t = R_MIPS(rela.Info & 0xff)1104		} else {1105			symNo = rela.Info & 0xffffffff1106			t = R_MIPS(rela.Info >> 56)1107		}11081109		if symNo == 0 || symNo > uint64(len(symbols)) {1110			continue1111		}1112		sym := &symbols[symNo-1]1113		if !canApplyRelocation(sym) {1114			continue1115		}11161117		switch t {1118		case R_MIPS_64:1119			putUint(f.ByteOrder, dst, rela.Off, 8, sym.Value, rela.Addend, false)1120		case R_MIPS_32:1121			putUint(f.ByteOrder, dst, rela.Off, 4, sym.Value, rela.Addend, false)1122		}1123	}11241125	return nil1126}11271128func (f *File) applyRelocationsLOONG64(dst []byte, rels []byte) error {1129	// 24 is the size of Rela64.1130	if len(rels)%24 != 0 {1131		return errors.New("length of relocation section is not a multiple of 24")1132	}11331134	symbols, _, err := f.getSymbols(SHT_SYMTAB)1135	if err != nil {1136		return err1137	}11381139	b := bytes.NewReader(rels)1140	var rela Rela6411411142	for b.Len() > 0 {1143		binary.Read(b, f.ByteOrder, &rela)1144		var symNo uint641145		var t R_LARCH1146		symNo = rela.Info >> 321147		t = R_LARCH(rela.Info & 0xffff)11481149		if symNo == 0 || symNo > uint64(len(symbols)) {1150			continue1151		}1152		sym := &symbols[symNo-1]1153		if !canApplyRelocation(sym) {1154			continue1155		}11561157		switch t {1158		case R_LARCH_64:1159			putUint(f.ByteOrder, dst, rela.Off, 8, sym.Value, rela.Addend, false)1160		case R_LARCH_32:1161			putUint(f.ByteOrder, dst, rela.Off, 4, sym.Value, rela.Addend, false)1162		}1163	}11641165	return nil1166}11671168func (f *File) applyRelocationsRISCV64(dst []byte, rels []byte) error {1169	// 24 is the size of Rela64.1170	if len(rels)%24 != 0 {1171		return errors.New("length of relocation section is not a multiple of 24")1172	}11731174	symbols, _, err := f.getSymbols(SHT_SYMTAB)1175	if err != nil {1176		return err1177	}11781179	b := bytes.NewReader(rels)1180	var rela Rela6411811182	for b.Len() > 0 {1183		binary.Read(b, f.ByteOrder, &rela)1184		symNo := rela.Info >> 321185		t := R_RISCV(rela.Info & 0xffff)11861187		if symNo == 0 || symNo > uint64(len(symbols)) {1188			continue1189		}1190		sym := &symbols[symNo-1]1191		if !canApplyRelocation(sym) {1192			continue1193		}11941195		switch t {1196		case R_RISCV_64:1197			putUint(f.ByteOrder, dst, rela.Off, 8, sym.Value, rela.Addend, false)1198		case R_RISCV_32:1199			putUint(f.ByteOrder, dst, rela.Off, 4, sym.Value, rela.Addend, false)1200		}1201	}12021203	return nil1204}12051206func (f *File) applyRelocationss390x(dst []byte, rels []byte) error {1207	// 24 is the size of Rela64.1208	if len(rels)%24 != 0 {1209		return errors.New("length of relocation section is not a multiple of 24")1210	}12111212	symbols, _, err := f.getSymbols(SHT_SYMTAB)1213	if err != nil {1214		return err1215	}12161217	b := bytes.NewReader(rels)1218	var rela Rela6412191220	for b.Len() > 0 {1221		binary.Read(b, f.ByteOrder, &rela)1222		symNo := rela.Info >> 321223		t := R_390(rela.Info & 0xffff)12241225		if symNo == 0 || symNo > uint64(len(symbols)) {1226			continue1227		}1228		sym := &symbols[symNo-1]1229		if !canApplyRelocation(sym) {1230			continue1231		}12321233		switch t {1234		case R_390_64:1235			putUint(f.ByteOrder, dst, rela.Off, 8, sym.Value, rela.Addend, false)1236		case R_390_32:1237			putUint(f.ByteOrder, dst, rela.Off, 4, sym.Value, rela.Addend, false)1238		}1239	}12401241	return nil1242}12431244func (f *File) applyRelocationsSPARC64(dst []byte, rels []byte) error {1245	// 24 is the size of Rela64.1246	if len(rels)%24 != 0 {1247		return errors.New("length of relocation section is not a multiple of 24")1248	}12491250	symbols, _, err := f.getSymbols(SHT_SYMTAB)1251	if err != nil {1252		return err1253	}12541255	b := bytes.NewReader(rels)1256	var rela Rela6412571258	for b.Len() > 0 {1259		binary.Read(b, f.ByteOrder, &rela)1260		symNo := rela.Info >> 321261		t := R_SPARC(rela.Info & 0xff)12621263		if symNo == 0 || symNo > uint64(len(symbols)) {1264			continue1265		}1266		sym := &symbols[symNo-1]1267		if !canApplyRelocation(sym) {1268			continue1269		}12701271		switch t {1272		case R_SPARC_64, R_SPARC_UA64:1273			putUint(f.ByteOrder, dst, rela.Off, 8, sym.Value, rela.Addend, false)12741275		case R_SPARC_32, R_SPARC_UA32:1276			putUint(f.ByteOrder, dst, rela.Off, 4, sym.Value, rela.Addend, false)1277		}1278	}12791280	return nil1281}12821283func (f *File) DWARF() (*dwarf.Data, error) {1284	dwarfSuffix := func(s *Section) string {1285		switch {1286		case strings.HasPrefix(s.Name, ".debug_"):1287			return s.Name[7:]1288		case strings.HasPrefix(s.Name, ".zdebug_"):1289			return s.Name[8:]1290		default:1291			return ""1292		}12931294	}1295	// sectionData gets the data for s, checks its size, and1296	// applies any applicable relations.1297	sectionData := func(i int, s *Section) ([]byte, error) {1298		b, err := s.Data()1299		if err != nil && uint64(len(b)) < s.Size {1300			return nil, err1301		}13021303		if f.Type == ET_EXEC {1304			// Do not apply relocations to DWARF sections for ET_EXEC binaries.1305			// Relocations should already be applied, and .rela sections may1306			// contain incorrect data.1307			return b, nil1308		}13091310		for _, r := range f.Sections {1311			if r.Type != SHT_RELA && r.Type != SHT_REL {1312				continue1313			}1314			if int(r.Info) != i {1315				continue1316			}1317			rd, err := r.Data()1318			if err != nil {1319				return nil, err1320			}1321			err = f.applyRelocations(b, rd)1322			if err != nil {1323				return nil, err1324			}1325		}1326		return b, nil1327	}13281329	// There are many DWARF sections, but these are the ones1330	// the debug/dwarf package started with.1331	var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil}1332	for i, s := range f.Sections {1333		suffix := dwarfSuffix(s)1334		if suffix == "" {1335			continue1336		}1337		if _, ok := dat[suffix]; !ok {1338			continue1339		}1340		b, err := sectionData(i, s)1341		if err != nil {1342			return nil, err1343		}1344		dat[suffix] = b1345	}13461347	d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, dat["ranges"], dat["str"])1348	if err != nil {1349		return nil, err1350	}13511352	// Look for DWARF4 .debug_types sections and DWARF5 sections.1353	for i, s := range f.Sections {1354		suffix := dwarfSuffix(s)1355		if suffix == "" {1356			continue1357		}1358		if _, ok := dat[suffix]; ok {1359			// Already handled.1360			continue1361		}13621363		b, err := sectionData(i, s)1364		if err != nil {1365			return nil, err1366		}13671368		if suffix == "types" {1369			if err := d.AddTypes(fmt.Sprintf("types-%d", i), b); err != nil {1370				return nil, err1371			}1372		} else {1373			if err := d.AddSection(".debug_"+suffix, b); err != nil {1374				return nil, err1375			}1376		}1377	}13781379	return d, nil1380}13811382// Symbols returns the symbol table for f. The symbols will be listed in the order1383// they appear in f.1384//1385// For compatibility with Go 1.0, Symbols omits the null symbol at index 0.1386// After retrieving the symbols as symtab, an externally supplied index x1387// corresponds to symtab[x-1], not symtab[x].1388func (f *File) Symbols() ([]Symbol, error) {1389	sym, _, err := f.getSymbols(SHT_SYMTAB)1390	return sym, err1391}13921393// DynamicSymbols returns the dynamic symbol table for f. The symbols1394// will be listed in the order they appear in f.1395//1396// If f has a symbol version table, the returned [File.Symbols] will have1397// initialized Version and Library fields.1398//1399// For compatibility with [File.Symbols], [File.DynamicSymbols] omits the null symbol at index 0.1400// After retrieving the symbols as symtab, an externally supplied index x1401// corresponds to symtab[x-1], not symtab[x].1402func (f *File) DynamicSymbols() ([]Symbol, error) {1403	sym, str, err := f.getSymbols(SHT_DYNSYM)1404	if err != nil {1405		return nil, err1406	}1407	hasVersions, err := f.gnuVersionInit(str)1408	if err != nil {1409		return nil, err1410	}1411	if hasVersions {1412		for i := range sym {1413			sym[i].HasVersion, sym[i].VersionIndex, sym[i].Version, sym[i].Library = f.gnuVersion(i)1414		}1415	}1416	return sym, nil1417}14181419type ImportedSymbol struct {1420	Name    string1421	Version string1422	Library string1423}14241425// ImportedSymbols returns the names of all symbols1426// referred to by the binary f that are expected to be1427// satisfied by other libraries at dynamic load time.1428// It does not return weak symbols.1429func (f *File) ImportedSymbols() ([]ImportedSymbol, error) {1430	sym, str, err := f.getSymbols(SHT_DYNSYM)1431	if err != nil {1432		return nil, err1433	}1434	if _, err := f.gnuVersionInit(str); err != nil {1435		return nil, err1436	}1437	var all []ImportedSymbol1438	for i, s := range sym {1439		if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF {1440			all = append(all, ImportedSymbol{Name: s.Name})1441			sym := &all[len(all)-1]1442			_, _, sym.Version, sym.Library = f.gnuVersion(i)1443		}1444	}1445	return all, nil1446}14471448// VersionIndex is the type of a [Symbol] version index.1449type VersionIndex uint1614501451// IsHidden reports whether the symbol is hidden within the version.1452// This means that the symbol can only be seen by specifying the exact version.1453func (vi VersionIndex) IsHidden() bool {1454	return vi&0x8000 != 01455}14561457// Index returns the version index.1458// If this is the value 0, it means that the symbol is local,1459// and is not visible externally.1460// If this is the value 1, it means that the symbol is in the base version,1461// and has no specific version; it may or may not match a1462// [DynamicVersion.Index] in the slice returned by [File.DynamicVersions].1463// Other values will match either [DynamicVersion.Index]1464// in the slice returned by [File.DynamicVersions],1465// or [DynamicVersionDep.Index] in the Needs field1466// of the elements of the slice returned by [File.DynamicVersionNeeds].1467// In general, a defined symbol will have an index referring1468// to DynamicVersions, and an undefined symbol will have an index1469// referring to some version in DynamicVersionNeeds.1470func (vi VersionIndex) Index() uint16 {1471	return uint16(vi & 0x7fff)1472}14731474// DynamicVersion is a version defined by a dynamic object.1475// This describes entries in the ELF SHT_GNU_verdef section.1476// We assume that the vd_version field is 1.1477// Note that the name of the version appears here;1478// it is not in the first Deps entry as it is in the ELF file.1479type DynamicVersion struct {1480	Name  string // Name of version defined by this index.1481	Index uint16 // Version index.1482	Flags DynamicVersionFlag1483	Deps  []string // Names of versions that this version depends upon.1484}14851486// DynamicVersionNeed describes a shared library needed by a dynamic object,1487// with a list of the versions needed from that shared library.1488// This describes entries in the ELF SHT_GNU_verneed section.1489// We assume that the vn_version field is 1.1490type DynamicVersionNeed struct {1491	Name  string              // Shared library name.1492	Needs []DynamicVersionDep // Dependencies.1493}14941495// DynamicVersionDep is a version needed from some shared library.1496type DynamicVersionDep struct {1497	Flags DynamicVersionFlag1498	Index uint16 // Version index.1499	Dep   string // Name of required version.1500}15011502// dynamicVersions returns version information for a dynamic object.1503func (f *File) dynamicVersions(str []byte) error {1504	if f.dynVers != nil {1505		// Already initialized.1506		return nil1507	}15081509	// Accumulate verdef information.1510	vd := f.SectionByType(SHT_GNU_VERDEF)1511	if vd == nil {1512		return nil1513	}1514	d, _ := vd.Data()15151516	var dynVers []DynamicVersion1517	i := 01518	for {1519		if i+20 > len(d) {1520			break1521		}1522		version := f.ByteOrder.Uint16(d[i : i+2])1523		if version != 1 {1524			return &FormatError{int64(vd.Offset + uint64(i)), "unexpected dynamic version", version}1525		}1526		flags := DynamicVersionFlag(f.ByteOrder.Uint16(d[i+2 : i+4]))1527		ndx := f.ByteOrder.Uint16(d[i+4 : i+6])1528		cnt := f.ByteOrder.Uint16(d[i+6 : i+8])1529		aux := f.ByteOrder.Uint32(d[i+12 : i+16])1530		next := f.ByteOrder.Uint32(d[i+16 : i+20])15311532		if cnt == 0 {1533			return &FormatError{int64(vd.Offset + uint64(i)), "dynamic version has no name", nil}1534		}15351536		var name string1537		var depName string1538		var deps []string1539		j := i + int(aux)1540		for c := 0; c < int(cnt); c++ {1541			if j+8 > len(d) {1542				break1543			}1544			vname := f.ByteOrder.Uint32(d[j : j+4])1545			vnext := f.ByteOrder.Uint32(d[j+4 : j+8])1546			depName, _ = getString(str, int(vname))15471548			if c == 0 {1549				name = depName1550			} else {1551				deps = append(deps, depName)1552			}15531554			if vnext == 0 {1555				break1556			}1557			j += int(vnext)1558		}15591560		dynVers = append(dynVers, DynamicVersion{1561			Name:  name,1562			Index: ndx,1563			Flags: flags,1564			Deps:  deps,1565		})15661567		if next == 0 {1568			break1569		}1570		i += int(next)1571	}15721573	f.dynVers = dynVers15741575	return nil1576}15771578// DynamicVersions returns version information for a dynamic object.1579func (f *File) DynamicVersions() ([]DynamicVersion, error) {1580	if f.dynVers == nil {1581		_, str, err := f.getSymbols(SHT_DYNSYM)1582		if err != nil {1583			return nil, err1584		}1585		hasVersions, err := f.gnuVersionInit(str)1586		if err != nil {1587			return nil, err1588		}1589		if !hasVersions {1590			return nil, errors.New("DynamicVersions: missing version table")1591		}1592	}15931594	return f.dynVers, nil1595}15961597// dynamicVersionNeeds returns version dependencies for a dynamic object.1598func (f *File) dynamicVersionNeeds(str []byte) error {1599	if f.dynVerNeeds != nil {1600		// Already initialized.1601		return nil1602	}16031604	// Accumulate verneed information.1605	vn := f.SectionByType(SHT_GNU_VERNEED)1606	if vn == nil {1607		return nil1608	}1609	d, _ := vn.Data()16101611	var dynVerNeeds []DynamicVersionNeed1612	i := 01613	for {1614		if i+16 > len(d) {1615			break1616		}1617		vers := f.ByteOrder.Uint16(d[i : i+2])1618		if vers != 1 {1619			return &FormatError{int64(vn.Offset + uint64(i)), "unexpected dynamic need version", vers}1620		}1621		cnt := f.ByteOrder.Uint16(d[i+2 : i+4])1622		fileoff := f.ByteOrder.Uint32(d[i+4 : i+8])1623		aux := f.ByteOrder.Uint32(d[i+8 : i+12])1624		next := f.ByteOrder.Uint32(d[i+12 : i+16])1625		file, _ := getString(str, int(fileoff))16261627		var deps []DynamicVersionDep1628		j := i + int(aux)1629		for c := 0; c < int(cnt); c++ {1630			if j+16 > len(d) {1631				break1632			}1633			flags := DynamicVersionFlag(f.ByteOrder.Uint16(d[j+4 : j+6]))1634			index := f.ByteOrder.Uint16(d[j+6 : j+8])1635			nameoff := f.ByteOrder.Uint32(d[j+8 : j+12])1636			next := f.ByteOrder.Uint32(d[j+12 : j+16])1637			depName, _ := getString(str, int(nameoff))16381639			deps = append(deps, DynamicVersionDep{1640				Flags: flags,1641				Index: index,1642				Dep:   depName,1643			})16441645			if next == 0 {1646				break1647			}1648			j += int(next)1649		}16501651		dynVerNeeds = append(dynVerNeeds, DynamicVersionNeed{1652			Name:  file,1653			Needs: deps,1654		})16551656		if next == 0 {1657			break1658		}1659		i += int(next)1660	}16611662	f.dynVerNeeds = dynVerNeeds16631664	return nil1665}16661667// DynamicVersionNeeds returns version dependencies for a dynamic object.1668func (f *File) DynamicVersionNeeds() ([]DynamicVersionNeed, error) {1669	if f.dynVerNeeds == nil {1670		_, str, err := f.getSymbols(SHT_DYNSYM)1671		if err != nil {1672			return nil, err1673		}1674		hasVersions, err := f.gnuVersionInit(str)1675		if err != nil {1676			return nil, err1677		}1678		if !hasVersions {1679			return nil, errors.New("DynamicVersionNeeds: missing version table")1680		}1681	}16821683	return f.dynVerNeeds, nil1684}16851686// gnuVersionInit parses the GNU version tables1687// for use by calls to gnuVersion.1688// It reports whether any version tables were found.1689func (f *File) gnuVersionInit(str []byte) (bool, error) {1690	// Versym parallels symbol table, indexing into verneed.1691	vs := f.SectionByType(SHT_GNU_VERSYM)1692	if vs == nil {1693		return false, nil1694	}1695	d, _ := vs.Data()16961697	f.gnuVersym = d1698	if err := f.dynamicVersions(str); err != nil {1699		return false, err1700	}1701	if err := f.dynamicVersionNeeds(str); err != nil {1702		return false, err1703	}1704	return true, nil1705}17061707// gnuVersion adds Library and Version information to sym,1708// which came from offset i of the symbol table.1709func (f *File) gnuVersion(i int) (hasVersion bool, versionIndex VersionIndex, version string, library string) {1710	// Each entry is two bytes; skip undef entry at beginning.1711	i = (i + 1) * 21712	if i >= len(f.gnuVersym) {1713		return false, 0, "", ""1714	}1715	s := f.gnuVersym[i:]1716	if len(s) < 2 {1717		return false, 0, "", ""1718	}1719	vi := VersionIndex(f.ByteOrder.Uint16(s))1720	ndx := vi.Index()17211722	if ndx == 0 || ndx == 1 {1723		return true, vi, "", ""1724	}17251726	for _, v := range f.dynVerNeeds {1727		for _, n := range v.Needs {1728			if ndx == n.Index {1729				return true, vi, n.Dep, v.Name1730			}1731		}1732	}17331734	for _, v := range f.dynVers {1735		if ndx == v.Index {1736			return true, vi, v.Name, ""1737		}1738	}17391740	return false, 0, "", ""1741}17421743// ImportedLibraries returns the names of all libraries1744// referred to by the binary f that are expected to be1745// linked with the binary at dynamic link time.1746func (f *File) ImportedLibraries() ([]string, error) {1747	return f.DynString(DT_NEEDED)1748}17491750// DynString returns the strings listed for the given tag in the file's dynamic1751// section.1752//1753// The tag must be one that takes string values: [DT_NEEDED], [DT_SONAME], [DT_RPATH], or1754// [DT_RUNPATH].1755func (f *File) DynString(tag DynTag) ([]string, error) {1756	switch tag {1757	case DT_NEEDED, DT_SONAME, DT_RPATH, DT_RUNPATH:1758	default:1759		return nil, fmt.Errorf("non-string-valued tag %v", tag)1760	}1761	ds := f.SectionByType(SHT_DYNAMIC)1762	if ds == nil {1763		// not dynamic, so no libraries1764		return nil, nil1765	}1766	d, err := ds.Data()1767	if err != nil {1768		return nil, err1769	}17701771	dynSize := 81772	if f.Class == ELFCLASS64 {1773		dynSize = 161774	}1775	if len(d)%dynSize != 0 {1776		return nil, errors.New("length of dynamic section is not a multiple of dynamic entry size")1777	}17781779	str, err := f.stringTable(ds.Link)1780	if err != nil {1781		return nil, err1782	}1783	var all []string1784	for len(d) > 0 {1785		var t DynTag1786		var v uint641787		switch f.Class {1788		case ELFCLASS32:1789			t = DynTag(f.ByteOrder.Uint32(d[0:4]))1790			v = uint64(f.ByteOrder.Uint32(d[4:8]))1791			d = d[8:]1792		case ELFCLASS64:1793			t = DynTag(f.ByteOrder.Uint64(d[0:8]))1794			v = f.ByteOrder.Uint64(d[8:16])1795			d = d[16:]1796		}1797		if t == tag {1798			s, ok := getString(str, int(v))1799			if ok {1800				all = append(all, s)1801			}1802		}1803	}1804	return all, nil1805}18061807// DynValue returns the values listed for the given tag in the file's dynamic1808// section.1809func (f *File) DynValue(tag DynTag) ([]uint64, error) {1810	ds := f.SectionByType(SHT_DYNAMIC)1811	if ds == nil {1812		return nil, nil1813	}1814	d, err := ds.Data()1815	if err != nil {1816		return nil, err1817	}18181819	dynSize := 81820	if f.Class == ELFCLASS64 {1821		dynSize = 161822	}1823	if len(d)%dynSize != 0 {1824		return nil, errors.New("length of dynamic section is not a multiple of dynamic entry size")1825	}18261827	// Parse the .dynamic section as a string of bytes.1828	var vals []uint641829	for len(d) > 0 {1830		var t DynTag1831		var v uint641832		switch f.Class {1833		case ELFCLASS32:1834			t = DynTag(f.ByteOrder.Uint32(d[0:4]))1835			v = uint64(f.ByteOrder.Uint32(d[4:8]))1836			d = d[8:]1837		case ELFCLASS64:1838			t = DynTag(f.ByteOrder.Uint64(d[0:8]))1839			v = f.ByteOrder.Uint64(d[8:16])1840			d = d[16:]1841		}1842		if t == tag {1843			vals = append(vals, v)1844		}1845	}1846	return vals, nil1847}18481849type nobitsSectionReader struct{}18501851func (*nobitsSectionReader) ReadAt(p []byte, off int64) (n int, err error) {1852	return 0, errors.New("unexpected read from SHT_NOBITS section")1853}18541855// putUint writes a relocation to slice1856// at offset start of length length (4 or 8 bytes),1857// adding sym+addend to the existing value if readUint is true,1858// or just writing sym+addend if readUint is false.1859// If the write would extend beyond the end of slice, putUint does nothing.1860// If the addend is negative, putUint does nothing.1861// If the addition would overflow, putUint does nothing.1862func putUint(byteOrder binary.ByteOrder, slice []byte, start, length, sym uint64, addend int64, readUint bool) {1863	if start+length > uint64(len(slice)) || math.MaxUint64-start < length {1864		return1865	}1866	if addend < 0 {1867		return1868	}18691870	s := slice[start : start+length]18711872	switch length {1873	case 4:1874		ae := uint32(addend)1875		if readUint {1876			ae += byteOrder.Uint32(s)1877		}1878		byteOrder.PutUint32(s, uint32(sym)+ae)1879	case 8:1880		ae := uint64(addend)1881		if readUint {1882			ae += byteOrder.Uint64(s)1883		}1884		byteOrder.PutUint64(s, sym+ae)1885	default:1886		panic("can't happen")1887	}1888}

Code quality findings 81

Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
data := make([]byte, unsafe.Sizeof(hdr))
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
f.Type = Type(bo.Uint16(data[unsafe.Offsetof(hdr.Type):]))
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
f.Machine = Machine(bo.Uint16(data[unsafe.Offsetof(hdr.Machine):]))
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
f.Entry = uint64(bo.Uint32(data[unsafe.Offsetof(hdr.Entry):]))
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
if v := Version(bo.Uint32(data[unsafe.Offsetof(hdr.Version):])); v != f.Version {
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
phoff = int64(bo.Uint32(data[unsafe.Offsetof(hdr.Phoff):]))
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
phentsize = int(bo.Uint16(data[unsafe.Offsetof(hdr.Phentsize):]))
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
phnum = int(bo.Uint16(data[unsafe.Offsetof(hdr.Phnum):]))
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
shoff = int64(bo.Uint32(data[unsafe.Offsetof(hdr.Shoff):]))
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
shentsize = int(bo.Uint16(data[unsafe.Offsetof(hdr.Shentsize):]))
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
shnum = int(bo.Uint16(data[unsafe.Offsetof(hdr.Shnum):]))
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
shstrndx = int(bo.Uint16(data[unsafe.Offsetof(hdr.Shstrndx):]))
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
data := make([]byte, unsafe.Sizeof(hdr))
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
f.Type = Type(bo.Uint16(data[unsafe.Offsetof(hdr.Type):]))
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
f.Machine = Machine(bo.Uint16(data[unsafe.Offsetof(hdr.Machine):]))
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
f.Entry = bo.Uint64(data[unsafe.Offsetof(hdr.Entry):])
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
if v := Version(bo.Uint32(data[unsafe.Offsetof(hdr.Version):])); v != f.Version {
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
phoff = int64(bo.Uint64(data[unsafe.Offsetof(hdr.Phoff):]))
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
phentsize = int(bo.Uint16(data[unsafe.Offsetof(hdr.Phentsize):]))
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
phnum = int(bo.Uint16(data[unsafe.Offsetof(hdr.Phnum):]))
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
shoff = int64(bo.Uint64(data[unsafe.Offsetof(hdr.Shoff):]))
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
shentsize = int(bo.Uint16(data[unsafe.Offsetof(hdr.Shentsize):]))
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
shnum = int(bo.Uint16(data[unsafe.Offsetof(hdr.Shnum):]))
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
shstrndx = int(bo.Uint16(data[unsafe.Offsetof(hdr.Shstrndx):]))
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
Type: ProgType(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Type):])),
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
Flags: ProgFlag(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Flags):])),
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
Off: uint64(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Off):])),
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
Vaddr: uint64(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Vaddr):])),
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
Paddr: uint64(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Paddr):])),
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
Filesz: uint64(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Filesz):])),
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
Memsz: uint64(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Memsz):])),
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
Align: uint64(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Align):])),
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
Type: ProgType(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Type):])),
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
Flags: ProgFlag(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Flags):])),
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
Off: bo.Uint64(phdata[off+unsafe.Offsetof(ph.Off):]),
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
Vaddr: bo.Uint64(phdata[off+unsafe.Offsetof(ph.Vaddr):]),
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
Paddr: bo.Uint64(phdata[off+unsafe.Offsetof(ph.Paddr):]),
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
Filesz: bo.Uint64(phdata[off+unsafe.Offsetof(ph.Filesz):]),
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
Memsz: bo.Uint64(phdata[off+unsafe.Offsetof(ph.Memsz):]),
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
Align: bo.Uint64(phdata[off+unsafe.Offsetof(ph.Align):]),
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
names = append(names, bo.Uint32(shdata[off+unsafe.Offsetof(sh.Name):]))
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
Type: SectionType(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Type):])),
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
Flags: SectionFlag(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Flags):])),
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
Addr: uint64(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Addr):])),
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
Offset: uint64(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Off):])),
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
FileSize: uint64(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Size):])),
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
Link: bo.Uint32(shdata[off+unsafe.Offsetof(sh.Link):]),
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
Info: bo.Uint32(shdata[off+unsafe.Offsetof(sh.Info):]),
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
Addralign: uint64(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Addralign):])),
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
Entsize: uint64(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Entsize):])),
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
names = append(names, bo.Uint32(shdata[off+unsafe.Offsetof(sh.Name):]))
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
Type: SectionType(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Type):])),
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
Flags: SectionFlag(bo.Uint64(shdata[off+unsafe.Offsetof(sh.Flags):])),
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
Offset: bo.Uint64(shdata[off+unsafe.Offsetof(sh.Off):]),
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
FileSize: bo.Uint64(shdata[off+unsafe.Offsetof(sh.Size):]),
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
Addr: bo.Uint64(shdata[off+unsafe.Offsetof(sh.Addr):]),
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
Link: bo.Uint32(shdata[off+unsafe.Offsetof(sh.Link):]),
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
Info: bo.Uint32(shdata[off+unsafe.Offsetof(sh.Info):]),
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
Addralign: bo.Uint64(shdata[off+unsafe.Offsetof(sh.Addralign):]),
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
Entsize: bo.Uint64(shdata[off+unsafe.Offsetof(sh.Entsize):]),
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
chdata := make([]byte, unsafe.Sizeof(ch))
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
s.compressionType = CompressionType(bo.Uint32(chdata[unsafe.Offsetof(ch.Type):]))
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
s.Size = uint64(bo.Uint32(chdata[unsafe.Offsetof(ch.Size):]))
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
s.Addralign = uint64(bo.Uint32(chdata[unsafe.Offsetof(ch.Addralign):]))
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
s.compressionOffset = int64(unsafe.Sizeof(ch))
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
chdata := make([]byte, unsafe.Sizeof(ch))
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
s.compressionType = CompressionType(bo.Uint32(chdata[unsafe.Offsetof(ch.Type):]))
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
s.Size = bo.Uint64(chdata[unsafe.Offsetof(ch.Size):])
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
s.Addralign = bo.Uint64(chdata[unsafe.Offsetof(ch.Addralign):])
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
s.compressionOffset = int64(unsafe.Sizeof(ch))
Blank identifier discarding results; verify intentional ignoring of return values
warning correctness blank-identifier-discard
depName, _ = getString(str, int(vname))
Multiple appends without pre-allocation; use make() with capacity when size is known
info performance append-without-prealloc
names = append(names, bo.Uint32(shdata[off+unsafe.Offsetof(sh.Name):]))
Range over slice copies each element by value; use index or pointer receiver for large structs to avoid copies
info performance copy-large-struct
for i, s := range f.Sections {
Range over slice copies each element by value; use index or pointer receiver for large structs to avoid copies
info performance copy-large-struct
for i, s := range f.Sections {
Range over slice copies each element by value; use index or pointer receiver for large structs to avoid copies
info performance copy-large-struct
for i, s := range f.Sections {
Range over slice copies each element by value; use index or pointer receiver for large structs to avoid copies
info performance copy-large-struct
for i, s := range sym {
Multiple appends without pre-allocation; use make() with capacity when size is known
info performance append-without-prealloc
all = append(all, ImportedSymbol{Name: s.Name})
Error string starts with uppercase; per Go convention error strings should not be capitalized or end with punctuation
info maintainability error-string-format
return nil, errors.New("DynamicVersions: missing version table")
Multiple appends without pre-allocation; use make() with capacity when size is known
info performance append-without-prealloc
deps = append(deps, DynamicVersionDep{
Error string starts with uppercase; per Go convention error strings should not be capitalized or end with punctuation
info maintainability error-string-format
return nil, errors.New("DynamicVersionNeeds: missing version table")
Multiple appends without pre-allocation; use make() with capacity when size is known
info performance append-without-prealloc
all = append(all, s)

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.