Shofel2_T124_python/venv/lib/python3.10/site-packages/qiling/loader/mcu.py

139 lines
4.0 KiB
Python
Raw Permalink Normal View History

2024-05-25 16:45:07 +00:00
#!/usr/bin/env python3
#
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
# Built on top of Unicorn emulator (www.unicorn-engine.org)
import io
from elftools.elf.elffile import ELFFile
from qiling.const import *
from qiling.core import Qiling
from .loader import QlLoader
class IhexParser:
def __init__(self, path):
self.mem = []
self.segments = []
self.base = 0
with open(path, 'r') as f:
for line in f.read().splitlines():
self.parse_line(line.strip())
begin, stream = 0, b''
for addr, data in self.mem:
if addr != begin + len(stream):
self.segments.append((begin, stream))
begin, stream = addr, data
else:
stream += data
self.segments.append((begin, stream))
def parse_line(self, line):
if len(line) < 9:
return
desc = line[7: 9]
size = int(line[1: 3], 16)
addr = bytes.fromhex(line[3: 7])
data = bytes.fromhex(line[9: 9 + size * 2])
if desc == '00': # Data
offset = int.from_bytes(addr, byteorder='big')
self.mem.append((self.base + offset, data))
elif desc == '02': # Extended Segment Address
self.base = int.from_bytes(data, byteorder='big') * 0x10
elif desc == '04': # Extended Linear Address
self.base = int.from_bytes(data, byteorder='big') * 0x10000
class QlLoaderMCU(QlLoader):
def __init__(self, ql:Qiling):
super().__init__(ql)
self.entry_point = 0
self.load_address = 0
self.filetype = self.guess_filetype()
if self.filetype == 'elf':
with open(self.ql.path, 'rb') as infile:
self.elf = ELFFile(io.BytesIO(infile.read()))
elif self.filetype == 'bin':
self.map_address = self.argv[1]
else: # self.filetype == 'hex':
self.ihex = IhexParser(self.ql.path)
def guess_filetype(self):
if self.ql.path.endswith('.elf'):
return 'elf'
if self.ql.path.endswith('.bin'):
return 'bin'
if self.ql.path.endswith('.hex'):
return 'hex'
return 'elf'
def reset(self):
if self.filetype == 'elf':
for segment in self.elf.iter_segments(type='PT_LOAD'):
self.ql.mem.write(segment['p_paddr'], segment.data())
# TODO: load symbol table
elif self.filetype == 'bin':
with open(self.ql.path, 'rb') as f:
self.ql.mem.write(self.map_address, f.read())
else: # self.filetype == 'hex':
for begin, data in self.ihex.segments:
self.ql.mem.write(begin, data)
self.ql.arch.init_context()
self.entry_point = self.ql.arch.regs.read('pc')
def load_profile(self):
self.ql.env.update(self.ql.profile)
def load_env(self):
for name, args in self.env.items():
memtype = args['type']
if memtype == 'memory':
size = args['size']
base = args['base']
self.ql.mem.map(base, size, info=f'[{name}]')
if memtype == 'remap':
size = args['size']
base = args['base']
alias = args['alias']
self.ql.hw.setup_remap(alias, base, size, info=f'[{name}]')
if memtype == 'mmio':
size = args['size']
base = args['base']
self.ql.hw.setup_mmio(base, size, info=f'[{name}]')
if memtype == 'core':
self.ql.hw.create(name.lower())
def run(self):
self.load_profile()
self.load_env()
## Handle interrupt from instruction execution
self.ql.hook_intr(self.ql.arch.unicorn_exception_handler)
self.reset()