Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

INTFowarder & HWRunner introduction #125

Merged
merged 52 commits into from
Dec 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
04e62ba
WIP: Getting coresight to work
albrecht-flo Jun 2, 2023
2a7761f
Fixing Coresight protocol and interrupt forwarding TO QEmu
albrecht-flo Jun 8, 2023
144fbf9
WIP interrupts fixing my own mistakes
albrecht-flo Jun 9, 2023
52eda23
Added interrupt state transfer
albrecht-flo Jun 15, 2023
3fc46d9
Reactivated interrupt forwarding, works with timer but the alarm runs…
albrecht-flo Jun 20, 2023
d729629
Fixing crash due to protocol shutdown order
albrecht-flo Jun 22, 2023
b508d97
Fixed issues with memory protocols
albrecht-flo Jun 22, 2023
25a570c
Fixed IVT setup in interrupt protocol
albrecht-flo Jun 22, 2023
b025459
WIP: Added interrupt recording plugin and protocol, not complete
albrecht-flo Jun 29, 2023
fcb3ba9
WIP: Fixed the stub to include an end of buffer flag
albrecht-flo Jun 30, 2023
28e1811
Interrupt recording protocol and plugin v1
albrecht-flo Jun 30, 2023
51a79d2
Interrupt recording protocol cleanup
albrecht-flo Jun 30, 2023
8741189
Added rudimentary support for ARM Cortex M4 (without FPU registers)
Jul 13, 2023
aa40e6e
Interrupt recording without manipulating main loop control flow
Jul 13, 2023
e42d833
WIP: USB rehosting
Jul 17, 2023
cfef225
Updated interrupt messages to include the IRQ-Address
Jul 17, 2023
d0a12e6
IRQ fixing
Jul 17, 2023
28cb00c
IRQ fixing; Reordering of setup code and removal of IRQ init because …
Jul 18, 2023
2142662
IRQ message passing fixes
Jul 18, 2023
7ad0046
Allow plugins to get configuration parameters at load time
Jul 19, 2023
7351ec4
Switch to trace approach for interrupt rehosting, to capture quickly …
Jul 19, 2023
f094978
Allow avatar peripherals to know on what target they got called
Jul 19, 2023
ebda57f
WIP: Prevent interrupt interleaving
Jul 19, 2023
bb018ac
Fixed wrong program counter
Jul 19, 2023
4bc2ac3
WIP: picow-blink rehosting, runs much further but crashes because it …
Jul 21, 2023
58564e0
Allow OpenOCD target to have a gdb binary for symbols
Jul 25, 2023
12b84bc
WIP HAL calling
Jul 26, 2023
b4936a5
WIP HAL calling step 2
Jul 27, 2023
52fb94d
WIP HAL calling step 2- THIS IS BROKEN AF
Jul 27, 2023
c60dc6a
Finally a working version
Jul 27, 2023
36447ec
First working HAL implementation for send-uart
Jul 27, 2023
cb7fc0d
Make HALCaller config more expressive
Jul 28, 2023
8b292c0
Made HAL calls more generic, allow for up more arguments, allow void …
Jul 28, 2023
f84e46f
OpenOCD protocol, rework raw memory read/write for higher performance…
Jul 28, 2023
743023f
Trigger HAL Exit after Hardware reset is complete
Jul 28, 2023
e843e67
Make protocol usable as a signaled target continue protocol
Aug 2, 2023
ac02eff
WIP: PICOW rehosting
Aug 4, 2023
32db035
WIP: Software interrupt rehosting support by using the hardware in th…
Aug 7, 2023
d770881
WIP: USB rehosting, cleanup of software interrupt stuff
Aug 7, 2023
8e1d1c7
Cleanup interrupt recording
Aug 16, 2023
3c26de7
HAL only deal with interrupt protocol if present
Aug 16, 2023
718beec
HALCaller rename to HWRunner
Aug 17, 2023
b361b90
HWRunner OpenOCD fix; WiFi experiments final
Aug 21, 2023
1eb31a4
HWRunner naming cleanup
Sep 1, 2023
308f97e
Interrupt Recorder naming cleanup
Sep 1, 2023
0a5dfac
Interrupt Forwarding naming cleanup
Sep 1, 2023
c0eed74
Cleanup and fixup of refactorings
Sep 4, 2023
80d5922
INTFowrader & HWRunner summary
Sep 30, 2023
abba38a
Final cleanup
Sep 30, 2023
36f82be
Remove union types for type hint
rawsample Dec 1, 2023
3197955
Remove crashing log
rawsample Dec 1, 2023
5271aed
Remove crashing log line when using pypanda
rawsample Dec 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions avatar2/archs/arm.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@ class ARM_CORTEX_M3(ARM):
qemu_name = 'arm'
gdb_name = 'arm'

