Android Boot Image: Go parsing library

File extension

img

KS implementation details

License: CC0-1.0

This page hosts a formal specification of Android Boot Image 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 Android Boot Image

android_img.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"
)


/**
 * @see <a href="https://source.android.com/docs/core/architecture/bootloader/boot-image-header">Source</a>
 */
type AndroidImg struct {
	Magic []byte
	Kernel *AndroidImg_Load
	Ramdisk *AndroidImg_Load
	Second *AndroidImg_Load
	TagsLoad uint32
	PageSize uint32
	HeaderVersion uint32
	OsVersion *AndroidImg_OsVersion
	Name string
	Cmdline string
	Sha []byte
	ExtraCmdline string
	RecoveryDtbo *AndroidImg_SizeOffset
	BootHeaderSize uint32
	Dtb *AndroidImg_LoadLong
	_io *kaitai.Stream
	_root *AndroidImg
	_parent interface{}
	_f_kernelImg bool
	kernelImg []byte
	_f_tagsOffset bool
	tagsOffset int
	_f_ramdiskOffset bool
	ramdiskOffset int
	_f_secondOffset bool
	secondOffset int
	_f_kernelOffset bool
	kernelOffset int
	_f_dtbOffset bool
	dtbOffset int
	_f_dtbImg bool
	dtbImg []byte
	_f_ramdiskImg bool
	ramdiskImg []byte
	_f_recoveryDtboImg bool
	recoveryDtboImg []byte
	_f_secondImg bool
	secondImg []byte
	_f_base bool
	base int
}
func NewAndroidImg() *AndroidImg {
	return &AndroidImg{
	}
}

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

	tmp1, err := this._io.ReadBytes(int(8))
	if err != nil {
		return err
	}
	tmp1 = tmp1
	this.Magic = tmp1
	if !(bytes.Equal(this.Magic, []uint8{65, 78, 68, 82, 79, 73, 68, 33})) {
		return kaitai.NewValidationNotEqualError([]uint8{65, 78, 68, 82, 79, 73, 68, 33}, this.Magic, this._io, "/seq/0")
	}
	tmp2 := NewAndroidImg_Load()
	err = tmp2.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.Kernel = tmp2
	tmp3 := NewAndroidImg_Load()
	err = tmp3.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.Ramdisk = tmp3
	tmp4 := NewAndroidImg_Load()
	err = tmp4.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.Second = tmp4
	tmp5, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.TagsLoad = uint32(tmp5)
	tmp6, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.PageSize = uint32(tmp6)
	tmp7, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.HeaderVersion = uint32(tmp7)
	tmp8 := NewAndroidImg_OsVersion()
	err = tmp8.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.OsVersion = tmp8
	tmp9, err := this._io.ReadBytes(int(16))
	if err != nil {
		return err
	}
	tmp9 = kaitai.BytesTerminate(tmp9, 0, false)
	this.Name = string(tmp9)
	tmp10, err := this._io.ReadBytes(int(512))
	if err != nil {
		return err
	}
	tmp10 = kaitai.BytesTerminate(tmp10, 0, false)
	this.Cmdline = string(tmp10)
	tmp11, err := this._io.ReadBytes(int(32))
	if err != nil {
		return err
	}
	tmp11 = tmp11
	this.Sha = tmp11
	tmp12, err := this._io.ReadBytes(int(1024))
	if err != nil {
		return err
	}
	tmp12 = kaitai.BytesTerminate(tmp12, 0, false)
	this.ExtraCmdline = string(tmp12)
	if (this.HeaderVersion > 0) {
		tmp13 := NewAndroidImg_SizeOffset()
		err = tmp13.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.RecoveryDtbo = tmp13
	}
	if (this.HeaderVersion > 0) {
		tmp14, err := this._io.ReadU4le()
		if err != nil {
			return err
		}
		this.BootHeaderSize = uint32(tmp14)
	}
	if (this.HeaderVersion > 1) {
		tmp15 := NewAndroidImg_LoadLong()
		err = tmp15.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Dtb = tmp15
	}
	return err
}
func (this *AndroidImg) KernelImg() (v []byte, err error) {
	if (this._f_kernelImg) {
		return this.kernelImg, nil
	}
	_pos, err := this._io.Pos()
	if err != nil {
		return nil, err
	}
	_, err = this._io.Seek(int64(this.PageSize), io.SeekStart)
	if err != nil {
		return nil, err
	}
	tmp16, err := this._io.ReadBytes(int(this.Kernel.Size))
	if err != nil {
		return nil, err
	}
	tmp16 = tmp16
	this.kernelImg = tmp16
	_, err = this._io.Seek(_pos, io.SeekStart)
	if err != nil {
		return nil, err
	}
	this._f_kernelImg = true
	this._f_kernelImg = true
	return this.kernelImg, nil
}

/**
 * tags offset from base
 */
