#
# ida_kernelcache/kernel.py
# Brandon Azad
#
# The kernel module holds functions and global variables pertaining to the kernel as a whole. No
# prior initialization via ida_kernelcache is necessary.
#

import idc
import idautils
import idaapi

import ida_utilities as idau
import kplist

_log = idau.make_log(0, __name__)

def find_kernel_base():
    """Find the kernel base."""
    return idaapi.get_fileregion_ea(0)

base = find_kernel_base()
"""The kernel base address (the address of the main kernel Mach-O header)."""

def _find_prelink_info_segments():
    """Find all candidate __PRELINK_INFO segments (or sections).

    We try to identify any IDA segments with __PRELINK_INFO in the name so that this function will
    work both before and after automatic rename. A more reliable method would be parsing the
    Mach-O.
    """
    segments = []
    # Gather a list of all the possible segments.
    for seg in idautils.Segments():
        name = idc.SegName(seg)
        if '__PRELINK_INFO' in name or name == '__info':
            segments.append(seg)
    if len(segments) < 1:
        _log(0, 'Could not find any __PRELINK_INFO segment candidates')
    elif len(segments) > 1:
        _log(1, 'Multiple segment names contain __PRELINK_INFO: {}',
                [idc.SegName(seg) for seg in segments])
    return segments

def parse_prelink_info():
    """Find and parse the kernel __PRELINK_INFO dictionary."""
    segments = _find_prelink_info_segments()
    for segment in segments:
        prelink_info_string = idc.GetString(segment)
        prelink_info = kplist.kplist_parse(prelink_info_string)
        if prelink_info:
            return prelink_info
    _log(0, 'Could not find __PRELINK_INFO')
    return None

prelink_info = parse_prelink_info()
"""The kernel __PRELINK_INFO dictionary."""

KC_11_NORMAL = '11-normal'
KC_12_MERGED = '12-merged'

def _get_kernelcache_format():
    if '_PrelinkLinkKASLROffsets' in prelink_info:
        return KC_11_NORMAL
    return KC_12_MERGED

kernelcache_format = _get_kernelcache_format()