Python装饰器针对avatar部分解析
Python装饰器
装饰器太难了,实在是看不懂,所以要写一篇对装饰器的详解,直接上Halucinator和Avatar的装饰器部分的代码来进行解释,如果需要知道装饰器的基础的话建议直接百度装饰器,本篇主要用于理解Halucinator和Avatar2。
# Halucinator——stm32f4_uart.py
@bp_handler(['HAL_UART_Transmit', 'HAL_UART_Transmit_IT', 'HAL_UART_Transmit_DMA'])
def handle_tx(self, qemu, bp_addr):
'''
Reads the frame out of the emulated device, returns it and an
id for the interface(id used if there are multiple ethernet devices)
'''
huart = qemu.get_arg(0)
hw_addr = qemu.read_memory(huart, 4, 1)
buf_addr = qemu.get_arg(1)
buf_len = qemu.get_arg(2)
data = qemu.read_memory(buf_addr, 1, buf_len, raw=True)
hal_log.info("UART %i TX:%s" % (hw_addr, data))
self.model.write(hw_addr, data)
return True, 0
在这个函数里他调用了get_arg函数好几次,查看它的定义会找到代码是这么写的
def get_arg(self, idx):
'''
Gets the value for a function argument (zero indexed)
:param idx The argument index to return
:returns Argument value
'''
if idx >= 0 and idx < 4:
return self.read_register("r%i" % idx)
elif idx >= 4:
sp = self.read_register("sp")
stack_addr = sp + (idx-4) * 4
return self.read_memory(stack_addr, 4, 1)
else:
raise ValueError("Invalid arg index")
所以通过这个函数就能知道,最关键的函数在read_register部分。但要是想找read_register的话,其定义就只在avatar2中了,现在去看看avatar2里搜一下

所有定义过read_register的都是在一些不是直接挂钩的py文件里,Halucinator直接调用的QemuTarget里却并没有写入这个函数的内容,可是直接看QemuTarget类的声明方式的话会发现其最根本的在这,类继承的问题。
class QemuTarget(Target):
""""""
def __init__(
self,
avatar,
...
我们首先需要知道类的概念,对于类,只要学过C++都能知道它是用来干什么的,而在python中,类也有一样的功能,Python的新建类如果继承了之前的类的话,那么它就可以调用上一个类中的函数,在QemuTarget类中,其继承了Target类,所以他能够调用Target中的所有已定义过的函数,这也就是为什么Halucinator能够直接使用read_register的原因。同时可以再看一下Target中定义的read_register本身,可以看见它对函数的定义:
@watch('TargetRegisterRead')
#@action_valid_decorator_factory(TargetStates.STOPPED, 'registers')
def read_register(self, register):
"""
Reading a register from the target
:param register: The name of the register
:return: The actual value read from the register
"""
return self.protocols.registers.read_register(register)
在这我们要开始讲一下watch函数!(终于要开始讲装饰器了嘛呜呜呜)
我们看一下watch函数中的内容(watchmen.py)对于该函数的解释大部分已经在注释中了
def watch(watched_type):
"""
Decorator for the watchmen system
"""
def decorator(func):
@wraps(func)
def watchtrigger(self, *args, **kwargs):
# To avoid circular dependencies, we import here ...
from .avatar2 import Avatar
from .targets.target import Target
cb_kwargs = dict(kwargs) #将多个参数转换成字典格式
if isinstance(self, Avatar): #检查调用该函数的类是否是Avatar类
avatar = self
elif isinstance(self, Target): #如果是Target类则赋一个值
avatar = self.avatar
cb_kwargs['watched_target'] = self #朝字典中添加一个新的键值,{'watched_target': 'Target'}
avatar.watchmen.t(watched_type, BEFORE, *args, **cb_kwargs) #Trigger函数部分,后面会讲
ret = func(self, *args, **kwargs) #运行函数本身
cb_kwargs.update({'watched_return': ret}) #给字典添加键值对
cb_ret = avatar.watchmen.t(watched_type, AFTER, *args, **cb_kwargs) #Trigger函数部分
return ret if cb_ret is None else cb_ret
return watchtrigger
return decorator
watchmen是一定要讲的,因为在Avatar中它放在了根目录就说明这个函数是由自己的用处的,并不是一点作用没有,当然不可否认这个主要功能还是做其他函数的装饰器的功能,可是因为本文是对装饰器的详解(笑),那么就要深层挖掘装饰器内容。
那么我们就看watchmen类中对Trigger函数的描述吧
def trigger(self, watch_type, when, *args, **kwargs):
ret = None
for watchman in self._watched_events[watch_type]:
if watchman.when == when:
if watchman.overwrite_return:
ret = watchman.react(self._avatar, *args, **kwargs)
kwargs.update({'watched_return': ret})
else:
watchman.react(self._avatar, *args, **kwargs)
return ret
该函数最主要的功能就是查看在运行函数之前/之后是否需要执行前置步骤,如果不需要的话那就直接返回None,在read_register中是不需要额外的步骤的,所以就没有Trigger的使用必要,那么在这个里面是否是全部都不需要Trigger呢?当然不是,有一些函数是需要运行Trigger的,下面这个就是一个需要Trigger的例子。
#target_wait.py
a.watchmen.add('TargetWait', when='before', callback=delay)
尽管目前我不知道这些有什么用,但是在这三四个月总会知道的诶嘿~☆
所以它最后read_register就会到相关协议的定义函数上,下一篇就会对每一个寄存器、断点等具体函数做详解。

浙公网安备 33010602011771号