aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMinos Galanakis <minos.galanakis@arm.com>2024-04-24 11:23:17 +0100
committerMinos Galanakis <minos.galanakis@arm.com>2024-04-24 11:23:17 +0100
commit10bd34f0063ff57c902464ceac1ece17ff06580f (patch)
tree23159760baaeab2b3be39b676362896c96e8c15d
parent771fd7d1dcd19a157812dde9766bb7781e60d075 (diff)
downloadmbedtls-dev/minosgalanakis/issue_8961_review_base.zip
mbedtls-dev/minosgalanakis/issue_8961_review_base.tar.gz
mbedtls-dev/minosgalanakis/issue_8961_review_base.tar.bz2
Removed the scripts to be revieweddev/minosgalanakis/issue_8961_review_base
Signed-off-by: Minos Galanakis <minos.galanakis@arm.com>
-rw-r--r--scripts/mbedtls_dev/c_parsing_helper.py131
-rw-r--r--scripts/mbedtls_dev/c_wrapper_generator.py473
2 files changed, 0 insertions, 604 deletions
diff --git a/scripts/mbedtls_dev/c_parsing_helper.py b/scripts/mbedtls_dev/c_parsing_helper.py
deleted file mode 100644
index 2657b7d..0000000
--- a/scripts/mbedtls_dev/c_parsing_helper.py
+++ /dev/null
@@ -1,131 +0,0 @@
-"""Helper functions to parse C code in heavily constrained scenarios.
-
-Currently supported functionality:
-
-* read_function_declarations: read function declarations from a header file.
-"""
-
-# Copyright The Mbed TLS Contributors
-# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
-
-### WARNING: the code in this file has not been extensively reviewed yet.
-### We do not think it is harmful, but it may be below our normal standards
-### for robustness and maintainability.
-
-import re
-from typing import Dict, Iterable, Iterator, List, Optional, Tuple
-
-
-class ArgumentInfo:
- """Information about an argument to an API function."""
- #pylint: disable=too-few-public-methods
-
- _KEYWORDS = [
- 'const', 'register', 'restrict',
- 'int', 'long', 'short', 'signed', 'unsigned',
- ]
- _DECLARATION_RE = re.compile(
- r'(?P<type>\w[\w\s*]*?)\s*' +
- r'(?!(?:' + r'|'.join(_KEYWORDS) + r'))(?P<name>\b\w+\b)?' +
- r'\s*(?P<suffix>\[[^][]*\])?\Z',
- re.A | re.S)
-
- @classmethod
- def normalize_type(cls, typ: str) -> str:
- """Normalize whitespace in a type."""
- typ = re.sub(r'\s+', r' ', typ)
- typ = re.sub(r'\s*\*', r' *', typ)
- return typ
-
- def __init__(self, decl: str) -> None:
- self.decl = decl.strip()
- m = self._DECLARATION_RE.match(self.decl)
- if not m:
- raise ValueError(self.decl)
- self.type = self.normalize_type(m.group('type')) #type: str
- self.name = m.group('name') #type: Optional[str]
- self.suffix = m.group('suffix') if m.group('suffix') else '' #type: str
-
-
-class FunctionInfo:
- """Information about an API function."""
- #pylint: disable=too-few-public-methods
-
- # Regex matching the declaration of a function that returns void.
- VOID_RE = re.compile(r'\s*\bvoid\s*\Z', re.A)
-
- def __init__(self, #pylint: disable=too-many-arguments
- filename: str,
- line_number: int,
- qualifiers: Iterable[str],
- return_type: str,
- name: str,
- arguments: List[str]) -> None:
- self.filename = filename
- self.line_number = line_number
- self.qualifiers = frozenset(qualifiers)
- self.return_type = return_type
- self.name = name
- self.arguments = [ArgumentInfo(arg) for arg in arguments]
-
- def returns_void(self) -> bool:
- """Whether the function returns void."""
- return bool(self.VOID_RE.search(self.return_type))
-
-
-# Match one C comment.
-# Note that we match both comment types, so things like // in a /*...*/
-# comment are handled correctly.
-_C_COMMENT_RE = re.compile(r'//(?:[^\n]|\\\n)*|/\*.*?\*/', re.S)
-_NOT_NEWLINES_RE = re.compile(r'[^\n]+')
-
-def read_logical_lines(filename: str) -> Iterator[Tuple[int, str]]:
- """Read logical lines from a file.
-
- Logical lines are one or more physical line, with balanced parentheses.
- """
- with open(filename, encoding='utf-8') as inp:
- content = inp.read()
- # Strip comments, but keep newlines for line numbering
- content = re.sub(_C_COMMENT_RE,
- lambda m: re.sub(_NOT_NEWLINES_RE, "", m.group(0)),
- content)
- lines = enumerate(content.splitlines(), 1)
- for line_number, line in lines:
- # Read a logical line, containing balanced parentheses.
- # We assume that parentheses are balanced (this should be ok
- # since comments have been stripped), otherwise there will be
- # a gigantic logical line at the end.
- paren_level = line.count('(') - line.count(')')
- while paren_level > 0:
- _, more = next(lines) #pylint: disable=stop-iteration-return
- paren_level += more.count('(') - more.count(')')
- line += '\n' + more
- yield line_number, line
-
-_C_FUNCTION_DECLARATION_RE = re.compile(
- r'(?P<qualifiers>(?:(?:extern|inline|static)\b\s*)*)'
- r'(?P<return_type>\w[\w\s*]*?)\s*' +
- r'\b(?P<name>\w+)' +
- r'\s*\((?P<arguments>.*)\)\s*;',
- re.A | re.S)
-
-def read_function_declarations(functions: Dict[str, FunctionInfo],
- filename: str) -> None:
- """Collect function declarations from a C header file."""
- for line_number, line in read_logical_lines(filename):
- m = _C_FUNCTION_DECLARATION_RE.match(line)
- if not m:
- continue
- qualifiers = m.group('qualifiers').split()
- return_type = m.group('return_type')
- name = m.group('name')
- arguments = m.group('arguments').split(',')
- if len(arguments) == 1 and re.match(FunctionInfo.VOID_RE, arguments[0]):
- arguments = []
- # Note: we replace any existing declaration for the same name.
- functions[name] = FunctionInfo(filename, line_number,
- qualifiers,
- return_type,
- name,
- arguments)
diff --git a/scripts/mbedtls_dev/c_wrapper_generator.py b/scripts/mbedtls_dev/c_wrapper_generator.py
deleted file mode 100644
index 3cf1e05..0000000
--- a/scripts/mbedtls_dev/c_wrapper_generator.py
+++ /dev/null
@@ -1,473 +0,0 @@
-"""Generate C wrapper functions.
-"""
-
-# Copyright The Mbed TLS Contributors
-# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
-
-### WARNING: the code in this file has not been extensively reviewed yet.
-### We do not think it is harmful, but it may be below our normal standards
-### for robustness and maintainability.
-
-import os
-import re
-import sys
-import typing
-from typing import Dict, List, Optional, Tuple
-
-from .c_parsing_helper import ArgumentInfo, FunctionInfo
-from . import typing_util
-
-
-def c_declare(prefix: str, name: str, suffix: str) -> str:
- """Format a declaration of name with the given type prefix and suffix."""
- if not prefix.endswith('*'):
- prefix += ' '
- return prefix + name + suffix
-
-
-WrapperInfo = typing.NamedTuple('WrapperInfo', [
- ('argument_names', List[str]),
- ('guard', Optional[str]),
- ('wrapper_name', str),
-])
-
-
-class Base:
- """Generate a C source file containing wrapper functions."""
-
- # This class is designed to have many methods potentially overloaded.
- # Tell pylint not to complain about methods that have unused arguments:
- # child classes are likely to override those methods and need the
- # arguments in question.
- #pylint: disable=no-self-use,unused-argument
-
- # Prefix prepended to the function's name to form the wrapper name.
- _WRAPPER_NAME_PREFIX = ''
- # Suffix appended to the function's name to form the wrapper name.
- _WRAPPER_NAME_SUFFIX = '_wrap'
-
- # Functions with one of these qualifiers are skipped.
- _SKIP_FUNCTION_WITH_QUALIFIERS = frozenset(['inline', 'static'])
-
- def __init__(self):
- """Construct a wrapper generator object.
- """
- self.program_name = os.path.basename(sys.argv[0])
- # To be populated in a derived class
- self.functions = {} #type: Dict[str, FunctionInfo]
- # Preprocessor symbol used as a guard against multiple inclusion in the
- # header. Must be set before writing output to a header.
- # Not used when writing .c output.
- self.header_guard = None #type: Optional[str]
-
- def _write_prologue(self, out: typing_util.Writable, header: bool) -> None:
- """Write the prologue of a C file.
-
- This includes a description comment and some include directives.
- """
- out.write("""/* Automatically generated by {}, do not edit! */
-
-/* Copyright The Mbed TLS Contributors
- * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
- */
-"""
- .format(self.program_name))
- if header:
- out.write("""
-#ifndef {guard}
-#define {guard}
-
-#ifdef __cplusplus
-extern "C" {{
-#endif
-"""
- .format(guard=self.header_guard))
- out.write("""
-#include <mbedtls/build_info.h>
-""")
-
- def _write_epilogue(self, out: typing_util.Writable, header: bool) -> None:
- """Write the epilogue of a C file.
- """
- if header:
- out.write("""
-#ifdef __cplusplus
-}}
-#endif
-
-#endif /* {guard} */
-"""
- .format(guard=self.header_guard))
- out.write("""
-/* End of automatically generated file. */
-""")
-
- def _wrapper_function_name(self, original_name: str) -> str:
- """The name of the wrapper function.
-
- By default, this adds a suffix.
- """
- return (self._WRAPPER_NAME_PREFIX +
- original_name +
- self._WRAPPER_NAME_SUFFIX)
-
- def _wrapper_declaration_start(self,
- function: FunctionInfo,
- wrapper_name: str) -> str:
- """The beginning of the wrapper function declaration.
-
- This ends just before the opening parenthesis of the argument list.
-
- This is a string containing at least the return type and the
- function name. It may start with additional qualifiers or attributes
- such as `static`, `__attribute__((...))`, etc.
- """
- return c_declare(function.return_type, wrapper_name, '')
-
- def _argument_name(self,
- function_name: str,
- num: int,
- arg: ArgumentInfo) -> str:
- """Name to use for the given argument in the wrapper function.
-
- Argument numbers count from 0.
- """
- name = 'arg' + str(num)
- if arg.name:
- name += '_' + arg.name
- return name
-
- def _wrapper_declaration_argument(self,
- function_name: str,
- num: int, name: str,
- arg: ArgumentInfo) -> str:
- """One argument definition in the wrapper function declaration.
-
- Argument numbers count from 0.
- """
- return c_declare(arg.type, name, arg.suffix)
-
- def _underlying_function_name(self, function: FunctionInfo) -> str:
- """The name of the underlying function.
-
- By default, this is the name of the wrapped function.
- """
- return function.name
-
- def _return_variable_name(self, function: FunctionInfo) -> str:
- """The name of the variable that will contain the return value."""
- return 'retval'
-
- def _write_function_call(self, out: typing_util.Writable,
- function: FunctionInfo,
- argument_names: List[str]) -> None:
- """Write the call to the underlying function.
- """
- # Note that the function name is in parentheses, to avoid calling
- # a function-like macro with the same name, since in typical usage
- # there is a function-like macro with the same name which is the
- # wrapper.
- call = '({})({})'.format(self._underlying_function_name(function),
- ', '.join(argument_names))
- if function.returns_void():
- out.write(' {};\n'.format(call))
- else:
- ret_name = self._return_variable_name(function)
- ret_decl = c_declare(function.return_type, ret_name, '')
- out.write(' {} = {};\n'.format(ret_decl, call))
-
- def _write_function_return(self, out: typing_util.Writable,
- function: FunctionInfo,
- if_void: bool = False) -> None:
- """Write a return statement.
-
- If the function returns void, only write a statement if if_void is true.
- """
- if function.returns_void():
- if if_void:
- out.write(' return;\n')
- else:
- ret_name = self._return_variable_name(function)
- out.write(' return {};\n'.format(ret_name))
-
- def _write_function_body(self, out: typing_util.Writable,
- function: FunctionInfo,
- argument_names: List[str]) -> None:
- """Write the body of the wrapper code for the specified function.
- """
- self._write_function_call(out, function, argument_names)
- self._write_function_return(out, function)
-
- def _skip_function(self, function: FunctionInfo) -> bool:
- """Whether to skip this function.
-
- By default, static or inline functions are skipped.
- """
- if not self._SKIP_FUNCTION_WITH_QUALIFIERS.isdisjoint(function.qualifiers):
- return True
- return False
-
- _FUNCTION_GUARDS = {
- } #type: Dict[str, str]
-
- def _function_guard(self, function: FunctionInfo) -> Optional[str]:
- """A preprocessor condition for this function.
-
- The wrapper will be guarded with `#if` on this condition, if not None.
- """
- return self._FUNCTION_GUARDS.get(function.name)
-
- def _wrapper_info(self, function: FunctionInfo) -> Optional[WrapperInfo]:
- """Information about the wrapper for one function.
-
- Return None if the function should be skipped.
- """
- if self._skip_function(function):
- return None
- argument_names = [self._argument_name(function.name, num, arg)
- for num, arg in enumerate(function.arguments)]
- return WrapperInfo(
- argument_names=argument_names,
- guard=self._function_guard(function),
- wrapper_name=self._wrapper_function_name(function.name),
- )
-
- def _write_function_prototype(self, out: typing_util.Writable,
- function: FunctionInfo,
- wrapper: WrapperInfo,
- header: bool) -> None:
- """Write the prototype of a wrapper function.
-
- If header is true, write a function declaration, with a semicolon at
- the end. Otherwise just write the prototype, intended to be followed
- by the function's body.
- """
- declaration_start = self._wrapper_declaration_start(function,
- wrapper.wrapper_name)
- arg_indent = ' '
- terminator = ';\n' if header else '\n'
- if function.arguments:
- out.write(declaration_start + '(\n')
- for num in range(len(function.arguments)):
- arg_def = self._wrapper_declaration_argument(
- function.name,
- num, wrapper.argument_names[num], function.arguments[num])
- arg_terminator = \
- (')' + terminator if num == len(function.arguments) - 1 else
- ',\n')
- out.write(arg_indent + arg_def + arg_terminator)
- else:
- out.write(declaration_start + '(void)' + terminator)
-
- def _write_c_function(self, out: typing_util.Writable,
- function: FunctionInfo) -> None:
- """Write wrapper code for one function.
-
- Do nothing if the function is skipped.
- """
- wrapper = self._wrapper_info(function)
- if wrapper is None:
- return
- out.write("""
-/* Wrapper for {} */
-"""
- .format(function.name))
- if wrapper.guard is not None:
- out.write('#if {}\n'.format(wrapper.guard))
- self._write_function_prototype(out, function, wrapper, False)
- out.write('{\n')
- self._write_function_body(out, function, wrapper.argument_names)
- out.write('}\n')
- if wrapper.guard is not None:
- out.write('#endif /* {} */\n'.format(wrapper.guard))
-
- def _write_h_function_declaration(self, out: typing_util.Writable,
- function: FunctionInfo,
- wrapper: WrapperInfo) -> None:
- """Write the declaration of one wrapper function.
- """
- self._write_function_prototype(out, function, wrapper, True)
-
- def _write_h_macro_definition(self, out: typing_util.Writable,
- function: FunctionInfo,
- wrapper: WrapperInfo) -> None:
- """Write the macro definition for one wrapper.
- """
- arg_list = ', '.join(wrapper.argument_names)
- out.write('#define {function_name}({args}) \\\n {wrapper_name}({args})\n'
- .format(function_name=function.name,
- wrapper_name=wrapper.wrapper_name,
- args=arg_list))
-
- def _write_h_function(self, out: typing_util.Writable,
- function: FunctionInfo) -> None:
- """Write the complete header content for one wrapper.
-
- This is the declaration of the wrapper function, and the
- definition of a function-like macro that calls the wrapper function.
-
- Do nothing if the function is skipped.
- """
- wrapper = self._wrapper_info(function)
- if wrapper is None:
- return
- out.write('\n')
- if wrapper.guard is not None:
- out.write('#if {}\n'.format(wrapper.guard))
- self._write_h_function_declaration(out, function, wrapper)
- self._write_h_macro_definition(out, function, wrapper)
- if wrapper.guard is not None:
- out.write('#endif /* {} */\n'.format(wrapper.guard))
-
- def write_c_file(self, filename: str) -> None:
- """Output a whole C file containing function wrapper definitions."""
- with open(filename, 'w', encoding='utf-8') as out:
- self._write_prologue(out, False)
- for name in sorted(self.functions):
- self._write_c_function(out, self.functions[name])
- self._write_epilogue(out, False)
-
- def _header_guard_from_file_name(self, filename: str) -> str:
- """Preprocessor symbol used as a guard against multiple inclusion."""
- # Heuristic to strip irrelevant leading directories
- filename = re.sub(r'.*include[\\/]', r'', filename)
- return re.sub(r'[^0-9A-Za-z]', r'_', filename, re.A).upper()
-
- def write_h_file(self, filename: str) -> None:
- """Output a header file with function wrapper declarations and macro definitions."""
- self.header_guard = self._header_guard_from_file_name(filename)
- with open(filename, 'w', encoding='utf-8') as out:
- self._write_prologue(out, True)
- for name in sorted(self.functions):
- self._write_h_function(out, self.functions[name])
- self._write_epilogue(out, True)
-
-
-class UnknownTypeForPrintf(Exception):
- """Exception raised when attempting to generate code that logs a value of an unknown type."""
-
- def __init__(self, typ: str) -> None:
- super().__init__("Unknown type for printf format generation: " + typ)
-
-
-class Logging(Base):
- """Generate wrapper functions that log the inputs and outputs."""
-
- def __init__(self) -> None:
- """Construct a wrapper generator including logging of inputs and outputs.
-
- Log to stdout by default. Call `set_stream` to change this.
- """
- super().__init__()
- self.stream = 'stdout'
-
- def set_stream(self, stream: str) -> None:
- """Set the stdio stream to log to.
-
- Call this method before calling `write_c_output` or `write_h_output`.
- """
- self.stream = stream
-
- def _write_prologue(self, out: typing_util.Writable, header: bool) -> None:
- super()._write_prologue(out, header)
- if not header:
- out.write("""
-#if defined(MBEDTLS_FS_IO) && defined(MBEDTLS_TEST_HOOKS)
-#include <stdio.h>
-#include <inttypes.h>
-#include <mbedtls/debug.h> // for MBEDTLS_PRINTF_SIZET
-#include <mbedtls/platform.h> // for mbedtls_fprintf
-#endif /* defined(MBEDTLS_FS_IO) && defined(MBEDTLS_TEST_HOOKS) */
-""")
-
- _PRINTF_SIMPLE_FORMAT = {
- 'int': '%d',
- 'long': '%ld',
- 'long long': '%lld',
- 'size_t': '%"MBEDTLS_PRINTF_SIZET"',
- 'unsigned': '0x%08x',
- 'unsigned int': '0x%08x',
- 'unsigned long': '0x%08lx',
- 'unsigned long long': '0x%016llx',
- }
-
- def _printf_simple_format(self, typ: str) -> Optional[str]:
- """Use this printf format for a value of typ.
-
- Return None if values of typ need more complex handling.
- """
- return self._PRINTF_SIMPLE_FORMAT.get(typ)
-
- _PRINTF_TYPE_CAST = {
- 'int32_t': 'int',
- 'uint32_t': 'unsigned',
- 'uint64_t': 'unsigned long long',
- } #type: Dict[str, str]
-
- def _printf_type_cast(self, typ: str) -> Optional[str]:
- """Cast values of typ to this type before passing them to printf.
-
- Return None if values of the given type do not need a cast.
- """
- return self._PRINTF_TYPE_CAST.get(typ)
-
- _POINTER_TYPE_RE = re.compile(r'\s*\*\Z')
-
- def _printf_parameters(self, typ: str, var: str) -> Tuple[str, List[str]]:
- """The printf format and arguments for a value of type typ stored in var.
- """
- expr = var
- base_type = typ
- # For outputs via a pointer, get the value that has been written.
- # Note: we don't support pointers to pointers here.
- pointer_match = self._POINTER_TYPE_RE.search(base_type)
- if pointer_match:
- base_type = base_type[:pointer_match.start(0)]
- expr = '*({})'.format(expr)
- # Maybe cast the value to a standard type.
- cast_to = self._printf_type_cast(base_type)
- if cast_to is not None:
- expr = '({}) {}'.format(cast_to, expr)
- base_type = cast_to
- # Try standard types.
- fmt = self._printf_simple_format(base_type)
- if fmt is not None:
- return '{}={}'.format(var, fmt), [expr]
- raise UnknownTypeForPrintf(typ)
-
- def _write_function_logging(self, out: typing_util.Writable,
- function: FunctionInfo,
- argument_names: List[str]) -> None:
- """Write code to log the function's inputs and outputs."""
- formats, values = '%s', ['"' + function.name + '"']
- for arg_info, arg_name in zip(function.arguments, argument_names):
- fmt, vals = self._printf_parameters(arg_info.type, arg_name)
- if fmt:
- formats += ' ' + fmt
- values += vals
- if not function.returns_void():
- ret_name = self._return_variable_name(function)
- fmt, vals = self._printf_parameters(function.return_type, ret_name)
- if fmt:
- formats += ' ' + fmt
- values += vals
- out.write("""\
-#if defined(MBEDTLS_FS_IO) && defined(MBEDTLS_TEST_HOOKS)
- if ({stream}) {{
- mbedtls_fprintf({stream}, "{formats}\\n",
- {values});
- }}
-#endif /* defined(MBEDTLS_FS_IO) && defined(MBEDTLS_TEST_HOOKS) */
-"""
- .format(stream=self.stream,
- formats=formats,
- values=', '.join(values)))
-
- def _write_function_body(self, out: typing_util.Writable,
- function: FunctionInfo,
- argument_names: List[str]) -> None:
- """Write the body of the wrapper code for the specified function.
- """
- self._write_function_call(out, function, argument_names)
- self._write_function_logging(out, function, argument_names)
- self._write_function_return(out, function)