board_inspector: add builders of AML AST nodes
This patch adds the acpiparser.aml.builder module which provides methods to construct AML trees from scratch in Python. Similar to how parsers and binary generators are implemented, this module constructs most builder methods from the AML grammar defined in the acpiparser.aml.grammar module. AML objects whose grammar are not present in the grammar module require special treatment and their builders are implemented explicitly. The methods have the same name as the AML tree labels defined in the grammar. In addition, this module also provides the method `build_value` which converts plain integers, strings or interpreter values (which are defined in the datatypes module) to AML trees. With the builders, the `interpret_method_call` method in the ConcreteInterpreter is refined to build the (fake) MethodInvocation node using the builders and handle the actual parameters as well. Tracked-On: #6287 Signed-off-by: Junjie Mao <junjie.mao@intel.com>
This commit is contained in:
parent
e91ace7341
commit
a3aa0797b1
|
@ -0,0 +1,140 @@
|
|||
# Copyright (C) 2021 Intel Corporation. All rights reserved.
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#
|
||||
|
||||
from . import grammar
|
||||
from . import datatypes
|
||||
from .tree import Tree
|
||||
|
||||
### Basic data types
|
||||
|
||||
def __build_value(label, value):
|
||||
tree = Tree(label, [value])
|
||||
tree.register_structure(("value",))
|
||||
tree.complete_parsing()
|
||||
return tree
|
||||
|
||||
def __build_string(label, s):
|
||||
assert isinstance(s, str)
|
||||
return __build_value(label, s)
|
||||
|
||||
def __build_const_data(label, data):
|
||||
assert isinstance(data, int)
|
||||
return __build_value(label, data)
|
||||
|
||||
NameSeg = lambda x: __build_string("NameSeg", x)
|
||||
NameString = lambda x: __build_string("NameString", x)
|
||||
String = lambda x: __build_string("String", x)
|
||||
|
||||
def ByteList(data):
|
||||
assert isinstance(data, (bytes, bytearray))
|
||||
return __build_value("ByteList", data)
|
||||
|
||||
ByteData = lambda x: __build_const_data("ByteData", x)
|
||||
WordData = lambda x: __build_const_data("WordData", x)
|
||||
DWordData = lambda x: __build_const_data("DWordData", x)
|
||||
TWordData = lambda x: __build_const_data("TWordData", x)
|
||||
QWordData = lambda x: __build_const_data("QWordData", x)
|
||||
|
||||
def PkgLength(length=0):
|
||||
return __build_const_data("PkgLength", length)
|
||||
|
||||
FieldLength = lambda x: __build_const_data("FieldLength", x)
|
||||
|
||||
### Sequences
|
||||
|
||||
def MethodInvocation(name, *args):
|
||||
if isinstance(name, str):
|
||||
name_tree = NameString(name)
|
||||
else:
|
||||
name_tree = name
|
||||
tree = Tree("MethodInvocation", [name])
|
||||
for arg in args:
|
||||
assert isinstance(arg, Tree)
|
||||
tree.append_child(arg)
|
||||
tree.register_structure(("NameString", "TermArg*"))
|
||||
tree.complete_parsing()
|
||||
return tree
|
||||
|
||||
def __create_sequence_builder(label):
|
||||
def aux(tree, elem, arg):
|
||||
if isinstance(arg, Tree):
|
||||
# TODO: validate the given arg
|
||||
tree.append_child(arg)
|
||||
else:
|
||||
tree.append_child(globals()[elem](arg))
|
||||
|
||||
seq = grammar.get_definition(label)
|
||||
structure = grammar.get_names(label)
|
||||
|
||||
def fn(*args):
|
||||
tree = Tree(label)
|
||||
it = iter(args)
|
||||
for elem in seq:
|
||||
if isinstance(elem, int): # The leading opcode
|
||||
continue
|
||||
elif elem.endswith("*"):
|
||||
for arg in it:
|
||||
aux(tree, elem, arg)
|
||||
elif elem.endswith("?"):
|
||||
try:
|
||||
aux(tree, elem, next(it))
|
||||
except StopIteration:
|
||||
pass
|
||||
else:
|
||||
aux(tree, elem, next(it))
|
||||
tree.register_structure(structure)
|
||||
tree.complete_parsing()
|
||||
return tree
|
||||
return fn
|
||||
|
||||
def build_value(value):
|
||||
if isinstance(value, (int, datatypes.Integer)):
|
||||
if isinstance(value, int):
|
||||
value = datatypes.Integer(value)
|
||||
v = value.get()
|
||||
return \
|
||||
ZeroOp() if v == 0 else \
|
||||
OneOp() if v == 1 else \
|
||||
ByteConst(v) if v <= 0xff else \
|
||||
WordConst(v) if v <= 0xffff else \
|
||||
DWordConst(v) if v <= 0xffffffff else \
|
||||
QWordConst(v)
|
||||
elif isinstance(value, datatypes.Buffer):
|
||||
buffer_size = len(value.get())
|
||||
builder = ByteConst if buffer_size <= 0xff else \
|
||||
WordConst if buffer_size <= 0xffff else \
|
||||
DWordConst if buffer_size <= 0xffffffff else \
|
||||
QWordConst
|
||||
return DefBuffer(
|
||||
PkgLength(),
|
||||
builder(buffer_size),
|
||||
ByteList(value.get()))
|
||||
elif isinstance(value, datatypes.Package):
|
||||
elements = list(map(build_value, value.elements))
|
||||
return DefPackage(
|
||||
PkgLength(),
|
||||
len(value.elements),
|
||||
PackageElementList(elements))
|
||||
elif isinstance(value, (str, datatypes.String)):
|
||||
if isinstance(value, str):
|
||||
return String(value)
|
||||
else:
|
||||
return String(value.get())
|
||||
elif isinstance(value, datatypes.BufferField):
|
||||
return build_value(value.to_integer())
|
||||
else:
|
||||
return None
|
||||
|
||||
for sym in dir(grammar):
|
||||
# Ignore builtin members and opcode constants
|
||||
if sym.startswith("__") or (sym.upper() == sym):
|
||||
continue
|
||||
|
||||
definition = getattr(grammar, sym)
|
||||
if isinstance(definition, tuple):
|
||||
globals()[sym] = __create_sequence_builder(sym)
|
||||
elif isinstance(definition, list) and len(definition) == 1:
|
||||
if definition[0] in globals().keys():
|
||||
globals()[sym] = globals()[definition[0]]
|
|
@ -6,6 +6,7 @@
|
|||
from .context import *
|
||||
from .datatypes import *
|
||||
from .tree import Tree, Interpreter
|
||||
from . import builder
|
||||
|
||||
class MethodReturn(Exception):
|
||||
""" A pseudo exception to return from a method"""
|
||||
|
@ -86,13 +87,18 @@ class ConcreteInterpreter(Interpreter):
|
|||
|
||||
def interpret_method_call(self, name, *args):
|
||||
stack_depth_before = len(self.stack)
|
||||
name_string = Tree("NameString", [name])
|
||||
name_string.register_structure(("value",))
|
||||
name_string.complete_parsing()
|
||||
name_string = builder.NameString(name)
|
||||
name_string.scope = self.context.parent(name)
|
||||
pseudo_invocation = Tree("MethodInvocation", [name_string])
|
||||
pseudo_invocation.register_structure(("NameString", "TermArg*"))
|
||||
pseudo_invocation.complete_parsing()
|
||||
|
||||
arg_trees = []
|
||||
for arg in args:
|
||||
v = builder.build_value(arg)
|
||||
if v != None:
|
||||
arg_trees.append(v)
|
||||
else:
|
||||
raise NotImplementedError(f"Unsupported type of method argument: {arg}")
|
||||
|
||||
pseudo_invocation = builder.MethodInvocation(name_string, *arg_trees)
|
||||
try:
|
||||
val = self.interpret(pseudo_invocation)
|
||||
except:
|
||||
|
|
Loading…
Reference in New Issue