capstone_arch = CS_ARCH_ARM
keystone_arch = KS_ARCH_ARM
capstone_mode = CS_MODE_LITTLE_ENDIAN | CS_MODE_THUMB | CS_MODE_MCLASS
keystone_arch = KS_ARCH_ARM
keystone_mode = KS_MODE_LITTLE_ENDIAN | KS_MODE_THUMB
Expand Down Expand Up @@ -86,7 +84,8 @@ def init(avatar):
pass


ARMV7M = ARM_CORTEX_M3

ARMV7M = [ARM_CORTEX_M3]


class ARMBE(ARM):
Expand Down
66 changes: 33 additions & 33 deletions avatar2/avatar2.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class Avatar(Thread):
"""

def __init__(
self, arch=ARM, cpu_model=None, output_directory=None, log_to_stdout=True, configure_logging=True
self, arch=ARM, cpu_model=None, output_directory=None, log_to_stdout=True, configure_logging=True
):
super(Avatar, self).__init__()

Expand Down Expand Up @@ -70,7 +70,7 @@ def __init__(
makedirs(self.output_directory)

self.log = logging.getLogger("avatar")

if configure_logging:
format = "%(asctime)s | %(name)s.%(levelname)s | %(message)s"

Expand Down Expand Up @@ -130,8 +130,8 @@ def load_config(self, file_name=None):
if not tname in self.targets:
raise Exception(
(
"Requested target %s not found in config. "
"Aborting." % tname
"Requested target %s not found in config. "
"Aborting." % tname
)
)
mr["forwarded_to"] = self.targets[tname]
Expand Down Expand Up @@ -183,15 +183,15 @@ def sigint_wrapper(self, signal, frame):
self.log.info("Avatar Received SIGINT")
self.sigint_handler()

def load_plugin(self, name, local=False):
def load_plugin(self, name, local=False, *args, **kwargs):
if local is True:
plugin = __import__(name, fromlist=["."])
else:
plugin = __import__(
"avatar2.plugins.%s" % name, fromlist=["avatar2.plugins"]
)

plugin.load_plugin(self)
plugin.load_plugin(self, *args, **kwargs)
self.loaded_plugins += [name]

@watch("AddTarget")
Expand Down Expand Up @@ -233,21 +233,21 @@ def init_targets(self):
t[1].init()

def add_memory_range(
self,
address,
size,
name=None,
permissions="rwx",
file=None,
file_offset=None,
file_bytes=None,
forwarded=False,
forwarded_to=None,
emulate=None,
interval_tree=None,
inline=False,
overwrite=False,
**kwargs
self,
address,
size,
name=None,
permissions="rwx",
file=None,
file_offset=None,
file_bytes=None,
forwarded=False,
forwarded_to=None,
emulate=None,
interval_tree=None,
inline=False,
overwrite=False,
**kwargs
):
"""
Adds a memory range to avatar
Expand Down Expand Up @@ -294,7 +294,7 @@ def add_memory_range(
**kwargs
)

mr_set = memory_ranges[address : address + size]
mr_set = memory_ranges[address: address + size]
if overwrite is True and len(mr_set) > 0:
start = min(mr_set, key=lambda x: x.begin).begin
end = max(mr_set, key=lambda x: x.end).end
Expand All @@ -312,7 +312,7 @@ def add_memory_range(
interval.data.size,
)

memory_ranges[address : address + size] = m
memory_ranges[address: address + size] = m

return m

