summaryrefslogtreecommitdiffstats
path: root/web/server/h2o/libh2o/deps/picotls/deps/cifra/src/arm/analyse.py
diff options
context:
space:
mode:
Diffstat (limited to 'web/server/h2o/libh2o/deps/picotls/deps/cifra/src/arm/analyse.py')
-rw-r--r--web/server/h2o/libh2o/deps/picotls/deps/cifra/src/arm/analyse.py207
1 files changed, 207 insertions, 0 deletions
diff --git a/web/server/h2o/libh2o/deps/picotls/deps/cifra/src/arm/analyse.py b/web/server/h2o/libh2o/deps/picotls/deps/cifra/src/arm/analyse.py
new file mode 100644
index 000000000..d2c456fef
--- /dev/null
+++ b/web/server/h2o/libh2o/deps/picotls/deps/cifra/src/arm/analyse.py
@@ -0,0 +1,207 @@
+import subprocess
+import sys
+import re
+
+function_intro_re = re.compile(r'^(?P<addr>[0-9a-fA-F]{8}) <(?P<name>[a-zA-Z0-9\._]+)>:$')
+insn_re = re.compile(r'^\s+(?P<addr>[0-9a-fA-F]+):\s+(?P<insn>[0-9a-fA-F ]+)\s+\t(?P<op>.*)$')
+
+class Instruction:
+ def __init__(self, addr, insn, op):
+ self.addr = long(addr, 16)
+ self.insn = insn
+
+ args = op.split('\t', 1)
+
+ self.op = args[0].strip()
+ if len(args) == 2:
+ comment = args[1].strip().split(';', 1)
+ else:
+ comment = args
+
+ self.args = comment[0].strip()
+
+ if len(comment) == 2:
+ self.comment = comment[1].strip()
+ else:
+ self.comment = ''
+
+ def __repr__(self):
+ return '<insn %r>' % (self.__dict__)
+
+
+def literal_branch_target(t):
+ return ' <' in t
+
+class Function:
+ def __init__(self, addr, name):
+ self.name = name
+ self.addr = long(addr, 16)
+ self.insns = []
+ self.calls = []
+
+ def __repr__(self):
+ return '<%s %d instructions>' % (self.name, len(self.insns))
+
+ def add_insn(self, insn):
+ self.insns.append(Instruction(**insn))
+
+ def contains_addr(self, addr):
+ if self.insns:
+ return addr >= self.addr and addr <= self.insns[-1].addr
+ else:
+ return addr == self.addr
+
+ def dump(self):
+ print self.name + ':'
+ for insn in self.insns:
+ print ' ', '%04x' % insn.addr + ':', insn.op, insn.args, '\t;', insn.comment
+
+ def get_literal_word(self, addr):
+ for insn in self.insns:
+ if insn.addr == addr and insn.op == '.word':
+ w = int(insn.args, 16)
+ if w & 0x80000000:
+ w = -(w ^ 0xffffffff) + 1
+ return w
+ return None
+
+ def analyse(self, prog):
+ self.stack_guess = None
+ regs = {}
+
+ for insn in self.insns:
+ # stack adjustment with literal
+ if insn.op == 'sub' and insn.args.startswith('sp, ') and self.stack_guess is None:
+ sz = int(insn.args.split('#', 1)[1])
+ self.stack_guess = sz
+
+ # literal pool loads
+ if insn.op == 'ldr' and ', [pc, #' in insn.args:
+ reg, offset = insn.args.split(', [pc, #')
+ offset = int(offset.replace(']', ''))
+ word = self.get_literal_word(insn.addr + offset + 2)
+ if word is not None:
+ regs[reg] = word
+
+ if insn.op == 'add' and insn.args.startswith('sp, r') and self.stack_guess is None:
+ reg = insn.args.split(', ')[1]
+ if reg in regs:
+ self.stack_guess = regs[reg]
+
+ # static branches
+ if insn.op[0] == 'b' and literal_branch_target(insn.args):
+ target = long(insn.args.split(' <', 1)[0], 16)
+
+ targetf = prog.function_at_addr(target)
+
+ if targetf and targetf != self:
+ self.calls.append(targetf)
+
+ if self.stack_guess is None:
+ self.stack_guess = 0
+
+ def stack_usage(self, hints, warns, prog, depth = 0):
+ hinted_calls = []
+ if self.stack_guess:
+ print ' ' * depth, 'stack:', self.name, self.stack_guess, 'bytes'
+
+ our_hints = [h for h in hints if h and h[0] == self.name]
+ if our_hints:
+ hints = [h[1:] for h in our_hints]
+ hinted_calls = [prog.function_by_name(h[0]) for h in hints if h]
+ else:
+ if self.name in warns:
+ print ' WARN: no calls hints for fn-ptr caller', self.name
+
+ if self.calls + hinted_calls:
+ call_usage = max([f.stack_usage(hints, warns, prog, depth + 1) for f in self.calls + hinted_calls])
+ else:
+ call_usage = 0
+ return self.stack_guess + call_usage
+
+class Program:
+ def __init__(self):
+ self.functions = []
+
+ # sequence of tuples naming a call sequence known to occur
+ # this allows working out calls through pointers
+ self.call_hints = []
+
+ # function names to warn on if we don't have callees
+ self.call_warns = set()
+
+ def read_elf(self, elf):
+ current_fn = None
+
+ for x in subprocess.Popen(['arm-none-eabi-objdump', '-d', elf],
+ stdout = subprocess.PIPE).stdout:
+ x = x.rstrip('\n')
+ m = function_intro_re.match(x)
+ if m:
+ fn = Function(**m.groupdict())
+ current_fn = fn
+ self.functions.append(fn)
+
+ m = insn_re.match(x)
+ if m:
+ assert current_fn
+ current_fn.add_insn(m.groupdict())
+
+ def analyse(self):
+ for f in self.functions:
+ f.analyse(self)
+
+ def function_by_name(self, name):
+ fns = [fn for fn in self.functions if fn.name == name]
+ if len(fns) == 0:
+ return None
+ elif len(fns) == 1:
+ return fns[0]
+ else:
+ print 'warn: more than one function named', name
+ return None
+
+ def function_at_addr(self, addr):
+ for f in self.functions:
+ if f.addr == addr:
+ return f
+ return None
+
+ def add_call_hint(self, *seq):
+ self.call_hints.append(seq)
+
+ def add_call_warn(self, fn):
+ self.call_warns.add(fn)
+
+ def measure_stack(self, name):
+ fn = self.function_by_name(name)
+ if fn is None:
+ return 0
+
+ return fn.stack_usage(self.call_hints, self.call_warns, self)
+
+_, exe, fn = sys.argv
+
+p = Program()
+p.read_elf(exe)
+
+p.analyse()
+
+# calls which indirect through fn ptrs
+p.add_call_warn('cf_blockwise_accumulate')
+p.add_call_warn('cf_blockwise_accumulate_final')
+
+# hints to resolve those
+p.add_call_hint('cf_sha224_update', 'cf_blockwise_accumulate', 'cf_blockwise_accumulate_final', 'sha256_update_block')
+p.add_call_hint('cf_sha256_update', 'cf_blockwise_accumulate', 'cf_blockwise_accumulate_final', 'sha256_update_block')
+p.add_call_hint('cf_sha384_update', 'cf_blockwise_accumulate', 'cf_blockwise_accumulate_final', 'sha512_update_block')
+p.add_call_hint('cf_sha512_update', 'cf_blockwise_accumulate', 'cf_blockwise_accumulate_final', 'sha512_update_block')
+p.add_call_hint('cf_norx32_encrypt', 'input', 'cf_blockwise_accumulate', 'cf_blockwise_accumulate_final', 'input_block')
+p.add_call_hint('cf_norx32_decrypt', 'input', 'cf_blockwise_accumulate', 'cf_blockwise_accumulate_final', 'input_block')
+p.add_call_hint('cf_cbcmac_stream_update', 'cf_blockwise_accumulate', 'cf_blockwise_accumulate_final', 'cbcmac_process')
+p.add_call_hint('cf_cmac_stream_update', 'cf_blockwise_accumulate', 'cf_blockwise_accumulate_final', 'cmac_process_final_pad')
+p.add_call_hint('cf_cmac_stream_update', 'cf_blockwise_accumulate_final', 'cmac_process')
+p.add_call_hint('cf_cmac_stream_update', 'cf_blockwise_accumulate_final', 'cmac_process_final_nopad')
+
+
+print 'stack', fn, '=', p.measure_stack(fn)