qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: "Alex Bennée" <alex.bennee@linaro.org>
To: qemu-devel@nongnu.org
Cc: "Palmer Dabbelt" <palmer@dabbelt.com>,
	"Alexandre Iooss" <erdnaxe@crans.org>,
	"Mahmoud Mandour" <ma.mandourr@gmail.com>,
	qemu-riscv@nongnu.org,
	"Daniel Henrique Barboza" <dbarboza@ventanamicro.com>,
	"Thomas Huth" <thuth@redhat.com>,
	"Peter Maydell" <peter.maydell@linaro.org>,
	"Alex Bennée" <alex.bennee@linaro.org>,
	"Alistair Francis" <alistair.francis@wdc.com>,
	qemu-arm@nongnu.org, "Philippe Mathieu-Daudé" <philmd@linaro.org>,
	"Weiwei Li" <liwei1518@gmail.com>,
	"Pierrick Bouvier" <pierrick.bouvier@linaro.org>,
	"Liu Zhiwei" <zhiwei_liu@linux.alibaba.com>
Subject: [PATCH 24/25] contrib/plugins/uftrace_symbols.py
Date: Mon, 22 Sep 2025 10:37:09 +0100	[thread overview]
Message-ID: <20250922093711.2768983-25-alex.bennee@linaro.org> (raw)
In-Reply-To: <20250922093711.2768983-1-alex.bennee@linaro.org>

From: Pierrick Bouvier <pierrick.bouvier@linaro.org>

usage:  contrib/plugins/uftrace_symbols.py \
        --prefix-symbols \
        arm-trusted-firmware/build/qemu/debug/bl1/bl1.elf \
        arm-trusted-firmware/build/qemu/debug/bl2/bl2.elf \
        arm-trusted-firmware/build/qemu/debug/bl31/bl31.elf \
        u-boot/u-boot:0x60000000 \
        u-boot/u-boot.relocated:0x000000023f6b6000 \
        linux/vmlinux

Will generate symbols and memory mapping files for uftrace, allowing to
have an enhanced trace, instead of raw addresses.

It takes a collection of elf files, and automatically find all their
symbols, and generate an ordered memory map based on that.

This script uses the python (native) pyelftools module.

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Acked-by: Alex Bennée <alex.bennee@linaro.org>
Message-ID: <20250902075042.223990-9-pierrick.bouvier@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 contrib/plugins/uftrace_symbols.py | 152 +++++++++++++++++++++++++++++
 1 file changed, 152 insertions(+)
 create mode 100755 contrib/plugins/uftrace_symbols.py

