github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/debug/elf/file.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 /* 6 Package elf implements access to ELF object files. 7 8 # Security 9 10 This package is not designed to be hardened against adversarial inputs, and is 11 outside the scope of https://go.dev/security/policy. In particular, only basic 12 validation is done when parsing object files. As such, care should be taken when 13 parsing untrusted inputs, as parsing malformed files may consume significant 14 resources, or cause panics. 15 */ 16 package elf 17 18 import ( 19 "bytes" 20 "compress/zlib" 21 "debug/dwarf" 22 "encoding/binary" 23 "errors" 24 "fmt" 25 "internal/saferio" 26 "internal/zstd" 27 "io" 28 "os" 29 "strings" 30 "unsafe" 31 ) 32 33 // TODO: error reporting detail 34 35 /* 36 * Internal ELF representation 37 */ 38 39 // A FileHeader represents an ELF file header. 40 type FileHeader struct { 41 Class Class 42 Data Data 43 Version Version 44 OSABI OSABI 45 ABIVersion uint8 46 ByteOrder binary.ByteOrder 47 Type Type 48 Machine Machine 49 Entry uint64 50 } 51 52 // A File represents an open ELF file. 53 type File struct { 54 FileHeader 55 Sections []*Section 56 Progs []*Prog 57 closer io.Closer 58 gnuNeed []verneed 59 gnuVersym []byte 60 } 61 62 // A SectionHeader represents a single ELF section header. 63 type SectionHeader struct { 64 Name string 65 Type SectionType 66 Flags SectionFlag 67 Addr uint64 68 Offset uint64 69 Size uint64 70 Link uint32 71 Info uint32 72 Addralign uint64 73 Entsize uint64 74 75 // FileSize is the size of this section in the file in bytes. 76 // If a section is compressed, FileSize is the size of the 77 // compressed data, while Size (above) is the size of the 78 // uncompressed data. 79 FileSize uint64 80 } 81 82 // A Section represents a single section in an ELF file. 83 type Section struct { 84 SectionHeader 85 86 // Embed ReaderAt for ReadAt method. 87 // Do not embed SectionReader directly 88 // to avoid having Read and Seek. 89 // If a client wants Read and Seek it must use 90 // Open() to avoid fighting over the seek offset 91 // with other clients. 92 // 93 // ReaderAt may be nil if the section is not easily available 94 // in a random-access form. For example, a compressed section 95 // may have a nil ReaderAt. 96 io.ReaderAt 97 sr *io.SectionReader 98 99 compressionType CompressionType 100 compressionOffset int64 101 } 102 103 // Data reads and returns the contents of the ELF section. 104 // Even if the section is stored compressed in the ELF file, 105 // Data returns uncompressed data. 106 // 107 // For an [SHT_NOBITS] section, Data always returns a non-nil error. 108 func (s *Section) Data() ([]byte, error) { 109 return saferio.ReadData(s.Open(), s.Size) 110 } 111 112 // stringTable reads and returns the string table given by the 113 // specified link value. 114 func (f *File) stringTable(link uint32) ([]byte, error) { 115 if link <= 0 || link >= uint32(len(f.Sections)) { 116 return nil, errors.New("section has invalid string table link") 117 } 118 return f.Sections[link].Data() 119 } 120 121 // Open returns a new ReadSeeker reading the ELF section. 122 // Even if the section is stored compressed in the ELF file, 123 // the ReadSeeker reads uncompressed data. 124 // 125 // For an [SHT_NOBITS] section, all calls to the opened reader 126 // will return a non-nil error. 127 func (s *Section) Open() io.ReadSeeker { 128 if s.Type == SHT_NOBITS { 129 return io.NewSectionReader(&nobitsSectionReader{}, 0, int64(s.Size)) 130 } 131 132 var zrd func(io.Reader) (io.ReadCloser, error) 133 if s.Flags&SHF_COMPRESSED == 0 { 134 135 if !strings.HasPrefix(s.Name, ".zdebug") { 136 return io.NewSectionReader(s.sr, 0, 1<<63-1) 137 } 138 139 b := make([]byte, 12) 140 n, _ := s.sr.ReadAt(b, 0) 141 if n != 12 || string(b[:4]) != "ZLIB" { 142 return io.NewSectionReader(s.sr, 0, 1<<63-1) 143 } 144 145 s.compressionOffset = 12 146 s.compressionType = COMPRESS_ZLIB 147 s.Size = binary.BigEndian.Uint64(b[4:12]) 148 zrd = zlib.NewReader 149 150 } else if s.Flags&SHF_ALLOC != 0 { 151 return errorReader{&FormatError{int64(s.Offset), 152 "SHF_COMPRESSED applies only to non-allocable sections", s.compressionType}} 153 } 154 155 switch s.compressionType { 156 case COMPRESS_ZLIB: 157 zrd = zlib.NewReader 158 case COMPRESS_ZSTD: 159 zrd = func(r io.Reader) (io.ReadCloser, error) { 160 return io.NopCloser(zstd.NewReader(r)), nil 161 } 162 } 163 164 if zrd == nil { 165 return errorReader{&FormatError{int64(s.Offset), "unknown compression type", s.compressionType}} 166 } 167 168 return &readSeekerFromReader{ 169 reset: func() (io.Reader, error) { 170 fr := io.NewSectionReader(s.sr, s.compressionOffset, int64(s.FileSize)-s.compressionOffset) 171 return zrd(fr) 172 }, 173 size: int64(s.Size), 174 } 175 } 176 177 // A ProgHeader represents a single ELF program header. 178 type ProgHeader struct { 179 Type ProgType 180 Flags ProgFlag 181 Off uint64 182 Vaddr uint64 183 Paddr uint64 184 Filesz uint64 185 Memsz uint64 186 Align uint64 187 } 188 189 // A Prog represents a single ELF program header in an ELF binary. 190 type Prog struct { 191 ProgHeader 192 193 // Embed ReaderAt for ReadAt method. 194 // Do not embed SectionReader directly 195 // to avoid having Read and Seek. 196 // If a client wants Read and Seek it must use 197 // Open() to avoid fighting over the seek offset 198 // with other clients. 199 io.ReaderAt 200 sr *io.SectionReader 201 } 202 203 // Open returns a new ReadSeeker reading the ELF program body. 204 func (p *Prog) Open() io.ReadSeeker { return io.NewSectionReader(p.sr, 0, 1<<63-1) } 205 206 // A Symbol represents an entry in an ELF symbol table section. 207 type Symbol struct { 208 Name string 209 Info, Other byte 210 Section SectionIndex 211 Value, Size uint64 212 213 // Version and Library are present only for the dynamic symbol 214 // table. 215 Version string 216 Library string 217 } 218 219 /* 220 * ELF reader 221 */ 222 223 type FormatError struct { 224 off int64 225 msg string 226 val any 227 } 228 229 func (e *FormatError) Error() string { 230 msg := e.msg 231 if e.val != nil { 232 msg += fmt.Sprintf(" '%v' ", e.val) 233 } 234 msg += fmt.Sprintf("in record at byte %#x", e.off) 235 return msg 236 } 237 238 // Open opens the named file using [os.Open] and prepares it for use as an ELF binary. 239 func Open(name string) (*File, error) { 240 f, err := os.Open(name) 241 if err != nil { 242 return nil, err 243 } 244 ff, err := NewFile(f) 245 if err != nil { 246 f.Close() 247 return nil, err 248 } 249 ff.closer = f 250 return ff, nil 251 } 252 253 // Close closes the [File]. 254 // If the [File] was created using [NewFile] directly instead of [Open], 255 // Close has no effect. 256 func (f *File) Close() error { 257 var err error 258 if f.closer != nil { 259 err = f.closer.Close() 260 f.closer = nil 261 } 262 return err 263 } 264 265 // SectionByType returns the first section in f with the 266 // given type, or nil if there is no such section. 267 func (f *File) SectionByType(typ SectionType) *Section { 268 for _, s := range f.Sections { 269 if s.Type == typ { 270 return s 271 } 272 } 273 return nil 274 } 275 276 // NewFile creates a new [File] for accessing an ELF binary in an underlying reader. 277 // The ELF binary is expected to start at position 0 in the ReaderAt. 278 func NewFile(r io.ReaderAt) (*File, error) { 279 sr := io.NewSectionReader(r, 0, 1<<63-1) 280 // Read and decode ELF identifier 281 var ident [16]uint8 282 if _, err := r.ReadAt(ident[0:], 0); err != nil { 283 return nil, err 284 } 285 if ident[0] != '\x7f' || ident[1] != 'E' || ident[2] != 'L' || ident[3] != 'F' { 286 return nil, &FormatError{0, "bad magic number", ident[0:4]} 287 } 288 289 f := new(File) 290 f.Class = Class(ident[EI_CLASS]) 291 switch f.Class { 292 case ELFCLASS32: 293 case ELFCLASS64: 294 // ok 295 default: 296 return nil, &FormatError{0, "unknown ELF class", f.Class} 297 } 298 299 f.Data = Data(ident[EI_DATA]) 300 var bo binary.ByteOrder 301 switch f.Data { 302 case ELFDATA2LSB: 303 bo = binary.LittleEndian 304 case ELFDATA2MSB: 305 bo = binary.BigEndian 306 default: 307 return nil, &FormatError{0, "unknown ELF data encoding", f.Data} 308 } 309 f.ByteOrder = bo 310 311 f.Version = Version(ident[EI_VERSION]) 312 if f.Version != EV_CURRENT { 313 return nil, &FormatError{0, "unknown ELF version", f.Version} 314 } 315 316 f.OSABI = OSABI(ident[EI_OSABI]) 317 f.ABIVersion = ident[EI_ABIVERSION] 318 319 // Read ELF file header 320 var phoff int64 321 var phentsize, phnum int 322 var shoff int64 323 var shentsize, shnum, shstrndx int 324 switch f.Class { 325 case ELFCLASS32: 326 var hdr Header32 327 data := make([]byte, unsafe.Sizeof(hdr)) 328 if _, err := sr.ReadAt(data, 0); err != nil { 329 return nil, err 330 } 331 f.Type = Type(bo.Uint16(data[unsafe.Offsetof(hdr.Type):])) 332 f.Machine = Machine(bo.Uint16(data[unsafe.Offsetof(hdr.Machine):])) 333 f.Entry = uint64(bo.Uint32(data[unsafe.Offsetof(hdr.Entry):])) 334 if v := Version(bo.Uint32(data[unsafe.Offsetof(hdr.Version):])); v != f.Version { 335 return nil, &FormatError{0, "mismatched ELF version", v} 336 } 337 phoff = int64(bo.Uint32(data[unsafe.Offsetof(hdr.Phoff):])) 338 phentsize = int(bo.Uint16(data[unsafe.Offsetof(hdr.Phentsize):])) 339 phnum = int(bo.Uint16(data[unsafe.Offsetof(hdr.Phnum):])) 340 shoff = int64(bo.Uint32(data[unsafe.Offsetof(hdr.Shoff):])) 341 shentsize = int(bo.Uint16(data[unsafe.Offsetof(hdr.Shentsize):])) 342 shnum = int(bo.Uint16(data[unsafe.Offsetof(hdr.Shnum):])) 343 shstrndx = int(bo.Uint16(data[unsafe.Offsetof(hdr.Shstrndx):])) 344 case ELFCLASS64: 345 var hdr Header64 346 data := make([]byte, unsafe.Sizeof(hdr)) 347 if _, err := sr.ReadAt(data, 0); err != nil { 348 return nil, err 349 } 350 f.Type = Type(bo.Uint16(data[unsafe.Offsetof(hdr.Type):])) 351 f.Machine = Machine(bo.Uint16(data[unsafe.Offsetof(hdr.Machine):])) 352 f.Entry = bo.Uint64(data[unsafe.Offsetof(hdr.Entry):]) 353 if v := Version(bo.Uint32(data[unsafe.Offsetof(hdr.Version):])); v != f.Version { 354 return nil, &FormatError{0, "mismatched ELF version", v} 355 } 356 phoff = int64(bo.Uint64(data[unsafe.Offsetof(hdr.Phoff):])) 357 phentsize = int(bo.Uint16(data[unsafe.Offsetof(hdr.Phentsize):])) 358 phnum = int(bo.Uint16(data[unsafe.Offsetof(hdr.Phnum):])) 359 shoff = int64(bo.Uint64(data[unsafe.Offsetof(hdr.Shoff):])) 360 shentsize = int(bo.Uint16(data[unsafe.Offsetof(hdr.Shentsize):])) 361 shnum = int(bo.Uint16(data[unsafe.Offsetof(hdr.Shnum):])) 362 shstrndx = int(bo.Uint16(data[unsafe.Offsetof(hdr.Shstrndx):])) 363 } 364 365 if shoff < 0 { 366 return nil, &FormatError{0, "invalid shoff", shoff} 367 } 368 if phoff < 0 { 369 return nil, &FormatError{0, "invalid phoff", phoff} 370 } 371 372 if shoff == 0 && shnum != 0 { 373 return nil, &FormatError{0, "invalid ELF shnum for shoff=0", shnum} 374 } 375 376 if shnum > 0 && shstrndx >= shnum { 377 return nil, &FormatError{0, "invalid ELF shstrndx", shstrndx} 378 } 379 380 var wantPhentsize, wantShentsize int 381 switch f.Class { 382 case ELFCLASS32: 383 wantPhentsize = 8 * 4 384 wantShentsize = 10 * 4 385 case ELFCLASS64: 386 wantPhentsize = 2*4 + 6*8 387 wantShentsize = 4*4 + 6*8 388 } 389 if phnum > 0 && phentsize < wantPhentsize { 390 return nil, &FormatError{0, "invalid ELF phentsize", phentsize} 391 } 392 393 // Read program headers 394 f.Progs = make([]*Prog, phnum) 395 phdata, err := saferio.ReadDataAt(sr, uint64(phnum)*uint64(phentsize), phoff) 396 if err != nil { 397 return nil, err 398 } 399 for i := 0; i < phnum; i++ { 400 off := uintptr(i) * uintptr(phentsize) 401 p := new(Prog) 402 switch f.Class { 403 case ELFCLASS32: 404 var ph Prog32 405 p.ProgHeader = ProgHeader{ 406 Type: ProgType(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Type):])), 407 Flags: ProgFlag(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Flags):])), 408 Off: uint64(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Off):])), 409 Vaddr: uint64(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Vaddr):])), 410 Paddr: uint64(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Paddr):])), 411 Filesz: uint64(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Filesz):])), 412 Memsz: uint64(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Memsz):])), 413 Align: uint64(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Align):])), 414 } 415 case ELFCLASS64: 416 var ph Prog64 417 p.ProgHeader = ProgHeader{ 418 Type: ProgType(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Type):])), 419 Flags: ProgFlag(bo.Uint32(phdata[off+unsafe.Offsetof(ph.Flags):])), 420 Off: bo.Uint64(phdata[off+unsafe.Offsetof(ph.Off):]), 421 Vaddr: bo.Uint64(phdata[off+unsafe.Offsetof(ph.Vaddr):]), 422 Paddr: bo.Uint64(phdata[off+unsafe.Offsetof(ph.Paddr):]), 423 Filesz: bo.Uint64(phdata[off+unsafe.Offsetof(ph.Filesz):]), 424 Memsz: bo.Uint64(phdata[off+unsafe.Offsetof(ph.Memsz):]), 425 Align: bo.Uint64(phdata[off+unsafe.Offsetof(ph.Align):]), 426 } 427 } 428 if int64(p.Off) < 0 { 429 return nil, &FormatError{phoff + int64(off), "invalid program header offset", p.Off} 430 } 431 if int64(p.Filesz) < 0 { 432 return nil, &FormatError{phoff + int64(off), "invalid program header file size", p.Filesz} 433 } 434 p.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz)) 435 p.ReaderAt = p.sr 436 f.Progs[i] = p 437 } 438 439 // If the number of sections is greater than or equal to SHN_LORESERVE 440 // (0xff00), shnum has the value zero and the actual number of section 441 // header table entries is contained in the sh_size field of the section 442 // header at index 0. 443 if shoff > 0 && shnum == 0 { 444 var typ, link uint32 445 sr.Seek(shoff, io.SeekStart) 446 switch f.Class { 447 case ELFCLASS32: 448 sh := new(Section32) 449 if err := binary.Read(sr, bo, sh); err != nil { 450 return nil, err 451 } 452 shnum = int(sh.Size) 453 typ = sh.Type 454 link = sh.Link 455 case ELFCLASS64: 456 sh := new(Section64) 457 if err := binary.Read(sr, bo, sh); err != nil { 458 return nil, err 459 } 460 shnum = int(sh.Size) 461 typ = sh.Type 462 link = sh.Link 463 } 464 if SectionType(typ) != SHT_NULL { 465 return nil, &FormatError{shoff, "invalid type of the initial section", SectionType(typ)} 466 } 467 468 if shnum < int(SHN_LORESERVE) { 469 return nil, &FormatError{shoff, "invalid ELF shnum contained in sh_size", shnum} 470 } 471 472 // If the section name string table section index is greater than or 473 // equal to SHN_LORESERVE (0xff00), this member has the value 474 // SHN_XINDEX (0xffff) and the actual index of the section name 475 // string table section is contained in the sh_link field of the 476 // section header at index 0. 477 if shstrndx == int(SHN_XINDEX) { 478 shstrndx = int(link) 479 if shstrndx < int(SHN_LORESERVE) { 480 return nil, &FormatError{shoff, "invalid ELF shstrndx contained in sh_link", shstrndx} 481 } 482 } 483 } 484 485 if shnum > 0 && shentsize < wantShentsize { 486 return nil, &FormatError{0, "invalid ELF shentsize", shentsize} 487 } 488 489 // Read section headers 490 c := saferio.SliceCap[Section](uint64(shnum)) 491 if c < 0 { 492 return nil, &FormatError{0, "too many sections", shnum} 493 } 494 f.Sections = make([]*Section, 0, c) 495 names := make([]uint32, 0, c) 496 shdata, err := saferio.ReadDataAt(sr, uint64(shnum)*uint64(shentsize), shoff) 497 if err != nil { 498 return nil, err 499 } 500 for i := 0; i < shnum; i++ { 501 off := uintptr(i) * uintptr(shentsize) 502 s := new(Section) 503 switch f.Class { 504 case ELFCLASS32: 505 var sh Section32 506 names = append(names, bo.Uint32(shdata[off+unsafe.Offsetof(sh.Name):])) 507 s.SectionHeader = SectionHeader{ 508 Type: SectionType(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Type):])), 509 Flags: SectionFlag(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Flags):])), 510 Addr: uint64(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Addr):])), 511 Offset: uint64(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Off):])), 512 FileSize: uint64(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Size):])), 513 Link: bo.Uint32(shdata[off+unsafe.Offsetof(sh.Link):]), 514 Info: bo.Uint32(shdata[off+unsafe.Offsetof(sh.Info):]), 515 Addralign: uint64(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Addralign):])), 516 Entsize: uint64(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Entsize):])), 517 } 518 case ELFCLASS64: 519 var sh Section64 520 names = append(names, bo.Uint32(shdata[off+unsafe.Offsetof(sh.Name):])) 521 s.SectionHeader = SectionHeader{ 522 Type: SectionType(bo.Uint32(shdata[off+unsafe.Offsetof(sh.Type):])), 523 Flags: SectionFlag(bo.Uint64(shdata[off+unsafe.Offsetof(sh.Flags):])), 524 Offset: bo.Uint64(shdata[off+unsafe.Offsetof(sh.Off):]), 525 FileSize: bo.Uint64(shdata[off+unsafe.Offsetof(sh.Size):]), 526 Addr: bo.Uint64(shdata[off+unsafe.Offsetof(sh.Addr):]), 527 Link: bo.Uint32(shdata[off+unsafe.Offsetof(sh.Link):]), 528 Info: bo.Uint32(shdata[off+unsafe.Offsetof(sh.Info):]), 529 Addralign: bo.Uint64(shdata[off+unsafe.Offsetof(sh.Addralign):]), 530 Entsize: bo.Uint64(shdata[off+unsafe.Offsetof(sh.Entsize):]), 531 } 532 } 533 if int64(s.Offset) < 0 { 534 return nil, &FormatError{shoff + int64(off), "invalid section offset", int64(s.Offset)} 535 } 536 if int64(s.FileSize) < 0 { 537 return nil, &FormatError{shoff + int64(off), "invalid section size", int64(s.FileSize)} 538 } 539 s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.FileSize)) 540 541 if s.Flags&SHF_COMPRESSED == 0 { 542 s.ReaderAt = s.sr 543 s.Size = s.FileSize 544 } else { 545 // Read the compression header. 546 switch f.Class { 547 case ELFCLASS32: 548 var ch Chdr32 549 chdata := make([]byte, unsafe.Sizeof(ch)) 550 if _, err := s.sr.ReadAt(chdata, 0); err != nil { 551 return nil, err 552 } 553 s.compressionType = CompressionType(bo.Uint32(chdata[unsafe.Offsetof(ch.Type):])) 554 s.Size = uint64(bo.Uint32(chdata[unsafe.Offsetof(ch.Size):])) 555 s.Addralign = uint64(bo.Uint32(chdata[unsafe.Offsetof(ch.Addralign):])) 556 s.compressionOffset = int64(unsafe.Sizeof(ch)) 557 case ELFCLASS64: 558 var ch Chdr64 559 chdata := make([]byte, unsafe.Sizeof(ch)) 560 if _, err := s.sr.ReadAt(chdata, 0); err != nil { 561 return nil, err 562 } 563 s.compressionType = CompressionType(bo.Uint32(chdata[unsafe.Offsetof(ch.Type):])) 564 s.Size = bo.Uint64(chdata[unsafe.Offsetof(ch.Size):]) 565 s.Addralign = bo.Uint64(chdata[unsafe.Offsetof(ch.Addralign):]) 566 s.compressionOffset = int64(unsafe.Sizeof(ch)) 567 } 568 } 569 570 f.Sections = append(f.Sections, s) 571 } 572 573 if len(f.Sections) == 0 { 574 return f, nil 575 } 576 577 // Load section header string table. 578 if shstrndx == 0 { 579 // If the file has no section name string table, 580 // shstrndx holds the value SHN_UNDEF (0). 581 return f, nil 582 } 583 shstr := f.Sections[shstrndx] 584 if shstr.Type != SHT_STRTAB { 585 return nil, &FormatError{shoff + int64(shstrndx*shentsize), "invalid ELF section name string table type", shstr.Type} 586 } 587 shstrtab, err := shstr.Data() 588 if err != nil { 589 return nil, err 590 } 591 for i, s := range f.Sections { 592 var ok bool 593 s.Name, ok = getString(shstrtab, int(names[i])) 594 if !ok { 595 return nil, &FormatError{shoff + int64(i*shentsize), "bad section name index", names[i]} 596 } 597 } 598 599 return f, nil 600 } 601 602 // getSymbols returns a slice of Symbols from parsing the symbol table 603 // with the given type, along with the associated string table. 604 func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, error) { 605 switch f.Class { 606 case ELFCLASS64: 607 return f.getSymbols64(typ) 608 609 case ELFCLASS32: 610 return f.getSymbols32(typ) 611 } 612 613 return nil, nil, errors.New("not implemented") 614 } 615 616 // ErrNoSymbols is returned by [File.Symbols] and [File.DynamicSymbols] 617 // if there is no such section in the File. 618 var ErrNoSymbols = errors.New("no symbol section") 619 620 func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) { 621 symtabSection := f.SectionByType(typ) 622 if symtabSection == nil { 623 return nil, nil, ErrNoSymbols 624 } 625 626 data, err := symtabSection.Data() 627 if err != nil { 628 return nil, nil, fmt.Errorf("cannot load symbol section: %w", err) 629 } 630 if len(data) == 0 { 631 return nil, nil, errors.New("symbol section is empty") 632 } 633 if len(data)%Sym32Size != 0 { 634 return nil, nil, errors.New("length of symbol section is not a multiple of SymSize") 635 } 636 637 strdata, err := f.stringTable(symtabSection.Link) 638 if err != nil { 639 return nil, nil, fmt.Errorf("cannot load string table section: %w", err) 640 } 641 642 // The first entry is all zeros. 643 data = data[Sym32Size:] 644 645 symbols := make([]Symbol, len(data)/Sym32Size) 646 647 i := 0 648 var sym Sym32 649 for len(data) > 0 { 650 sym.Name = f.ByteOrder.Uint32(data[0:4]) 651 sym.Value = f.ByteOrder.Uint32(data[4:8]) 652 sym.Size = f.ByteOrder.Uint32(data[8:12]) 653 sym.Info = data[12] 654 sym.Other = data[13] 655 sym.Shndx = f.ByteOrder.Uint16(data[14:16]) 656 str, _ := getString(strdata, int(sym.Name)) 657 symbols[i].Name = str 658 symbols[i].Info = sym.Info 659 symbols[i].Other = sym.Other 660 symbols[i].Section = SectionIndex(sym.Shndx) 661 symbols[i].Value = uint64(sym.Value) 662 symbols[i].Size = uint64(sym.Size) 663 i++ 664 data = data[Sym32Size:] 665 } 666 667 return symbols, strdata, nil 668 } 669 670 func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) { 671 symtabSection := f.SectionByType(typ) 672 if symtabSection == nil { 673 return nil, nil, ErrNoSymbols 674 } 675 676 data, err := symtabSection.Data() 677 if err != nil { 678 return nil, nil, fmt.Errorf("cannot load symbol section: %w", err) 679 } 680 if len(data)%Sym64Size != 0 { 681 return nil, nil, errors.New("length of symbol section is not a multiple of Sym64Size") 682 } 683 684 strdata, err := f.stringTable(symtabSection.Link) 685 if err != nil { 686 return nil, nil, fmt.Errorf("cannot load string table section: %w", err) 687 } 688 689 // The first entry is all zeros. 690 data = data[Sym64Size:] 691 692 symbols := make([]Symbol, len(data)/Sym64Size) 693 694 i := 0 695 var sym Sym64 696 for len(data) > 0 { 697 sym.Name = f.ByteOrder.Uint32(data[0:4]) 698 sym.Info = data[4] 699 sym.Other = data[5] 700 sym.Shndx = f.ByteOrder.Uint16(data[6:8]) 701 sym.Value = f.ByteOrder.Uint64(data[8:16]) 702 sym.Size = f.ByteOrder.Uint64(data[16:24]) 703 str, _ := getString(strdata, int(sym.Name)) 704 symbols[i].Name = str 705 symbols[i].Info = sym.Info 706 symbols[i].Other = sym.Other 707 symbols[i].Section = SectionIndex(sym.Shndx) 708 symbols[i].Value = sym.Value 709 symbols[i].Size = sym.Size 710 i++ 711 data = data[Sym64Size:] 712 } 713 714 return symbols, strdata, nil 715 } 716 717 // getString extracts a string from an ELF string table. 718 func getString(section []byte, start int) (string, bool) { 719 if start < 0 || start >= len(section) { 720 return "", false 721 } 722 723 for end := start; end < len(section); end++ { 724 if section[end] == 0 { 725 return string(section[start:end]), true 726 } 727 } 728 return "", false 729 } 730 731 // Section returns a section with the given name, or nil if no such 732 // section exists. 733 func (f *File) Section(name string) *Section { 734 for _, s := range f.Sections { 735 if s.Name == name { 736 return s 737 } 738 } 739 return nil 740 } 741 742 // applyRelocations applies relocations to dst. rels is a relocations section 743 // in REL or RELA format. 744 func (f *File) applyRelocations(dst []byte, rels []byte) error { 745 switch { 746 case f.Class == ELFCLASS64 && f.Machine == EM_X86_64: 747 return f.applyRelocationsAMD64(dst, rels) 748 case f.Class == ELFCLASS32 && f.Machine == EM_386: 749 return f.applyRelocations386(dst, rels) 750 case f.Class == ELFCLASS32 && f.Machine == EM_ARM: 751 return f.applyRelocationsARM(dst, rels) 752 case f.Class == ELFCLASS64 && f.Machine == EM_AARCH64: 753 return f.applyRelocationsARM64(dst, rels) 754 case f.Class == ELFCLASS32 && f.Machine == EM_PPC: 755 return f.applyRelocationsPPC(dst, rels) 756 case f.Class == ELFCLASS64 && f.Machine == EM_PPC64: 757 return f.applyRelocationsPPC64(dst, rels) 758 case f.Class == ELFCLASS32 && f.Machine == EM_MIPS: 759 return f.applyRelocationsMIPS(dst, rels) 760 case f.Class == ELFCLASS64 && f.Machine == EM_MIPS: 761 return f.applyRelocationsMIPS64(dst, rels) 762 case f.Class == ELFCLASS64 && f.Machine == EM_LOONGARCH: 763 return f.applyRelocationsLOONG64(dst, rels) 764 case f.Class == ELFCLASS64 && f.Machine == EM_RISCV: 765 return f.applyRelocationsRISCV64(dst, rels) 766 case f.Class == ELFCLASS64 && f.Machine == EM_S390: 767 return f.applyRelocationss390x(dst, rels) 768 case f.Class == ELFCLASS64 && f.Machine == EM_SPARCV9: 769 return f.applyRelocationsSPARC64(dst, rels) 770 default: 771 return errors.New("applyRelocations: not implemented") 772 } 773 } 774 775 // canApplyRelocation reports whether we should try to apply a 776 // relocation to a DWARF data section, given a pointer to the symbol 777 // targeted by the relocation. 778 // Most relocations in DWARF data tend to be section-relative, but 779 // some target non-section symbols (for example, low_PC attrs on 780 // subprogram or compilation unit DIEs that target function symbols). 781 func canApplyRelocation(sym *Symbol) bool { 782 return sym.Section != SHN_UNDEF && sym.Section < SHN_LORESERVE 783 } 784 785 func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error { 786 // 24 is the size of Rela64. 787 if len(rels)%24 != 0 { 788 return errors.New("length of relocation section is not a multiple of 24") 789 } 790 791 symbols, _, err := f.getSymbols(SHT_SYMTAB) 792 if err != nil { 793 return err 794 } 795 796 b := bytes.NewReader(rels) 797 var rela Rela64 798 799 for b.Len() > 0 { 800 binary.Read(b, f.ByteOrder, &rela) 801 symNo := rela.Info >> 32 802 t := R_X86_64(rela.Info & 0xffff) 803 804 if symNo == 0 || symNo > uint64(len(symbols)) { 805 continue 806 } 807 sym := &symbols[symNo-1] 808 if !canApplyRelocation(sym) { 809 continue 810 } 811 812 // There are relocations, so this must be a normal 813 // object file. The code below handles only basic relocations 814 // of the form S + A (symbol plus addend). 815 816 switch t { 817 case R_X86_64_64: 818 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 819 continue 820 } 821 val64 := sym.Value + uint64(rela.Addend) 822 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64) 823 case R_X86_64_32: 824 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 825 continue 826 } 827 val32 := uint32(sym.Value) + uint32(rela.Addend) 828 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32) 829 } 830 } 831 832 return nil 833 } 834 835 func (f *File) applyRelocations386(dst []byte, rels []byte) error { 836 // 8 is the size of Rel32. 837 if len(rels)%8 != 0 { 838 return errors.New("length of relocation section is not a multiple of 8") 839 } 840 841 symbols, _, err := f.getSymbols(SHT_SYMTAB) 842 if err != nil { 843 return err 844 } 845 846 b := bytes.NewReader(rels) 847 var rel Rel32 848 849 for b.Len() > 0 { 850 binary.Read(b, f.ByteOrder, &rel) 851 symNo := rel.Info >> 8 852 t := R_386(rel.Info & 0xff) 853 854 if symNo == 0 || symNo > uint32(len(symbols)) { 855 continue 856 } 857 sym := &symbols[symNo-1] 858 859 if t == R_386_32 { 860 if rel.Off+4 >= uint32(len(dst)) { 861 continue 862 } 863 val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4]) 864 val += uint32(sym.Value) 865 f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val) 866 } 867 } 868 869 return nil 870 } 871 872 func (f *File) applyRelocationsARM(dst []byte, rels []byte) error { 873 // 8 is the size of Rel32. 874 if len(rels)%8 != 0 { 875 return errors.New("length of relocation section is not a multiple of 8") 876 } 877 878 symbols, _, err := f.getSymbols(SHT_SYMTAB) 879 if err != nil { 880 return err 881 } 882 883 b := bytes.NewReader(rels) 884 var rel Rel32 885 886 for b.Len() > 0 { 887 binary.Read(b, f.ByteOrder, &rel) 888 symNo := rel.Info >> 8 889 t := R_ARM(rel.Info & 0xff) 890 891 if symNo == 0 || symNo > uint32(len(symbols)) { 892 continue 893 } 894 sym := &symbols[symNo-1] 895 896 switch t { 897 case R_ARM_ABS32: 898 if rel.Off+4 >= uint32(len(dst)) { 899 continue 900 } 901 val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4]) 902 val += uint32(sym.Value) 903 f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val) 904 } 905 } 906 907 return nil 908 } 909 910 func (f *File) applyRelocationsARM64(dst []byte, rels []byte) error { 911 // 24 is the size of Rela64. 912 if len(rels)%24 != 0 { 913 return errors.New("length of relocation section is not a multiple of 24") 914 } 915 916 symbols, _, err := f.getSymbols(SHT_SYMTAB) 917 if err != nil { 918 return err 919 } 920 921 b := bytes.NewReader(rels) 922 var rela Rela64 923 924 for b.Len() > 0 { 925 binary.Read(b, f.ByteOrder, &rela) 926 symNo := rela.Info >> 32 927 t := R_AARCH64(rela.Info & 0xffff) 928 929 if symNo == 0 || symNo > uint64(len(symbols)) { 930 continue 931 } 932 sym := &symbols[symNo-1] 933 if !canApplyRelocation(sym) { 934 continue 935 } 936 937 // There are relocations, so this must be a normal 938 // object file. The code below handles only basic relocations 939 // of the form S + A (symbol plus addend). 940 941 switch t { 942 case R_AARCH64_ABS64: 943 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 944 continue 945 } 946 val64 := sym.Value + uint64(rela.Addend) 947 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64) 948 case R_AARCH64_ABS32: 949 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 950 continue 951 } 952 val32 := uint32(sym.Value) + uint32(rela.Addend) 953 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32) 954 } 955 } 956 957 return nil 958 } 959 960 func (f *File) applyRelocationsPPC(dst []byte, rels []byte) error { 961 // 12 is the size of Rela32. 962 if len(rels)%12 != 0 { 963 return errors.New("length of relocation section is not a multiple of 12") 964 } 965 966 symbols, _, err := f.getSymbols(SHT_SYMTAB) 967 if err != nil { 968 return err 969 } 970 971 b := bytes.NewReader(rels) 972 var rela Rela32 973 974 for b.Len() > 0 { 975 binary.Read(b, f.ByteOrder, &rela) 976 symNo := rela.Info >> 8 977 t := R_PPC(rela.Info & 0xff) 978 979 if symNo == 0 || symNo > uint32(len(symbols)) { 980 continue 981 } 982 sym := &symbols[symNo-1] 983 if !canApplyRelocation(sym) { 984 continue 985 } 986 987 switch t { 988 case R_PPC_ADDR32: 989 if rela.Off+4 >= uint32(len(dst)) || rela.Addend < 0 { 990 continue 991 } 992 val32 := uint32(sym.Value) + uint32(rela.Addend) 993 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32) 994 } 995 } 996 997 return nil 998 } 999 1000 func (f *File) applyRelocationsPPC64(dst []byte, rels []byte) error { 1001 // 24 is the size of Rela64. 1002 if len(rels)%24 != 0 { 1003 return errors.New("length of relocation section is not a multiple of 24") 1004 } 1005 1006 symbols, _, err := f.getSymbols(SHT_SYMTAB) 1007 if err != nil { 1008 return err 1009 } 1010 1011 b := bytes.NewReader(rels) 1012 var rela Rela64 1013 1014 for b.Len() > 0 { 1015 binary.Read(b, f.ByteOrder, &rela) 1016 symNo := rela.Info >> 32 1017 t := R_PPC64(rela.Info & 0xffff) 1018 1019 if symNo == 0 || symNo > uint64(len(symbols)) { 1020 continue 1021 } 1022 sym := &symbols[symNo-1] 1023 if !canApplyRelocation(sym) { 1024 continue 1025 } 1026 1027 switch t { 1028 case R_PPC64_ADDR64: 1029 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 1030 continue 1031 } 1032 val64 := sym.Value + uint64(rela.Addend) 1033 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64) 1034 case R_PPC64_ADDR32: 1035 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 1036 continue 1037 } 1038 val32 := uint32(sym.Value) + uint32(rela.Addend) 1039 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32) 1040 } 1041 } 1042 1043 return nil 1044 } 1045 1046 func (f *File) applyRelocationsMIPS(dst []byte, rels []byte) error { 1047 // 8 is the size of Rel32. 1048 if len(rels)%8 != 0 { 1049 return errors.New("length of relocation section is not a multiple of 8") 1050 } 1051 1052 symbols, _, err := f.getSymbols(SHT_SYMTAB) 1053 if err != nil { 1054 return err 1055 } 1056 1057 b := bytes.NewReader(rels) 1058 var rel Rel32 1059 1060 for b.Len() > 0 { 1061 binary.Read(b, f.ByteOrder, &rel) 1062 symNo := rel.Info >> 8 1063 t := R_MIPS(rel.Info & 0xff) 1064 1065 if symNo == 0 || symNo > uint32(len(symbols)) { 1066 continue 1067 } 1068 sym := &symbols[symNo-1] 1069 1070 switch t { 1071 case R_MIPS_32: 1072 if rel.Off+4 >= uint32(len(dst)) { 1073 continue 1074 } 1075 val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4]) 1076 val += uint32(sym.Value) 1077 f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val) 1078 } 1079 } 1080 1081 return nil 1082 } 1083 1084 func (f *File) applyRelocationsMIPS64(dst []byte, rels []byte) error { 1085 // 24 is the size of Rela64. 1086 if len(rels)%24 != 0 { 1087 return errors.New("length of relocation section is not a multiple of 24") 1088 } 1089 1090 symbols, _, err := f.getSymbols(SHT_SYMTAB) 1091 if err != nil { 1092 return err 1093 } 1094 1095 b := bytes.NewReader(rels) 1096 var rela Rela64 1097 1098 for b.Len() > 0 { 1099 binary.Read(b, f.ByteOrder, &rela) 1100 var symNo uint64 1101 var t R_MIPS 1102 if f.ByteOrder == binary.BigEndian { 1103 symNo = rela.Info >> 32 1104 t = R_MIPS(rela.Info & 0xff) 1105 } else { 1106 symNo = rela.Info & 0xffffffff 1107 t = R_MIPS(rela.Info >> 56) 1108 } 1109 1110 if symNo == 0 || symNo > uint64(len(symbols)) { 1111 continue 1112 } 1113 sym := &symbols[symNo-1] 1114 if !canApplyRelocation(sym) { 1115 continue 1116 } 1117 1118 switch t { 1119 case R_MIPS_64: 1120 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 1121 continue 1122 } 1123 val64 := sym.Value + uint64(rela.Addend) 1124 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64) 1125 case R_MIPS_32: 1126 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 1127 continue 1128 } 1129 val32 := uint32(sym.Value) + uint32(rela.Addend) 1130 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32) 1131 } 1132 } 1133 1134 return nil 1135 } 1136 1137 func (f *File) applyRelocationsLOONG64(dst []byte, rels []byte) error { 1138 // 24 is the size of Rela64. 1139 if len(rels)%24 != 0 { 1140 return errors.New("length of relocation section is not a multiple of 24") 1141 } 1142 1143 symbols, _, err := f.getSymbols(SHT_SYMTAB) 1144 if err != nil { 1145 return err 1146 } 1147 1148 b := bytes.NewReader(rels) 1149 var rela Rela64 1150 1151 for b.Len() > 0 { 1152 binary.Read(b, f.ByteOrder, &rela) 1153 var symNo uint64 1154 var t R_LARCH 1155 symNo = rela.Info >> 32 1156 t = R_LARCH(rela.Info & 0xffff) 1157 1158 if symNo == 0 || symNo > uint64(len(symbols)) { 1159 continue 1160 } 1161 sym := &symbols[symNo-1] 1162 if !canApplyRelocation(sym) { 1163 continue 1164 } 1165 1166 switch t { 1167 case R_LARCH_64: 1168 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 1169 continue 1170 } 1171 val64 := sym.Value + uint64(rela.Addend) 1172 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64) 1173 case R_LARCH_32: 1174 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 1175 continue 1176 } 1177 val32 := uint32(sym.Value) + uint32(rela.Addend) 1178 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32) 1179 } 1180 } 1181 1182 return nil 1183 } 1184 1185 func (f *File) applyRelocationsRISCV64(dst []byte, rels []byte) error { 1186 // 24 is the size of Rela64. 1187 if len(rels)%24 != 0 { 1188 return errors.New("length of relocation section is not a multiple of 24") 1189 } 1190 1191 symbols, _, err := f.getSymbols(SHT_SYMTAB) 1192 if err != nil { 1193 return err 1194 } 1195 1196 b := bytes.NewReader(rels) 1197 var rela Rela64 1198 1199 for b.Len() > 0 { 1200 binary.Read(b, f.ByteOrder, &rela) 1201 symNo := rela.Info >> 32 1202 t := R_RISCV(rela.Info & 0xffff) 1203 1204 if symNo == 0 || symNo > uint64(len(symbols)) { 1205 continue 1206 } 1207 sym := &symbols[symNo-1] 1208 if !canApplyRelocation(sym) { 1209 continue 1210 } 1211 1212 switch t { 1213 case R_RISCV_64: 1214 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 1215 continue 1216 } 1217 val64 := sym.Value + uint64(rela.Addend) 1218 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64) 1219 case R_RISCV_32: 1220 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 1221 continue 1222 } 1223 val32 := uint32(sym.Value) + uint32(rela.Addend) 1224 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32) 1225 } 1226 } 1227 1228 return nil 1229 } 1230 1231 func (f *File) applyRelocationss390x(dst []byte, rels []byte) error { 1232 // 24 is the size of Rela64. 1233 if len(rels)%24 != 0 { 1234 return errors.New("length of relocation section is not a multiple of 24") 1235 } 1236 1237 symbols, _, err := f.getSymbols(SHT_SYMTAB) 1238 if err != nil { 1239 return err 1240 } 1241 1242 b := bytes.NewReader(rels) 1243 var rela Rela64 1244 1245 for b.Len() > 0 { 1246 binary.Read(b, f.ByteOrder, &rela) 1247 symNo := rela.Info >> 32 1248 t := R_390(rela.Info & 0xffff) 1249 1250 if symNo == 0 || symNo > uint64(len(symbols)) { 1251 continue 1252 } 1253 sym := &symbols[symNo-1] 1254 if !canApplyRelocation(sym) { 1255 continue 1256 } 1257 1258 switch t { 1259 case R_390_64: 1260 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 1261 continue 1262 } 1263 val64 := sym.Value + uint64(rela.Addend) 1264 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64) 1265 case R_390_32: 1266 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 1267 continue 1268 } 1269 val32 := uint32(sym.Value) + uint32(rela.Addend) 1270 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32) 1271 } 1272 } 1273 1274 return nil 1275 } 1276 1277 func (f *File) applyRelocationsSPARC64(dst []byte, rels []byte) error { 1278 // 24 is the size of Rela64. 1279 if len(rels)%24 != 0 { 1280 return errors.New("length of relocation section is not a multiple of 24") 1281 } 1282 1283 symbols, _, err := f.getSymbols(SHT_SYMTAB) 1284 if err != nil { 1285 return err 1286 } 1287 1288 b := bytes.NewReader(rels) 1289 var rela Rela64 1290 1291 for b.Len() > 0 { 1292 binary.Read(b, f.ByteOrder, &rela) 1293 symNo := rela.Info >> 32 1294 t := R_SPARC(rela.Info & 0xff) 1295 1296 if symNo == 0 || symNo > uint64(len(symbols)) { 1297 continue 1298 } 1299 sym := &symbols[symNo-1] 1300 if !canApplyRelocation(sym) { 1301 continue 1302 } 1303 1304 switch t { 1305 case R_SPARC_64, R_SPARC_UA64: 1306 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 1307 continue 1308 } 1309 val64 := sym.Value + uint64(rela.Addend) 1310 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64) 1311 case R_SPARC_32, R_SPARC_UA32: 1312 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 1313 continue 1314 } 1315 val32 := uint32(sym.Value) + uint32(rela.Addend) 1316 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32) 1317 } 1318 } 1319 1320 return nil 1321 } 1322 1323 func (f *File) DWARF() (*dwarf.Data, error) { 1324 dwarfSuffix := func(s *Section) string { 1325 switch { 1326 case strings.HasPrefix(s.Name, ".debug_"): 1327 return s.Name[7:] 1328 case strings.HasPrefix(s.Name, ".zdebug_"): 1329 return s.Name[8:] 1330 default: 1331 return "" 1332 } 1333 1334 } 1335 // sectionData gets the data for s, checks its size, and 1336 // applies any applicable relations. 1337 sectionData := func(i int, s *Section) ([]byte, error) { 1338 b, err := s.Data() 1339 if err != nil && uint64(len(b)) < s.Size { 1340 return nil, err 1341 } 1342 1343 if f.Type == ET_EXEC { 1344 // Do not apply relocations to DWARF sections for ET_EXEC binaries. 1345 // Relocations should already be applied, and .rela sections may 1346 // contain incorrect data. 1347 return b, nil 1348 } 1349 1350 for _, r := range f.Sections { 1351 if r.Type != SHT_RELA && r.Type != SHT_REL { 1352 continue 1353 } 1354 if int(r.Info) != i { 1355 continue 1356 } 1357 rd, err := r.Data() 1358 if err != nil { 1359 return nil, err 1360 } 1361 err = f.applyRelocations(b, rd) 1362 if err != nil { 1363 return nil, err 1364 } 1365 } 1366 return b, nil 1367 } 1368 1369 // There are many DWARf sections, but these are the ones 1370 // the debug/dwarf package started with. 1371 var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil} 1372 for i, s := range f.Sections { 1373 suffix := dwarfSuffix(s) 1374 if suffix == "" { 1375 continue 1376 } 1377 if _, ok := dat[suffix]; !ok { 1378 continue 1379 } 1380 b, err := sectionData(i, s) 1381 if err != nil { 1382 return nil, err 1383 } 1384 dat[suffix] = b 1385 } 1386 1387 d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, dat["ranges"], dat["str"]) 1388 if err != nil { 1389 return nil, err 1390 } 1391 1392 // Look for DWARF4 .debug_types sections and DWARF5 sections. 1393 for i, s := range f.Sections { 1394 suffix := dwarfSuffix(s) 1395 if suffix == "" { 1396 continue 1397 } 1398 if _, ok := dat[suffix]; ok { 1399 // Already handled. 1400 continue 1401 } 1402 1403 b, err := sectionData(i, s) 1404 if err != nil { 1405 return nil, err 1406 } 1407 1408 if suffix == "types" { 1409 if err := d.AddTypes(fmt.Sprintf("types-%d", i), b); err != nil { 1410 return nil, err 1411 } 1412 } else { 1413 if err := d.AddSection(".debug_"+suffix, b); err != nil { 1414 return nil, err 1415 } 1416 } 1417 } 1418 1419 return d, nil 1420 } 1421 1422 // Symbols returns the symbol table for f. The symbols will be listed in the order 1423 // they appear in f. 1424 // 1425 // For compatibility with Go 1.0, Symbols omits the null symbol at index 0. 1426 // After retrieving the symbols as symtab, an externally supplied index x 1427 // corresponds to symtab[x-1], not symtab[x]. 1428 func (f *File) Symbols() ([]Symbol, error) { 1429 sym, _, err := f.getSymbols(SHT_SYMTAB) 1430 return sym, err 1431 } 1432 1433 // DynamicSymbols returns the dynamic symbol table for f. The symbols 1434 // will be listed in the order they appear in f. 1435 // 1436 // If f has a symbol version table, the returned [File.Symbols] will have 1437 // initialized [Version] and Library fields. 1438 // 1439 // For compatibility with [File.Symbols], [File.DynamicSymbols] omits the null symbol at index 0. 1440 // After retrieving the symbols as symtab, an externally supplied index x 1441 // corresponds to symtab[x-1], not symtab[x]. 1442 func (f *File) DynamicSymbols() ([]Symbol, error) { 1443 sym, str, err := f.getSymbols(SHT_DYNSYM) 1444 if err != nil { 1445 return nil, err 1446 } 1447 if f.gnuVersionInit(str) { 1448 for i := range sym { 1449 sym[i].Library, sym[i].Version = f.gnuVersion(i) 1450 } 1451 } 1452 return sym, nil 1453 } 1454 1455 type ImportedSymbol struct { 1456 Name string 1457 Version string 1458 Library string 1459 } 1460 1461 // ImportedSymbols returns the names of all symbols 1462 // referred to by the binary f that are expected to be 1463 // satisfied by other libraries at dynamic load time. 1464 // It does not return weak symbols. 1465 func (f *File) ImportedSymbols() ([]ImportedSymbol, error) { 1466 sym, str, err := f.getSymbols(SHT_DYNSYM) 1467 if err != nil { 1468 return nil, err 1469 } 1470 f.gnuVersionInit(str) 1471 var all []ImportedSymbol 1472 for i, s := range sym { 1473 if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF { 1474 all = append(all, ImportedSymbol{Name: s.Name}) 1475 sym := &all[len(all)-1] 1476 sym.Library, sym.Version = f.gnuVersion(i) 1477 } 1478 } 1479 return all, nil 1480 } 1481 1482 type verneed struct { 1483 File string 1484 Name string 1485 } 1486 1487 // gnuVersionInit parses the GNU version tables 1488 // for use by calls to gnuVersion. 1489 func (f *File) gnuVersionInit(str []byte) bool { 1490 if f.gnuNeed != nil { 1491 // Already initialized 1492 return true 1493 } 1494 1495 // Accumulate verneed information. 1496 vn := f.SectionByType(SHT_GNU_VERNEED) 1497 if vn == nil { 1498 return false 1499 } 1500 d, _ := vn.Data() 1501 1502 var need []verneed 1503 i := 0 1504 for { 1505 if i+16 > len(d) { 1506 break 1507 } 1508 vers := f.ByteOrder.Uint16(d[i : i+2]) 1509 if vers != 1 { 1510 break 1511 } 1512 cnt := f.ByteOrder.Uint16(d[i+2 : i+4]) 1513 fileoff := f.ByteOrder.Uint32(d[i+4 : i+8]) 1514 aux := f.ByteOrder.Uint32(d[i+8 : i+12]) 1515 next := f.ByteOrder.Uint32(d[i+12 : i+16]) 1516 file, _ := getString(str, int(fileoff)) 1517 1518 var name string 1519 j := i + int(aux) 1520 for c := 0; c < int(cnt); c++ { 1521 if j+16 > len(d) { 1522 break 1523 } 1524 // hash := f.ByteOrder.Uint32(d[j:j+4]) 1525 // flags := f.ByteOrder.Uint16(d[j+4:j+6]) 1526 other := f.ByteOrder.Uint16(d[j+6 : j+8]) 1527 nameoff := f.ByteOrder.Uint32(d[j+8 : j+12]) 1528 next := f.ByteOrder.Uint32(d[j+12 : j+16]) 1529 name, _ = getString(str, int(nameoff)) 1530 ndx := int(other) 1531 if ndx >= len(need) { 1532 a := make([]verneed, 2*(ndx+1)) 1533 copy(a, need) 1534 need = a 1535 } 1536 1537 need[ndx] = verneed{file, name} 1538 if next == 0 { 1539 break 1540 } 1541 j += int(next) 1542 } 1543 1544 if next == 0 { 1545 break 1546 } 1547 i += int(next) 1548 } 1549 1550 // Versym parallels symbol table, indexing into verneed. 1551 vs := f.SectionByType(SHT_GNU_VERSYM) 1552 if vs == nil { 1553 return false 1554 } 1555 d, _ = vs.Data() 1556 1557 f.gnuNeed = need 1558 f.gnuVersym = d 1559 return true 1560 } 1561 1562 // gnuVersion adds Library and Version information to sym, 1563 // which came from offset i of the symbol table. 1564 func (f *File) gnuVersion(i int) (library string, version string) { 1565 // Each entry is two bytes; skip undef entry at beginning. 1566 i = (i + 1) * 2 1567 if i >= len(f.gnuVersym) { 1568 return 1569 } 1570 s := f.gnuVersym[i:] 1571 if len(s) < 2 { 1572 return 1573 } 1574 j := int(f.ByteOrder.Uint16(s)) 1575 if j < 2 || j >= len(f.gnuNeed) { 1576 return 1577 } 1578 n := &f.gnuNeed[j] 1579 return n.File, n.Name 1580 } 1581 1582 // ImportedLibraries returns the names of all libraries 1583 // referred to by the binary f that are expected to be 1584 // linked with the binary at dynamic link time. 1585 func (f *File) ImportedLibraries() ([]string, error) { 1586 return f.DynString(DT_NEEDED) 1587 } 1588 1589 // DynString returns the strings listed for the given tag in the file's dynamic 1590 // section. 1591 // 1592 // The tag must be one that takes string values: [DT_NEEDED], [DT_SONAME], [DT_RPATH], or 1593 // [DT_RUNPATH]. 1594 func (f *File) DynString(tag DynTag) ([]string, error) { 1595 switch tag { 1596 case DT_NEEDED, DT_SONAME, DT_RPATH, DT_RUNPATH: 1597 default: 1598 return nil, fmt.Errorf("non-string-valued tag %v", tag) 1599 } 1600 ds := f.SectionByType(SHT_DYNAMIC) 1601 if ds == nil { 1602 // not dynamic, so no libraries 1603 return nil, nil 1604 } 1605 d, err := ds.Data() 1606 if err != nil { 1607 return nil, err 1608 } 1609 1610 dynSize := 8 1611 if f.Class == ELFCLASS64 { 1612 dynSize = 16 1613 } 1614 if len(d)%dynSize != 0 { 1615 return nil, errors.New("length of dynamic section is not a multiple of dynamic entry size") 1616 } 1617 1618 str, err := f.stringTable(ds.Link) 1619 if err != nil { 1620 return nil, err 1621 } 1622 var all []string 1623 for len(d) > 0 { 1624 var t DynTag 1625 var v uint64 1626 switch f.Class { 1627 case ELFCLASS32: 1628 t = DynTag(f.ByteOrder.Uint32(d[0:4])) 1629 v = uint64(f.ByteOrder.Uint32(d[4:8])) 1630 d = d[8:] 1631 case ELFCLASS64: 1632 t = DynTag(f.ByteOrder.Uint64(d[0:8])) 1633 v = f.ByteOrder.Uint64(d[8:16]) 1634 d = d[16:] 1635 } 1636 if t == tag { 1637 s, ok := getString(str, int(v)) 1638 if ok { 1639 all = append(all, s) 1640 } 1641 } 1642 } 1643 return all, nil 1644 } 1645 1646 // DynValue returns the values listed for the given tag in the file's dynamic 1647 // section. 1648 func (f *File) DynValue(tag DynTag) ([]uint64, error) { 1649 ds := f.SectionByType(SHT_DYNAMIC) 1650 if ds == nil { 1651 return nil, nil 1652 } 1653 d, err := ds.Data() 1654 if err != nil { 1655 return nil, err 1656 } 1657 1658 dynSize := 8 1659 if f.Class == ELFCLASS64 { 1660 dynSize = 16 1661 } 1662 if len(d)%dynSize != 0 { 1663 return nil, errors.New("length of dynamic section is not a multiple of dynamic entry size") 1664 } 1665 1666 // Parse the .dynamic section as a string of bytes. 1667 var vals []uint64 1668 for len(d) > 0 { 1669 var t DynTag 1670 var v uint64 1671 switch f.Class { 1672 case ELFCLASS32: 1673 t = DynTag(f.ByteOrder.Uint32(d[0:4])) 1674 v = uint64(f.ByteOrder.Uint32(d[4:8])) 1675 d = d[8:] 1676 case ELFCLASS64: 1677 t = DynTag(f.ByteOrder.Uint64(d[0:8])) 1678 v = f.ByteOrder.Uint64(d[8:16]) 1679 d = d[16:] 1680 } 1681 if t == tag { 1682 vals = append(vals, v) 1683 } 1684 } 1685 return vals, nil 1686 } 1687 1688 type nobitsSectionReader struct{} 1689 1690 func (*nobitsSectionReader) ReadAt(p []byte, off int64) (n int, err error) { 1691 return 0, errors.New("unexpected read from SHT_NOBITS section") 1692 }