func (this *AndroidImg) TagsOffset() (v int, err error) {
	if (this._f_tagsOffset) {
		return this.tagsOffset, nil
	}
	tmp17, err := this.Base()
	if err != nil {
		return 0, err
	}
	this.tagsOffset = int((this.TagsLoad - tmp17))
	this._f_tagsOffset = true
	return this.tagsOffset, nil
}

/**
 * ramdisk offset from base
 */
func (this *AndroidImg) RamdiskOffset() (v int, err error) {
	if (this._f_ramdiskOffset) {
		return this.ramdiskOffset, nil
	}
	var tmp18 int;
	if (this.Ramdisk.Addr > 0) {
		tmp19, err := this.Base()
		if err != nil {
			return 0, err
		}
		tmp18 = (this.Ramdisk.Addr - tmp19)
	} else {
		tmp18 = 0
	}
	this.ramdiskOffset = int(tmp18)
	this._f_ramdiskOffset = true
	return this.ramdiskOffset, nil
}

/**
 * 2nd bootloader offset from base
 */
func (this *AndroidImg) SecondOffset() (v int, err error) {
	if (this._f_secondOffset) {
		return this.secondOffset, nil
	}
	var tmp20 int;
	if (this.Second.Addr > 0) {
		tmp21, err := this.Base()
		if err != nil {
			return 0, err
		}
		tmp20 = (this.Second.Addr - tmp21)
	} else {
		tmp20 = 0
	}
	this.secondOffset = int(tmp20)
	this._f_secondOffset = true
	return this.secondOffset, nil
}

/**
 * kernel offset from base
 */
func (this *AndroidImg) KernelOffset() (v int, err error) {
	if (this._f_kernelOffset) {
		return this.kernelOffset, nil
	}
	tmp22, err := this.Base()
	if err != nil {
		return 0, err
	}
	this.kernelOffset = int((this.Kernel.Addr - tmp22))
	this._f_kernelOffset = true
	return this.kernelOffset, nil
}

/**
 * dtb offset from base
 */
func (this *AndroidImg) DtbOffset() (v int, err error) {
	if (this._f_dtbOffset) {
		return this.dtbOffset, nil
	}
	if (this.HeaderVersion > 1) {
		var tmp23 int;
		if (this.Dtb.Addr > 0) {
			tmp24, err := this.Base()
			if err != nil {
				return 0, err
			}
			tmp23 = (this.Dtb.Addr - tmp24)
		} else {
			tmp23 = 0
		}
		this.dtbOffset = int(tmp23)
	}
	this._f_dtbOffset = true
	return this.dtbOffset, nil
}
func (this *AndroidImg) DtbImg() (v []byte, err error) {
	if (this._f_dtbImg) {
		return this.dtbImg, nil
	}
	if ( ((this.HeaderVersion > 1) && (this.Dtb.Size > 0)) ) {
		_pos, err := this._io.Pos()
		if err != nil {
			return nil, err
		}
		_, err = this._io.Seek(int64(((((((((this.PageSize + this.Kernel.Size) + this.Ramdisk.Size) + this.Second.Size) + this.RecoveryDtbo.Size) + this.PageSize) - 1) / this.PageSize) * this.PageSize)), io.SeekStart)
		if err != nil {
			return nil, err
		}
		tmp25, err := this._io.ReadBytes(int(this.Dtb.Size))
		if err != nil {
			return nil, err
		}
		tmp25 = tmp25
		this.dtbImg = tmp25
		_, err = this._io.Seek(_pos, io.SeekStart)
		if err != nil {
			return nil, err
		}
		this._f_dtbImg = true
	}
	this._f_dtbImg = true
	return this.dtbImg, nil
}
func (this *AndroidImg) RamdiskImg() (v []byte, err error) {
	if (this._f_ramdiskImg) {
		return this.ramdiskImg, nil
	}
	if (this.Ramdisk.Size > 0) {
		_pos, err := this._io.Pos()
		if err != nil {
			return nil, err
		}
		_, err = this._io.Seek(int64((((((this.PageSize + this.Kernel.Size) + this.PageSize) - 1) / this.PageSize) * this.PageSize)), io.SeekStart)
		if err != nil {
			return nil, err
		}
		tmp26, err := this._io.ReadBytes(int(this.Ramdisk.Size))
		if err != nil {
			return nil, err
		}
		tmp26 = tmp26
		this.ramdiskImg = tmp26
		_, err = this._io.Seek(_pos, io.SeekStart)
		if err != nil {
			return nil, err
		}
		this._f_ramdiskImg = true
	}
	this._f_ramdiskImg = true
	return this.ramdiskImg, nil
}
func (this *AndroidImg) RecoveryDtboImg() (v []byte, err error) {
	if (this._f_recoveryDtboImg) {
		return this.recoveryDtboImg, nil
	}
	if ( ((this.HeaderVersion > 0) && (this.RecoveryDtbo.Size > 0)) ) {
		_pos, err := this._io.Pos()
		if err != nil {
			return nil, err
		}
		_, err = this._io.Seek(int64(this.RecoveryDtbo.Offset), io.SeekStart)
		if err != nil {
			return nil, err
		}
		tmp27, err := this._io.ReadBytes(int(this.RecoveryDtbo.Size))
		if err != nil {
			return nil, err
		}
		tmp27 = tmp27
		this.recoveryDtboImg = tmp27
		_, err = this._io.Seek(_pos, io.SeekStart)
		if err != nil {
			return nil, err
		}
		this._f_recoveryDtboImg = true
	}
	this._f_recoveryDtboImg = true
	return this.recoveryDtboImg, nil
}
func (this *AndroidImg) SecondImg() (v []byte, err error) {
	if (this._f_secondImg) {
		return this.secondImg, nil
	}
	if (this.Second.Size > 0) {
		_pos, err := this._io.Pos()
		if err != nil {
			return nil, err
		}
		_, err = this._io.Seek(int64(((((((this.PageSize + this.Kernel.Size) + this.Ramdisk.Size) + this.PageSize) - 1) / this.PageSize) * this.PageSize)), io.SeekStart)
		if err != nil {
			return nil, err
		}
		tmp28, err := this._io.ReadBytes(int(this.Second.Size))
		if err != nil {
			return nil, err
		}
		tmp28 = tmp28
		this.secondImg = tmp28
		_, err = this._io.Seek(_pos, io.SeekStart)
		if err != nil {
			return nil, err
		}
		this._f_secondImg = true
	}
	this._f_secondImg = true
	return this.secondImg, nil
}