diff --git a/contrib/plugins/uftrace_symbols.py b/contrib/plugins/uftrace_symbols.py
new file mode 100755
index 00000000000..b49e03203c8
--- /dev/null
+++ b/contrib/plugins/uftrace_symbols.py
@@ -0,0 +1,152 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Create symbols and mapping files for uftrace.
+#
+# Copyright 2025 Linaro Ltd
+# Author: Pierrick Bouvier <pierrick.bouvier@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import argparse
+import elftools # pip install pyelftools
+import os
+
+from elftools.elf.elffile import ELFFile
+from elftools.elf.sections import SymbolTableSection
+
+def elf_func_symbols(elf):
+    symbol_tables = [(idx, s) for idx, s in enumerate(elf.iter_sections())
+                  if isinstance(s, SymbolTableSection)]
+    symbols = []
+    for _, section in symbol_tables:
+        for _, symbol in enumerate(section.iter_symbols()):
+            if symbol_size(symbol) == 0:
+                continue
+            type = symbol['st_info']['type']
+            if type == 'STT_FUNC' or type == 'STT_NOTYPE':
+                symbols.append(symbol)
+    symbols.sort(key = lambda x: symbol_addr(x))
+    return symbols
+
+def symbol_size(symbol):
+    return symbol['st_size']
+
+def symbol_addr(symbol):
+    addr = symbol['st_value']
+    # clamp addr to 48 bits, like uftrace entries
+    return addr & 0xffffffffffff
+
+def symbol_name(symbol):
+    return symbol.name
+
+class BinaryFile:
+    def __init__(self, path, map_offset):
+        self.fullpath = os.path.realpath(path)
+        self.map_offset = map_offset
+        with open(path, 'rb') as f:
+            self.elf = ELFFile(f)
+            self.symbols = elf_func_symbols(self.elf)
+
+    def path(self):
+        return self.fullpath
+
+    def addr_start(self):
+        return self.map_offset
+
+    def addr_end(self):
+        last_sym = self.symbols[-1]
+        return symbol_addr(last_sym) + symbol_size(last_sym) + self.map_offset
+
+    def generate_symbol_file(self, prefix_symbols):
+        binary_name = os.path.basename(self.fullpath)
+        sym_file_path = f'./uftrace.data/{binary_name}.sym'
+        print(f'{sym_file_path} ({len(self.symbols)} symbols)')
+        with open(sym_file_path, 'w') as sym_file:
+            # print hexadecimal addresses on 48 bits
+            addrx = "0>12x"
+            for s in self.symbols:
+                addr = symbol_addr(s)
+                addr = f'{addr:{addrx}}'
+                size = f'{symbol_size(s):{addrx}}'
+                name = symbol_name(s)
+                if prefix_symbols:
+                    name = f'{binary_name}:{name}'
+                print(addr, size, 'T', name, file=sym_file)
+
+def parse_parameter(p):
+    s = p.split(":")
+    path = s[0]
+    if len(s) == 1:
+        return path, 0
+    if len(s) > 2:
+        raise ValueError('only one offset can be set')
+    offset = s[1]
+    if not offset.startswith('0x'):
+        err = f'offset "{offset}" is not an hexadecimal constant. '
+        err += 'It should starts with "0x".'
+        raise ValueError(err)
+    offset = int(offset, 16)
+    return path, offset
+
+def is_from_user_mode(map_file_path):
+    if os.path.exists(map_file_path):
+        with open(map_file_path, 'r') as map_file:
+            if not map_file.readline().startswith('# map stack on'):
+                return True
+    return False
+
+def generate_map(binaries):
+    map_file_path = './uftrace.data/sid-0.map'
+
+    if is_from_user_mode(map_file_path):
+        print(f'do not overwrite {map_file_path} generated from qemu-user')
+        return
+
+    mappings = []
+
+    # print hexadecimal addresses on 48 bits
+    addrx = "0>12x"
+
+    mappings += ['# map stack on highest address possible, to prevent uftrace']
+    mappings += ['# from considering any kernel address']
+    mappings += ['ffffffffffff-ffffffffffff rw-p 00000000 00:00 0 [stack]']
+
+    for b in binaries:
+        m = f'{b.addr_start():{addrx}}-{b.addr_end():{addrx}}'
+        m += f' r--p 00000000 00:00 0 {b.path()}'
+        mappings.append(m)
+
+    with open(map_file_path, 'w') as map_file:
+        print('\n'.join(mappings), file=map_file)
+    print(f'{map_file_path}')
+    print('\n'.join(mappings))
+
+def main():
+    parser = argparse.ArgumentParser(description=
+                                     'generate symbol files for uftrace')
+    parser.add_argument('elf_file', nargs='+',
+                        help='path to an ELF file. '
+                        'Use /path/to/file:0xdeadbeef to add a mapping offset.')
+    parser.add_argument('--prefix-symbols',
+                        help='prepend binary name to symbols',
+                        action=argparse.BooleanOptionalAction)
+    args = parser.parse_args()
+
+    if not os.path.exists('./uftrace.data'):
+        os.mkdir('./uftrace.data')
+
+    binaries = []
+    for file in args.elf_file:
+        path, offset = parse_parameter(file)
+        b = BinaryFile(path, offset)
+        binaries.append(b)
+    binaries.sort(key = lambda b: b.addr_end());
+
+    for b in binaries:
+        b.generate_symbol_file(args.prefix_symbols)
+
+    generate_map(binaries)
+
+if __name__ == '__main__':
+    main()
-- 
2.47.3



  parent reply	other threads:[~2025-09-22  9:44 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-09-22  9:36 [PATCH 00/25] September maintainer updates (docs, plugins, semihosting) pre-PR Alex Bennée
2025-09-22  9:36 ` [PATCH 01/25] docs/devel: fix typo in code-provenance.rst Alex Bennée
2025-09-22 11:32   ` Thomas Huth
2025-09-22 19:37   ` Richard Henderson
2025-09-22  9:36 ` [PATCH 02/25] scripts/ci: add gitlab-failure-analysis script Alex Bennée
2025-09-22  9:36 ` [PATCH 03/25] checkpatch: Ignore removed lines in license check Alex Bennée
2025-09-22  9:36 ` [PATCH 04/25] semihosting/syscalls: compile once in system and per target for user mode Alex Bennée
2025-09-22  9:36 ` [PATCH 05/25] semihosting/syscalls: replace uint64_t with vaddr where appropriate Alex Bennée
2025-09-22  9:36 ` [PATCH 06/25] semihosting/guestfd: compile once for system/user Alex Bennée
2025-09-22  9:36 ` [PATCH 07/25] semihosting/arm-compat-semi: change common_semi_sys_exit_extended Alex Bennée
2025-09-22  9:36 ` [PATCH 08/25] target/riscv/common-semi-target: remove sizeof(target_ulong) Alex Bennée
2025-09-22  9:36 ` [PATCH 09/25] target/{arm, riscv}/common-semi-target: eradicate target_ulong Alex Bennée
2025-09-22  9:36 ` [PATCH 10/25] include/semihosting/common-semi: extract common_semi API Alex Bennée
2025-09-22  9:36 ` [PATCH 11/25] semihosting/arm-compat-semi: eradicate sizeof(target_ulong) Alex Bennée
2025-09-22 11:52   ` Philippe Mathieu-Daudé
2025-09-22  9:36 ` [PATCH 12/25] semihosting/arm-compat-semi: replace target_ulong with vaddr Alex Bennée
2025-09-22 11:53   ` Philippe Mathieu-Daudé
2025-09-22 12:43     ` Alex Bennée
2025-09-25 21:13       ` Pierrick Bouvier
2025-09-22  9:36 ` [PATCH 13/25] semihosting/arm-compat-semi: eradicate target_long Alex Bennée
2025-09-22  9:36 ` [PATCH 14/25] semihosting/arm-compat-semi: remove dependency on cpu.h Alex Bennée
2025-09-22  9:37 ` [PATCH 15/25] semihosting/arm-compat-semi: compile once in system and per target for user mode Alex Bennée
2025-09-22  9:37 ` [PATCH 16/25] contrib/plugins/execlog: Explicitly check for qemu_plugin_read_register() failure Alex Bennée
2025-09-22  9:37 ` [PATCH 17/25] contrib/plugins/uftrace: skeleton file Alex Bennée
2025-09-22  9:37 ` [PATCH 18/25] contrib/plugins/uftrace: define cpu operations and implement aarch64 Alex Bennée
2025-09-22  9:37 ` [PATCH 19/25] contrib/plugins/uftrace: track callstack Alex Bennée
2025-09-22  9:37 ` [PATCH 20/25] contrib/plugins/uftrace: implement tracing Alex Bennée
2025-09-22  9:37 ` [PATCH 21/25] contrib/plugins/uftrace: implement privilege level tracing Alex Bennée
2025-09-22  9:37 ` [PATCH 22/25] contrib/plugins/uftrace: generate additional files for uftrace Alex Bennée
2025-09-22  9:37 ` [PATCH 23/25] contrib/plugins/uftrace: implement x64 support Alex Bennée
2025-09-22  9:37 ` Alex Bennée [this message]
2025-09-22  9:37 ` [PATCH 25/25] contrib/plugins/uftrace: add documentation Alex Bennée

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250922093711.2768983-25-alex.bennee@linaro.org \
    --to=alex.bennee@linaro.org \
    --cc=alistair.francis@wdc.com \
    --cc=dbarboza@ventanamicro.com \
    --cc=erdnaxe@crans.org \
    --cc=liwei1518@gmail.com \
    --cc=ma.mandourr@gmail.com \
    --cc=palmer@dabbelt.com \
    --cc=peter.maydell@linaro.org \
    --cc=philmd@linaro.org \
    --cc=pierrick.bouvier@linaro.org \
    --cc=qemu-arm@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    --cc=qemu-riscv@nongnu.org \
    --cc=thuth@redhat.com \
    --cc=zhiwei_liu@linux.alibaba.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).