1*5c2c0fb3SJerome Forissier#!/usr/bin/env python3 2*5c2c0fb3SJerome Forissier# SPDX-License-Identifier: BSD-2-Clause 3*5c2c0fb3SJerome Forissier# 4*5c2c0fb3SJerome Forissier# Copyright (c) 2023, Linaro Limited 5*5c2c0fb3SJerome Forissier# 6*5c2c0fb3SJerome Forissier# Converts a ftrace binary file to text. The input file has the following 7*5c2c0fb3SJerome Forissier# format: 8*5c2c0fb3SJerome Forissier# 9*5c2c0fb3SJerome Forissier# <ASCII text> <zero or more nul bytes> FTRACE\x00\x01 <binary data>... 10*5c2c0fb3SJerome Forissier# 11*5c2c0fb3SJerome Forissier# <binary data> is an array of 64-bit integers. 12*5c2c0fb3SJerome Forissier# - When the topmost byte is 0, the entry indicates a function return and the 13*5c2c0fb3SJerome Forissier# remaining bytes are a duration in nanoseconds. 14*5c2c0fb3SJerome Forissier# - A non-zero value is a stack depth, indicating a function entry, and the 15*5c2c0fb3SJerome Forissier# remaining bytes are the function's address. 16*5c2c0fb3SJerome Forissier 17*5c2c0fb3SJerome Forissierimport sys 18*5c2c0fb3SJerome Forissier 19*5c2c0fb3SJerome Forissier 20*5c2c0fb3SJerome Forissierline = "" 21*5c2c0fb3SJerome Forissiercurr_depth = 0 22*5c2c0fb3SJerome Forissier 23*5c2c0fb3SJerome Forissier 24*5c2c0fb3SJerome Forissierdef usage(): 25*5c2c0fb3SJerome Forissier print(f"Usage: {sys.argv[0]} ftrace.out") 26*5c2c0fb3SJerome Forissier print("Converts a ftrace file to text. Output is written to stdout.") 27*5c2c0fb3SJerome Forissier sys.exit(0) 28*5c2c0fb3SJerome Forissier 29*5c2c0fb3SJerome Forissier 30*5c2c0fb3SJerome Forissierdef format_time(ns): 31*5c2c0fb3SJerome Forissier if ns < 1000000: 32*5c2c0fb3SJerome Forissier us = ns / 1000 33*5c2c0fb3SJerome Forissier return f"{us:7.3f} us" 34*5c2c0fb3SJerome Forissier else: 35*5c2c0fb3SJerome Forissier ms = ns / 1000000 36*5c2c0fb3SJerome Forissier return f"{ms:7.3f} ms" 37*5c2c0fb3SJerome Forissier 38*5c2c0fb3SJerome Forissier 39*5c2c0fb3SJerome Forissierdef display(depth, val): 40*5c2c0fb3SJerome Forissier global line, curr_depth 41*5c2c0fb3SJerome Forissier if depth != 0: 42*5c2c0fb3SJerome Forissier curr_depth = depth 43*5c2c0fb3SJerome Forissier if line != "": 44*5c2c0fb3SJerome Forissier line = line.replace("TIME", " " * 10) + " {" 45*5c2c0fb3SJerome Forissier print(line) 46*5c2c0fb3SJerome Forissier line = "" 47*5c2c0fb3SJerome Forissier line = f" TIME | {depth:3} | " + " " * depth + f"0x{val:016x}()" 48*5c2c0fb3SJerome Forissier else: 49*5c2c0fb3SJerome Forissier if line != "": 50*5c2c0fb3SJerome Forissier line = line.replace("TIME", format_time(val)) 51*5c2c0fb3SJerome Forissier print(line) 52*5c2c0fb3SJerome Forissier line = "" 53*5c2c0fb3SJerome Forissier else: 54*5c2c0fb3SJerome Forissier if curr_depth != 0: 55*5c2c0fb3SJerome Forissier curr_depth = curr_depth - 1 56*5c2c0fb3SJerome Forissier print(" " + format_time(val) + f" | {curr_depth:3} | " + 57*5c2c0fb3SJerome Forissier " " * curr_depth + "}") 58*5c2c0fb3SJerome Forissier 59*5c2c0fb3SJerome Forissier 60*5c2c0fb3SJerome Forissierdef main(): 61*5c2c0fb3SJerome Forissier if len(sys.argv) < 2: 62*5c2c0fb3SJerome Forissier usage() 63*5c2c0fb3SJerome Forissier with open(sys.argv[1], 'rb') as f: 64*5c2c0fb3SJerome Forissier s = f.read() 65*5c2c0fb3SJerome Forissier magic = s.find(b'FTRACE\x00\x01') 66*5c2c0fb3SJerome Forissier if magic == -1: 67*5c2c0fb3SJerome Forissier print("Magic not found", file=sys.stderr) 68*5c2c0fb3SJerome Forissier sys.exit(1) 69*5c2c0fb3SJerome Forissier print(s[:magic].rstrip(b'\x00').decode()) 70*5c2c0fb3SJerome Forissier s = s[magic + 8:] 71*5c2c0fb3SJerome Forissier for i in range(0, len(s), 8): 72*5c2c0fb3SJerome Forissier elem = int.from_bytes(s[i:i + 8], byteorder="little", signed=False) 73*5c2c0fb3SJerome Forissier depth = elem >> 56 74*5c2c0fb3SJerome Forissier val = elem & 0xFFFFFFFFFFFFFF 75*5c2c0fb3SJerome Forissier display(depth, val) 76*5c2c0fb3SJerome Forissier 77*5c2c0fb3SJerome Forissier 78*5c2c0fb3SJerome Forissierif __name__ == "__main__": 79*5c2c0fb3SJerome Forissier main() 80