Beispiel #1
0
func openMacho(r *os.File) (rawFile, error) {
	f, err := macho.NewFile(r)
	if err != nil {
		return nil, err
	}
	return &machoFile{f}, nil
}
Beispiel #2
0
func openDebugFile(r io.ReaderAt) (debugFile, error) {
	f, err := macho.NewFile(r)
	if err != nil {
		return nil, err
	}
	return &file{f}, nil
}
Beispiel #3
0
// zipExeReaderMacho treats the file as a Mach-O binary
// (Mac OS X / Darwin executable) and attempts to find a zip archive.
func zipExeReaderMacho(rda io.ReaderAt, size int64) (*zip.Reader, error) {
	file, err := macho.NewFile(rda)
	if err != nil {
		return nil, err
	}

	var max int64
	for _, load := range file.Loads {
		seg, ok := load.(*macho.Segment)
		if ok {
			// Check if the segment contains a zip file
			if zfile, err := zip.NewReader(seg, int64(seg.Filesz)); err == nil {
				return zfile, nil
			}

			// Otherwise move end of file pointer
			end := int64(seg.Offset + seg.Filesz)
			if end > max {
				max = end
			}
		}
	}

	// No zip file within binary, try appended to end
	section := io.NewSectionReader(rda, max, size-max)
	return zip.NewReader(section, section.Size())
}
Beispiel #4
0
func newSectionReader(rf io.ReaderAt) (ret sectionReader, err error) {
	ret.macho, err = macho.NewFile(rf)
	if err != nil {
		ret.elf, err = elf.NewFile(rf)
	}
	return
}
Beispiel #5
0
Datei: note.go Projekt: sreis/go
// The Go build ID is stored at the beginning of the Mach-O __text segment.
// The caller has already opened filename, to get f, and read a few kB out, in data.
// Sadly, that's not guaranteed to hold the note, because there is an arbitrary amount
// of other junk placed in the file ahead of the main text.
func readMachoGoBuildID(filename string, f *os.File, data []byte) (buildid string, err error) {
	// If the data we want has already been read, don't worry about Mach-O parsing.
	// This is both an optimization and a hedge against the Mach-O parsing failing
	// in the future due to, for example, the name of the __text section changing.
	if b, err := readRawGoBuildID(filename, data); b != "" && err == nil {
		return b, err
	}

	mf, err := macho.NewFile(f)
	if err != nil {
		return "", &os.PathError{Path: filename, Op: "parse", Err: err}
	}

	sect := mf.Section("__text")
	if sect == nil {
		// Every binary has a __text section. Something is wrong.
		return "", &os.PathError{Path: filename, Op: "parse", Err: fmt.Errorf("cannot find __text section")}
	}

	// It should be in the first few bytes, but read a lot just in case,
	// especially given our past problems on OS X with the build ID moving.
	// There shouldn't be much difference between reading 4kB and 32kB:
	// the hard part is getting to the data, not transferring it.
	n := sect.Size
	if n > uint64(BuildIDReadSize) {
		n = uint64(BuildIDReadSize)
	}
	buf := make([]byte, n)
	if _, err := f.ReadAt(buf, int64(sect.Offset)); err != nil {
		return "", err
	}

	return readRawGoBuildID(filename, buf)
}
Beispiel #6
0
func Fuzz(data []byte) int {
	f, err := macho.NewFile(bytes.NewReader(data))
	if err != nil {
		if f != nil {
			panic("file is not nil on error")
		}
		return 0
	}
	defer f.Close()
	f.ImportedLibraries()
	f.ImportedSymbols()
	f.Section(".text")
	f.Segment("macho")
	dw, err := f.DWARF()
	if err != nil {
		if dw != nil {
			panic("dwarf is not nil on error")
		}
		return 1
	}
	dr := dw.Reader()
	for {
		e, _ := dr.Next()
		if e == nil {
			break
		}
	}
	return 2
}
Beispiel #7
0
func NewMachOLoader(r io.ReaderAt) (models.Loader, error) {
	file, err := macho.NewFile(r)
	if err != nil {
		return nil, err
	}
	var bits int
	switch file.Magic {
	case macho.Magic32:
		bits = 32
	case macho.Magic64:
		bits = 64
	default:
		return nil, errors.New("Unknown ELF class.")
	}
	machineName, ok := machoCpuMap[file.Cpu]
	if !ok {
		return nil, fmt.Errorf("Unsupported CPU: %s", file.Cpu)
	}
	entry, err := findEntry(file, bits)
	if err != nil {
		return nil, err
	}
	return &MachOLoader{
		LoaderHeader: LoaderHeader{
			arch:  machineName,
			bits:  bits,
			os:    "darwin",
			entry: entry,
		},
		file: file,
	}, nil
}
Beispiel #8
0
func machoSymbols(f *os.File) (syms []Sym, goarch string) {
	p, err := macho.NewFile(f)
	if err != nil {
		errorf("parsing %s: %v", f.Name(), err)
		return
	}

	if p.Symtab == nil {
		errorf("%s: no symbol table", f.Name())
		return
	}

	switch p.Cpu {
	case macho.Cpu386:
		goarch = "386"
	case macho.CpuAmd64:
		goarch = "amd64"
	case macho.CpuArm:
		goarch = "arm"
	}

	// Build sorted list of addresses of all symbols.
	// We infer the size of a symbol by looking at where the next symbol begins.
	var addrs []uint64
	for _, s := range p.Symtab.Syms {
		addrs = append(addrs, s.Value)
	}
	sort.Sort(uint64s(addrs))

	for _, s := range p.Symtab.Syms {
		sym := Sym{Name: s.Name, Addr: s.Value, Code: '?'}
		i := sort.Search(len(addrs), func(x int) bool { return addrs[x] > s.Value })
		if i < len(addrs) {
			sym.Size = int64(addrs[i] - s.Value)
		}
		if s.Sect == 0 {
			sym.Code = 'U'
		} else if int(s.Sect) <= len(p.Sections) {
			sect := p.Sections[s.Sect-1]
			switch sect.Seg {
			case "__TEXT":
				sym.Code = 'R'
			case "__DATA":
				sym.Code = 'D'
			}
			switch sect.Seg + " " + sect.Name {
			case "__TEXT __text":
				sym.Code = 'T'
			case "__DATA __bss", "__DATA __noptrbss":
				sym.Code = 'B'
			}
		}
		syms = append(syms, sym)
	}

	return
}
Beispiel #9
0
func NewMachOLoader(r io.ReaderAt, archHint string) (models.Loader, error) {
	var (
		file    *macho.File
		fatFile *macho.FatFile
		err     error
	)
	magic := getMagic(r)
	if bytes.Equal(magic, fatMagic) {
		fatFile, err = macho.NewFatFile(r)
		if fatFile != nil {
			for _, arch := range fatFile.Arches {
				if machineName, ok := machoCpuMap[arch.Cpu]; ok {
					if machineName == archHint || archHint == "any" {
						file = arch.File
						break
					}
				}
			}
			if file == nil {
				return nil, fmt.Errorf("Could not find Mach-O fat binary entry for arch '%s'.", archHint)
			}
		}
	} else {
		file, err = macho.NewFile(r)
	}
	if err != nil {
		return nil, err
	}
	var bits int
	switch file.Magic {
	case macho.Magic32:
		bits = 32
	case macho.Magic64:
		bits = 64
	default:
		return nil, errors.New("Unknown ELF class.")
	}
	machineName, ok := machoCpuMap[file.Cpu]
	if !ok {
		return nil, fmt.Errorf("Unsupported CPU: %s", file.Cpu)
	}
	entry, err := findEntry(file, bits)
	if err != nil {
		return nil, err
	}
	return &MachOLoader{
		LoaderHeader: LoaderHeader{
			arch:  machineName,
			bits:  bits,
			os:    "darwin",
			entry: entry,
		},
		file: file,
	}, nil
}
Beispiel #10
0
func loadTables(f *os.File) (textStart uint64, symtab, pclntab []byte, err error) {
	if obj, err := elf.NewFile(f); err == nil {
		if sect := obj.Section(".text"); sect != nil {
			textStart = sect.Addr
		}
		if sect := obj.Section(".gosymtab"); sect != nil {
			if symtab, err = sect.Data(); err != nil {
				return 0, nil, nil, err
			}
		}
		if sect := obj.Section(".gopclntab"); sect != nil {
			if pclntab, err = sect.Data(); err != nil {
				return 0, nil, nil, err
			}
		}
		return textStart, symtab, pclntab, nil
	}

	if obj, err := macho.NewFile(f); err == nil {
		if sect := obj.Section("__text"); sect != nil {
			textStart = sect.Addr
		}
		if sect := obj.Section("__gosymtab"); sect != nil {
			if symtab, err = sect.Data(); err != nil {
				return 0, nil, nil, err
			}
		}
		if sect := obj.Section("__gopclntab"); sect != nil {
			if pclntab, err = sect.Data(); err != nil {
				return 0, nil, nil, err
			}
		}
		return textStart, symtab, pclntab, nil
	}

	if obj, err := pe.NewFile(f); err == nil {
		if sect := obj.Section(".text"); sect != nil {
			textStart = uint64(sect.VirtualAddress)
		}
		if sect := obj.Section(".gosymtab"); sect != nil {
			if symtab, err = sect.Data(); err != nil {
				return 0, nil, nil, err
			}
		}
		if sect := obj.Section(".gopclntab"); sect != nil {
			if pclntab, err = sect.Data(); err != nil {
				return 0, nil, nil, err
			}
		}
		return textStart, symtab, pclntab, nil
	}

	return 0, nil, nil, fmt.Errorf("unrecognized binary format")
}
Beispiel #11
0
func NewFile(r io.ReaderAt) (binaryx.File, error) {
	elfBinary, err := elf.NewFile(r)
	if err == nil {
		return newFile(&elfx.File{elfBinary})
	}
	machoBinary, err := macho.NewFile(r)
	if err == nil {
		return newFile(&machox.File{machoBinary})
	}
	peBinary, err := pe.NewFile(r)
	if err == nil {
		return newFile(&pex.File{peBinary})
	}
	return nil, err
}
Beispiel #12
0
func grabDebugLineSection(p string, t *testing.T) []byte {
	f, err := os.Open(p)
	if err != nil {
		t.Fatal(err)
	}
	defer f.Close()

	ef, err := elf.NewFile(f)
	if err == nil {
		data, _ := ef.Section(".debug_line").Data()
		return data
	}

	mf, _ := macho.NewFile(f)
	data, _ := mf.Section("__debug_line").Data()

	return data
}
Beispiel #13
0
func NewDWARFHelper(id string, r io.ReaderAt) (*DWARFHelper, error) {
	// TODO: detect file format..
	if f, err := macho.NewFile(r); err != nil {
		return nil, err
	} else {
		defer f.Close()
		if df, err := f.DWARF(); err != nil {
			for i := range f.Sections {
				log4go.Debug(f.Sections[i])
			}
			return nil, err
		} else {
			var ret DWARFHelper
			ret.df = df
			ret.id = id
			return &ret, nil
		}
	}
}
Beispiel #14
0
func (fq *findQueue) worker() {
	for fp := range fq.queue {
		blacklisted := false
		for _, re := range blacklistRegexps {
			blacklisted = blacklisted || re.MatchString(fp)
		}
		if blacklisted {
			continue
		}

		f, err := os.Open(fp)
		if err != nil {
			log.Printf("%s: %v", fp, err)
			continue
		}

		fatFile, err := macho.NewFatFile(f)
		if err == nil {
			// The file is fat, so dump its architectures.
			for _, fatArch := range fatFile.Arches {
				fq.dumpMachOFile(fp, fatArch.File)
			}
			fatFile.Close()
		} else if err == macho.ErrNotFat {
			// The file isn't fat but may still be MachO.
			thinFile, err := macho.NewFile(f)
			if err != nil {
				log.Printf("%s: %v", fp, err)
				continue
			}
			fq.dumpMachOFile(fp, thinFile)
			thinFile.Close()
		} else {
			f.Close()
		}
	}
}
Beispiel #15
0
// machoCombineDwarf merges dwarf info generated by dsymutil into a macho executable.
// With internal linking, DWARF is embedded into the executable, this lets us do the
// same for external linking.
// inexe is the path to the executable with no DWARF. It must have enough room in the macho
// header to add the DWARF sections. (Use ld's -headerpad option)
// dsym is the path to the macho file containing DWARF from dsymutil.
// outexe is the path where the combined executable should be saved.
func machoCombineDwarf(inexe, dsym, outexe string) error {
	exef, err := os.Open(inexe)
	if err != nil {
		return err
	}
	dwarff, err := os.Open(dsym)
	if err != nil {
		return err
	}
	outf, err := os.Create(outexe)
	if err != nil {
		return err
	}
	outf.Chmod(0755)

	exem, err := macho.NewFile(exef)
	if err != nil {
		return err
	}
	dwarfm, err := macho.NewFile(dwarff)
	if err != nil {
		return err
	}

	// The string table needs to be the last thing in the file
	// for code signing to work. So we'll need to move the
	// linkedit section, but all the others can be copied directly.
	linkseg = exem.Segment("__LINKEDIT")
	if linkseg == nil {
		return fmt.Errorf("missing __LINKEDIT segment")
	}

	if _, err = exef.Seek(0, 0); err != nil {
		return err
	}
	if _, err := io.CopyN(outf, exef, int64(linkseg.Offset)); err != nil {
		return err
	}

	realdwarf = dwarfm.Segment("__DWARF")
	if realdwarf == nil {
		return fmt.Errorf("missing __DWARF segment")
	}

	// Now copy the dwarf data into the output.
	maxalign := uint32(dwarfMinAlign) //
	for _, sect := range dwarfm.Sections {
		if sect.Align > maxalign {
			maxalign = sect.Align
		}
	}
	dwarfstart = machoCalcStart(realdwarf.Offset, linkseg.Offset, maxalign)
	if _, err = outf.Seek(dwarfstart, 0); err != nil {
		return err
	}

	if _, err = dwarff.Seek(int64(realdwarf.Offset), 0); err != nil {
		return err
	}
	if _, err := io.CopyN(outf, dwarff, int64(realdwarf.Filesz)); err != nil {
		return err
	}

	// And finally the linkedit section.
	if _, err = exef.Seek(int64(linkseg.Offset), 0); err != nil {
		return err
	}
	linkstart = machoCalcStart(linkseg.Offset, uint64(dwarfstart)+realdwarf.Filesz, pageAlign)
	linkoffset = uint32(linkstart - int64(linkseg.Offset))
	if _, err = outf.Seek(linkstart, 0); err != nil {
		return err
	}
	if _, err := io.Copy(outf, exef); err != nil {
		return err
	}

	// Now we need to update the headers.
	cmdOffset := unsafe.Sizeof(exem.FileHeader)
	is64bit := exem.Magic == macho.Magic64
	if is64bit {
		// mach_header_64 has one extra uint32.
		cmdOffset += unsafe.Sizeof(exem.Magic)
	}

	textsect := exem.Section("__text")
	if linkseg == nil {
		return fmt.Errorf("missing __text section")
	}

	dwarfCmdOffset := int64(cmdOffset) + int64(exem.FileHeader.Cmdsz)
	availablePadding := int64(textsect.Offset) - dwarfCmdOffset
	if availablePadding < int64(realdwarf.Len) {
		return fmt.Errorf("No room to add dwarf info. Need at least %d padding bytes, found %d", realdwarf.Len, availablePadding)
	}
	// First, copy the dwarf load command into the header
	if _, err = outf.Seek(dwarfCmdOffset, 0); err != nil {
		return err
	}
	if _, err := io.CopyN(outf, bytes.NewReader(realdwarf.Raw()), int64(realdwarf.Len)); err != nil {
		return err
	}

	if _, err = outf.Seek(int64(unsafe.Offsetof(exem.FileHeader.Ncmd)), 0); err != nil {
		return err
	}
	if err = binary.Write(outf, exem.ByteOrder, exem.Ncmd+1); err != nil {
		return err
	}
	if err = binary.Write(outf, exem.ByteOrder, exem.Cmdsz+realdwarf.Len); err != nil {
		return err
	}

	reader := loadCmdReader{next: int64(cmdOffset), f: outf, order: exem.ByteOrder}
	for i := uint32(0); i < exem.Ncmd; i++ {
		cmd, err := reader.Next()
		if err != nil {
			return err
		}
		switch cmd.Cmd {
		case macho.LoadCmdSegment64:
			err = machoUpdateSegment(reader, &macho.Segment64{}, &macho.Section64{})
		case macho.LoadCmdSegment:
			err = machoUpdateSegment(reader, &macho.Segment32{}, &macho.Section32{})
		case LC_DYLD_INFO, LC_DYLD_INFO_ONLY:
			err = machoUpdateLoadCommand(reader, &dyldInfoCmd{}, "RebaseOff", "BindOff", "WeakBindOff", "LazyBindOff", "ExportOff")
		case macho.LoadCmdSymtab:
			err = machoUpdateLoadCommand(reader, &macho.SymtabCmd{}, "Symoff", "Stroff")
		case macho.LoadCmdDysymtab:
			err = machoUpdateLoadCommand(reader, &macho.DysymtabCmd{}, "Tocoffset", "Modtaboff", "Extrefsymoff", "Indirectsymoff", "Extreloff", "Locreloff")
		case LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO, LC_FUNCTION_STARTS, LC_DATA_IN_CODE, LC_DYLIB_CODE_SIGN_DRS:
			err = machoUpdateLoadCommand(reader, &linkEditDataCmd{}, "DataOff")
		case LC_ENCRYPTION_INFO, LC_ENCRYPTION_INFO_64:
			err = machoUpdateLoadCommand(reader, &encryptionInfoCmd{}, "CryptOff")
		case macho.LoadCmdDylib, macho.LoadCmdThread, macho.LoadCmdUnixThread, LC_PREBOUND_DYLIB, LC_UUID, LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, LC_SOURCE_VERSION, LC_MAIN, LC_LOAD_DYLINKER, LC_LOAD_WEAK_DYLIB, LC_REEXPORT_DYLIB, LC_RPATH, LC_ID_DYLIB:
			// Nothing to update
		default:
			err = fmt.Errorf("Unknown load command 0x%x (%s)\n", int(cmd.Cmd), cmd.Cmd)
		}
		if err != nil {
			return err
		}
	}
	return machoUpdateDwarfHeader(&reader)
}
Beispiel #16
0
// machoRead reads the mach-o file in data and returns a corresponding prog.
func machoRead(arch machoArch, data []byte) (*Prog, error) {
	f, err := macho.NewFile(bytes.NewReader(data))
	if err != nil {
		return nil, err
	}

	var errors []string
	errorf := func(format string, args ...interface{}) {
		errors = append(errors, fmt.Sprintf(format, args...))
	}

	magic := uint32(0xFEEDFACE)
	if arch.CPU&macho64Bit != 0 {
		magic |= 1
	}
	if f.Magic != magic {
		errorf("header: Magic = %#x, want %#x", f.Magic, magic)
	}
	if f.Cpu != macho.CpuAmd64 {
		errorf("header: CPU = %#x, want %#x", f.Cpu, macho.CpuAmd64)
	}
	if f.SubCpu != 3 {
		errorf("header: SubCPU = %#x, want %#x", f.SubCpu, 3)
	}
	if f.Type != 2 {
		errorf("header: FileType = %d, want %d", f.Type, 2)
	}
	if f.Flags != 1 {
		errorf("header: Flags = %d, want %d", f.Flags, 1)
	}

	msects := f.Sections
	var limit uint64
	prog := new(Prog)
	for _, load := range f.Loads {
		switch load := load.(type) {
		default:
			errorf("unexpected macho load %T %x", load, load.Raw())

		case macho.LoadBytes:
			if len(load) < 8 || len(load)%4 != 0 {
				errorf("unexpected load length %d", len(load))
				continue
			}
			cmd := f.ByteOrder.Uint32(load)
			switch macho.LoadCmd(cmd) {
			default:
				errorf("unexpected macho load cmd %s", macho.LoadCmd(cmd))
			case macho.LoadCmdUnixThread:
				data := make([]uint32, len(load[8:])/4)
				binary.Read(bytes.NewReader(load[8:]), f.ByteOrder, data)
				if len(data) != 44 {
					errorf("macho thread len(data) = %d, want 42", len(data))
					continue
				}
				if data[0] != 4 {
					errorf("macho thread type = %d, want 4", data[0])
				}
				if data[1] != uint32(len(data))-2 {
					errorf("macho thread desc len = %d, want %d", data[1], uint32(len(data))-2)
					continue
				}
				for i, val := range data[2:] {
					switch i {
					default:
						if val != 0 {
							errorf("macho thread data[%d] = %#x, want 0", i, val)
						}
					case 32:
						prog.Entry = Addr(val)
					case 33:
						prog.Entry |= Addr(val) << 32
					}
				}
			}

		case *macho.Segment:
			if load.Addr < limit {
				errorf("segments out of order: %q at %#x after %#x", load.Name, load.Addr, limit)
			}
			limit = load.Addr + load.Memsz
			if load.Name == "__PAGEZERO" || load.Addr == 0 && load.Filesz == 0 {
				if load.Name != "__PAGEZERO" {
					errorf("segment with Addr=0, Filesz=0 is named %q, want %q", load.Name, "__PAGEZERO")
				} else if load.Addr != 0 || load.Filesz != 0 {
					errorf("segment %q has Addr=%#x, Filesz=%d, want Addr=%#x, Filesz=%d", load.Name, load.Addr, load.Filesz, 0, 0)
				}
				prog.UnmappedSize = Addr(load.Memsz)
				continue
			}

			if !strings.HasPrefix(load.Name, "__") {
				errorf("segment name %q does not begin with %q", load.Name, "__")
			}
			if strings.ToUpper(load.Name) != load.Name {
				errorf("segment name %q is not all upper case", load.Name)
			}

			seg := &Segment{
				Name:       strings.ToLower(strings.TrimPrefix(load.Name, "__")),
				VirtAddr:   Addr(load.Addr),
				VirtSize:   Addr(load.Memsz),
				FileOffset: Addr(load.Offset),
				FileSize:   Addr(load.Filesz),
			}
			prog.Segments = append(prog.Segments, seg)

			data, err := load.Data()
			if err != nil {
				errorf("loading data from %q: %v", load.Name, err)
			}
			seg.Data = data

			var maxprot, prot uint32
			if load.Name == "__TEXT" {
				maxprot, prot = 7, 5
			} else {
				maxprot, prot = 3, 3
			}
			if load.Maxprot != maxprot || load.Prot != prot {
				errorf("segment %q protection is %d, %d, want %d, %d",
					load.Maxprot, load.Prot, maxprot, prot)
			}

			for len(msects) > 0 && msects[0].Addr < load.Addr+load.Memsz {
				msect := msects[0]
				msects = msects[1:]

				if msect.Offset > 0 && prog.HeaderSize == 0 {
					prog.HeaderSize = Addr(msect.Offset)
					if seg.FileOffset != 0 {
						errorf("initial segment %q does not map header", load.Name)
					}
					seg.VirtAddr += prog.HeaderSize
					seg.VirtSize -= prog.HeaderSize
					seg.FileOffset += prog.HeaderSize
					seg.FileSize -= prog.HeaderSize
					seg.Data = seg.Data[prog.HeaderSize:]
				}

				if msect.Addr < load.Addr {
					errorf("section %q at address %#x is missing segment", msect.Name, msect.Addr)
					continue
				}

				if !strings.HasPrefix(msect.Name, "__") {
					errorf("section name %q does not begin with %q", msect.Name, "__")
				}
				if strings.ToLower(msect.Name) != msect.Name {
					errorf("section name %q is not all lower case", msect.Name)
				}
				if msect.Seg != load.Name {
					errorf("section %q is lists segment name %q, want %q",
						msect.Name, msect.Seg, load.Name)
				}
				if uint64(msect.Offset) != uint64(load.Offset)+msect.Addr-load.Addr {
					errorf("section %q file offset is %#x, want %#x",
						msect.Name, msect.Offset, load.Offset+msect.Addr-load.Addr)
				}
				if msect.Reloff != 0 || msect.Nreloc != 0 {
					errorf("section %q has reloff %d,%d, want %d,%d",
						msect.Name, msect.Reloff, msect.Nreloc, 0, 0)
				}
				flags := uint32(0)
				if msect.Name == "__text" {
					flags = 0x400
				}
				if msect.Offset == 0 {
					flags = 1
				}
				if msect.Flags != flags {
					errorf("section %q flags = %#x, want %#x", msect.Flags, flags)
				}
				sect := &Section{
					Name:     strings.ToLower(strings.TrimPrefix(msect.Name, "__")),
					VirtAddr: Addr(msect.Addr),
					Size:     Addr(msect.Size),
					Align:    1 << msect.Align,
				}
				seg.Sections = append(seg.Sections, sect)
			}
		}
	}

	for _, msect := range msects {
		errorf("section %q has no segment", msect.Name)
	}

	limit = 0
	for _, msect := range f.Sections {
		if msect.Addr < limit {
			errorf("sections out of order: %q at %#x after %#x", msect.Name, msect.Addr, limit)
		}
		limit = msect.Addr + msect.Size
	}

	err = nil
	if errors != nil {
		err = fmt.Errorf("%s", strings.Join(errors, "\n\t"))
	}
	return prog, err
}
Beispiel #17
0
func loadTables(f *os.File) (textStart uint64, textData, symtab, pclntab []byte, err error) {
	if obj, err := elf.NewFile(f); err == nil {
		if sect := obj.Section(".text"); sect != nil {
			textStart = sect.Addr
			textData, _ = sect.Data()
		}
		if sect := obj.Section(".gosymtab"); sect != nil {
			if symtab, err = sect.Data(); err != nil {
				return 0, nil, nil, nil, err
			}
		}
		if sect := obj.Section(".gopclntab"); sect != nil {
			if pclntab, err = sect.Data(); err != nil {
				return 0, nil, nil, nil, err
			}
		}
		return textStart, textData, symtab, pclntab, nil
	}

	if obj, err := macho.NewFile(f); err == nil {
		if sect := obj.Section("__text"); sect != nil {
			textStart = sect.Addr
			textData, _ = sect.Data()
		}
		if sect := obj.Section("__gosymtab"); sect != nil {
			if symtab, err = sect.Data(); err != nil {
				return 0, nil, nil, nil, err
			}
		}
		if sect := obj.Section("__gopclntab"); sect != nil {
			if pclntab, err = sect.Data(); err != nil {
				return 0, nil, nil, nil, err
			}
		}
		return textStart, textData, symtab, pclntab, nil
	}

	if obj, err := pe.NewFile(f); err == nil {
		var imageBase uint64
		switch oh := obj.OptionalHeader.(type) {
		case *pe.OptionalHeader32:
			imageBase = uint64(oh.ImageBase)
		case *pe.OptionalHeader64:
			imageBase = oh.ImageBase
		default:
			return 0, nil, nil, nil, fmt.Errorf("pe file format not recognized")
		}
		if sect := obj.Section(".text"); sect != nil {
			textStart = imageBase + uint64(sect.VirtualAddress)
			textData, _ = sect.Data()
		}
		if pclntab, err = loadPETable(obj, "pclntab", "epclntab"); err != nil {
			return 0, nil, nil, nil, err
		}
		if symtab, err = loadPETable(obj, "symtab", "esymtab"); err != nil {
			return 0, nil, nil, nil, err
		}
		return textStart, textData, symtab, pclntab, nil
	}

	if obj, err := plan9obj.NewFile(f); err == nil {
		sym, err := findPlan9Symbol(obj, "text")
		if err != nil {
			return 0, nil, nil, nil, err
		}
		textStart = sym.Value
		if sect := obj.Section("text"); sect != nil {
			textData, _ = sect.Data()
		}
		if pclntab, err = loadPlan9Table(obj, "pclntab", "epclntab"); err != nil {
			return 0, nil, nil, nil, err
		}
		if symtab, err = loadPlan9Table(obj, "symtab", "esymtab"); err != nil {
			return 0, nil, nil, nil, err
		}
		return textStart, textData, symtab, pclntab, nil
	}

	return 0, nil, nil, nil, fmt.Errorf("unrecognized binary format")
}