Rework Translation Layers to tie more closely to configurations

This change is quite signficant, and requires that TranslationLayers
get all additional parameters that they need through their requirements.

These are now automatically enumerated and populated on object
construction based on the requirements, so should not require lots of
repetitive filling out of fields.

It does come with the downside that TranslationLayers can only be
contructed with a context (and appropiate config), but TLs in particular
always require a context (to contain the base layer) and blank configs
can be constructed relatively easily (convenience functions can be added
if necessary).

This allows configuration trees to be built up, and their configs
spliced into an existing config (as if it were being loaded from a
file).

Not all ConstructableRequirements use this method, since SymbolTables
(for example) do not have access to the context or config_path in order
to get to any parameters stored in the context's config.  They therefore
are still passed their requirement values as __init__ parameters
instead.
This commit is contained in:
Mike Auty
2016-08-22 02:20:10 +01:00
parent d3e63fbc1a
commit 3dc161f9b4
5 changed files with 37 additions and 28 deletions
+9 -8
View File
@@ -24,11 +24,11 @@ class LayerStacker(interfaces.automagic.AutomagicInterface):
self.local_store = self.location.path
new_context = context.clone()
current_layer = context.memory.free_layer_name()
# This must be specific to get us started
new_context.add_layer(
physical.FileLayer(new_context, interfaces.configuration.path_join("automagic_general", current_layer),
current_layer, self.local_store))
current_layer_name = context.memory.free_layer_name()
current_config_path = interfaces.configuration.path_join("automagic_general", current_layer_name)
# This must be specific to get us started, setup the config and run
new_context.config[interfaces.configuration.path_join(current_config_path, "filename")] = self.local_store
new_context.add_layer(physical.FileLayer(new_context, current_config_path, current_layer_name))
# Repeatedly apply "determine what this is" code and build as much up as possible
stacked = True
@@ -42,15 +42,16 @@ class LayerStacker(interfaces.automagic.AutomagicInterface):
for stacker_cls in stack_set:
stacker = stacker_cls()
try:
new_layer = stacker.stack(new_context, current_layer)
new_layer = stacker.stack(new_context, current_layer_name)
new_context.memory.add_layer(new_layer)
break
except Exception as excp:
pass
else:
stacked = False
if new_layer and stacker_cls:
stacked_layers = [new_layer] + stacked_layers
current_layer = new_layer
stacked_layers = [new_layer.name] + stacked_layers
current_layer_name = new_layer.name
stacked = True
stack_set.remove(stacker_cls)
+11 -8
View File
@@ -183,15 +183,17 @@ class IntelHelper(interfaces.automagic.AutomagicInterface, interfaces.automagic.
def stack(cls, context, layer_name):
"""Attempts to determine and stack an intel layer on a physical layer where possible"""
hits = context.memory[layer_name].scan(context, PageMapScanner(cls.tests))
new_layer = None
layer = None
for test, dtb in hits:
new_layer = context.memory.free_layer_name("IntelLayer")
new_layer_name = context.memory.free_layer_name("IntelLayer")
config_path = interfaces.configuration.path_join("IntelHelper", new_layer_name)
context.config[interfaces.configuration.path_join(config_path, "memory_layer")] = layer_name
context.config[interfaces.configuration.path_join(config_path, "page_map_offset")] = dtb
layer = test.layer_type(context,
config_path = interfaces.configuration.path_join("IntelHelper", new_layer),
name = new_layer,
page_map_offset = dtb)
config_path = config_path,
name = new_layer_name)
break
return new_layer
return layer
if __name__ == '__main__':
@@ -215,10 +217,11 @@ if __name__ == '__main__':
nativelst = native.x86NativeTable
ctx = contexts.Context(nativelst)
for filename in args.filenames:
ctx.config[
interfaces.configuration.path_join('config' + str(args.filenames.index(filename)), "filename")] = filename
data = layers.physical.FileLayer(ctx,
'config' + str(args.filenames.index(filename)),
'data' + str(args.filenames.index(filename)),
filename = filename)
'data' + str(args.filenames.index(filename)))
ctx.memory.add_layer(data)
tests = []
@@ -163,11 +163,6 @@ class ConstructableRequirementInterface(RequirementInterface):
if requirement_dict is None:
requirement_dict = {}
node_config = context.config.branch(config_path)
# Construct the class
for req in cls.get_requirements():
if req.name in node_config.data and req.name != "class":
requirement_dict[req.name] = node_config.data[req.name]
# Fulfillment must happen, exceptions happening here mean the requirements aren't correct
# and these need to be raised and fixed, rather than caught and ignored
obj = cls(**requirement_dict)
@@ -184,6 +179,12 @@ class ConfigurableInterface(validity.ValidityRoutines, metaclass = ABCMeta):
self._context = self._check_type(context, ContextInterface)
self._config_path = self._check_type(config_path, str)
# Store these programmatically, so we don't keep repreating the requirements
# This also allows constructed objects to populate a configuration without too much trouble
for requirement in self.get_requirements():
# Create the (private) properties using the config as backend storage
setattr(self, "_" + requirement.name, self.config.get(requirement.name, requirement.default))
@property
def context(self):
return self._context
@@ -192,6 +193,10 @@ class ConfigurableInterface(validity.ValidityRoutines, metaclass = ABCMeta):
def config_path(self):
return self._config_path
@config_path.setter
def config_path(self, value):
self._config_path = self._check_type(value, str)
@property
def config(self):
return self._context.config.branch(self._config_path)
+3 -3
View File
@@ -19,10 +19,10 @@ class Intel(interfaces.layers.TranslationLayerInterface):
"architecture": "ia32"
}
def __init__(self, context, config_path, name, page_map_offset, memory_layer, swap_layer = None):
def __init__(self, context, config_path, name):
super().__init__(context, config_path, name)
self._base_layer = self._check_type(memory_layer, str)
self._page_map_offset = self._check_type(page_map_offset, int)
self._base_layer = self._check_type(self.config["memory_layer"], str)
self._page_map_offset = self._check_type(self.config["page_map_offset"], int)
# All Intel address spaces work on 4096 byte pages
self._page_size_in_bits = 12
+4 -4
View File
@@ -63,16 +63,16 @@ class FileLayer(interfaces.layers.DataLayerInterface):
provides = {"type": "physical"}
priority = 20
def __init__(self, context, config_path, name, filename):
def __init__(self, context, config_path, name):
super().__init__(context, config_path, name)
self._filename = filename
self._filename = self.config["filename"]
self._file_ = None
self._size = os.path.getsize(filename)
self._size = os.path.getsize(self._filename)
@property
def _file(self):
"""Property to prevent the intializer storing an unserializable open file (for context cloning)"""
"""Property to prevent the initializer storing an unserializable open file (for context cloning)"""
# FIXME: Add "+" to the mode once we've determined whether write mode is enabled
mode = "rb"
if not self._file_: