diff --git a/tools/gcov.py b/tools/gcov.py index 48887f5e7a679..d888658181441 100755 --- a/tools/gcov.py +++ b/tools/gcov.py @@ -20,11 +20,59 @@ import argparse import os +import re import shutil import subprocess import sys +def parse_gcda_data(path): + with open(path, "r") as file: + lines = file.read().strip().splitlines() + + started = False + filename = "" + output = "" + size = 0 + + for line in lines: + if line.startswith("gcov start"): + started = True + match = re.search(r"filename:(.*?)\s+size:\s*(\d+)Byte", line) + if match: + filename = match.group(1) + size = int(match.group(2)) + continue + + if not started: + continue + + if line.startswith("gcov end"): + started = False + if size != len(output) // 2: + print( + f"Size mismatch for {filename}: expected {size} bytes, got {len(output) // 2} bytes" + ) + + match = re.search(r"checksum:\s*(0x[0-9a-fA-F]+)", line) + if match: + checksum = int(match.group(1), 16) + output = bytearray.fromhex(output) + expected = sum(output) % 65536 + if checksum != expected: + print( + f"Checksum mismatch for {filename}: expected {checksum}, got {expected}" + ) + continue + + with open(filename, "wb") as fp: + fp.write(output) + print(f"write {filename} success") + output = "" + else: + output += line.strip() + + def copy_file_endswith(endswith, source_dir, target_dir): print(f"Collect {endswith} files {source_dir} -> {target_dir}") @@ -43,6 +91,7 @@ def arg_parser(): parser = argparse.ArgumentParser( description="Code coverage generation tool.", add_help=False ) + parser.add_argument("-i", "--input", help="Input dump data") parser.add_argument("-t", dest="gcov_tool", help="Path to gcov tool") parser.add_argument("-s", dest="gcno_dir", help="Directory containing gcno files") parser.add_argument("-a", dest="gcda_dir", help="Directory containing gcda files") @@ -79,6 +128,9 @@ def main(): debug_file = os.path.join(gcov_dir, "debug.log") sys.stdout = open(debug_file, "w+") + if args.input: + parse_gcda_data(os.path.join(root_dir, args.input)) + os.makedirs(os.path.join(gcov_dir, "data"), exist_ok=True) # Collect gcno, gcda files diff --git a/tools/gcov_convert.py b/tools/gcov_convert.py deleted file mode 100755 index 7648784d853e6..0000000000000 --- a/tools/gcov_convert.py +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env python3 -############################################################################ -# tools/gcov_convert.py -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. The -# ASF licenses this file to you 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 argparse -import re - -# Parse gcda data from stdout dump format to binary format -# The stdout dump format is: -# gcov start filename: size: Byte -# -# gcov end filename: checksum: -# -# The hex dump data will be converted to binary and written to -# The checksum is calculated by summing all bytes and taking modulo 65536 - - -def parse_gcda_data(input_file): - with open(input_file, "r") as file: - lines = file.read().strip().splitlines() - - for line in lines: - if not line.startswith("gcov start"): - continue - - match = re.search(r"filename:(.*?)\s+size:\s*(\d+)Byte", line) - if not match: - continue - - hex_dump = "" - filename = match.group(1) - size = int(match.group(2)) - - # Read the hex dump until the end of the file - next_line_index = lines.index(line) + 1 - while next_line_index < len(lines) and not lines[next_line_index].startswith( - "gcov end" - ): - hex_dump += lines[next_line_index].strip() - next_line_index += 1 - - if size != len(hex_dump) // 2: - print( - f"Size mismatch for {filename}: expected {size} bytes, got {len(hex_dump) // 2} bytes" - ) - - checksum_match = ( - re.search(r"checksum:\s*(0x[0-9a-fA-F]+)", lines[next_line_index]) - if next_line_index < len(lines) - else None - ) - if not checksum_match: - continue - - checksum = int(checksum_match.group(1), 16) - calculated_checksum = sum(bytearray.fromhex(hex_dump)) % 65536 - if calculated_checksum != checksum: - print( - f"Checksum mismatch for {filename}: expected {checksum}, got {calculated_checksum}" - ) - continue - - with open(filename, "wb") as fp: - fp.write(bytes.fromhex(hex_dump)) - print(f"write {filename} success") - - print( - "Execute the 'nuttx/tools/gcov.sh -t arm-none-eabi-gcov' command to view the coverage report" - ) - - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument("-i", "--input", required=True, help="Input dump data") - args = parser.parse_args() - - parse_gcda_data(args.input)