[#76149] retracer: Enable handling multiple files at once
diff --git a/tools/execution_tracer/execution_tracer/dwarf.py b/tools/execution_tracer/execution_tracer/dwarf.py
index 11001d8..e214eca 100644
--- a/tools/execution_tracer/execution_tracer/dwarf.py
+++ b/tools/execution_tracer/execution_tracer/dwarf.py
@@ -243,7 +243,7 @@
             address_count_cache = self._build_addr_map(code_lines_with_address, trace_data.pc_length)
 
         # This step takes some time for large traces and codebases, let's advise the user to wait
-        print('Processing the trace, please wait...')
+        print(f'Processing trace file {trace_data.file.name}, please wait...')
         for address_bytes, _, _, _ in trace_data:
             if address_bytes in address_count_cache:
                 address_count_cache[address_bytes].count_up()
diff --git a/tools/execution_tracer/execution_tracer/execution_tracer_reader.py b/tools/execution_tracer/execution_tracer/execution_tracer_reader.py
index 451d591..a822e9d 100755
--- a/tools/execution_tracer/execution_tracer/execution_tracer_reader.py
+++ b/tools/execution_tracer/execution_tracer/execution_tracer_reader.py
@@ -8,11 +8,11 @@
 from __future__ import annotations
 
 import argparse
+import contextlib
 import platform
 import sys
 import os
 import gzip
-import typing
 from enum import Enum
 from dataclasses import dataclass
 from typing import IO, BinaryIO, NamedTuple, Optional
@@ -297,7 +297,7 @@
 
         return (bytes_read, disas_str.value)
 
-def handle_coverage(args, trace_data) -> None:
+def handle_coverage(args, trace_data_per_file) -> None:
     coverage_config = dwarf.Coverage(
         elf_file_handler=args.coverage_binary,
         code_filenames=args.coverage_code,
@@ -312,7 +312,8 @@
     if args.no_shorten_paths:
         remove_common_path_prefix = False
 
-    coverage_config.aggregate_coverage(trace_data)
+    for trace_data in trace_data_per_file:
+        coverage_config.aggregate_coverage(trace_data)
     printed_report = coverage_config.get_printed_report(
         args.legacy,
         remove_common_path_prefix=remove_common_path_prefix
@@ -345,13 +346,13 @@
 
     subparsers = parser.add_subparsers(title='subcommands', dest='subcommands', required=True)
     trace_parser = subparsers.add_parser('inspect', help='Inspect the binary trace format')
-    trace_parser.add_argument("file", help="binary trace file")
+    trace_parser.add_argument("files", nargs='+', help="binary trace files")
 
     trace_parser.add_argument("--disassemble", action="store_true", default=False)
     trace_parser.add_argument("--llvm-disas-path", default=None, help="path to libllvm-disas library")
 
     cov_parser = subparsers.add_parser('coverage', help='Generate coverage reports')
-    cov_parser.add_argument("file", help="binary trace file")
+    cov_parser.add_argument("files", nargs='+', help="binary trace files")
 
     cov_parser.add_argument("--binary", dest='coverage_binary', required=True, default=None, type=argparse.FileType('rb'), help="path to an ELF file with DWARF data")
     cov_parser.add_argument("--sources", dest='coverage_code', default=None, nargs='+', type=str, help="path to a (list of) source file(s)")
@@ -393,17 +394,20 @@
             raise FileNotFoundError('Could not find ' + lib_name + ' in any of the following locations: ' + ', '.join([os.path.abspath(path) for path in lib_search_paths]))
 
     try:
-        filename, file_extension = os.path.splitext(args.file)
-        if (args.decompress or file_extension == ".gz") and not args.force_disable_decompression:
-            file_open = typing.cast(typing.Callable[..., BinaryIO], gzip.open)
-        else:
-            file_open = open
+        with contextlib.ExitStack() as stack:
+            files = []
+            for file in args.files:
+                _, file_extension = os.path.splitext(file)
+                if (args.decompress or file_extension == ".gz") and not args.force_disable_decompression:
+                    files.append(stack.enter_context(gzip.open(file, "rb")))
+                else:
+                    files.append(stack.enter_context(open(file, "rb")))
 
-        with file_open(args.file, "rb") as file:
             if args.subcommands == 'coverage':
-                trace_data = read_file(file, False, None)
+                trace_data_per_file = [read_file(file, False, None) for file in files]
             else:
-                trace_data = read_file(file, args.disassemble, args.llvm_disas_path)
+                trace_data_per_file = [read_file(file, args.disassemble, args.llvm_disas_path) for file in files]
+
             if args.subcommands == 'coverage':
                 if args.export_for_coverview:
                     if args.legacy:
@@ -412,10 +416,12 @@
                     if not args.coverage_output:
                         raise ValueError("Specify a file with '--output' when packing an archive for Coverview")
 
-                handle_coverage(args, trace_data)
+                handle_coverage(args, trace_data_per_file)
             else:
-                for entry in trace_data:
-                    print(trace_data.format_entry(entry))
+                for trace_data in trace_data_per_file:
+                    for entry in trace_data:
+                        print(trace_data.format_entry(entry))
+                    print()
     except BrokenPipeError:
         # Avoid crashing when piping the results e.g. to less
         sys.exit(0)