Files
zinnia/scripts/get_options.py
T
2026-09-19 21:57:06 +02:00

109 lines
3.9 KiB
Python
Executable File

#!/usr/bin/env python3
# Small script to print all options available inside a built kernel.
# fmt: off
import sys
from elftools.elf.elffile import ELFFile
SIZEOF_PTR = 8
SIZEOF_STRUCT = 40
ENDIAN = "little"
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Provide a path to the kernel binary to use")
sys.exit(1)
with open(sys.argv[1], "rb") as elffile:
file = ELFFile(elffile)
section = file.get_section_by_name(".cmdline")
if section == None:
sys.exit(1)
cmdline_data = section.data()
num_options = int(section.data_size / SIZEOF_PTR)
print(f"Kernel contains {num_options} options:")
for i in range(num_options):
# Read "struct cmdline_option*"
addr = int.from_bytes(cmdline_data[(i * SIZEOF_PTR) :][:SIZEOF_PTR], byteorder=ENDIAN)
elffile.seek(next(file.address_offsets(start=addr)))
option = elffile.read(SIZEOF_STRUCT)
# Name
name = ""
name_ptr = int.from_bytes(option[0:][:SIZEOF_PTR], byteorder=ENDIAN)
elffile.seek(next(file.address_offsets(start=name_ptr)))
while True:
b = int.from_bytes(elffile.read(1))
if b == 0:
break
name += chr(b)
# Description
desc = ""
desc_ptr = int.from_bytes(option[8:][:SIZEOF_PTR], byteorder=ENDIAN)
elffile.seek(next(file.address_offsets(start=desc_ptr)))
while True:
b = int.from_bytes(elffile.read(1))
if b == 0:
break
desc += chr(b)
# Type
kind_str = "unknown"
kind = int.from_bytes(option[16:][:4], byteorder=ENDIAN)
match kind:
case 0:
kind_str = "string"
case 1:
kind_str = "bool"
case 2:
kind_str = "integer"
case 2:
kind_str = "unsigned integer"
# Skip function pointer
# Allowed values
limit = ""
limit_ptr = int.from_bytes(option[32:][:SIZEOF_PTR], byteorder=ENDIAN)
if limit_ptr != 0:
elffile.seek(next(file.address_offsets(start=limit_ptr)))
match kind:
case 0:
limit = []
i = 0
while True:
ptr = next(file.address_offsets(start=limit_ptr + i * SIZEOF_PTR))
elffile.seek(ptr)
str_ptr = int.from_bytes(elffile.read(SIZEOF_PTR), byteorder=ENDIAN)
if str_ptr == 0:
break
strstr_off = next(file.address_offsets(start=str_ptr))
val = ""
elffile.seek(strstr_off)
while True:
b = int.from_bytes(elffile.read(1))
if b == 0:
break
val += chr(b)
i += 1
limit.append(val)
case 2:
min = int.from_bytes(elffile.read(SIZEOF_PTR), byteorder=ENDIAN, signed=True)
max = int.from_bytes(elffile.read(SIZEOF_PTR), byteorder=ENDIAN)
limit = f"[{min}, {max}]"
case 3:
min = int.from_bytes(elffile.read(SIZEOF_PTR), byteorder=ENDIAN)
max = int.from_bytes(elffile.read(SIZEOF_PTR), byteorder=ENDIAN)
limit = f"[{min}, {max}]"
print(f"- {name}:\t{desc} ({kind_str}) {limit if len(limit) != 0 else ""}")