Miasm2
 All Classes Namespaces Files Functions Variables Typedefs Properties Macros
jitcore.py
Go to the documentation of this file.
1 #
2 # Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net>
3 #
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 2 of the License, or
7 # (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License along
15 # with this program; if not, write to the Free Software Foundation, Inc.,
16 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 #
18 from miasm2.core import asmbloc
19 from miasm2.core.interval import interval
20 from miasm2.core.utils import BoundedDict
21 from miasm2.jitter.csts import *
22 
23 
24 class JitCore(object):
25 
26  "JiT management. This is an abstract class"
27 
28  jitted_block_delete_cb = None
29  jitted_block_max_size = 10000
30 
31  def __init__(self, ir_arch, bs=None):
32  """Initialise a JitCore instance.
33  @ir_arch: ir instance for current architecture
34  @bs: bitstream
35  """
36 
37  self.ir_arch = ir_arch
38  self.bs = bs
39  self.known_blocs = {}
41  delete_cb=self.jitted_block_delete_cb)
42  self.lbl2bloc = {}
43  self.log_mn = False
44  self.log_regs = False
45  self.log_newbloc = False
46  self.segm_to_do = set()
47  self.job_done = set()
48  self.jitcount = 0
49  self.addr2obj = {}
50  self.addr2objref = {}
52  self.disasm_cb = None
53  self.split_dis = set()
54  self.addr_mod = interval()
55 
56  self.options = {"jit_maxline": 50 # Maximum number of line jitted
57  }
58 
59  def set_options(self, **kwargs):
60  "Set options relative to the backend"
61 
62  self.options.update(kwargs)
63 
64  def add_disassembly_splits(self, *args):
65  """The disassembly engine will stop on address in args if they
66  are not at the block beginning"""
67  self.split_dis.update(set(args))
68 
69  def remove_disassembly_splits(self, *args):
70  """The disassembly engine will no longer stop on address in args"""
71  self.split_dis.difference_update(set(args))
72 
73  def load(self, arch, attrib):
74  "Initialise the Jitter according to arch and attrib"
75 
76  raise NotImplementedError("Abstract class")
77 
78  def get_bloc_min_max(self, cur_bloc):
79  "Update cur_bloc to set min/max address"
80 
81  if cur_bloc.lines:
82  cur_bloc.ad_min = cur_bloc.lines[0].offset
83  cur_bloc.ad_max = cur_bloc.lines[-1].offset + cur_bloc.lines[-1].l
84 
85  def add_bloc_to_mem_interval(self, vm, bloc):
86  "Update vm to include bloc addresses in its memory range"
87 
88  self.blocs_mem_interval += interval([(bloc.ad_min, bloc.ad_max - 1)])
89 
90  vm.reset_code_bloc_pool()
91  for a, b in self.blocs_mem_interval:
92  vm.add_code_bloc(a, b + 1)
93 
94  def jitirblocs(self, label, irblocs):
95  """JiT a group of irblocs.
96  @label: the label of the irblocs
97  @irblocs: a gorup of irblocs
98  """
99 
100  raise NotImplementedError("Abstract class")
101 
102  def add_bloc(self, b):
103  """Add a bloc to JiT and JiT it.
104  @b: the bloc to add
105  """
106 
107  irblocs = self.ir_arch.add_bloc(b, gen_pc_updt = True)
108  b.irblocs = irblocs
109  self.jitirblocs(b.label, irblocs)
110 
111  def disbloc(self, addr, cpu, vm):
112  "Disassemble a new bloc and JiT it"
113 
114  # Get the bloc
115  if isinstance(addr, asmbloc.asm_label):
116  addr = addr.offset
117 
118  l = self.ir_arch.symbol_pool.getby_offset_create(addr)
119  cur_bloc = asmbloc.asm_bloc(l)
120 
121  # Disassemble it
122  try:
123  asmbloc.dis_bloc(self.ir_arch.arch, self.bs, cur_bloc, addr,
124  set(), self.ir_arch.symbol_pool, [],
125  follow_call=False, dontdis_retcall=False,
126  lines_wd=self.options["jit_maxline"],
127  # max 10 asm lines
128  attrib=self.ir_arch.attrib,
129  split_dis=self.split_dis)
130  except IOError:
131  # vm_exception_flag is set
132  pass
133 
134  # Logging
135  if self.log_newbloc:
136  print cur_bloc
137  if self.disasm_cb is not None:
138  self.disasm_cb(cur_bloc)
139 
140  # Check for empty blocks
141  if not cur_bloc.lines:
142  raise ValueError("Cannot JIT a block without any assembly line")
143 
144  # Update label -> bloc
145  self.lbl2bloc[l] = cur_bloc
146 
147  # Store min/max bloc address needed in jit automod code
148  self.get_bloc_min_max(cur_bloc)
149 
150  # JiT it
151  self.add_bloc(cur_bloc)
152 
153  # Update jitcode mem range
154  self.add_bloc_to_mem_interval(vm, cur_bloc)
155 
156  def jit_call(self, label, cpu, _vmmngr, breakpoints):
157  """Call the function label with cpu and vmmngr states
158  @label: function's label
159  @cpu: JitCpu instance
160  @breakpoints: Dict instance of used breakpoints
161  """
162  return self.exec_wrapper(label, cpu, self.lbl2jitbloc.data, breakpoints)
163 
164  def runbloc(self, cpu, vm, lbl, breakpoints):
165  """Run the bloc starting at lbl.
166  @cpu: JitCpu instance
167  @vm: VmMngr instance
168  @lbl: target label
169  """
170 
171  if lbl is None:
172  lbl = cpu.get_gpreg()[self.ir_arch.pc.name]
173 
174  if not lbl in self.lbl2jitbloc:
175  # Need to JiT the bloc
176  self.disbloc(lbl, cpu, vm)
177 
178  # Run the bloc and update cpu/vmmngr state
179  ret = self.jit_call(lbl, cpu, vm, breakpoints)
180 
181  return ret
182 
183  def blocs2memrange(self, blocs):
184  """Return an interval instance standing for blocs addresses
185  @blocs: list of asm_bloc instances
186  """
187 
188  mem_range = interval()
189 
190  for b in blocs:
191  mem_range += interval([(b.ad_min, b.ad_max - 1)])
192 
193  return mem_range
194 
196  """Rebuild the VM blocs address memory range
197  @vm: VmMngr instance
198  """
199 
200  # Reset the current pool
201  vm.reset_code_bloc_pool()
202 
203  # Add blocs in the pool
204  for a, b in self.blocs_mem_interval:
205  vm.add_code_bloc(a, b + 1)
206 
207  def del_bloc_in_range(self, ad1, ad2):
208  """Find and remove jitted bloc in range [ad1, ad2].
209  Return the list of bloc removed.
210  @ad1: First address
211  @ad2: Last address
212  """
213 
214  # Find concerned blocs
215  modified_blocs = set()
216  for b in self.lbl2bloc.values():
217  if not b.lines:
218  continue
219  if b.ad_max <= ad1 or b.ad_min >= ad2:
220  # Bloc not modified
221  pass
222  else:
223  # Modified blocs
224  modified_blocs.add(b)
225 
226  # Generate interval to delete
227  del_interval = self.blocs2memrange(modified_blocs)
228 
229  # Remove interval from monitored interval list
230  self.blocs_mem_interval -= del_interval
231 
232  # Remove modified blocs
233  for b in modified_blocs:
234  try:
235  for irbloc in b.irblocs:
236 
237  # Remove offset -> jitted bloc link
238  if irbloc.label.offset in self.lbl2jitbloc:
239  del(self.lbl2jitbloc[irbloc.label.offset])
240 
241  except AttributeError:
242  # The bloc has never been translated in IR
243  if b.label.offset in self.lbl2jitbloc:
244  del(self.lbl2jitbloc[b.label.offset])
245 
246  # Remove label -> bloc link
247  del(self.lbl2bloc[b.label])
248 
249  return modified_blocs
250 
251  def updt_automod_code(self, vm):
252  """Remove code jitted in range self.addr_mod
253  @vm: VmMngr instance
254  """
255  for addr_start, addr_stop in self.addr_mod:
256  self.del_bloc_in_range(addr_start, addr_stop + 1)
257  self.__updt_jitcode_mem_range(vm)
258  self.addr_mod = interval()
259 
260  def automod_cb(self, addr=0, size=0):
261  self.addr_mod += interval([(addr, addr + size / 8 - 1)])
262  return None