11320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#!/usr/bin/python
21320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci# Copyright 2014 The Chromium Authors. All rights reserved.
31320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci# Use of this source code is governed by a BSD-style license that can be
41320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci# found in the LICENSE file.
51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
61320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci# pylint: disable=W0104,W0106,F0401,R0201
71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport optparse
91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport os.path
101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport sys
111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport interface
131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccidef _ScriptDir():
161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return os.path.dirname(os.path.abspath(__file__))
171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccidef _GetDirAbove(dirname):
201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  """Returns the directory "above" this file containing |dirname| (which must
211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  also be "above" this file)."""
221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  path = _ScriptDir()
231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  while True:
241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    path, tail = os.path.split(path)
251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    assert tail
261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if tail == dirname:
271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return path
281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccidef _AddThirdPartyImportPath():
311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  sys.path.append(os.path.join(_GetDirAbove('mojo'), 'third_party'))
321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci_AddThirdPartyImportPath()
351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport jinja2
361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciloader = jinja2.FileSystemLoader(_ScriptDir())
381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccijinja_env = jinja2.Environment(loader=loader, keep_trailing_newline=True)
391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci# Accumulate lines of code with varying levels of indentation.
421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciclass CodeWriter(object):
431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def __init__(self):
441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self._lines = []
451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self._margin = ''
461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self._margin_stack = []
471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def __lshift__(self, line):
491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self._lines.append((self._margin + line).rstrip())
501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def PushMargin(self):
521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self._margin_stack.append(self._margin)
531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self._margin += '  '
541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def PopMargin(self):
561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self._margin = self._margin_stack.pop()
571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def GetValue(self):
591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return '\n'.join(self._lines).rstrip() + '\n'
601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def Indent(self):
621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return Indent(self)
631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci# Context handler that automatically indents and dedents a CodeWriter
661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciclass Indent(object):
671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def __init__(self, writer):
681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self._writer = writer
691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def __enter__(self):
711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self._writer.PushMargin()
721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def __exit__(self, type_, value, traceback):
741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self._writer.PopMargin()
751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccidef TemplateFile(name):
781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return os.path.join(os.path.dirname(__file__), name)
791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci# Wraps comma separated lists as needed.
821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccidef Wrap(pre, items, post):
831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  complete = pre + ', '.join(items) + post
841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if len(complete) <= 80:
851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return [complete]
861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  lines = [pre]
871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  indent = '    '
881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  for i, item in enumerate(items):
891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if i < len(items) - 1:
901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      lines.append(indent + item + ',')
911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    else:
921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      lines.append(indent + item + post)
931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return lines
941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccidef GeneratorWarning():
971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return ('// WARNING this file was generated by %s\n// Do not edit by hand.' %
981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          os.path.basename(__file__))
991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci# Untrusted library implementing the public Mojo API.
1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccidef GenerateLibMojo(functions, out):
1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  template = jinja_env.get_template('libmojo.cc.tmpl')
1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  code = CodeWriter()
1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  for f in functions:
1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    for line in Wrap('%s %s(' % (f.return_type, f.name), f.ParamList(), ') {'):
1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      code << line
1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    # 2 extra parameters: message ID and return value.
1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    num_params = len(f.params) + 2
1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    with code.Indent():
1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      code << 'uint32_t params[%d];' % num_params
1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return_type = f.result_param.base_type
1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      if return_type == 'MojoResult':
1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        default = 'MOJO_RESULT_INVALID_ARGUMENT'
1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      elif return_type == 'MojoTimeTicks':
1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        default = '0'
1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      else:
1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        raise Exception('Unhandled return type: ' + return_type)
1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      code << '%s %s = %s;' % (return_type, f.result_param.name, default)
1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      # Message ID
1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      code << 'params[0] = %d;' % f.uid
1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      # Parameter pointers
1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      cast_template = 'params[%d] = reinterpret_cast<uint32_t>(%s);'
1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      for p in f.params:
1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        ptr = p.name
1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        if p.IsPassedByValue():
1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          ptr = '&' + ptr
1331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        code << cast_template % (p.uid + 1, ptr)
1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      # Return value pointer
1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      code << cast_template % (num_params - 1, '&' + f.result_param.name)
1361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      code << 'DoMojoCall(params, sizeof(params));'
1381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      code << 'return %s;' % f.result_param.name
1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    code << '}'
1411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    code << ''
1421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  body = code.GetValue()
1441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  text = template.render(
1451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    generator_warning=GeneratorWarning(),
1461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    body=body)
1471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  out.write(text)
1481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci# Parameters passed into trusted code are handled differently depending on
1511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci# details of the parameter.  ParamImpl instances encapsulate these differences
1521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci# and are used to generate the code that transfers parameters across the
1531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci# untrusted/trusted boundary.
1541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciclass ParamImpl(object):
1551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def __init__(self, param):
1561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self.param = param
1571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  # Declare whatever variables are needed to handle this particular parameter.
1591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def DeclareVars(self, code):
1601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    raise NotImplementedError()
1611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  # Convert the untrusted representation of the parameter into a trusted
1631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  # representation, such as a scalar value or a trusted pointer into the
1641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  # untrusted address space.
1651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def ConvertParam(self):
1661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    raise NotImplementedError()
1671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  # For this particular parameter, what expression should be passed when
1691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  # invoking the trusted Mojo API function?
1701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def CallParam(self):
1711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    raise NotImplementedError()
1721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  # After invoking the trusted Mojo API function, transfer data back into
1741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  # untrusted memory.  Overriden for Out and InOut parameters.
1751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def CopyOut(self, code):
1761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    pass
1771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  # Converting array parameters needs to be defered until after the scalar
1791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  # parameter containing the size of the array has itself been converted.
1801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def IsArray(self):
1811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return False
1821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciclass ScalarInputImpl(ParamImpl):
1851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def DeclareVars(self, code):
1861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    code << '%s %s_value;' % (self.param.base_type, self.param.name)
1871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def ConvertParam(self):
1891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    p = self.param
1901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return ('ConvertScalarInput(nap, params[%d], &%s_value)' %
1911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            (p.uid + 1, p.name))
1921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def CallParam(self):
1941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return '%s_value' % self.param.name
1951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciclass ScalarOutputImpl(ParamImpl):
1981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def DeclareVars(self, code):
1991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    code << '%s volatile* %s_ptr;' % (self.param.base_type, self.param.name)
2001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    code << '%s %s_value;' % (self.param.base_type, self.param.name)
2011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def ConvertParam(self):
2031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    p = self.param
2041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return 'ConvertScalarOutput(nap, params[%d], &%s_ptr)' % (p.uid + 1, p.name)
2051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def CallParam(self):
2071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return '&%s_value' % self.param.name
2081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def CopyOut(self, code):
2101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    name = self.param.name
2111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    code << '*%s_ptr = %s_value;' % (name, name)
2121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciclass ScalarInOutImpl(ParamImpl):
2151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def DeclareVars(self, code):
2161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    code << '%s volatile* %s_ptr;' % (self.param.base_type, self.param.name)
2171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    code << '%s %s_value;' % (self.param.base_type, self.param.name)
2181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def ConvertParam(self):
2201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    p = self.param
2211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return ('ConvertScalarInOut(nap, params[%d], %s, &%s_value, &%s_ptr)' %
2221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            (p.uid + 1, CBool(p.is_optional), p.name, p.name))
2231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def CallParam(self):
2251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    name = self.param.name
2261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    expr = '&%s_value' % name
2271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if self.param.is_optional:
2281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      expr = '%s_ptr ? %s : NULL' % (name, expr)
2291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return expr
2301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def CopyOut(self, code):
2321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    name = self.param.name
2331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if self.param.is_optional:
2341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      code << 'if (%s_ptr != NULL) {' % (name)
2351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      with code.Indent():
2361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        code << '*%s_ptr = %s_value;' % (name, name)
2371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      code << '}'
2381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    else:
2391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      code << '*%s_ptr = %s_value;' % (name, name)
2401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciclass ArrayImpl(ParamImpl):
2431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def DeclareVars(self, code):
2441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    code << '%s %s;' % (self.param.param_type, self.param.name)
2451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def ConvertParam(self):
2471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    p = self.param
2481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if p.base_type == 'void':
2491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      element_size = '1'
2501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    else:
2511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      element_size = 'sizeof(*%s)' % p.name
2521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return ('ConvertArray(nap, params[%d], %s, %s, %s, &%s)' %
2541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            (p.uid + 1, p.size + '_value', element_size, CBool(p.is_optional),
2551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci             p.name))
2561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def CallParam(self):
2581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return self.param.name
2591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def IsArray(self):
2611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return True
2621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciclass StructInputImpl(ParamImpl):
2651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def DeclareVars(self, code):
2661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    code << '%s %s;' % (self.param.param_type, self.param.name)
2671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def ConvertParam(self):
2691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    p = self.param
2701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return ('ConvertStruct(nap, params[%d], %s, &%s)' %
2711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            (p.uid + 1, CBool(p.is_optional), p.name))
2721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def CallParam(self):
2741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return self.param.name
2751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccidef ImplForParam(p):
2781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if p.IsScalar():
2791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if p.is_output:
2801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      if p.is_input:
2811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        return ScalarInOutImpl(p)
2821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      else:
2831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        return ScalarOutputImpl(p)
2841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    else:
2851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return ScalarInputImpl(p)
2861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  elif p.is_array:
2871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return ArrayImpl(p)
2881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  elif p.is_struct:
2891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return StructInputImpl(p)
2901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  else:
2911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    assert False, p
2921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccidef CBool(value):
2951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return 'true' if value else 'false'
2961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci# A trusted wrapper that validates the arguments passed from untrusted code
2991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci# before passing them to the underlying public Mojo API.
3001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccidef GenerateMojoSyscall(functions, out):
3011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  template = jinja_env.get_template('mojo_syscall.cc.tmpl')
3021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  code = CodeWriter()
3041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  code.PushMargin()
3051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  for f in functions:
3071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    impls = [ImplForParam(p) for p in f.params]
3081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    impls.append(ImplForParam(f.result_param))
3091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    code << 'case %d:' % f.uid
3111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    code.PushMargin()
3131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    code << '{'
3151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    with code.Indent():
3171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      num_params = len(f.params) + 2
3181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      code << 'if (num_params != %d) {' % num_params
3191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      with code.Indent():
3201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        code << 'return -1;'
3211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      code << '}'
3221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      # Declare temporaries.
3241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      for impl in impls:
3251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        impl.DeclareVars(code)
3261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      def ConvertParam(code, impl):
3281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        code << 'if (!%s) {' % impl.ConvertParam()
3291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        with code.Indent():
3301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          code << 'return -1;'
3311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        code << '}'
3321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      code << '{'
3341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      with code.Indent():
3351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        code << 'ScopedCopyLock copy_lock(nap);'
3361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        # Convert and validate pointers in two passes.
3371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        # Arrays cannot be validated until the size parameter has been
3381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        # converted.
3391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        for impl in impls:
3401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          if not impl.IsArray():
3411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            ConvertParam(code, impl)
3421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        for impl in impls:
3431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          if impl.IsArray():
3441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            ConvertParam(code, impl)
3451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      code << '}'
3461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      code << ''
3471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      # Call
3491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      getParams = [impl.CallParam() for impl in impls[:-1]]
3501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      code << 'result_value = %s(%s);' % (f.name, ', '.join(getParams))
3511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      code << ''
3521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      # Write outputs
3541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      code << '{'
3551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      with code.Indent():
3561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        code << 'ScopedCopyLock copy_lock(nap);'
3571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        for impl in impls:
3581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          impl.CopyOut(code)
3591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      code << '}'
3601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      code << ''
3611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      code << 'return 0;'
3631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    code << '}'
3641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    code.PopMargin()
3661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  body = code.GetValue()
3681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  text = template.render(
3691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    generator_warning=GeneratorWarning(),
3701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    body=body)
3711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  out.write(text)
3721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccidef OutFile(dir_path, name):
3751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if not os.path.exists(dir_path):
3761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    os.makedirs(dir_path)
3771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return open(os.path.join(dir_path, name), 'w')
3781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccidef main(args):
3811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  usage = 'usage: %prog [options]'
3821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  parser = optparse.OptionParser(usage=usage)
3831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  parser.add_option(
3841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      '-d',
3851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      dest='out_dir',
3861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      metavar='DIR',
3871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      help='output generated code into directory DIR')
3881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  options, args = parser.parse_args(args=args)
3891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if not options.out_dir:
3901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    parser.error('-d is required')
3911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if args:
3921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    parser.error('unexpected positional arguments: %s' % ' '.join(args))
3931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  mojo = interface.MakeInterface()
3951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  out = OutFile(options.out_dir, 'libmojo.cc')
3971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  GenerateLibMojo(mojo.functions, out)
3981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  out = OutFile(options.out_dir, 'mojo_syscall.cc')
4001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  GenerateMojoSyscall(mojo.functions, out)
4011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
4021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
4031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciif __name__ == '__main__':
4041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  main(sys.argv[1:])
405