# SPDX-License-Identifier: GPL-2.0 # arm-cs-trace-disasm.py: ARM CoreSight Trace Dump With Disassember # # Author: Tor Jeremiassen <tor@ti.com> # Mathieu Poirier <mathieu.poirier@linaro.org> # Leo Yan <leo.yan@linaro.org> # Al Grant <Al.Grant@arm.com>
from __future__ import print_function import os from os import path import re from subprocess import * import argparse import platform
from perf_trace_context import perf_sample_srccode, perf_config_get
# Below are some example commands for using this script. # Note a --kcore recording is required for accurate decode # due to the alternatives patching mechanism. However this # script only supports reading vmlinux for disassembly dump, # meaning that any patched instructions will appear # as unpatched, but the instruction ranges themselves will # be correct. In addition to this, source line info comes # from Perf, and when using kcore there is no debug info. The # following lists the supported features in each mode: # # +-----------+-----------------+------------------+------------------+ # | Recording | Accurate decode | Source line dump | Disassembly dump | # +-----------+-----------------+------------------+------------------+ # | --kcore | yes | no | yes | # | normal | no | yes | yes | # +-----------+-----------------+------------------+------------------+ # # Output disassembly with objdump and auto detect vmlinux # (when running on same machine.) # perf script -s scripts/python/arm-cs-trace-disasm.py -d # # Output disassembly with llvm-objdump: # perf script -s scripts/python/arm-cs-trace-disasm.py \ # -- -d llvm-objdump-11 -k path/to/vmlinux # # Output only source line and symbols: # perf script -s scripts/python/arm-cs-trace-disasm.py
def default_objdump():
config = perf_config_get("annotate.objdump") return config if config else"objdump"
# Command line parsing. def int_arg(v):
v = int(v) if v < 0: raise argparse.ArgumentTypeError("Argument must be a positive integer") return v
args = argparse.ArgumentParser()
args.add_argument("-k", "--vmlinux",
help="Set path to vmlinux file. Omit to autodetect if running on same machine")
args.add_argument("-d", "--objdump", nargs="?", const=default_objdump(),
help="Show disassembly. Can also be used to change the objdump path"),
args.add_argument("-v", "--verbose", action="store_true", help="Enable debugging log")
args.add_argument("--start-time", type=int_arg, help="Monotonic clock time of sample to start from. " "See 'time' field on samples in -v mode.")
args.add_argument("--stop-time", type=int_arg, help="Monotonic clock time of sample to stop at. " "See 'time' field on samples in -v mode.")
args.add_argument("--start-sample", type=int_arg, help="Index of sample to start from. " "See 'index' field on samples in -v mode.")
args.add_argument("--stop-sample", type=int_arg, help="Index of sample to stop at. " "See 'index' field on samples in -v mode.")
options = args.parse_args() if (options.start_time and options.stop_time and
options.start_time >= options.stop_time):
print("--start-time must less than --stop-time")
exit(2) if (options.start_sample and options.stop_sample and
options.start_sample >= options.stop_sample):
print("--start-sample must less than --stop-sample")
exit(2)
def print_disam(dso_fname, dso_start, start_addr, stop_addr): for line in read_disam(dso_fname, dso_start, start_addr, stop_addr):
m = disasm_func_re.search(line) if m isNone:
m = disasm_re.search(line) if m isNone: continue
print("\t" + line)
def process_event(param_dict): global cache_size global options global sample_idx
sample = param_dict["sample"]
comm = param_dict["comm"]
name = param_dict["ev_name"]
dso = get_optional(param_dict, "dso")
dso_bid = get_optional(param_dict, "dso_bid")
dso_start = get_optional(param_dict, "dso_map_start")
dso_end = get_optional(param_dict, "dso_map_end")
symbol = get_optional(param_dict, "symbol")
map_pgoff = get_optional(param_dict, "map_pgoff") # check for valid map offset if (str(map_pgoff) == '[unknown]'):
map_pgoff = 0
cpu = sample["cpu"]
ip = sample["ip"]
addr = sample["addr"]
sample_idx += 1
if (options.start_time and sample["time"] < options.start_time): return if (options.stop_time and sample["time"] > options.stop_time):
exit(0) if (options.start_sample and sample_idx < options.start_sample): return if (options.stop_sample and sample_idx > options.stop_sample):
exit(0)
if (options.verbose == True):
print("Event type: %s" % name)
print_sample(sample)
# Initialize CPU data if it's empty, and directly return back # if this is the first tracing event for this CPU. if (cpu_data.get(str(cpu) + 'addr') == None):
cpu_data[str(cpu) + 'addr'] = addr return
# If cannot find dso so cannot dump assembler, bail out if (dso == '[unknown]'): return
# Validate dso start and end addresses if ((dso_start == '[unknown]') or (dso_end == '[unknown]')):
print("Failed to find valid dso map for dso %s" % dso) return
if (name[0:12] == "instructions"):
print_srccode(comm, param_dict, sample, symbol, dso) return
# Don't proceed if this event is not a branch sample, . if (name[0:8] != "branches"): return
# The format for packet is: # # +------------+------------+------------+ # sample_prev: | addr | ip | cpu | # +------------+------------+------------+ # sample_next: | addr | ip | cpu | # +------------+------------+------------+ # # We need to combine the two continuous packets to get the instruction # range for sample_prev::cpu: # # [ sample_prev::addr .. sample_next::ip ] # # For this purose, sample_prev::addr is stored into cpu_data structure # and read back for 'start_addr' when the new packet comes, and we need # to use sample_next::ip to calculate 'stop_addr', plusing extra 4 for # 'stop_addr' is for the sake of objdump so the final assembler dump can # include last instruction for sample_next::ip.
start_addr = cpu_data[str(cpu) + 'addr']
stop_addr = ip + 4
# Record for previous sample packet
cpu_data[str(cpu) + 'addr'] = addr
# Filter out zero start_address. Optionally identify CS_ETM_TRACE_ON packet if (start_addr == 0): if ((stop_addr == 4) and (options.verbose == True)):
print("CPU%d: CS_ETM_TRACE_ON packet is inserted" % cpu) return
if (start_addr < int(dso_start) or start_addr > int(dso_end)):
print("Start address 0x%x is out of range [ 0x%x .. 0x%x ] for dso %s" % (start_addr, int(dso_start), int(dso_end), dso)) return
if (stop_addr < int(dso_start) or stop_addr > int(dso_end)):
print("Stop address 0x%x is out of range [ 0x%x .. 0x%x ] for dso %s" % (stop_addr, int(dso_start), int(dso_end), dso)) return
if (options.objdump != None): # It doesn't need to decrease virtual memory offset for disassembly # for kernel dso and executable file dso, so in this case we set # vm_start to zero. if (dso == "[kernel.kallsyms]"or dso_start == 0x400000):
dso_vm_start = 0
map_pgoff = 0 else:
dso_vm_start = int(dso_start)
dso_fname = get_dso_file_path(dso, dso_bid) if path.exists(dso_fname):
print_disam(dso_fname, dso_vm_start, start_addr + map_pgoff, stop_addr + map_pgoff) else:
print("Failed to find dso %s for address range [ 0x%x .. 0x%x ]" % (dso, start_addr + map_pgoff, stop_addr + map_pgoff))
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.