src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

exe.go (7203B)


      1 // Copyright 2017 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 package goversion
      6 
      7 import (
      8 	"bytes"
      9 	"debug/elf"
     10 	"debug/macho"
     11 	"debug/pe"
     12 	"encoding/binary"
     13 	"fmt"
     14 	"io"
     15 	"os"
     16 )
     17 
     18 type sym struct {
     19 	Name string
     20 	Addr uint64
     21 	Size uint64
     22 }
     23 
     24 type exe interface {
     25 	AddrSize() int // bytes
     26 	ReadData(addr, size uint64) ([]byte, error)
     27 	Symbols() ([]sym, error)
     28 	SectionNames() []string
     29 	Close() error
     30 	ByteOrder() binary.ByteOrder
     31 	Entry() uint64
     32 	TextRange() (uint64, uint64)
     33 	RODataRange() (uint64, uint64)
     34 }
     35 
     36 func openExe(file string) (exe, error) {
     37 	f, err := os.Open(file)
     38 	if err != nil {
     39 		return nil, err
     40 	}
     41 	data := make([]byte, 16)
     42 	if _, err := io.ReadFull(f, data); err != nil {
     43 		return nil, err
     44 	}
     45 	f.Seek(0, 0)
     46 	if bytes.HasPrefix(data, []byte("\x7FELF")) {
     47 		e, err := elf.NewFile(f)
     48 		if err != nil {
     49 			f.Close()
     50 			return nil, err
     51 		}
     52 		return &elfExe{f, e}, nil
     53 	}
     54 	if bytes.HasPrefix(data, []byte("MZ")) {
     55 		e, err := pe.NewFile(f)
     56 		if err != nil {
     57 			f.Close()
     58 			return nil, err
     59 		}
     60 		return &peExe{f, e}, nil
     61 	}
     62 	if bytes.HasPrefix(data, []byte("\xFE\xED\xFA")) || bytes.HasPrefix(data[1:], []byte("\xFA\xED\xFE")) {
     63 		e, err := macho.NewFile(f)
     64 		if err != nil {
     65 			f.Close()
     66 			return nil, err
     67 		}
     68 		return &machoExe{f, e}, nil
     69 	}
     70 	return nil, fmt.Errorf("unrecognized executable format")
     71 }
     72 
     73 type elfExe struct {
     74 	os *os.File
     75 	f  *elf.File
     76 }
     77 
     78 func (x *elfExe) AddrSize() int { return 0 }
     79 
     80 func (x *elfExe) ByteOrder() binary.ByteOrder { return x.f.ByteOrder }
     81 
     82 func (x *elfExe) Close() error {
     83 	return x.os.Close()
     84 }
     85 
     86 func (x *elfExe) Entry() uint64 { return x.f.Entry }
     87 
     88 func (x *elfExe) ReadData(addr, size uint64) ([]byte, error) {
     89 	for _, prog := range x.f.Progs {
     90 		// The following line was commented from the original code.
     91 		//fmt.Printf("%#x %#x %#x\n", addr, prog.Vaddr, prog.Vaddr+prog.Filesz)
     92 		if prog.Vaddr <= addr && addr <= prog.Vaddr+prog.Filesz-1 {
     93 			n := prog.Vaddr + prog.Filesz - addr
     94 			if n > size {
     95 				n = size
     96 			}
     97 			data := make([]byte, n)
     98 			_, err := prog.ReadAt(data, int64(addr-prog.Vaddr))
     99 			if err != nil {
    100 				return nil, err
    101 			}
    102 			return data, nil
    103 		}
    104 	}
    105 	return nil, fmt.Errorf("address not mapped")
    106 }
    107 
    108 func (x *elfExe) Symbols() ([]sym, error) {
    109 	syms, err := x.f.Symbols()
    110 	if err != nil {
    111 		return nil, err
    112 	}
    113 	var out []sym
    114 	for _, s := range syms {
    115 		out = append(out, sym{s.Name, s.Value, s.Size})
    116 	}
    117 	return out, nil
    118 }
    119 
    120 func (x *elfExe) SectionNames() []string {
    121 	var names []string
    122 	for _, sect := range x.f.Sections {
    123 		names = append(names, sect.Name)
    124 	}
    125 	return names
    126 }
    127 
    128 func (x *elfExe) TextRange() (uint64, uint64) {
    129 	for _, p := range x.f.Progs {
    130 		if p.Type == elf.PT_LOAD && p.Flags&elf.PF_X != 0 {
    131 			return p.Vaddr, p.Vaddr + p.Filesz
    132 		}
    133 	}
    134 	return 0, 0
    135 }
    136 
    137 func (x *elfExe) RODataRange() (uint64, uint64) {
    138 	for _, p := range x.f.Progs {
    139 		if p.Type == elf.PT_LOAD && p.Flags&(elf.PF_R|elf.PF_W|elf.PF_X) == elf.PF_R {
    140 			return p.Vaddr, p.Vaddr + p.Filesz
    141 		}
    142 	}
    143 	for _, p := range x.f.Progs {
    144 		if p.Type == elf.PT_LOAD && p.Flags&(elf.PF_R|elf.PF_W|elf.PF_X) == (elf.PF_R|elf.PF_X) {
    145 			return p.Vaddr, p.Vaddr + p.Filesz
    146 		}
    147 	}
    148 	return 0, 0
    149 }
    150 
    151 type peExe struct {
    152 	os *os.File
    153 	f  *pe.File
    154 }
    155 
    156 func (x *peExe) imageBase() uint64 {
    157 	switch oh := x.f.OptionalHeader.(type) {
    158 	case *pe.OptionalHeader32:
    159 		return uint64(oh.ImageBase)
    160 	case *pe.OptionalHeader64:
    161 		return oh.ImageBase
    162 	}
    163 	return 0
    164 }
    165 
    166 func (x *peExe) AddrSize() int {
    167 	if x.f.Machine == pe.IMAGE_FILE_MACHINE_AMD64 {
    168 		return 8
    169 	}
    170 	return 4
    171 }
    172 
    173 func (x *peExe) ByteOrder() binary.ByteOrder { return binary.LittleEndian }
    174 
    175 func (x *peExe) Close() error {
    176 	return x.os.Close()
    177 }
    178 
    179 func (x *peExe) Entry() uint64 {
    180 	switch oh := x.f.OptionalHeader.(type) {
    181 	case *pe.OptionalHeader32:
    182 		return uint64(oh.ImageBase + oh.AddressOfEntryPoint)
    183 	case *pe.OptionalHeader64:
    184 		return oh.ImageBase + uint64(oh.AddressOfEntryPoint)
    185 	}
    186 	return 0
    187 }
    188 
    189 func (x *peExe) ReadData(addr, size uint64) ([]byte, error) {
    190 	addr -= x.imageBase()
    191 	data := make([]byte, size)
    192 	for _, sect := range x.f.Sections {
    193 		if uint64(sect.VirtualAddress) <= addr && addr+size-1 <= uint64(sect.VirtualAddress+sect.Size-1) {
    194 			_, err := sect.ReadAt(data, int64(addr-uint64(sect.VirtualAddress)))
    195 			if err != nil {
    196 				return nil, err
    197 			}
    198 			return data, nil
    199 		}
    200 	}
    201 	return nil, fmt.Errorf("address not mapped")
    202 }
    203 
    204 func (x *peExe) Symbols() ([]sym, error) {
    205 	base := x.imageBase()
    206 	var out []sym
    207 	for _, s := range x.f.Symbols {
    208 		if s.SectionNumber <= 0 || int(s.SectionNumber) > len(x.f.Sections) {
    209 			continue
    210 		}
    211 		sect := x.f.Sections[s.SectionNumber-1]
    212 		out = append(out, sym{s.Name, uint64(s.Value) + base + uint64(sect.VirtualAddress), 0})
    213 	}
    214 	return out, nil
    215 }
    216 
    217 func (x *peExe) SectionNames() []string {
    218 	var names []string
    219 	for _, sect := range x.f.Sections {
    220 		names = append(names, sect.Name)
    221 	}
    222 	return names
    223 }
    224 
    225 func (x *peExe) TextRange() (uint64, uint64) {
    226 	// Assume text is first non-empty section.
    227 	for _, sect := range x.f.Sections {
    228 		if sect.VirtualAddress != 0 && sect.Size != 0 {
    229 			return uint64(sect.VirtualAddress) + x.imageBase(), uint64(sect.VirtualAddress+sect.Size) + x.imageBase()
    230 		}
    231 	}
    232 	return 0, 0
    233 }
    234 
    235 func (x *peExe) RODataRange() (uint64, uint64) {
    236 	return x.TextRange()
    237 }
    238 
    239 type machoExe struct {
    240 	os *os.File
    241 	f  *macho.File
    242 }
    243 
    244 func (x *machoExe) AddrSize() int {
    245 	if x.f.Cpu&0x01000000 != 0 {
    246 		return 8
    247 	}
    248 	return 4
    249 }
    250 
    251 func (x *machoExe) ByteOrder() binary.ByteOrder { return x.f.ByteOrder }
    252 
    253 func (x *machoExe) Close() error {
    254 	return x.os.Close()
    255 }
    256 
    257 func (x *machoExe) Entry() uint64 {
    258 	for _, load := range x.f.Loads {
    259 		b, ok := load.(macho.LoadBytes)
    260 		if !ok {
    261 			continue
    262 		}
    263 		// TODO: Other thread states.
    264 		bo := x.f.ByteOrder
    265 		const x86_THREAD_STATE64 = 4
    266 		cmd, siz := macho.LoadCmd(bo.Uint32(b[0:4])), bo.Uint32(b[4:8])
    267 		if cmd == macho.LoadCmdUnixThread && siz == 184 && bo.Uint32(b[8:12]) == x86_THREAD_STATE64 {
    268 			return bo.Uint64(b[144:])
    269 		}
    270 	}
    271 	return 0
    272 }
    273 
    274 func (x *machoExe) ReadData(addr, size uint64) ([]byte, error) {
    275 	data := make([]byte, size)
    276 	for _, load := range x.f.Loads {
    277 		seg, ok := load.(*macho.Segment)
    278 		if !ok {
    279 			continue
    280 		}
    281 		if seg.Addr <= addr && addr+size-1 <= seg.Addr+seg.Filesz-1 {
    282 			if seg.Name == "__PAGEZERO" {
    283 				continue
    284 			}
    285 			_, err := seg.ReadAt(data, int64(addr-seg.Addr))
    286 			if err != nil {
    287 				return nil, err
    288 			}
    289 			return data, nil
    290 		}
    291 	}
    292 	return nil, fmt.Errorf("address not mapped")
    293 }
    294 
    295 func (x *machoExe) Symbols() ([]sym, error) {
    296 	var out []sym
    297 	for _, s := range x.f.Symtab.Syms {
    298 		out = append(out, sym{s.Name, s.Value, 0})
    299 	}
    300 	return out, nil
    301 }
    302 
    303 func (x *machoExe) SectionNames() []string {
    304 	var names []string
    305 	for _, sect := range x.f.Sections {
    306 		names = append(names, sect.Name)
    307 	}
    308 	return names
    309 }
    310 
    311 func (x *machoExe) TextRange() (uint64, uint64) {
    312 	// Assume text is first non-empty segment.
    313 	for _, load := range x.f.Loads {
    314 		seg, ok := load.(*macho.Segment)
    315 		if ok && seg.Name != "__PAGEZERO" && seg.Addr != 0 && seg.Filesz != 0 {
    316 			return seg.Addr, seg.Addr + seg.Filesz
    317 		}
    318 	}
    319 	return 0, 0
    320 }
    321 
    322 func (x *machoExe) RODataRange() (uint64, uint64) {
    323 	return x.TextRange()
    324 }