/**
 * base loading address
 */
func (this *AndroidImg) Base() (v int, err error) {
	if (this._f_base) {
		return this.base, nil
	}
	this.base = int((this.Kernel.Addr - 32768))
	this._f_base = true
	return this.base, nil
}
type AndroidImg_Load struct {
	Size uint32
	Addr uint32
	_io *kaitai.Stream
	_root *AndroidImg
	_parent *AndroidImg
}
func NewAndroidImg_Load() *AndroidImg_Load {
	return &AndroidImg_Load{
	}
}

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

	tmp29, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.Size = uint32(tmp29)
	tmp30, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.Addr = uint32(tmp30)
	return err
}
type AndroidImg_LoadLong struct {
	Size uint32
	Addr uint64
	_io *kaitai.Stream
	_root *AndroidImg
	_parent *AndroidImg
}
func NewAndroidImg_LoadLong() *AndroidImg_LoadLong {
	return &AndroidImg_LoadLong{
	}
}

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

	tmp31, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.Size = uint32(tmp31)
	tmp32, err := this._io.ReadU8le()
	if err != nil {
		return err
	}
	this.Addr = uint64(tmp32)
	return err
}
type AndroidImg_SizeOffset struct {
	Size uint32
	Offset uint64
	_io *kaitai.Stream
	_root *AndroidImg
	_parent *AndroidImg
}
func NewAndroidImg_SizeOffset() *AndroidImg_SizeOffset {
	return &AndroidImg_SizeOffset{
	}
}

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

	tmp33, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.Size = uint32(tmp33)
	tmp34, err := this._io.ReadU8le()
	if err != nil {
		return err
	}
	this.Offset = uint64(tmp34)
	return err
}
type AndroidImg_OsVersion struct {
	Version uint32
	_io *kaitai.Stream
	_root *AndroidImg
	_parent *AndroidImg
	_f_month bool
	month int
	_f_patch bool
	patch int
	_f_year bool
	year int
	_f_major bool
	major int
	_f_minor bool
	minor int
}
func NewAndroidImg_OsVersion() *AndroidImg_OsVersion {
	return &AndroidImg_OsVersion{
	}
}

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

	tmp35, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.Version = uint32(tmp35)
	return err
}
func (this *AndroidImg_OsVersion) Month() (v int, err error) {
	if (this._f_month) {
		return this.month, nil
	}
	this.month = int((this.Version & 15))
	this._f_month = true
	return this.month, nil
}
func (this *AndroidImg_OsVersion) Patch() (v int, err error) {
	if (this._f_patch) {
		return this.patch, nil
	}
	this.patch = int(((this.Version >> 11) & 127))
	this._f_patch = true
	return this.patch, nil
}
func (this *AndroidImg_OsVersion) Year() (v int, err error) {
	if (this._f_year) {
		return this.year, nil
	}
	this.year = int((((this.Version >> 4) & 127) + 2000))
	this._f_year = true
	return this.year, nil
}
func (this *AndroidImg_OsVersion) Major() (v int, err error) {
	if (this._f_major) {
		return this.major, nil
	}
	this.major = int(((this.Version >> 25) & 127))
	this._f_major = true
	return this.major, nil
}
func (this *AndroidImg_OsVersion) Minor() (v int, err error) {
	if (this._f_minor) {
		return this.minor, nil
	}
	this.minor = int(((this.Version >> 18) & 127))
	this._f_minor = true
	return this.minor, nil
}