xref: /aosp_15_r20/kernel/tests/tools/create-tracefile.py (revision 2f2c4c7ab4226c71756b9c31670392fdd6887c4f)
1*2f2c4c7aSAndroid Build Coastguard Worker#!/usr/bin/python3
2*2f2c4c7aSAndroid Build Coastguard Worker# SPDX-License-Identifier: GPL-2.0
3*2f2c4c7aSAndroid Build Coastguard Worker# Copyright (C) 2024 The Android Open Source Project
4*2f2c4c7aSAndroid Build Coastguard Worker#
5*2f2c4c7aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
6*2f2c4c7aSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
7*2f2c4c7aSAndroid Build Coastguard Worker# You may obtain a copy of the License at
8*2f2c4c7aSAndroid Build Coastguard Worker#
9*2f2c4c7aSAndroid Build Coastguard Worker#      http://www.apache.org/licenses/LICENSE-2.0
10*2f2c4c7aSAndroid Build Coastguard Worker#
11*2f2c4c7aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
12*2f2c4c7aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
13*2f2c4c7aSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*2f2c4c7aSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
15*2f2c4c7aSAndroid Build Coastguard Worker# limitations under the License.
16*2f2c4c7aSAndroid Build Coastguard Worker
17*2f2c4c7aSAndroid Build Coastguard Worker"""This utility generates a single lcov tracefile from a gcov tar file."""
18*2f2c4c7aSAndroid Build Coastguard Worker
19*2f2c4c7aSAndroid Build Coastguard Workerimport argparse
20*2f2c4c7aSAndroid Build Coastguard Workerimport collections
21*2f2c4c7aSAndroid Build Coastguard Workerimport fnmatch
22*2f2c4c7aSAndroid Build Coastguard Workerimport glob
23*2f2c4c7aSAndroid Build Coastguard Workerimport json
24*2f2c4c7aSAndroid Build Coastguard Workerimport logging
25*2f2c4c7aSAndroid Build Coastguard Workerimport os
26*2f2c4c7aSAndroid Build Coastguard Workerimport pathlib
27*2f2c4c7aSAndroid Build Coastguard Workerimport re
28*2f2c4c7aSAndroid Build Coastguard Workerimport shutil
29*2f2c4c7aSAndroid Build Coastguard Workerimport sys
30*2f2c4c7aSAndroid Build Coastguard Workerimport tarfile
31*2f2c4c7aSAndroid Build Coastguard Worker
32*2f2c4c7aSAndroid Build Coastguard Worker
33*2f2c4c7aSAndroid Build Coastguard WorkerLCOV = "lcov"
34*2f2c4c7aSAndroid Build Coastguard Worker
35*2f2c4c7aSAndroid Build Coastguard Worker# Relative to the root of the source tree.
36*2f2c4c7aSAndroid Build Coastguard WorkerOUTPUT_COV_DIR = os.path.join("out", "coverage")
37*2f2c4c7aSAndroid Build Coastguard Worker
38*2f2c4c7aSAndroid Build Coastguard WorkerBUILD_CONFIG_CONSTANTS_PATH = os.path.join("common", "build.config.constants")
39*2f2c4c7aSAndroid Build Coastguard Worker
40*2f2c4c7aSAndroid Build Coastguard WorkerPREBUILT_CLANG_DIR = os.path.join("prebuilts", "clang", "host", "linux-x86")
41*2f2c4c7aSAndroid Build Coastguard Worker
42*2f2c4c7aSAndroid Build Coastguard WorkerPREBUILT_LLVM_COV_PATH_FORMAT = os.path.join(
43*2f2c4c7aSAndroid Build Coastguard Worker    PREBUILT_CLANG_DIR, "clang-%s", "bin", "llvm-cov"
44*2f2c4c7aSAndroid Build Coastguard Worker)
45*2f2c4c7aSAndroid Build Coastguard Worker
46*2f2c4c7aSAndroid Build Coastguard WorkerPREBUILT_STABLE_LLVM_COV_PATH = os.path.join(
47*2f2c4c7aSAndroid Build Coastguard Worker    PREBUILT_CLANG_DIR, "llvm-binutils-stable", "llvm-cov"
48*2f2c4c7aSAndroid Build Coastguard Worker)
49*2f2c4c7aSAndroid Build Coastguard Worker
50*2f2c4c7aSAndroid Build Coastguard WorkerEXCLUDED_FILES = [
51*2f2c4c7aSAndroid Build Coastguard Worker    "*/security/selinux/av_permissions.h",
52*2f2c4c7aSAndroid Build Coastguard Worker    "*/security/selinux/flask.h",
53*2f2c4c7aSAndroid Build Coastguard Worker]
54*2f2c4c7aSAndroid Build Coastguard Worker
55*2f2c4c7aSAndroid Build Coastguard Worker
56*2f2c4c7aSAndroid Build Coastguard Workerdef create_llvm_gcov_sh(
57*2f2c4c7aSAndroid Build Coastguard Worker    llvm_cov_filename: str,
58*2f2c4c7aSAndroid Build Coastguard Worker    llvm_gcov_sh_filename: str,
59*2f2c4c7aSAndroid Build Coastguard Worker) -> None:
60*2f2c4c7aSAndroid Build Coastguard Worker  """Create a shell script that is compatible with gcov.
61*2f2c4c7aSAndroid Build Coastguard Worker
62*2f2c4c7aSAndroid Build Coastguard Worker  Args:
63*2f2c4c7aSAndroid Build Coastguard Worker    llvm_cov_filename: The absolute path to llvm-cov.
64*2f2c4c7aSAndroid Build Coastguard Worker    llvm_gcov_sh_filename: The path to the script to be created.
65*2f2c4c7aSAndroid Build Coastguard Worker  """
66*2f2c4c7aSAndroid Build Coastguard Worker  file_path = pathlib.Path(llvm_gcov_sh_filename)
67*2f2c4c7aSAndroid Build Coastguard Worker  file_path.parent.mkdir(parents=True, exist_ok=True)
68*2f2c4c7aSAndroid Build Coastguard Worker  file_path.write_text(f'#!/bin/bash\nexec {llvm_cov_filename} gcov "$@"')
69*2f2c4c7aSAndroid Build Coastguard Worker  os.chmod(llvm_gcov_sh_filename, 0o755)
70*2f2c4c7aSAndroid Build Coastguard Worker
71*2f2c4c7aSAndroid Build Coastguard Worker
72*2f2c4c7aSAndroid Build Coastguard Workerdef generate_lcov_tracefile(
73*2f2c4c7aSAndroid Build Coastguard Worker    gcov_dir: str,
74*2f2c4c7aSAndroid Build Coastguard Worker    kernel_source: str,
75*2f2c4c7aSAndroid Build Coastguard Worker    gcov_filename: str,
76*2f2c4c7aSAndroid Build Coastguard Worker    tracefile_filename: str,
77*2f2c4c7aSAndroid Build Coastguard Worker    included_files: [],
78*2f2c4c7aSAndroid Build Coastguard Worker) -> None:
79*2f2c4c7aSAndroid Build Coastguard Worker  """Call lcov to create tracefile based on gcov data files.
80*2f2c4c7aSAndroid Build Coastguard Worker
81*2f2c4c7aSAndroid Build Coastguard Worker  Args:
82*2f2c4c7aSAndroid Build Coastguard Worker    gcov_dir: Directory that contains the extracted gcov data files as retrieved
83*2f2c4c7aSAndroid Build Coastguard Worker      from debugfs.
84*2f2c4c7aSAndroid Build Coastguard Worker    kernel_source: Directory containing the kernel source same as what was used
85*2f2c4c7aSAndroid Build Coastguard Worker      to build system under test.
86*2f2c4c7aSAndroid Build Coastguard Worker    gcov_filename: The absolute path to gcov or a compatible script.
87*2f2c4c7aSAndroid Build Coastguard Worker    tracefile_filename: The name of tracefile to create.
88*2f2c4c7aSAndroid Build Coastguard Worker    included_files: List of source file pattern to include in tracefile. Can be
89*2f2c4c7aSAndroid Build Coastguard Worker      empty in which case include allo source.
90*2f2c4c7aSAndroid Build Coastguard Worker  """
91*2f2c4c7aSAndroid Build Coastguard Worker  exclude_args = " ".join([f'--exclude "{f}"' for f in EXCLUDED_FILES])
92*2f2c4c7aSAndroid Build Coastguard Worker  include_args = (
93*2f2c4c7aSAndroid Build Coastguard Worker      " ".join([f'--include "{f[0]}"' for f in included_files])
94*2f2c4c7aSAndroid Build Coastguard Worker      if included_files is not None
95*2f2c4c7aSAndroid Build Coastguard Worker      else ""
96*2f2c4c7aSAndroid Build Coastguard Worker  )
97*2f2c4c7aSAndroid Build Coastguard Worker
98*2f2c4c7aSAndroid Build Coastguard Worker  logging.info("Running lcov on %s", gcov_dir)
99*2f2c4c7aSAndroid Build Coastguard Worker  lcov_cmd = (
100*2f2c4c7aSAndroid Build Coastguard Worker      f"{LCOV} -q "
101*2f2c4c7aSAndroid Build Coastguard Worker      "--ignore-errors=source "
102*2f2c4c7aSAndroid Build Coastguard Worker      "--rc branch_coverage=1 "
103*2f2c4c7aSAndroid Build Coastguard Worker      f"-b {kernel_source} "
104*2f2c4c7aSAndroid Build Coastguard Worker      f"-d {gcov_dir} "
105*2f2c4c7aSAndroid Build Coastguard Worker      f"--gcov-tool {gcov_filename} "
106*2f2c4c7aSAndroid Build Coastguard Worker      f"{exclude_args} "
107*2f2c4c7aSAndroid Build Coastguard Worker      f"{include_args} "
108*2f2c4c7aSAndroid Build Coastguard Worker      "--ignore-errors gcov,gcov,unused,unused "
109*2f2c4c7aSAndroid Build Coastguard Worker      "--capture "
110*2f2c4c7aSAndroid Build Coastguard Worker      f"-o {tracefile_filename} "
111*2f2c4c7aSAndroid Build Coastguard Worker  )
112*2f2c4c7aSAndroid Build Coastguard Worker  os.system(lcov_cmd)
113*2f2c4c7aSAndroid Build Coastguard Worker
114*2f2c4c7aSAndroid Build Coastguard Worker
115*2f2c4c7aSAndroid Build Coastguard Workerdef update_symlink_from_mapping(filepath: str, prefix_mappings: {}) -> bool:
116*2f2c4c7aSAndroid Build Coastguard Worker  """Update symbolic link based on prefix mappings.
117*2f2c4c7aSAndroid Build Coastguard Worker
118*2f2c4c7aSAndroid Build Coastguard Worker  It will attempt to update the given symbolic link based on the prefix
119*2f2c4c7aSAndroid Build Coastguard Worker  mappings. For every "from" prefix that matches replace with the new "to"
120*2f2c4c7aSAndroid Build Coastguard Worker  value. If the resulting path doesn't exist, try the next.
121*2f2c4c7aSAndroid Build Coastguard Worker
122*2f2c4c7aSAndroid Build Coastguard Worker  Args:
123*2f2c4c7aSAndroid Build Coastguard Worker    filepath: Path of symbolic link to update.
124*2f2c4c7aSAndroid Build Coastguard Worker    prefix_mappings: A multimap where the key is the "from" prefix to match, and
125*2f2c4c7aSAndroid Build Coastguard Worker      the value is an array of "to" values to attempt to replace with.
126*2f2c4c7aSAndroid Build Coastguard Worker
127*2f2c4c7aSAndroid Build Coastguard Worker  Returns:
128*2f2c4c7aSAndroid Build Coastguard Worker    True or false depending on the whether symbolic link was successfully
129*2f2c4c7aSAndroid Build Coastguard Worker      updated to a new path that exists.
130*2f2c4c7aSAndroid Build Coastguard Worker  """
131*2f2c4c7aSAndroid Build Coastguard Worker
132*2f2c4c7aSAndroid Build Coastguard Worker  link_target = os.readlink(filepath)
133*2f2c4c7aSAndroid Build Coastguard Worker  for old_prefix, new_prefix_list in prefix_mappings.items():
134*2f2c4c7aSAndroid Build Coastguard Worker    for new_prefix in new_prefix_list:
135*2f2c4c7aSAndroid Build Coastguard Worker      if link_target.startswith(old_prefix):
136*2f2c4c7aSAndroid Build Coastguard Worker        new_target = os.path.abspath(
137*2f2c4c7aSAndroid Build Coastguard Worker            link_target.replace(old_prefix, new_prefix)
138*2f2c4c7aSAndroid Build Coastguard Worker        )
139*2f2c4c7aSAndroid Build Coastguard Worker        if not os.path.exists(new_target):
140*2f2c4c7aSAndroid Build Coastguard Worker          continue
141*2f2c4c7aSAndroid Build Coastguard Worker        os.unlink(filepath)  # Remove the old symbolic link
142*2f2c4c7aSAndroid Build Coastguard Worker        os.symlink(new_target, filepath)  # Create the updated link
143*2f2c4c7aSAndroid Build Coastguard Worker        return True
144*2f2c4c7aSAndroid Build Coastguard Worker
145*2f2c4c7aSAndroid Build Coastguard Worker  return False
146*2f2c4c7aSAndroid Build Coastguard Worker
147*2f2c4c7aSAndroid Build Coastguard Worker
148*2f2c4c7aSAndroid Build Coastguard Workerdef correct_symlinks_in_directory(directory: str, prefix_mappings: {}) -> None:
149*2f2c4c7aSAndroid Build Coastguard Worker  """Recursively traverses a directory, updating symbolic links.
150*2f2c4c7aSAndroid Build Coastguard Worker
151*2f2c4c7aSAndroid Build Coastguard Worker  Replaces 'old_prefix' in the link destination with 'new_prefix'.
152*2f2c4c7aSAndroid Build Coastguard Worker
153*2f2c4c7aSAndroid Build Coastguard Worker  Args:
154*2f2c4c7aSAndroid Build Coastguard Worker    directory: The root directory to traverse.
155*2f2c4c7aSAndroid Build Coastguard Worker    prefix_mappings: Dictionary where the keys are the old prefixes and the
156*2f2c4c7aSAndroid Build Coastguard Worker      values are the new prefixes
157*2f2c4c7aSAndroid Build Coastguard Worker  """
158*2f2c4c7aSAndroid Build Coastguard Worker
159*2f2c4c7aSAndroid Build Coastguard Worker  logging.info("Fixing up symbolic links in %s", directory)
160*2f2c4c7aSAndroid Build Coastguard Worker
161*2f2c4c7aSAndroid Build Coastguard Worker  for root, _, files in os.walk(directory):
162*2f2c4c7aSAndroid Build Coastguard Worker    for filename in files:
163*2f2c4c7aSAndroid Build Coastguard Worker      filepath = os.path.join(root, filename)
164*2f2c4c7aSAndroid Build Coastguard Worker      if os.path.islink(filepath):
165*2f2c4c7aSAndroid Build Coastguard Worker        if not update_symlink_from_mapping(filepath, prefix_mappings):
166*2f2c4c7aSAndroid Build Coastguard Worker          logging.error(
167*2f2c4c7aSAndroid Build Coastguard Worker              "Unable to update link at %s with any prefix mappings: %s",
168*2f2c4c7aSAndroid Build Coastguard Worker              filepath,
169*2f2c4c7aSAndroid Build Coastguard Worker              prefix_mappings,
170*2f2c4c7aSAndroid Build Coastguard Worker          )
171*2f2c4c7aSAndroid Build Coastguard Worker          sys.exit(-1)
172*2f2c4c7aSAndroid Build Coastguard Worker
173*2f2c4c7aSAndroid Build Coastguard Worker
174*2f2c4c7aSAndroid Build Coastguard Workerdef find_most_recent_tarfile(path: str, pattern: str = "*.tar.gz") -> str:
175*2f2c4c7aSAndroid Build Coastguard Worker  """Attempts to find a valid tar file given the location.
176*2f2c4c7aSAndroid Build Coastguard Worker
177*2f2c4c7aSAndroid Build Coastguard Worker  If location is a directory finds the most recent tarfile or if location is a
178*2f2c4c7aSAndroid Build Coastguard Worker  a valid tar file returns, if neither of these return None.
179*2f2c4c7aSAndroid Build Coastguard Worker
180*2f2c4c7aSAndroid Build Coastguard Worker  Args:
181*2f2c4c7aSAndroid Build Coastguard Worker    path (str): The path to either a tarfile or a directory.
182*2f2c4c7aSAndroid Build Coastguard Worker    pattern (str, optional): Glob pattern for matching tarfiles. Defaults to
183*2f2c4c7aSAndroid Build Coastguard Worker      "*.tar.gz".
184*2f2c4c7aSAndroid Build Coastguard Worker
185*2f2c4c7aSAndroid Build Coastguard Worker  Returns:
186*2f2c4c7aSAndroid Build Coastguard Worker      str: The path to the most recent tarfile found, or the original path
187*2f2c4c7aSAndroid Build Coastguard Worker           if it was a valid tarfile. None if no matching tarfiles are found.
188*2f2c4c7aSAndroid Build Coastguard Worker  """
189*2f2c4c7aSAndroid Build Coastguard Worker
190*2f2c4c7aSAndroid Build Coastguard Worker  if os.path.isfile(path):
191*2f2c4c7aSAndroid Build Coastguard Worker    if tarfile.is_tarfile(path):
192*2f2c4c7aSAndroid Build Coastguard Worker      return path  # Path is a valid tarfile
193*2f2c4c7aSAndroid Build Coastguard Worker    return None  # Path is a file but not a tar file
194*2f2c4c7aSAndroid Build Coastguard Worker
195*2f2c4c7aSAndroid Build Coastguard Worker  if os.path.isdir(path):
196*2f2c4c7aSAndroid Build Coastguard Worker    results = []
197*2f2c4c7aSAndroid Build Coastguard Worker    for root, _, files in os.walk(path):
198*2f2c4c7aSAndroid Build Coastguard Worker      for file in files:
199*2f2c4c7aSAndroid Build Coastguard Worker        if fnmatch.fnmatch(file, pattern):
200*2f2c4c7aSAndroid Build Coastguard Worker          full_path = os.path.join(root, file)
201*2f2c4c7aSAndroid Build Coastguard Worker          results.append((full_path, os.path.getmtime(full_path)))
202*2f2c4c7aSAndroid Build Coastguard Worker
203*2f2c4c7aSAndroid Build Coastguard Worker    if results:
204*2f2c4c7aSAndroid Build Coastguard Worker      return max(results, key=lambda item: item[1])[
205*2f2c4c7aSAndroid Build Coastguard Worker          0
206*2f2c4c7aSAndroid Build Coastguard Worker      ]  # Return path of the most recent one
207*2f2c4c7aSAndroid Build Coastguard Worker    else:
208*2f2c4c7aSAndroid Build Coastguard Worker      return None  # No tarfiles found in the directory
209*2f2c4c7aSAndroid Build Coastguard Worker
210*2f2c4c7aSAndroid Build Coastguard Worker  return None  # Path is neither a tarfile nor a directory
211*2f2c4c7aSAndroid Build Coastguard Worker
212*2f2c4c7aSAndroid Build Coastguard Worker
213*2f2c4c7aSAndroid Build Coastguard Workerdef make_absolute(path: str, base_dir: str) -> str:
214*2f2c4c7aSAndroid Build Coastguard Worker  if os.path.isabs(path):
215*2f2c4c7aSAndroid Build Coastguard Worker    return path
216*2f2c4c7aSAndroid Build Coastguard Worker
217*2f2c4c7aSAndroid Build Coastguard Worker  return os.path.join(base_dir, path)
218*2f2c4c7aSAndroid Build Coastguard Worker
219*2f2c4c7aSAndroid Build Coastguard Worker
220*2f2c4c7aSAndroid Build Coastguard Workerdef append_slash(path: str) -> str:
221*2f2c4c7aSAndroid Build Coastguard Worker  if path is not None and path[-1] != "/":
222*2f2c4c7aSAndroid Build Coastguard Worker    path += "/"
223*2f2c4c7aSAndroid Build Coastguard Worker  return path
224*2f2c4c7aSAndroid Build Coastguard Worker
225*2f2c4c7aSAndroid Build Coastguard Worker
226*2f2c4c7aSAndroid Build Coastguard Workerdef update_multimap_from_json(
227*2f2c4c7aSAndroid Build Coastguard Worker    json_file: str, base_dir: str, result_multimap: collections.defaultdict
228*2f2c4c7aSAndroid Build Coastguard Worker) -> None:
229*2f2c4c7aSAndroid Build Coastguard Worker  """Reads 'to' and 'from' fields from a JSON file and updates a multimap.
230*2f2c4c7aSAndroid Build Coastguard Worker
231*2f2c4c7aSAndroid Build Coastguard Worker  'from' refers to a bazel sandbox directory.
232*2f2c4c7aSAndroid Build Coastguard Worker  'to' refers to the output directory of gcno files.
233*2f2c4c7aSAndroid Build Coastguard Worker  The multimap is implemented as a dictionary of lists allowing multiple 'to'
234*2f2c4c7aSAndroid Build Coastguard Worker  values for each 'from' key.
235*2f2c4c7aSAndroid Build Coastguard Worker
236*2f2c4c7aSAndroid Build Coastguard Worker  Sample input:
237*2f2c4c7aSAndroid Build Coastguard Worker  [
238*2f2c4c7aSAndroid Build Coastguard Worker    {
239*2f2c4c7aSAndroid Build Coastguard Worker      "from": "/sandbox/1/execroot/_main/out/android-mainline/common",
240*2f2c4c7aSAndroid Build Coastguard Worker      "to": "bazel-out/k8-fastbuild/bin/common/kernel_x86_64/kernel_x86_64_gcno"
241*2f2c4c7aSAndroid Build Coastguard Worker    },
242*2f2c4c7aSAndroid Build Coastguard Worker    {
243*2f2c4c7aSAndroid Build Coastguard Worker      "from": "/sandbox/2/execroot/_main/out/android-mainline/common",
244*2f2c4c7aSAndroid Build Coastguard Worker      "to": "bazel-out/k8-fastbuild/bin/common-modules/virtual-device/virtual_device_x86_64/virtual_device_x86_64_gcno"
245*2f2c4c7aSAndroid Build Coastguard Worker    }
246*2f2c4c7aSAndroid Build Coastguard Worker  ]
247*2f2c4c7aSAndroid Build Coastguard Worker
248*2f2c4c7aSAndroid Build Coastguard Worker  Args:
249*2f2c4c7aSAndroid Build Coastguard Worker    json_file: The path to the JSON file.
250*2f2c4c7aSAndroid Build Coastguard Worker    base_dir: Used if either of the 'to' or 'from' paths are relative to make
251*2f2c4c7aSAndroid Build Coastguard Worker      them absolute by prepending this base_dir value.
252*2f2c4c7aSAndroid Build Coastguard Worker    result_multimap: A multimap that is updated with every 'to' and 'from'
253*2f2c4c7aSAndroid Build Coastguard Worker      found.
254*2f2c4c7aSAndroid Build Coastguard Worker
255*2f2c4c7aSAndroid Build Coastguard Worker  Returns:
256*2f2c4c7aSAndroid Build Coastguard Worker    The updated dictionary.
257*2f2c4c7aSAndroid Build Coastguard Worker  """
258*2f2c4c7aSAndroid Build Coastguard Worker  with open(json_file, "r") as file:
259*2f2c4c7aSAndroid Build Coastguard Worker    data = json.load(file)
260*2f2c4c7aSAndroid Build Coastguard Worker
261*2f2c4c7aSAndroid Build Coastguard Worker  for item in data:
262*2f2c4c7aSAndroid Build Coastguard Worker    to_value = append_slash(item.get("to"))
263*2f2c4c7aSAndroid Build Coastguard Worker    from_value = append_slash(item.get("from"))
264*2f2c4c7aSAndroid Build Coastguard Worker    if to_value and from_value:
265*2f2c4c7aSAndroid Build Coastguard Worker      to_value = make_absolute(to_value, base_dir)
266*2f2c4c7aSAndroid Build Coastguard Worker      from_value = make_absolute(from_value, base_dir)
267*2f2c4c7aSAndroid Build Coastguard Worker      result_multimap[from_value].append(to_value)
268*2f2c4c7aSAndroid Build Coastguard Worker
269*2f2c4c7aSAndroid Build Coastguard Worker
270*2f2c4c7aSAndroid Build Coastguard Workerdef read_gcno_mapping_files(
271*2f2c4c7aSAndroid Build Coastguard Worker    search_dir_pattern: str,
272*2f2c4c7aSAndroid Build Coastguard Worker    base_dir: str,
273*2f2c4c7aSAndroid Build Coastguard Worker    result_multimap: collections.defaultdict
274*2f2c4c7aSAndroid Build Coastguard Worker) -> None:
275*2f2c4c7aSAndroid Build Coastguard Worker  """Search a directory for gcno_mapping."""
276*2f2c4c7aSAndroid Build Coastguard Worker  found = False
277*2f2c4c7aSAndroid Build Coastguard Worker  pattern = os.path.join(search_dir_pattern, "gcno_mapping.*.json")
278*2f2c4c7aSAndroid Build Coastguard Worker  for filepath in glob.iglob(pattern, recursive=False):
279*2f2c4c7aSAndroid Build Coastguard Worker    found = True
280*2f2c4c7aSAndroid Build Coastguard Worker    logging.info("Reading %s", filepath)
281*2f2c4c7aSAndroid Build Coastguard Worker    update_multimap_from_json(filepath, base_dir, result_multimap)
282*2f2c4c7aSAndroid Build Coastguard Worker
283*2f2c4c7aSAndroid Build Coastguard Worker  if not found:
284*2f2c4c7aSAndroid Build Coastguard Worker    logging.error("No gcno_mapping in %s", search_dir_pattern)
285*2f2c4c7aSAndroid Build Coastguard Worker
286*2f2c4c7aSAndroid Build Coastguard Worker
287*2f2c4c7aSAndroid Build Coastguard Workerdef read_gcno_dir(
288*2f2c4c7aSAndroid Build Coastguard Worker    gcno_dir: str, result_multimap: collections.defaultdict
289*2f2c4c7aSAndroid Build Coastguard Worker) -> None:
290*2f2c4c7aSAndroid Build Coastguard Worker  """Read a directory containing gcno_mapping and gcno files."""
291*2f2c4c7aSAndroid Build Coastguard Worker  multimap = collections.defaultdict(list)
292*2f2c4c7aSAndroid Build Coastguard Worker  read_gcno_mapping_files(gcno_dir, gcno_dir, multimap)
293*2f2c4c7aSAndroid Build Coastguard Worker
294*2f2c4c7aSAndroid Build Coastguard Worker  to_value = append_slash(os.path.abspath(gcno_dir))
295*2f2c4c7aSAndroid Build Coastguard Worker  for from_value in multimap:
296*2f2c4c7aSAndroid Build Coastguard Worker    result_multimap[from_value].append(to_value)
297*2f2c4c7aSAndroid Build Coastguard Worker
298*2f2c4c7aSAndroid Build Coastguard Worker
299*2f2c4c7aSAndroid Build Coastguard Workerdef get_testname_from_filename(file_path: str) -> str:
300*2f2c4c7aSAndroid Build Coastguard Worker  filename = os.path.basename(file_path)
301*2f2c4c7aSAndroid Build Coastguard Worker  if "_kernel_coverage" in filename:
302*2f2c4c7aSAndroid Build Coastguard Worker    tmp = filename[: filename.find("_kernel_coverage")]
303*2f2c4c7aSAndroid Build Coastguard Worker    testname = tmp[: tmp.rfind("_")]
304*2f2c4c7aSAndroid Build Coastguard Worker  else:
305*2f2c4c7aSAndroid Build Coastguard Worker    testname = filename[: filename.rfind("_")]
306*2f2c4c7aSAndroid Build Coastguard Worker  return testname
307*2f2c4c7aSAndroid Build Coastguard Worker
308*2f2c4c7aSAndroid Build Coastguard Worker
309*2f2c4c7aSAndroid Build Coastguard Workerdef unpack_gcov_tar(file_path: str, output_dir: str) -> str:
310*2f2c4c7aSAndroid Build Coastguard Worker  """Unpack the tar file into the specified directory.
311*2f2c4c7aSAndroid Build Coastguard Worker
312*2f2c4c7aSAndroid Build Coastguard Worker  Args:
313*2f2c4c7aSAndroid Build Coastguard Worker    file_path: The path of the tar file to be unpacked.
314*2f2c4c7aSAndroid Build Coastguard Worker    output_dir: The root directory where the unpacked folder will reside.
315*2f2c4c7aSAndroid Build Coastguard Worker
316*2f2c4c7aSAndroid Build Coastguard Worker  Returns:
317*2f2c4c7aSAndroid Build Coastguard Worker    The path of extracted data.
318*2f2c4c7aSAndroid Build Coastguard Worker  """
319*2f2c4c7aSAndroid Build Coastguard Worker
320*2f2c4c7aSAndroid Build Coastguard Worker  testname = get_testname_from_filename(file_path)
321*2f2c4c7aSAndroid Build Coastguard Worker  logging.info(
322*2f2c4c7aSAndroid Build Coastguard Worker      "Unpacking %s for test %s...", os.path.basename(file_path), testname
323*2f2c4c7aSAndroid Build Coastguard Worker  )
324*2f2c4c7aSAndroid Build Coastguard Worker
325*2f2c4c7aSAndroid Build Coastguard Worker  test_dest_dir = os.path.join(output_dir, testname)
326*2f2c4c7aSAndroid Build Coastguard Worker  if os.path.exists(test_dest_dir):
327*2f2c4c7aSAndroid Build Coastguard Worker    shutil.rmtree(test_dest_dir)
328*2f2c4c7aSAndroid Build Coastguard Worker  os.makedirs(test_dest_dir)
329*2f2c4c7aSAndroid Build Coastguard Worker  shutil.unpack_archive(file_path, test_dest_dir, "tar")
330*2f2c4c7aSAndroid Build Coastguard Worker  return test_dest_dir
331*2f2c4c7aSAndroid Build Coastguard Worker
332*2f2c4c7aSAndroid Build Coastguard Worker
333*2f2c4c7aSAndroid Build Coastguard Workerdef get_parent_path(path: str, levels_up: int) -> str:
334*2f2c4c7aSAndroid Build Coastguard Worker  """Goes up a specified number of levels from a given path.
335*2f2c4c7aSAndroid Build Coastguard Worker
336*2f2c4c7aSAndroid Build Coastguard Worker  Args:
337*2f2c4c7aSAndroid Build Coastguard Worker    path: The path to find desired ancestor.
338*2f2c4c7aSAndroid Build Coastguard Worker    levels_up: The number of levels up to go.
339*2f2c4c7aSAndroid Build Coastguard Worker
340*2f2c4c7aSAndroid Build Coastguard Worker  Returns:
341*2f2c4c7aSAndroid Build Coastguard Worker    The desired ancestor of the given path.
342*2f2c4c7aSAndroid Build Coastguard Worker  """
343*2f2c4c7aSAndroid Build Coastguard Worker  p = pathlib.Path(path)
344*2f2c4c7aSAndroid Build Coastguard Worker  for _ in range(levels_up):
345*2f2c4c7aSAndroid Build Coastguard Worker    p = p.parent
346*2f2c4c7aSAndroid Build Coastguard Worker  return str(p)
347*2f2c4c7aSAndroid Build Coastguard Worker
348*2f2c4c7aSAndroid Build Coastguard Worker
349*2f2c4c7aSAndroid Build Coastguard Workerdef get_kernel_repo_dir() -> str:
350*2f2c4c7aSAndroid Build Coastguard Worker  # Assume this script is in a kernel source tree:
351*2f2c4c7aSAndroid Build Coastguard Worker  # kernel_repo/kernel/tests/tools/<this_script>
352*2f2c4c7aSAndroid Build Coastguard Worker  return get_parent_path(os.path.abspath(__file__), 4)
353*2f2c4c7aSAndroid Build Coastguard Worker
354*2f2c4c7aSAndroid Build Coastguard Worker
355*2f2c4c7aSAndroid Build Coastguard Workerdef load_kernel_clang_version(repo_dir: str) -> str:
356*2f2c4c7aSAndroid Build Coastguard Worker  """Load CLANG_VERSION from build.config.constants."""
357*2f2c4c7aSAndroid Build Coastguard Worker  config_path = os.path.join(repo_dir, BUILD_CONFIG_CONSTANTS_PATH)
358*2f2c4c7aSAndroid Build Coastguard Worker  if not os.path.isfile(config_path):
359*2f2c4c7aSAndroid Build Coastguard Worker    return ""
360*2f2c4c7aSAndroid Build Coastguard Worker  clang_version = ""
361*2f2c4c7aSAndroid Build Coastguard Worker  with open(config_path, "r") as config_file:
362*2f2c4c7aSAndroid Build Coastguard Worker    for line in config_file:
363*2f2c4c7aSAndroid Build Coastguard Worker      match = re.fullmatch(r"\s*CLANG_VERSION=(\S*)\s*", line)
364*2f2c4c7aSAndroid Build Coastguard Worker      if match:
365*2f2c4c7aSAndroid Build Coastguard Worker        clang_version = match.group(1)
366*2f2c4c7aSAndroid Build Coastguard Worker  return clang_version
367*2f2c4c7aSAndroid Build Coastguard Worker
368*2f2c4c7aSAndroid Build Coastguard Worker
369*2f2c4c7aSAndroid Build Coastguard Workerclass Config:
370*2f2c4c7aSAndroid Build Coastguard Worker  """The input and output paths of this script."""
371*2f2c4c7aSAndroid Build Coastguard Worker
372*2f2c4c7aSAndroid Build Coastguard Worker  def __init__(self, repo_dir: str, llvm_cov_path: str, tmp_dir: str):
373*2f2c4c7aSAndroid Build Coastguard Worker    """Each argument can be empty."""
374*2f2c4c7aSAndroid Build Coastguard Worker    self._repo_dir = os.path.abspath(repo_dir) if repo_dir else None
375*2f2c4c7aSAndroid Build Coastguard Worker    self._llvm_cov_path = (
376*2f2c4c7aSAndroid Build Coastguard Worker        os.path.abspath(llvm_cov_path) if llvm_cov_path else None
377*2f2c4c7aSAndroid Build Coastguard Worker    )
378*2f2c4c7aSAndroid Build Coastguard Worker    self._tmp_dir = os.path.abspath(tmp_dir) if tmp_dir else None
379*2f2c4c7aSAndroid Build Coastguard Worker    self._repo_out_dir = None
380*2f2c4c7aSAndroid Build Coastguard Worker
381*2f2c4c7aSAndroid Build Coastguard Worker  @property
382*2f2c4c7aSAndroid Build Coastguard Worker  def repo_dir(self) -> str:
383*2f2c4c7aSAndroid Build Coastguard Worker    if not self._repo_dir:
384*2f2c4c7aSAndroid Build Coastguard Worker      self._repo_dir = get_kernel_repo_dir()
385*2f2c4c7aSAndroid Build Coastguard Worker    return self._repo_dir
386*2f2c4c7aSAndroid Build Coastguard Worker
387*2f2c4c7aSAndroid Build Coastguard Worker  def _get_repo_path(self, rel_path: str) -> str:
388*2f2c4c7aSAndroid Build Coastguard Worker    repo_path = os.path.join(self.repo_dir, rel_path)
389*2f2c4c7aSAndroid Build Coastguard Worker    if not os.path.exists(repo_path):
390*2f2c4c7aSAndroid Build Coastguard Worker      logging.error(
391*2f2c4c7aSAndroid Build Coastguard Worker          "%s does not exist. If this script is not in the source directory,"
392*2f2c4c7aSAndroid Build Coastguard Worker          " specify --repo-dir. If you do not have full kernel source,"
393*2f2c4c7aSAndroid Build Coastguard Worker          " specify --llvm-cov, --gcno-dir, and --tmp-dir.",
394*2f2c4c7aSAndroid Build Coastguard Worker          repo_path,
395*2f2c4c7aSAndroid Build Coastguard Worker      )
396*2f2c4c7aSAndroid Build Coastguard Worker      sys.exit(-1)
397*2f2c4c7aSAndroid Build Coastguard Worker    return repo_path
398*2f2c4c7aSAndroid Build Coastguard Worker
399*2f2c4c7aSAndroid Build Coastguard Worker  @property
400*2f2c4c7aSAndroid Build Coastguard Worker  def llvm_cov_path(self) -> str:
401*2f2c4c7aSAndroid Build Coastguard Worker    if not self._llvm_cov_path:
402*2f2c4c7aSAndroid Build Coastguard Worker      # Load the clang version in kernel repo,
403*2f2c4c7aSAndroid Build Coastguard Worker      # or use the stable version in platform repo.
404*2f2c4c7aSAndroid Build Coastguard Worker      clang_version = load_kernel_clang_version(self.repo_dir)
405*2f2c4c7aSAndroid Build Coastguard Worker      self._llvm_cov_path = self._get_repo_path(
406*2f2c4c7aSAndroid Build Coastguard Worker          PREBUILT_LLVM_COV_PATH_FORMAT % clang_version if clang_version else
407*2f2c4c7aSAndroid Build Coastguard Worker          PREBUILT_STABLE_LLVM_COV_PATH
408*2f2c4c7aSAndroid Build Coastguard Worker      )
409*2f2c4c7aSAndroid Build Coastguard Worker    return self._llvm_cov_path
410*2f2c4c7aSAndroid Build Coastguard Worker
411*2f2c4c7aSAndroid Build Coastguard Worker  @property
412*2f2c4c7aSAndroid Build Coastguard Worker  def repo_out_dir(self) -> str:
413*2f2c4c7aSAndroid Build Coastguard Worker    if not self._repo_out_dir:
414*2f2c4c7aSAndroid Build Coastguard Worker      self._repo_out_dir = self._get_repo_path("out")
415*2f2c4c7aSAndroid Build Coastguard Worker    return self._repo_out_dir
416*2f2c4c7aSAndroid Build Coastguard Worker
417*2f2c4c7aSAndroid Build Coastguard Worker  @property
418*2f2c4c7aSAndroid Build Coastguard Worker  def tmp_dir(self) -> str:
419*2f2c4c7aSAndroid Build Coastguard Worker    if not self._tmp_dir:
420*2f2c4c7aSAndroid Build Coastguard Worker      # Temporary directory does not have to exist.
421*2f2c4c7aSAndroid Build Coastguard Worker      self._tmp_dir = os.path.join(self.repo_dir, OUTPUT_COV_DIR)
422*2f2c4c7aSAndroid Build Coastguard Worker    return self._tmp_dir
423*2f2c4c7aSAndroid Build Coastguard Worker
424*2f2c4c7aSAndroid Build Coastguard Worker  @property
425*2f2c4c7aSAndroid Build Coastguard Worker  def llvm_gcov_sh_path(self) -> str:
426*2f2c4c7aSAndroid Build Coastguard Worker    return os.path.join(self.tmp_dir, "tmp", "llvm-gcov.sh")
427*2f2c4c7aSAndroid Build Coastguard Worker
428*2f2c4c7aSAndroid Build Coastguard Worker
429*2f2c4c7aSAndroid Build Coastguard Workerdef main() -> None:
430*2f2c4c7aSAndroid Build Coastguard Worker  arg_parser = argparse.ArgumentParser(
431*2f2c4c7aSAndroid Build Coastguard Worker      description="Generate lcov tracefiles from gcov file dumps"
432*2f2c4c7aSAndroid Build Coastguard Worker  )
433*2f2c4c7aSAndroid Build Coastguard Worker
434*2f2c4c7aSAndroid Build Coastguard Worker  arg_parser.add_argument(
435*2f2c4c7aSAndroid Build Coastguard Worker      "-t",
436*2f2c4c7aSAndroid Build Coastguard Worker      dest="tar_location",
437*2f2c4c7aSAndroid Build Coastguard Worker      required=True,
438*2f2c4c7aSAndroid Build Coastguard Worker      help=(
439*2f2c4c7aSAndroid Build Coastguard Worker          "Either a path to a gcov tar file or a directory that contains gcov"
440*2f2c4c7aSAndroid Build Coastguard Worker          " tar file(s). The gcov tar file is expected to be created from"
441*2f2c4c7aSAndroid Build Coastguard Worker          " Tradefed. If a directory is used, will search the entire directory"
442*2f2c4c7aSAndroid Build Coastguard Worker          " for files matching *_kernel_coverage*.tar.gz and select the most"
443*2f2c4c7aSAndroid Build Coastguard Worker          " recent one."
444*2f2c4c7aSAndroid Build Coastguard Worker      ),
445*2f2c4c7aSAndroid Build Coastguard Worker  )
446*2f2c4c7aSAndroid Build Coastguard Worker  arg_parser.add_argument(
447*2f2c4c7aSAndroid Build Coastguard Worker      "-o",
448*2f2c4c7aSAndroid Build Coastguard Worker      dest="out_file",
449*2f2c4c7aSAndroid Build Coastguard Worker      required=False,
450*2f2c4c7aSAndroid Build Coastguard Worker      help="Name of output tracefile generated. Default: cov.info",
451*2f2c4c7aSAndroid Build Coastguard Worker      default="cov.info",
452*2f2c4c7aSAndroid Build Coastguard Worker  )
453*2f2c4c7aSAndroid Build Coastguard Worker  arg_parser.add_argument(
454*2f2c4c7aSAndroid Build Coastguard Worker      "--include",
455*2f2c4c7aSAndroid Build Coastguard Worker      action="append",
456*2f2c4c7aSAndroid Build Coastguard Worker      nargs=1,
457*2f2c4c7aSAndroid Build Coastguard Worker      required=False,
458*2f2c4c7aSAndroid Build Coastguard Worker      help=(
459*2f2c4c7aSAndroid Build Coastguard Worker          "File pattern of source file(s) to include in generated tracefile."
460*2f2c4c7aSAndroid Build Coastguard Worker          " Multiple patterns can be specified by using multiple --include"
461*2f2c4c7aSAndroid Build Coastguard Worker          " command line switches. If no includes are specified all source is"
462*2f2c4c7aSAndroid Build Coastguard Worker          " included."
463*2f2c4c7aSAndroid Build Coastguard Worker      ),
464*2f2c4c7aSAndroid Build Coastguard Worker  )
465*2f2c4c7aSAndroid Build Coastguard Worker  arg_parser.add_argument(
466*2f2c4c7aSAndroid Build Coastguard Worker      "--repo-dir",
467*2f2c4c7aSAndroid Build Coastguard Worker      required=False,
468*2f2c4c7aSAndroid Build Coastguard Worker      help="Root directory of kernel source"
469*2f2c4c7aSAndroid Build Coastguard Worker  )
470*2f2c4c7aSAndroid Build Coastguard Worker  arg_parser.add_argument(
471*2f2c4c7aSAndroid Build Coastguard Worker      "--dist-dir",
472*2f2c4c7aSAndroid Build Coastguard Worker      dest="dist_dirs",
473*2f2c4c7aSAndroid Build Coastguard Worker      action="append",
474*2f2c4c7aSAndroid Build Coastguard Worker      default=[],
475*2f2c4c7aSAndroid Build Coastguard Worker      required=False,
476*2f2c4c7aSAndroid Build Coastguard Worker      help="Dist directory containing gcno mapping files"
477*2f2c4c7aSAndroid Build Coastguard Worker  )
478*2f2c4c7aSAndroid Build Coastguard Worker  arg_parser.add_argument(
479*2f2c4c7aSAndroid Build Coastguard Worker      "--gcno-dir",
480*2f2c4c7aSAndroid Build Coastguard Worker      dest="gcno_dirs",
481*2f2c4c7aSAndroid Build Coastguard Worker      action="append",
482*2f2c4c7aSAndroid Build Coastguard Worker      default=[],
483*2f2c4c7aSAndroid Build Coastguard Worker      required=False,
484*2f2c4c7aSAndroid Build Coastguard Worker      help="Path to an extracted .gcno.tar.gz"
485*2f2c4c7aSAndroid Build Coastguard Worker  )
486*2f2c4c7aSAndroid Build Coastguard Worker  arg_parser.add_argument(
487*2f2c4c7aSAndroid Build Coastguard Worker      "--llvm-cov",
488*2f2c4c7aSAndroid Build Coastguard Worker      required=False,
489*2f2c4c7aSAndroid Build Coastguard Worker      help=(
490*2f2c4c7aSAndroid Build Coastguard Worker          "Path to llvm-cov. Default: "
491*2f2c4c7aSAndroid Build Coastguard Worker          + os.path.join("<repo_dir>", PREBUILT_LLVM_COV_PATH_FORMAT % "*")
492*2f2c4c7aSAndroid Build Coastguard Worker          + " or " + os.path.join("<repo_dir>", PREBUILT_STABLE_LLVM_COV_PATH)
493*2f2c4c7aSAndroid Build Coastguard Worker      )
494*2f2c4c7aSAndroid Build Coastguard Worker  )
495*2f2c4c7aSAndroid Build Coastguard Worker  arg_parser.add_argument(
496*2f2c4c7aSAndroid Build Coastguard Worker      "--tmp-dir",
497*2f2c4c7aSAndroid Build Coastguard Worker      required=False,
498*2f2c4c7aSAndroid Build Coastguard Worker      help=(
499*2f2c4c7aSAndroid Build Coastguard Worker          "Path to the directory where the temporary files are created."
500*2f2c4c7aSAndroid Build Coastguard Worker          " Default: " + os.path.join("<repo_dir>", OUTPUT_COV_DIR)
501*2f2c4c7aSAndroid Build Coastguard Worker      )
502*2f2c4c7aSAndroid Build Coastguard Worker  )
503*2f2c4c7aSAndroid Build Coastguard Worker  arg_parser.add_argument(
504*2f2c4c7aSAndroid Build Coastguard Worker      "--verbose",
505*2f2c4c7aSAndroid Build Coastguard Worker      action="store_true",
506*2f2c4c7aSAndroid Build Coastguard Worker      default=False,
507*2f2c4c7aSAndroid Build Coastguard Worker      help="Enable verbose logging",
508*2f2c4c7aSAndroid Build Coastguard Worker  )
509*2f2c4c7aSAndroid Build Coastguard Worker
510*2f2c4c7aSAndroid Build Coastguard Worker  args = arg_parser.parse_args()
511*2f2c4c7aSAndroid Build Coastguard Worker
512*2f2c4c7aSAndroid Build Coastguard Worker  if args.verbose:
513*2f2c4c7aSAndroid Build Coastguard Worker    logging.basicConfig(level=logging.DEBUG)
514*2f2c4c7aSAndroid Build Coastguard Worker  else:
515*2f2c4c7aSAndroid Build Coastguard Worker    logging.basicConfig(level=logging.WARNING)
516*2f2c4c7aSAndroid Build Coastguard Worker
517*2f2c4c7aSAndroid Build Coastguard Worker  if shutil.which(LCOV) is None:
518*2f2c4c7aSAndroid Build Coastguard Worker    logging.error(
519*2f2c4c7aSAndroid Build Coastguard Worker        "%s is not found and is required for this script. Please install from:",
520*2f2c4c7aSAndroid Build Coastguard Worker        LCOV,
521*2f2c4c7aSAndroid Build Coastguard Worker    )
522*2f2c4c7aSAndroid Build Coastguard Worker    logging.critical("       https://github.com/linux-test-project/lcov")
523*2f2c4c7aSAndroid Build Coastguard Worker    sys.exit(-1)
524*2f2c4c7aSAndroid Build Coastguard Worker
525*2f2c4c7aSAndroid Build Coastguard Worker  if args.repo_dir and not os.path.isdir(args.repo_dir):
526*2f2c4c7aSAndroid Build Coastguard Worker    logging.error("%s is not a directory.", args.repo_dir)
527*2f2c4c7aSAndroid Build Coastguard Worker    sys.exit(-1)
528*2f2c4c7aSAndroid Build Coastguard Worker
529*2f2c4c7aSAndroid Build Coastguard Worker  if args.llvm_cov and not os.path.isfile(args.llvm_cov):
530*2f2c4c7aSAndroid Build Coastguard Worker    logging.error("%s is not a file.", args.llvm_cov)
531*2f2c4c7aSAndroid Build Coastguard Worker    sys.exit(-1)
532*2f2c4c7aSAndroid Build Coastguard Worker
533*2f2c4c7aSAndroid Build Coastguard Worker  for gcno_dir in args.gcno_dirs + args.dist_dirs:
534*2f2c4c7aSAndroid Build Coastguard Worker    if not os.path.isdir(gcno_dir):
535*2f2c4c7aSAndroid Build Coastguard Worker      logging.error("%s is not a directory.", gcno_dir)
536*2f2c4c7aSAndroid Build Coastguard Worker      sys.exit(-1)
537*2f2c4c7aSAndroid Build Coastguard Worker
538*2f2c4c7aSAndroid Build Coastguard Worker  config = Config(args.repo_dir, args.llvm_cov, args.tmp_dir)
539*2f2c4c7aSAndroid Build Coastguard Worker
540*2f2c4c7aSAndroid Build Coastguard Worker  gcno_mappings = collections.defaultdict(list)
541*2f2c4c7aSAndroid Build Coastguard Worker  if not args.gcno_dirs and not args.dist_dirs:
542*2f2c4c7aSAndroid Build Coastguard Worker    dist_dir_pattern = os.path.join(config.repo_out_dir, "**", "dist")
543*2f2c4c7aSAndroid Build Coastguard Worker    read_gcno_mapping_files(dist_dir_pattern, config.repo_dir, gcno_mappings)
544*2f2c4c7aSAndroid Build Coastguard Worker
545*2f2c4c7aSAndroid Build Coastguard Worker  for dist_dir in args.dist_dirs:
546*2f2c4c7aSAndroid Build Coastguard Worker    read_gcno_mapping_files(dist_dir, config.repo_dir, gcno_mappings)
547*2f2c4c7aSAndroid Build Coastguard Worker
548*2f2c4c7aSAndroid Build Coastguard Worker  for gcno_dir in args.gcno_dirs:
549*2f2c4c7aSAndroid Build Coastguard Worker    read_gcno_dir(gcno_dir, gcno_mappings)
550*2f2c4c7aSAndroid Build Coastguard Worker
551*2f2c4c7aSAndroid Build Coastguard Worker  if not gcno_mappings:
552*2f2c4c7aSAndroid Build Coastguard Worker    # read_gcno_mapping_files prints the error messages
553*2f2c4c7aSAndroid Build Coastguard Worker    sys.exit(-1)
554*2f2c4c7aSAndroid Build Coastguard Worker
555*2f2c4c7aSAndroid Build Coastguard Worker  tar_file = find_most_recent_tarfile(
556*2f2c4c7aSAndroid Build Coastguard Worker      args.tar_location, pattern="*kernel_coverage_*.tar.gz"
557*2f2c4c7aSAndroid Build Coastguard Worker  )
558*2f2c4c7aSAndroid Build Coastguard Worker  if tar_file is None:
559*2f2c4c7aSAndroid Build Coastguard Worker    logging.error("Unable to find a gcov tar under %s", args.tar_location)
560*2f2c4c7aSAndroid Build Coastguard Worker    sys.exit(-1)
561*2f2c4c7aSAndroid Build Coastguard Worker
562*2f2c4c7aSAndroid Build Coastguard Worker  gcov_dir = unpack_gcov_tar(tar_file, config.tmp_dir)
563*2f2c4c7aSAndroid Build Coastguard Worker  correct_symlinks_in_directory(gcov_dir, gcno_mappings)
564*2f2c4c7aSAndroid Build Coastguard Worker
565*2f2c4c7aSAndroid Build Coastguard Worker  create_llvm_gcov_sh(
566*2f2c4c7aSAndroid Build Coastguard Worker      config.llvm_cov_path,
567*2f2c4c7aSAndroid Build Coastguard Worker      config.llvm_gcov_sh_path,
568*2f2c4c7aSAndroid Build Coastguard Worker  )
569*2f2c4c7aSAndroid Build Coastguard Worker
570*2f2c4c7aSAndroid Build Coastguard Worker  generate_lcov_tracefile(
571*2f2c4c7aSAndroid Build Coastguard Worker      gcov_dir,
572*2f2c4c7aSAndroid Build Coastguard Worker      config.repo_dir,
573*2f2c4c7aSAndroid Build Coastguard Worker      config.llvm_gcov_sh_path,
574*2f2c4c7aSAndroid Build Coastguard Worker      args.out_file,
575*2f2c4c7aSAndroid Build Coastguard Worker      args.include,
576*2f2c4c7aSAndroid Build Coastguard Worker  )
577*2f2c4c7aSAndroid Build Coastguard Worker
578*2f2c4c7aSAndroid Build Coastguard Worker
579*2f2c4c7aSAndroid Build Coastguard Workerif __name__ == "__main__":
580*2f2c4c7aSAndroid Build Coastguard Worker  main()
581