1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0 OR MIT
#
# Copyright (C) 2022 Intel Corporation
#
# gather_on_test.py
#
# by Tomi Sarvela <tomi.p.sarvela@intel.com>
#
# Faster implementation for linux kernel GCOV data collection
# Command line compatible with original gather_on_test.sh
#
# Refs:
# https://www.kernel.org/doc/html/latest/dev-tools/gcov.html
#
import argparse
import errno
import io
import os
import sys
import tarfile
def parse_args() -> argparse.Namespace:
'''Command line arguments'''
ap = argparse.ArgumentParser(description="Gather Linux kernel GCOV data")
ap.add_argument('output',
help="Output file name (.tar.gz will be added)")
ap.add_argument('--gcov', default='/sys/kernel/debug/gcov',
help="GCOV directory, default: /sys/kernel/debug/gcov")
return ap.parse_args()
def tar_add_link(tar:tarfile.TarFile, filename:str):
'''Add filename as symlink to tarfile'''
info = tarfile.TarInfo(filename)
if info.name[0] == '/': info.name = info.name[1:]
info.type = tarfile.SYMTYPE
info.linkname = os.readlink(filename)
tar.addfile(info)
def tar_add_file(tar:tarfile.TarFile, filename:str):
'''Add filename to tarfile, file size expected to be invalid'''
try:
with open(filename, "rb") as fp:
data = fp.read() # big gulp
except OSError as e:
print(f"ERROR: {filename}: {e}", file=sys.stderr)
return
info = tarfile.TarInfo(filename)
if info.name[0] == '/': info.name = info.name[1:]
info.size = len(data)
tar.addfile(info, io.BytesIO(data))
def tar_add_tree(tar:tarfile.TarFile, tree:str):
'''Add gcov files in directory tree to tar'''
# FIXME: should dirs be added to tar for compatibility?
for root, _, files in os.walk(tree, followlinks=False):
for file in files:
filepath = os.path.join(root, file)
if file.endswith('.gcda'): tar_add_file(tar, filepath)
if file.endswith('.gcno'): tar_add_link(tar, filepath)
def main() -> int:
'''MAIN'''
if not os.path.isdir(args.gcov):
print(f"ERROR: [Errno {errno.ENOTDIR}] {os.strerror(errno.ENOTDIR)}: '{args.gcov}'",
file=sys.stderr)
return errno.ENOTDIR
if args.output == '-':
# reopen stdout as bytes for tarfile
fp = os.fdopen(sys.stdout.fileno(), "wb", closefd=False)
else:
if not args.output.endswith('.tgz') and \
not args.output.endswith('.tar.gz'):
args.output+='.tar.gz'
try:
fp = open(args.output, 'wb')
except OSError as e:
print(f"ERROR: {e}", file=sys.stderr)
return e.errno
with tarfile.open(fileobj=fp, mode='w:gz') as tar:
tar_add_tree(tar, args.gcov)
fp.close()
return 0
if __name__ == '__main__':
try:
args = parse_args()
sys.exit(main())
except KeyboardInterrupt:
print("Interrupted", file=sys.stderr)
sys.exit(errno.EINTR)
|