loadFunctions extracts instruction streams from the given program section starting at each symbol in the section. The section's symbols must already be narrowed down to STT_NOTYPE (emitted by clang <8) or STT_FUNC. The resulting map is indexed by function name.
(sec *elfSection)
| 439 | // |
| 440 | // The resulting map is indexed by function name. |
| 441 | func (ec *elfCode) loadFunctions(sec *elfSection) (map[string]asm.Instructions, error) { |
| 442 | progs := make(map[string]asm.Instructions) |
| 443 | |
| 444 | // Pull out ExtInfos once per section to avoid map lookups on every |
| 445 | // instruction. |
| 446 | fo, lo, ro := ec.extInfo.Section(sec.Name) |
| 447 | |
| 448 | // Raw instruction count since start of the section. ExtInfos point at raw |
| 449 | // insn offsets and ignore the gaps between symbols in case of linked objects. |
| 450 | // We need to count them, we can't obtain this info by any other means. |
| 451 | var raw asm.RawInstructionOffset |
| 452 | |
| 453 | // Sort symbols by offset so we can track instructions by their raw offsets. |
| 454 | for _, sym := range sec.symbolsSorted() { |
| 455 | if progs[sym.Name] != nil { |
| 456 | return nil, fmt.Errorf("duplicate symbol %s in section %s", sym.Name, sec.Name) |
| 457 | } |
| 458 | |
| 459 | if sym.Value > math.MaxUint32 || sym.Size > math.MaxUint32 { |
| 460 | return nil, fmt.Errorf("symbol %s: offset or size exceeds 32 bits in section %s", sym.Name, sec.Name) |
| 461 | } |
| 462 | if sym.Value+sym.Size > sec.Size { |
| 463 | return nil, fmt.Errorf("symbol %s: size goes out of bounds of section %s", sym.Name, sec.Name) |
| 464 | } |
| 465 | |
| 466 | // Decode the symbol's instruction stream, limited to its size. |
| 467 | sr := internal.NewBufferedSectionReader(sec, int64(sym.Value), int64(sym.Size)) |
| 468 | insns := make(asm.Instructions, 0, sym.Size/asm.InstructionSize) |
| 469 | insns, err := asm.AppendInstructions(insns, sr, ec.ByteOrder, platform.Linux) |
| 470 | if err != nil { |
| 471 | return nil, fmt.Errorf("decoding instructions for symbol %s in section %s: %w", sym.Name, sec.Name, err) |
| 472 | } |
| 473 | if len(insns) == 0 { |
| 474 | return nil, fmt.Errorf("no instructions found for symbol %s in section %s", sym.Name, sec.Name) |
| 475 | } |
| 476 | |
| 477 | // Mark the first instruction as the start of a function. |
| 478 | insns[0] = insns[0].WithSymbol(sym.Name) |
| 479 | |
| 480 | iter := insns.Iterate() |
| 481 | for iter.Next() { |
| 482 | // Global byte offset of the instruction within the ELF section. |
| 483 | offset := sym.Value + iter.Offset.Bytes() |
| 484 | |
| 485 | // Apply any relocations for the current instruction. If no relocation is |
| 486 | // present, resolve any section-relative function calls. |
| 487 | if rel, ok := sec.relocations[offset]; ok { |
| 488 | if err := ec.relocateInstruction(iter.Ins, rel); err != nil { |
| 489 | return nil, fmt.Errorf("offset %d in section %s: relocating instruction: %w", offset, sec.Name, err) |
| 490 | } |
| 491 | } else { |
| 492 | if err := referenceRelativeJump(iter.Ins, offset, sec.symbols); err != nil { |
| 493 | return nil, fmt.Errorf("offset %d in section %s: resolving relative jump: %w", offset, sec.Name, err) |
| 494 | } |
| 495 | } |
| 496 | |
| 497 | assignMetadata(iter.Ins, raw, &fo, &lo, &ro) |
| 498 |
no test coverage detected