pw_snapshot/processor: Add optional --artifacts-dir flag
Adds an optional --artifacts-dir flag to pw_snapshot/processor.py
to use GNU Build IDs to look up a matching *.elf file in the
specified directory to be used with the LlvmSymbolzer for snapshot
decoding.
Change-Id: I2885b1e2f8f75aa14495a44e710467d52af1046e
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/81623
Pigweed-Auto-Submit: Ewout van Bekkum <ewout@google.com>
Reviewed-by: Armando Montanez <amontanez@google.com>
Commit-Queue: Auto-Submit <auto-submit@pigweed.google.com.iam.gserviceaccount.com>
diff --git a/pw_snapshot/py/BUILD.gn b/pw_snapshot/py/BUILD.gn
index af7cdc0..51cb683 100644
--- a/pw_snapshot/py/BUILD.gn
+++ b/pw_snapshot/py/BUILD.gn
@@ -52,6 +52,7 @@
tests = [ "metadata_test.py" ]
python_deps = [
":pw_snapshot_metadata",
+ "$dir_pw_build_info/py",
"$dir_pw_cpu_exception_cortex_m/py",
"$dir_pw_symbolizer/py",
"$dir_pw_thread:protos.python",
diff --git a/pw_snapshot/py/pw_snapshot/processor.py b/pw_snapshot/py/pw_snapshot/processor.py
index dbcaf4a..d96691028 100644
--- a/pw_snapshot/py/pw_snapshot/processor.py
+++ b/pw_snapshot/py/pw_snapshot/processor.py
@@ -14,16 +14,21 @@
"""Tool for processing and outputting Snapshot protos as text"""
import argparse
+import functools
+import logging
import sys
from pathlib import Path
from typing import Optional, BinaryIO, TextIO, Callable
import pw_tokenizer
import pw_cpu_exception_cortex_m
+import pw_build_info.build_id
from pw_snapshot_metadata import metadata
from pw_snapshot_protos import snapshot_pb2
from pw_symbolizer import LlvmSymbolizer, Symbolizer
from pw_thread import thread_analyzer
+_LOG = logging.getLogger('snapshot_processor')
+
_BRANDING = """
____ _ __ _____ _ _____ ____ _____ __ ______ ______
/ __ \\ | / / / ___// | / / | / __ \\/ ___// / / / __ \\/_ __/
@@ -128,12 +133,31 @@
return '\n'.join(output)
+def _snapshot_symbolizer_matcher(
+ artifacts_dir: Path,
+ snapshot: snapshot_pb2.Snapshot) -> LlvmSymbolizer:
+ matching_elf: Optional[Path] = pw_build_info.build_id.find_matching_elf(
+ snapshot.metadata.software_build_uuid, artifacts_dir)
+ if not matching_elf:
+ _LOG.error('Error: No matching ELF found for GNU build ID %s.',
+ snapshot.metadata.software_build_uuid.hex())
+ return LlvmSymbolizer(matching_elf)
+
+
def _load_and_dump_snapshots(in_file: BinaryIO, out_file: TextIO,
- token_db: Optional[TextIO]):
+ token_db: Optional[TextIO],
+ artifacts_dir: Optional[Path]):
detokenizer = None
if token_db:
detokenizer = pw_tokenizer.Detokenizer(token_db)
- out_file.write(process_snapshots(in_file.read(), detokenizer))
+ symbolizer_matcher: Optional[SymbolizerMatcher] = None
+ if artifacts_dir:
+ symbolizer_matcher = functools.partial(_snapshot_symbolizer_matcher,
+ artifacts_dir)
+ out_file.write(
+ process_snapshots(serialized_snapshot=in_file.read(),
+ detokenizer=detokenizer,
+ symbolizer_matcher=symbolizer_matcher))
def _parse_args():
@@ -151,9 +175,15 @@
'--token-db',
type=argparse.FileType('r'),
help='Token database or ELF file to use for detokenization.')
+ parser.add_argument(
+ '--artifacts-dir',
+ type=Path,
+ help=('Directory to recursively search for matching ELF files to use '
+ 'for symbolization.'))
return parser.parse_args()
if __name__ == '__main__':
+ logging.basicConfig(format='%(message)s', level=logging.INFO)
_load_and_dump_snapshots(**vars(_parse_args()))
sys.exit(0)