diff options
Diffstat (limited to 'scripts/generate_ssl_debug_helpers.py')
-rwxr-xr-x | scripts/generate_ssl_debug_helpers.py | 414 |
1 files changed, 0 insertions, 414 deletions
diff --git a/scripts/generate_ssl_debug_helpers.py b/scripts/generate_ssl_debug_helpers.py deleted file mode 100755 index a0544f1537d..00000000000 --- a/scripts/generate_ssl_debug_helpers.py +++ /dev/null @@ -1,414 +0,0 @@ -#!/usr/bin/env python3 - -"""Generate library/ssl_debug_helpers_generated.c - -The code generated by this module includes debug helper functions that can not be -implemented by fixed codes. - -""" - -# Copyright The Mbed TLS Contributors -# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later -import sys -import re -import os -import textwrap -import argparse -from mbedtls_dev import build_tree - - -def remove_c_comments(string): - """ - Remove C style comments from input string - """ - string_pattern = r"(?P<string>\".*?\"|\'.*?\')" - comment_pattern = r"(?P<comment>/\*.*?\*/|//[^\r\n]*$)" - pattern = re.compile(string_pattern + r'|' + comment_pattern, - re.MULTILINE | re.DOTALL) - - def replacer(match): - if match.lastgroup == 'comment': - return "" - return match.group() - return pattern.sub(replacer, string) - - -class CondDirectiveNotMatch(Exception): - pass - - -def preprocess_c_source_code(source, *classes): - """ - Simple preprocessor for C source code. - - Only processes condition directives without expanding them. - Yield object according to the classes input. Most match firstly - - If the directive pair does not match , raise CondDirectiveNotMatch. - - Assume source code does not include comments and compile pass. - - """ - - pattern = re.compile(r"^[ \t]*#[ \t]*" + - r"(?P<directive>(if[ \t]|ifndef[ \t]|ifdef[ \t]|else|endif))" + - r"[ \t]*(?P<param>(.*\\\n)*.*$)", - re.MULTILINE) - stack = [] - - def _yield_objects(s, d, p, st, end): - """ - Output matched source piece - """ - nonlocal stack - start_line, end_line = '', '' - if stack: - start_line = '#{} {}'.format(d, p) - if d == 'if': - end_line = '#endif /* {} */'.format(p) - elif d == 'ifdef': - end_line = '#endif /* defined({}) */'.format(p) - else: - end_line = '#endif /* !defined({}) */'.format(p) - has_instance = False - for cls in classes: - for instance in cls.extract(s, st, end): - if has_instance is False: - has_instance = True - yield pair_start, start_line - yield instance.span()[0], instance - if has_instance: - yield start, end_line - - for match in pattern.finditer(source): - - directive = match.groupdict()['directive'].strip() - param = match.groupdict()['param'] - start, end = match.span() - - if directive in ('if', 'ifndef', 'ifdef'): - stack.append((directive, param, start, end)) - continue - - if not stack: - raise CondDirectiveNotMatch() - - pair_directive, pair_param, pair_start, pair_end = stack.pop() - yield from _yield_objects(source, - pair_directive, - pair_param, - pair_end, - start) - - if directive == 'endif': - continue - - if pair_directive == 'if': - directive = 'if' - param = "!( {} )".format(pair_param) - elif pair_directive == 'ifdef': - directive = 'ifndef' - param = pair_param - else: - directive = 'ifdef' - param = pair_param - - stack.append((directive, param, start, end)) - assert not stack, len(stack) - - -class EnumDefinition: - """ - Generate helper functions around enumeration. - - Currently, it generate translation function from enum value to string. - Enum definition looks like: - [typedef] enum [prefix name] { [body] } [suffix name]; - - Known limitation: - - the '}' and ';' SHOULD NOT exist in different macro blocks. Like - ``` - enum test { - .... - #if defined(A) - .... - }; - #else - .... - }; - #endif - ``` - """ - - @classmethod - def extract(cls, source_code, start=0, end=-1): - enum_pattern = re.compile(r'enum\s*(?P<prefix_name>\w*)\s*' + - r'{\s*(?P<body>[^}]*)}' + - r'\s*(?P<suffix_name>\w*)\s*;', - re.MULTILINE | re.DOTALL) - - for match in enum_pattern.finditer(source_code, start, end): - yield EnumDefinition(source_code, - span=match.span(), - group=match.groupdict()) - - def __init__(self, source_code, span=None, group=None): - assert isinstance(group, dict) - prefix_name = group.get('prefix_name', None) - suffix_name = group.get('suffix_name', None) - body = group.get('body', None) - assert prefix_name or suffix_name - assert body - assert span - # If suffix_name exists, it is a typedef - self._prototype = suffix_name if suffix_name else 'enum ' + prefix_name - self._name = suffix_name if suffix_name else prefix_name - self._body = body - self._source = source_code - self._span = span - - def __repr__(self): - return 'Enum({},{})'.format(self._name, self._span) - - def __str__(self): - return repr(self) - - def span(self): - return self._span - - def generate_translation_function(self): - """ - Generate function for translating value to string - """ - translation_table = [] - - for line in self._body.splitlines(): - - if line.strip().startswith('#'): - # Preprocess directive, keep it in table - translation_table.append(line.strip()) - continue - - if not line.strip(): - continue - - for field in line.strip().split(','): - if not field.strip(): - continue - member = field.strip().split()[0] - translation_table.append( - '{space}case {member}:\n{space} return "{member}";' - .format(member=member, space=' '*8) - ) - - body = textwrap.dedent('''\ - const char *{name}_str( {prototype} in ) - {{ - switch (in) {{ - {translation_table} - default: - return "UNKNOWN_VALUE"; - }} - }} - ''') - body = body.format(translation_table='\n'.join(translation_table), - name=self._name, - prototype=self._prototype) - return body - - -class SignatureAlgorithmDefinition: - """ - Generate helper functions for signature algorithms. - - It generates translation function from signature algorithm define to string. - Signature algorithm definition looks like: - #define MBEDTLS_TLS1_3_SIG_[ upper case signature algorithm ] [ value(hex) ] - - Known limitation: - - the definitions SHOULD exist in same macro blocks. - """ - - @classmethod - def extract(cls, source_code, start=0, end=-1): - sig_alg_pattern = re.compile(r'#define\s+(?P<name>MBEDTLS_TLS1_3_SIG_\w+)\s+' + - r'(?P<value>0[xX][0-9a-fA-F]+)$', - re.MULTILINE | re.DOTALL) - matches = list(sig_alg_pattern.finditer(source_code, start, end)) - if matches: - yield SignatureAlgorithmDefinition(source_code, definitions=matches) - - def __init__(self, source_code, definitions=None): - if definitions is None: - definitions = [] - assert isinstance(definitions, list) and definitions - self._definitions = definitions - self._source = source_code - - def __repr__(self): - return 'SigAlgs({})'.format(self._definitions[0].span()) - - def span(self): - return self._definitions[0].span() - - def __str__(self): - """ - Generate function for translating value to string - """ - translation_table = [] - for m in self._definitions: - name = m.groupdict()['name'] - return_val = name[len('MBEDTLS_TLS1_3_SIG_'):].lower() - translation_table.append( - ' case {}:\n return "{}";'.format(name, return_val)) - - body = textwrap.dedent('''\ - const char *mbedtls_ssl_sig_alg_to_str( uint16_t in ) - {{ - switch( in ) - {{ - {translation_table} - }}; - - return "UNKNOWN"; - }}''') - body = body.format(translation_table='\n'.join(translation_table)) - return body - - -class NamedGroupDefinition: - """ - Generate helper functions for named group - - It generates translation function from named group define to string. - Named group definition looks like: - #define MBEDTLS_SSL_IANA_TLS_GROUP_[ upper case named group ] [ value(hex) ] - - Known limitation: - - the definitions SHOULD exist in same macro blocks. - """ - - @classmethod - def extract(cls, source_code, start=0, end=-1): - named_group_pattern = re.compile(r'#define\s+(?P<name>MBEDTLS_SSL_IANA_TLS_GROUP_\w+)\s+' + - r'(?P<value>0[xX][0-9a-fA-F]+)$', - re.MULTILINE | re.DOTALL) - matches = list(named_group_pattern.finditer(source_code, start, end)) - if matches: - yield NamedGroupDefinition(source_code, definitions=matches) - - def __init__(self, source_code, definitions=None): - if definitions is None: - definitions = [] - assert isinstance(definitions, list) and definitions - self._definitions = definitions - self._source = source_code - - def __repr__(self): - return 'NamedGroup({})'.format(self._definitions[0].span()) - - def span(self): - return self._definitions[0].span() - - def __str__(self): - """ - Generate function for translating value to string - """ - translation_table = [] - for m in self._definitions: - name = m.groupdict()['name'] - iana_name = name[len('MBEDTLS_SSL_IANA_TLS_GROUP_'):].lower() - translation_table.append(' case {}:\n return "{}";'.format(name, iana_name)) - - body = textwrap.dedent('''\ - const char *mbedtls_ssl_named_group_to_str( uint16_t in ) - {{ - switch( in ) - {{ - {translation_table} - }}; - - return "UNKOWN"; - }}''') - body = body.format(translation_table='\n'.join(translation_table)) - return body - - -OUTPUT_C_TEMPLATE = '''\ -/* Automatically generated by generate_ssl_debug_helpers.py. DO NOT EDIT. */ - -/** - * \\file ssl_debug_helpers_generated.c - * - * \\brief Automatically generated helper functions for debugging - */ -/* - * Copyright The Mbed TLS Contributors - * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later - * - */ - -#include "common.h" - -#if defined(MBEDTLS_DEBUG_C) - -#include "ssl_debug_helpers.h" - -{functions} - -#endif /* MBEDTLS_DEBUG_C */ -/* End of automatically generated file. */ - -''' - - -def generate_ssl_debug_helpers(output_directory, mbedtls_root): - """ - Generate functions of debug helps - """ - mbedtls_root = os.path.abspath( - mbedtls_root or build_tree.guess_mbedtls_root()) - with open(os.path.join(mbedtls_root, 'include/mbedtls/ssl.h')) as f: - source_code = remove_c_comments(f.read()) - - definitions = dict() - for start, instance in preprocess_c_source_code(source_code, - EnumDefinition, - SignatureAlgorithmDefinition, - NamedGroupDefinition): - if start in definitions: - continue - if isinstance(instance, EnumDefinition): - definition = instance.generate_translation_function() - else: - definition = instance - definitions[start] = definition - - function_definitions = [str(v) for _, v in sorted(definitions.items())] - if output_directory == sys.stdout: - sys.stdout.write(OUTPUT_C_TEMPLATE.format( - functions='\n'.join(function_definitions))) - else: - with open(os.path.join(output_directory, 'ssl_debug_helpers_generated.c'), 'w') as f: - f.write(OUTPUT_C_TEMPLATE.format( - functions='\n'.join(function_definitions))) - - -def main(): - """ - Command line entry - """ - parser = argparse.ArgumentParser() - parser.add_argument('--mbedtls-root', nargs='?', default=None, - help='root directory of mbedtls source code') - parser.add_argument('output_directory', nargs='?', - default='library', help='source/header files location') - - args = parser.parse_args() - - generate_ssl_debug_helpers(args.output_directory, args.mbedtls_root) - return 0 - - -if __name__ == '__main__': - sys.exit(main()) |