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 kaitai.Struct
	_f_base bool
	base int
	_f_dtbImg bool
	dtbImg []byte
	_f_dtbOffset bool
	dtbOffset int
	_f_kernelImg bool
	kernelImg []byte
	_f_kernelOffset bool
	kernelOffset int
	_f_ramdiskImg bool
	ramdiskImg []byte
	_f_ramdiskOffset bool
	ramdiskOffset int
	_f_recoveryDtboImg bool
	recoveryDtboImg []byte
	_f_secondImg bool
	secondImg []byte
	_f_secondOffset bool
	secondOffset int
	_f_tagsOffset bool
	tagsOffset int
}
func NewAndroidImg() *AndroidImg {
	return &AndroidImg{
	}
}

func (this AndroidImg) IO_() *kaitai.Stream {
	return this._io
}

func (this *AndroidImg) Read(io *kaitai.Stream, parent kaitai.Struct, 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
}

/**
 * base loading address
 */
func (this *AndroidImg) Base() (v int, err error) {
	if (this._f_base) {
		return this.base, nil
	}
	this._f_base = true
	this.base = int(this.Kernel.Addr - 32768)
	return this.base, nil
}
func (this *AndroidImg) DtbImg() (v []byte, err error) {
	if (this._f_dtbImg) {
		return this.dtbImg, nil
	}
	this._f_dtbImg = true
	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
		}
		tmp16, err := this._io.ReadBytes(int(this.Dtb.Size))
		if err != nil {
			return nil, err
		}
		tmp16 = tmp16
		this.dtbImg = tmp16
		_, err = this._io.Seek(_pos, io.SeekStart)
		if err != nil {
			return nil, err
		}
	}
	return this.dtbImg, nil
}

/**
 * dtb offset from base
 */
func (this *AndroidImg) DtbOffset() (v int, err error) {
	if (this._f_dtbOffset) {
		return this.dtbOffset, nil
	}
	this._f_dtbOffset = true
	if (this.HeaderVersion > 1) {
		var tmp17 int;
		if (this.Dtb.Addr > 0) {
			tmp18, err := this.Base()
			if err != nil {
				return 0, err
			}
			tmp17 = this.Dtb.Addr - tmp18
		} else {
			tmp17 = 0
		}
		this.dtbOffset = int(tmp17)
	}
	return this.dtbOffset, nil
}
func (this *AndroidImg) KernelImg() (v []byte, err error) {
	if (this._f_kernelImg) {
		return this.kernelImg, nil
	}
	this._f_kernelImg = true
	_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
	}
	tmp19, err := this._io.ReadBytes(int(this.Kernel.Size))
	if err != nil {
		return nil, err
	}
	tmp19 = tmp19
	this.kernelImg = tmp19
	_, err = this._io.Seek(_pos, io.SeekStart)
	if err != nil {
		return nil, err
	}
	return this.kernelImg, nil
}

/**
 * kernel offset from base
 */
func (this *AndroidImg) KernelOffset() (v int, err error) {
	if (this._f_kernelOffset) {
		return this.kernelOffset, nil
	}
	this._f_kernelOffset = true
	tmp20, err := this.Base()
	if err != nil {
		return 0, err
	}
	this.kernelOffset = int(this.Kernel.Addr - tmp20)
	return this.kernelOffset, nil
}
func (this *AndroidImg) RamdiskImg() (v []byte, err error) {
	if (this._f_ramdiskImg) {
		return this.ramdiskImg, nil
	}
	this._f_ramdiskImg = true
	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
		}
		tmp21, err := this._io.ReadBytes(int(this.Ramdisk.Size))
		if err != nil {
			return nil, err
		}
		tmp21 = tmp21
		this.ramdiskImg = tmp21
		_, err = this._io.Seek(_pos, io.SeekStart)
		if err != nil {
			return nil, err
		}
	}
	return this.ramdiskImg, nil
}

/**
 * ramdisk offset from base
 */
