mirror of
https://github.com/ARMmbed/mbedtls.git
synced 2025-05-09 16:41:19 +08:00
add enum value to string helpers
Only add helpers for enum in `ssl.h`. Signed-off-by: Jerry Yu <jerry.h.yu@arm.com>
This commit is contained in:
parent
1dc3c4553d
commit
e78ee99624
2
library/.gitignore
vendored
2
library/.gitignore
vendored
@ -6,3 +6,5 @@ libmbed*
|
|||||||
# Automatically generated files
|
# Automatically generated files
|
||||||
/error.c
|
/error.c
|
||||||
/version_features.c
|
/version_features.c
|
||||||
|
/ssl_debug_helpers_generated.c
|
||||||
|
/ssl_debug_helpers_generated.h
|
||||||
|
@ -77,6 +77,7 @@ set(src_crypto
|
|||||||
sha1.c
|
sha1.c
|
||||||
sha256.c
|
sha256.c
|
||||||
sha512.c
|
sha512.c
|
||||||
|
ssl_debug_helpers_generated.c
|
||||||
threading.c
|
threading.c
|
||||||
timing.c
|
timing.c
|
||||||
version.c
|
version.c
|
||||||
|
@ -24,6 +24,12 @@ endif
|
|||||||
|
|
||||||
PERL ?= perl
|
PERL ?= perl
|
||||||
|
|
||||||
|
ifdef WINDOWS
|
||||||
|
PYTHON ?= python
|
||||||
|
else
|
||||||
|
PYTHON ?= $(shell if type python3 >/dev/null 2>/dev/null; then echo python3; else echo python; fi)
|
||||||
|
endif
|
||||||
|
|
||||||
# if were running on Windows build for Windows
|
# if were running on Windows build for Windows
|
||||||
ifdef WINDOWS
|
ifdef WINDOWS
|
||||||
WINDOWS_BUILD=1
|
WINDOWS_BUILD=1
|
||||||
@ -136,6 +142,7 @@ OBJS_CRYPTO= \
|
|||||||
sha1.o \
|
sha1.o \
|
||||||
sha256.o \
|
sha256.o \
|
||||||
sha512.o \
|
sha512.o \
|
||||||
|
ssl_debug_helpers_generated.o \
|
||||||
threading.o \
|
threading.o \
|
||||||
timing.o \
|
timing.o \
|
||||||
version.o \
|
version.o \
|
||||||
@ -281,7 +288,7 @@ libmbedcrypto.dll: $(OBJS_CRYPTO)
|
|||||||
$(CC) $(LOCAL_CFLAGS) $(CFLAGS) -o $@ -c $<
|
$(CC) $(LOCAL_CFLAGS) $(CFLAGS) -o $@ -c $<
|
||||||
|
|
||||||
.PHONY: generated_files
|
.PHONY: generated_files
|
||||||
GENERATED_FILES = error.c version_features.c
|
GENERATED_FILES = error.c version_features.c ssl_debug_helpers_generated.c
|
||||||
generated_files: $(GENERATED_FILES)
|
generated_files: $(GENERATED_FILES)
|
||||||
|
|
||||||
error.c: ../scripts/generate_errors.pl
|
error.c: ../scripts/generate_errors.pl
|
||||||
@ -291,6 +298,12 @@ error.c:
|
|||||||
echo " Gen $@"
|
echo " Gen $@"
|
||||||
$(PERL) ../scripts/generate_errors.pl
|
$(PERL) ../scripts/generate_errors.pl
|
||||||
|
|
||||||
|
ssl_debug_helpers_generated.c: ../scripts/generate_ssl_debug_helpers.py
|
||||||
|
ssl_debug_helpers_generated.c: $(filter-out %config%,$(wildcard ../include/mbedtls/*.h))
|
||||||
|
ssl_debug_helpers_generated.c:
|
||||||
|
echo " Gen $@"
|
||||||
|
$(PYTHON) ../scripts/generate_ssl_debug_helpers.py
|
||||||
|
|
||||||
version_features.c: ../scripts/generate_features.pl
|
version_features.c: ../scripts/generate_features.pl
|
||||||
version_features.c: ../scripts/data_files/version_features.fmt
|
version_features.c: ../scripts/data_files/version_features.fmt
|
||||||
## The generated file only depends on the options that are present in mbedtls_config.h,
|
## The generated file only depends on the options that are present in mbedtls_config.h,
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
#include "ssl_misc.h"
|
#include "ssl_misc.h"
|
||||||
#include "ecdh_misc.h"
|
#include "ecdh_misc.h"
|
||||||
#include "ssl_tls13_keys.h"
|
#include "ssl_tls13_keys.h"
|
||||||
|
#include "ssl_debug_helpers_generated.h"
|
||||||
|
|
||||||
/* Write extensions */
|
/* Write extensions */
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include "mbedtls/debug.h"
|
#include "mbedtls/debug.h"
|
||||||
|
|
||||||
#include "ssl_misc.h"
|
#include "ssl_misc.h"
|
||||||
|
#include "ssl_debug_helpers_generated.h"
|
||||||
|
|
||||||
int mbedtls_ssl_tls13_handshake_server_step( mbedtls_ssl_context *ssl )
|
int mbedtls_ssl_tls13_handshake_server_step( mbedtls_ssl_context *ssl )
|
||||||
{
|
{
|
||||||
|
310
scripts/generate_ssl_debug_helpers.py
Executable file
310
scripts/generate_ssl_debug_helpers.py
Executable file
@ -0,0 +1,310 @@
|
|||||||
|
#!/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
|
||||||
|
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 preprocesse_c_source_code(source, *classes):
|
||||||
|
"""
|
||||||
|
Simple preprocessor for C source code.
|
||||||
|
|
||||||
|
Only processs condition directives without expanding them.
|
||||||
|
Yield object accodring to the classes input. Most match firstly
|
||||||
|
|
||||||
|
If there are 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 tranlation 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_tranlation_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)
|
||||||
|
prototype = 'const char *{name}_str( {prototype} in );\n'
|
||||||
|
prototype = prototype.format(name=self._name,
|
||||||
|
prototype=self._prototype)
|
||||||
|
return body, prototype
|
||||||
|
|
||||||
|
OUTPUT_C_TEMPLATE = '''\
|
||||||
|
/* Automatically generated by generate_ssl_debug_helpers.py. DO NOT EDIT. */
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#if defined(MBEDTLS_DEBUG_C)
|
||||||
|
|
||||||
|
#include "ssl_debug_helpers_generated.h"
|
||||||
|
|
||||||
|
{functions}
|
||||||
|
|
||||||
|
#endif /* MBEDTLS_DEBUG_C */
|
||||||
|
/* End of automatically generated file. */
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
OUTPUT_H_TEMPLATE = '''\
|
||||||
|
/* Automatically generated by generate_ssl_debug_helpers.py. DO NOT EDIT. */
|
||||||
|
#ifndef MBEDTLS_SSL_DEBUG_HELPERS_H
|
||||||
|
#define MBEDTLS_SSL_DEBUG_HELPERS_H
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#if defined(MBEDTLS_DEBUG_C)
|
||||||
|
|
||||||
|
#include "mbedtls/ssl.h"
|
||||||
|
#include "ssl_misc.h"
|
||||||
|
|
||||||
|
{functions}
|
||||||
|
|
||||||
|
#endif /* MBEDTLS_DEBUG_C */
|
||||||
|
|
||||||
|
#endif /* SSL_DEBUG_HELPERS_H */
|
||||||
|
|
||||||
|
/* End of automatically generated file. */
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
def generate_ssl_debug_helpers(target_dir):
|
||||||
|
"""
|
||||||
|
Generate functions of debug helps
|
||||||
|
"""
|
||||||
|
with open('include/mbedtls/ssl.h') as f:
|
||||||
|
source_code = remove_c_comments(f.read())
|
||||||
|
|
||||||
|
definitions = dict()
|
||||||
|
prototypes = dict()
|
||||||
|
for start, instance in preprocesse_c_source_code(source_code, EnumDefinition):
|
||||||
|
if start in definitions:
|
||||||
|
continue
|
||||||
|
if isinstance(instance, EnumDefinition):
|
||||||
|
definition, prototype = instance.generate_tranlation_function()
|
||||||
|
else:
|
||||||
|
definition = instance
|
||||||
|
prototype = instance
|
||||||
|
definitions[start] = definition
|
||||||
|
prototypes[start] = prototype
|
||||||
|
|
||||||
|
functions = [str(v) for _, v in sorted(definitions.items())]
|
||||||
|
with open(os.path.join(target_dir, 'ssl_debug_helpers_generated.c'), 'w') as f:
|
||||||
|
f.write(OUTPUT_C_TEMPLATE.format(functions='\n'.join(functions)))
|
||||||
|
|
||||||
|
functions = [str(v) for _, v in sorted(prototypes.items())]
|
||||||
|
with open(os.path.join(target_dir, 'ssl_debug_helpers_generated.h'), 'w') as f:
|
||||||
|
f.write(OUTPUT_H_TEMPLATE.format(functions='\n'.join(functions)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
build_tree.chdir_to_root()
|
||||||
|
OUTPUT_FILE_DIR = sys.argv[1] if len(sys.argv) == 2 else "library"
|
||||||
|
generate_ssl_debug_helpers(OUTPUT_FILE_DIR)
|
@ -4,6 +4,7 @@
|
|||||||
perl scripts\generate_errors.pl || exit /b 1
|
perl scripts\generate_errors.pl || exit /b 1
|
||||||
perl scripts\generate_query_config.pl || exit /b 1
|
perl scripts\generate_query_config.pl || exit /b 1
|
||||||
perl scripts\generate_features.pl || exit /b 1
|
perl scripts\generate_features.pl || exit /b 1
|
||||||
|
python scripts\generate_ssl_debug_helpers.py || exit /b 1
|
||||||
perl scripts\generate_visualc_files.pl || exit /b 1
|
perl scripts\generate_visualc_files.pl || exit /b 1
|
||||||
python scripts\generate_psa_constants.py || exit /b 1
|
python scripts\generate_psa_constants.py || exit /b 1
|
||||||
python tests\scripts\generate_psa_tests.py || exit /b 1
|
python tests\scripts\generate_psa_tests.py || exit /b 1
|
||||||
|
@ -118,6 +118,7 @@ check()
|
|||||||
check scripts/generate_errors.pl library/error.c
|
check scripts/generate_errors.pl library/error.c
|
||||||
check scripts/generate_query_config.pl programs/test/query_config.c
|
check scripts/generate_query_config.pl programs/test/query_config.c
|
||||||
check scripts/generate_features.pl library/version_features.c
|
check scripts/generate_features.pl library/version_features.c
|
||||||
|
check scripts/generate_ssl_debug_helpers.py library/ssl_debug_helpers_generated.c
|
||||||
# generate_visualc_files enumerates source files (library/*.c). It doesn't
|
# generate_visualc_files enumerates source files (library/*.c). It doesn't
|
||||||
# care about their content, but the files must exist. So it must run after
|
# care about their content, but the files must exist. So it must run after
|
||||||
# the step that creates or updates these files.
|
# the step that creates or updates these files.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user