Expand Down Expand Up @@ -354,8 +354,8 @@ def transfer_state(self, from_target, to_target, sync_regs=True, synced_ranges=[
"""

if (
from_target.state & TargetStates.STOPPED == 0
or to_target.state & TargetStates.STOPPED == 0
from_target.state & TargetStates.STOPPED == 0
or to_target.state & TargetStates.STOPPED == 0
):
raise Exception(
"Targets must be stopped for State Transfer, \
Expand Down Expand Up @@ -403,6 +403,7 @@ def _handle_update_state_message(self, message):
def _handle_breakpoint_hit_message(self, message):
self.log.info("Breakpoint hit for Target: %s" % message.origin.name)
self._handle_update_state_message(message)

# Breakpoints are two stages: SYNCING | STOPPED -> HandleBreakpoint -> STOPPED
# This makes sure that all handlers are complete before stopping and breaking wait()

Expand Down Expand Up @@ -446,8 +447,8 @@ def _handle_remote_memory_read_message(self, message):
try:
kwargs = {"num_words": message.num_words, "raw": message.raw}
if (
hasattr(range.forwarded_to, "read_supports_pc")
and range.forwarded_to.read_supports_pc is True
hasattr(range.forwarded_to, "read_supports_pc")
and range.forwarded_to.read_supports_pc is True
):
kwargs["pc"] = message.pc

Expand All @@ -457,13 +458,13 @@ def _handle_remote_memory_read_message(self, message):
if not message.raw and message.num_words == 1 and not isinstance(mem, int):
raise Exception(
(
"Forwarded read returned data of type %s "
"(expected: int)" % type(mem)
"Forwarded read returned data of type %s "
"(expected: int)" % type(mem)
)
)
success = True
except Exception as e:
self.log.exception("RemoteMemoryRead failed: %s" % e)
self.log.exception("RemoteMemoryRead from %s failed: %s" % (range.forwarded_to, e))
mem = -1
success = False

Expand All @@ -484,8 +485,8 @@ def _handle_remote_memory_write_message(self, message):

kwargs = {}
if (
hasattr(mem_range.forwarded_to, "write_supports_pc")
and mem_range.forwarded_to.write_supports_pc is True
hasattr(mem_range.forwarded_to, "write_supports_pc")
and mem_range.forwarded_to.write_supports_pc is True
):
kwargs["pc"] = message.pc

Expand Down Expand Up @@ -515,7 +516,6 @@ def run(self):
"Avatar received %s. Queue-Status: %d/%d"
% (message, self.queue.qsize(), self.fast_queue.qsize())
)

handler = self.message_handlers.get(message.__class__, None)
if handler is None:
raise Exception("No handler for Avatar-message %s registered" % message)
Expand Down
18 changes: 9 additions & 9 deletions avatar2/memory_range.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def __init__(self, address, size, name=None, permissions='rwx',
self.name = (
name
if name is not None else
"mem_range_0x{:08x}_0x{:08x}".format(address, address+size))
"mem_range_0x{:08x}_0x{:08x}".format(address, address + size))
self.permissions = permissions
self.file = abspath(file) if file is not None else None
self.file_offset = file_offset if file_offset is not None else None
Expand All @@ -44,23 +44,25 @@ def __init__(self, address, size, name=None, permissions='rwx',
self.forwarded_to = forwarded_to
self.__dict__.update(kwargs)


def dictify(self):
"""
Returns the memory range as *printable* dictionary
"""
from .avatar2 import Avatar # we cannot do this import at top-level
from .avatar2 import Avatar # we cannot do this import at top-level
# Assumption: dicts saved in mrs are of primitive types only
expected_types = (str, bool, int, dict, AvatarPeripheral, Avatar, list)
if version_info < (3, 0): expected_types += (unicode, )
if version_info < (3, 0): expected_types += (unicode,)

tmp_dict = dict(self.__dict__)
mr_dict = {}
while tmp_dict != {}:
k, v = tmp_dict.popitem()
if v is None or False: continue
elif k == 'forwarded_to': v = v.name
# TODO handle emulate
if v is None or False:
continue
elif k == 'forwarded_to':
v = v.name
if k == 'emulate_config': # Skip config for emulated peripheral
continue
if not isinstance(v, expected_types):
raise Exception(
"Unsupported type %s for dictifying %s for mem_range at 0x%x"
Expand All @@ -71,5 +73,3 @@ def dictify(self):
v = v.__class__.__name__
mr_dict[k] = v
return mr_dict


48 changes: 48 additions & 0 deletions avatar2/message.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from .plugins.arm.hal import HWFunction


class AvatarMessage(object):
Expand All @@ -23,6 +24,7 @@ def __init__(self, origin, breakpoint_number, address):
self.breakpoint_number = breakpoint_number
self.address = address


class SyscallCatchedMessage(BreakpointHitMessage):
def __init__(self, origin, breakpoint_number, address, type='entry'):
super(self.__class__, self).__init__(origin, breakpoint_number, address)
Expand All @@ -40,6 +42,7 @@ def __init__(self, origin, id, pc, address, size, dst=None):
self.num_words = 1
self.raw = False


class RemoteMemoryWriteMessage(AvatarMessage):
def __init__(self, origin, id, pc, address, value, size, dst=None):
super(self.__class__, self).__init__(origin)
Expand All @@ -50,12 +53,14 @@ def __init__(self, origin, id, pc, address, value, size, dst=None):
self.size = size
self.dst = dst


class RemoteInterruptEnterMessage(AvatarMessage):
def __init__(self, origin, id, interrupt_num):
super(self.__class__, self).__init__(origin)
self.id = id
self.interrupt_num = interrupt_num


class RemoteInterruptExitMessage(AvatarMessage):
def __init__(self, origin, id, transition_type, interrupt_num):
super(self.__class__, self).__init__(origin)
Expand All @@ -64,4 +69,47 @@ def __init__(self, origin, id, transition_type, interrupt_num):
self.interrupt_num = interrupt_num


class TargetInterruptEnterMessage(AvatarMessage):
def __init__(self, origin, id, interrupt_num, isr_addr):
super(self.__class__, self).__init__(origin)
self.id = id
self.interrupt_num = interrupt_num
self.isr_addr = isr_addr


class TargetInterruptExitMessage(AvatarMessage):
def __init__(self, origin, id, interrupt_num, isr_addr):
super(self.__class__, self).__init__(origin)
self.id = id
self.interrupt_num = interrupt_num
self.isr_addr = isr_addr


class HWEnterMessage(AvatarMessage):
def __init__(self, origin, function: HWFunction, return_address: int):
super(self.__class__, self).__init__(origin)
self.function = function
self.return_address = return_address

def __str__(self):
return f"{self.__class__.__name__} from {self.origin.name} returning to 0x{self.return_address:x}"

def __repr__(self):
return self.__str__()


class HWExitMessage(AvatarMessage):
def __init__(self, origin, function: HWFunction, return_val: int, return_address: int):
super(self.__class__, self).__init__(origin)
self.function = function
self.return_val = return_val
self.return_address = return_address

def __str__(self):
return f"{self.__class__.__name__} from {self.origin.name} to 0x{self.return_address:x} with return_value 0x{self.return_val:x}"

def __repr__(self):
return self.__str__()


from .targets.target import TargetStates
17 changes: 10 additions & 7 deletions avatar2/peripherals/avatar_peripheral.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from cached_property import cached_property



class AvatarPeripheral(object):
def __init__(self, name, address, size, **kwargs):
self.name = name if name else "%s_%x" % (self.__class__.__name__, address)
Expand Down Expand Up @@ -39,7 +38,7 @@ def shutdown(self):
"""
pass

def write_memory(self, address, size, value, num_words=1, raw=False, pc=0):
def write_memory(self, address, size, value, num_words=1, raw=False, origin=None, pc=0):

if num_words != 1 or raw is True:
raise Exception(
Expand All @@ -48,7 +47,7 @@ def write_memory(self, address, size, value, num_words=1, raw=False, pc=0):
)

offset = address - self.address
intervals = self.write_handler[offset : offset + size]
intervals = self.write_handler[offset: offset + size]
if intervals == set():
raise Exception(
"No write handler for peripheral %s at offset %d \
Expand All @@ -62,18 +61,20 @@ def write_memory(self, address, size, value, num_words=1, raw=False, pc=0):
% (self.name, offset)
)

kwargs = {} if self.write_supports_pc is False else {"pc": pc}
kwargs = {'origin': origin}
if self.write_supports_pc is True:
kwargs["pc"] = pc
return intervals.pop().data(offset, size, value, **kwargs)

def read_memory(self, address, size, num_words=1, raw=False, pc=0):
def read_memory(self, address, size, num_words=1, raw=False, origin=None, pc=0):
if num_words != 1 or raw is True:
raise Exception(
"read_memory for AvatarPeripheral does not support \
'num_words' or 'raw' kwarg"
)

offset = address - self.address
intervals = self.read_handler[offset : offset + size]
intervals = self.read_handler[offset: offset + size]

if intervals == set():
raise Exception(
Expand All @@ -87,5 +88,7 @@ def read_memory(self, address, size, num_words=1, raw=False, pc=0):
at offset %d"
% (self.name, offset)
)
kwargs = {} if self.write_supports_pc is False else {"pc": pc}
kwargs = {'origin': origin}
if self.write_supports_pc is True:
kwargs["pc"] = pc
return intervals.pop().data(offset, size, **kwargs)
Loading
Loading