macOS Mach-O multiarch ("fat") binary: Go parsing library

This is a simple container format that encapsulates multiple Mach-O files, each generally for a different architecture. XNU can execute these files just like single-arch Mach-Os and will pick the appropriate entry.

KS implementation details

License: CC0-1.0

This page hosts a formal specification of macOS Mach-O multiarch ("fat") binary using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Go source code to parse macOS Mach-O multiarch ("fat") binary

mach_o_fat.go

// Code generated by kaitai-struct-compiler from a .ksy source file. DO NOT EDIT.

import (
	"github.com/kaitai-io/kaitai_struct_go_runtime/kaitai"
	"bytes"
	"io"
)


/**
 * This is a simple container format that encapsulates multiple Mach-O files,
 * each generally for a different architecture. XNU can execute these files just
 * like single-arch Mach-Os and will pick the appropriate entry.
 * @see <a href="https://opensource.apple.com/source/xnu/xnu-7195.121.3/EXTERNAL_HEADERS/mach-o/fat.h.auto.html">Source</a>
 */
type MachOFat struct {
	Magic []byte
	NumFatArch uint32
	FatArchs []*MachOFat_FatArch
	_io *kaitai.Stream
	_root *MachOFat
	_parent interface{}
}
func NewMachOFat() *MachOFat {
	return &MachOFat{
	}
}

func (this *MachOFat) Read(io *kaitai.Stream, parent interface{}, root *MachOFat) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp1, err := this._io.ReadBytes(int(4))
	if err != nil {
		return err
	}
	tmp1 = tmp1
	this.Magic = tmp1
	if !(bytes.Equal(this.Magic, []uint8{202, 254, 186, 190})) {
		return kaitai.NewValidationNotEqualError([]uint8{202, 254, 186, 190}, this.Magic, this._io, "/seq/0")
	}
	tmp2, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.NumFatArch = uint32(tmp2)
	for i := 0; i < int(this.NumFatArch); i++ {
		_ = i
		tmp3 := NewMachOFat_FatArch()
		err = tmp3.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.FatArchs = append(this.FatArchs, tmp3)
	}
	return err
}
type MachOFat_FatArch struct {
	CpuType MachO_CpuType
	CpuSubtype uint32
	OfsObject uint32
	LenObject uint32
	Align uint32
	_io *kaitai.Stream
	_root *MachOFat
	_parent *MachOFat
	_raw_object []byte
	_f_object bool
	object *MachO
}
func NewMachOFat_FatArch() *MachOFat_FatArch {
	return &MachOFat_FatArch{
	}
}

func (this *MachOFat_FatArch) Read(io *kaitai.Stream, parent *MachOFat, root *MachOFat) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp4, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.CpuType = MachO_CpuType(tmp4)
	tmp5, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.CpuSubtype = uint32(tmp5)
	tmp6, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.OfsObject = uint32(tmp6)
	tmp7, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.LenObject = uint32(tmp7)
	tmp8, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.Align = uint32(tmp8)
	return err
}
func (this *MachOFat_FatArch) Object() (v *MachO, err error) {
	if (this._f_object) {
		return this.object, nil
	}
	_pos, err := this._io.Pos()
	if err != nil {
		return nil, err
	}
	_, err = this._io.Seek(int64(this.OfsObject), io.SeekStart)
	if err != nil {
		return nil, err
	}
	tmp9, err := this._io.ReadBytes(int(this.LenObject))
	if err != nil {
		return nil, err
	}
	tmp9 = tmp9
	this._raw_object = tmp9
	_io__raw_object := kaitai.NewStream(bytes.NewReader(this._raw_object))
	tmp10 := NewMachO()
	err = tmp10.Read(_io__raw_object, this, nil)
	if err != nil {
		return nil, err
	}
	this.object = tmp10
	_, err = this._io.Seek(_pos, io.SeekStart)
	if err != nil {
		return nil, err
	}
	this._f_object = true
	this._f_object = true
	return this.object, nil
}