func (this *AndroidImg) RamdiskOffset() (v int, err error) {
	if (this._f_ramdiskOffset) {
		return this.ramdiskOffset, nil
	}
	this._f_ramdiskOffset = true
	var tmp22 int;
	if (this.Ramdisk.Addr > 0) {
		tmp23, err := this.Base()
		if err != nil {
			return 0, err
		}
		tmp22 = this.Ramdisk.Addr - tmp23
	} else {
		tmp22 = 0
	}
	this.ramdiskOffset = int(tmp22)
	return this.ramdiskOffset, nil
}
func (this *AndroidImg) RecoveryDtboImg() (v []byte, err error) {
	if (this._f_recoveryDtboImg) {
		return this.recoveryDtboImg, nil
	}
	this._f_recoveryDtboImg = true
	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
		}
		tmp24, err := this._io.ReadBytes(int(this.RecoveryDtbo.Size))
		if err != nil {
			return nil, err
		}
		tmp24 = tmp24
		this.recoveryDtboImg = tmp24
		_, err = this._io.Seek(_pos, io.SeekStart)
		if err != nil {
			return nil, err
		}
	}
	return this.recoveryDtboImg, nil
}
func (this *AndroidImg) SecondImg() (v []byte, err error) {
	if (this._f_secondImg) {
		return this.secondImg, nil
	}
	this._f_secondImg = true
	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
		}
		tmp25, err := this._io.ReadBytes(int(this.Second.Size))
		if err != nil {
			return nil, err
		}
		tmp25 = tmp25
		this.secondImg = tmp25
		_, err = this._io.Seek(_pos, io.SeekStart)
		if err != nil {
			return nil, err
		}
	}
	return this.secondImg, nil
}

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

/**
 * tags offset from base
 */
func (this *AndroidImg) TagsOffset() (v int, err error) {
	if (this._f_tagsOffset) {
		return this.tagsOffset, nil
	}
	this._f_tagsOffset = true
	tmp28, err := this.Base()
	if err != nil {
		return 0, err
	}
	this.tagsOffset = int(this.TagsLoad - tmp28)
	return this.tagsOffset, 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) IO_() *kaitai.Stream {
	return this._io
}

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) IO_() *kaitai.Stream {
	return this._io
}

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_OsVersion struct {
	Version uint32
	_io *kaitai.Stream
	_root *AndroidImg
	_parent *AndroidImg
	_f_major bool
	major int
	_f_minor bool
	minor int
	_f_month bool
	month int
	_f_patch bool
	patch int
	_f_year bool
	year int
}
func NewAndroidImg_OsVersion() *AndroidImg_OsVersion {
	return &AndroidImg_OsVersion{
	}
}

func (this AndroidImg_OsVersion) IO_() *kaitai.Stream {
	return this._io
}

func (this *AndroidImg_OsVersion) 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.Version = uint32(tmp33)
	return err
}
func (this *AndroidImg_OsVersion) Major() (v int, err error) {
	if (this._f_major) {
		return this.major, nil
	}
	this._f_major = true
	this.major = int((this.Version >> 25) & 127)
	return this.major, nil
}
func (this *AndroidImg_OsVersion) Minor() (v int, err error) {
	if (this._f_minor) {
		return this.minor, nil
	}
	this._f_minor = true
	this.minor = int((this.Version >> 18) & 127)
	return this.minor, nil
}
func (this *AndroidImg_OsVersion) Month() (v int, err error) {
	if (this._f_month) {
		return this.month, nil
	}
	this._f_month = true
	this.month = int(this.Version & 15)
	return this.month, nil
}
func (this *AndroidImg_OsVersion) Patch() (v int, err error) {
	if (this._f_patch) {
		return this.patch, nil
	}
	this._f_patch = true
	this.patch = int((this.Version >> 11) & 127)
	return this.patch, nil
}
func (this *AndroidImg_OsVersion) Year() (v int, err error) {
	if (this._f_year) {
		return this.year, nil
	}
	this._f_year = true
	this.year = int((this.Version >> 4) & 127 + 2000)
	return this.year, nil
}
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) IO_() *kaitai.Stream {
	return this._io
}

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

	tmp34, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.Size = uint32(tmp34)
	tmp35, err := this._io.ReadU8le()
	if err != nil {
		return err
	}
	this.Offset = uint64(tmp35)
	return err
}