mirror of
				https://github.com/cuberite/polarssl.git
				synced 2025-11-04 04:32:24 -05:00 
			
		
		
		
	Change 'tranlation' -> 'translation' in the name of a method in `scripts/generate_ssl_debug_headers.py`. Signed-off-by: David Horstmann <david.horstmann@arm.com>
		
			
				
	
	
		
			323 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			323 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
#!/usr/bin/env python3
 | 
						|
 | 
						|
"""Generate library/ssl_debug_helps_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
 | 
						|
#
 | 
						|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
 | 
						|
# not use this file except in compliance with the License.
 | 
						|
# You may obtain a copy of the License at
 | 
						|
#
 | 
						|
# http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
#
 | 
						|
# Unless required by applicable law or agreed to in writing, software
 | 
						|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
						|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
# See the License for the specific language governing permissions and
 | 
						|
# limitations under the License.
 | 
						|
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 processses 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}[{member}] = "{member}",'.format(member=member,
 | 
						|
                                                             space=' '*8)
 | 
						|
                )
 | 
						|
 | 
						|
        body = textwrap.dedent('''\
 | 
						|
            const char *{name}_str( {prototype} in )
 | 
						|
            {{
 | 
						|
                const char * in_to_str[]=
 | 
						|
                {{
 | 
						|
            {translation_table}
 | 
						|
                }};
 | 
						|
 | 
						|
                if( in > ( sizeof( in_to_str )/sizeof( in_to_str[0]) - 1 ) ||
 | 
						|
                    in_to_str[ in ] == NULL )
 | 
						|
                {{
 | 
						|
                    return "UNKOWN_VAULE";
 | 
						|
                }}
 | 
						|
                return in_to_str[ in ];
 | 
						|
            }}
 | 
						|
                    ''')
 | 
						|
        body = body.format(translation_table='\n'.join(translation_table),
 | 
						|
                           name=self._name,
 | 
						|
                           prototype=self._prototype)
 | 
						|
        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
 | 
						|
 *
 | 
						|
 *  Licensed under the Apache License, Version 2.0 (the "License"); you may
 | 
						|
 *  not use this file except in compliance with the License.
 | 
						|
 *  You may obtain a copy of the License at
 | 
						|
 *
 | 
						|
 *  http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 *
 | 
						|
 *  Unless required by applicable law or agreed to in writing, software
 | 
						|
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
						|
 *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
 *  See the License for the specific language governing permissions and
 | 
						|
 *  limitations under the License.
 | 
						|
 */
 | 
						|
 | 
						|
#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):
 | 
						|
        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())
 |