123 lines
3.7 KiB
Python
Executable File
123 lines
3.7 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# tools/parsecallstack.py
|
|
#
|
|
# Licensed to the Apache Software Foundation (ASF) under one or more
|
|
# contributor license agreements. See the NOTICE file distributed with
|
|
# this work for additional information regarding copyright ownership. The
|
|
# ASF licenses this file to you under the Apache License, Version 2.0 (the
|
|
# "License"); you may not use this file except in compliance with the
|
|
# License. You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
#
|
|
|
|
import argparse
|
|
import os
|
|
|
|
|
|
def parse_args():
|
|
|
|
parser = argparse.ArgumentParser(
|
|
"""
|
|
parsecallstack.py -c CPUTYPE -f FILENAME\n\
|
|
This file can get the call stack when you get the log with the
|
|
register values from R0 to R15, together with the stack dump.\n
|
|
Then you will get a file with name callstack.cmm, run this file
|
|
in Trace32, load the symbol according to the indication, the call
|
|
stack will pop up.\n
|
|
Trace32 software is available at: https://www.lauterbach.com
|
|
"""
|
|
)
|
|
|
|
parser.add_argument(
|
|
"-f",
|
|
"--filename",
|
|
action="store",
|
|
help="log file with registers and stack information",
|
|
)
|
|
parser.add_argument(
|
|
"-c",
|
|
"--cputype",
|
|
action="store",
|
|
help='''It supports ARM family CPU such as:
|
|
"CortexM0" "CortexM1" "CortexM3" "CortexM4"
|
|
"CortexM7" "CortexM23" "CortexM33" "CortexM35P"
|
|
"CortexR5" "CortexR7" "CortexA5" "CortexA7"''',
|
|
)
|
|
|
|
return parser.parse_args()
|
|
|
|
|
|
def get_regs(filename):
|
|
|
|
reglist = []
|
|
with open(filename, mode="r") as fl:
|
|
for line in fl:
|
|
lst = line.strip("\n").split(" ")
|
|
if "R0:" in lst:
|
|
reglist = lst[-8:]
|
|
if "R8:" in lst:
|
|
reglist += lst[-8:]
|
|
|
|
return reglist
|
|
|
|
|
|
def get_stackvalue(filename):
|
|
|
|
stackvalue = []
|
|
first = 1
|
|
with open(filename, mode="r") as fl:
|
|
for line in fl:
|
|
lst = line.strip("\n").split(" ")
|
|
if "up_stackdump:" in lst:
|
|
if first == 1:
|
|
first += 1
|
|
# strip ":" of sp
|
|
sp = lst[-9].strip(":")
|
|
# The first item is the sp to restore the stack.
|
|
stackvalue.append(sp)
|
|
stackvalue += lst[-8:]
|
|
|
|
return stackvalue
|
|
|
|
|
|
def generate_cmm(cpu, regs, stackvalue):
|
|
|
|
filename = os.path.join(os.getcwd(), "callstack.cmm")
|
|
with open(filename, mode="w") as fl:
|
|
# Select the CPU and symbol.
|
|
fl.write("SYStem.CPU %d\n" % cpu)
|
|
fl.write("SYS.M UP\n")
|
|
fl.write("Data.LOAD *\n")
|
|
fl.write("\n")
|
|
|
|
# Set R0-R15.
|
|
for num in range(len(regs)):
|
|
fl.write("Register.Set R%d 0x%s\n" % num, regs[num])
|
|
fl.write("\n")
|
|
|
|
# Recover the value in stack.
|
|
sp = int(stackvalue[0], 16)
|
|
for num in range(len(stackvalue) - 1):
|
|
address = hex(sp + num * 4)
|
|
value = stackvalue[num + 1]
|
|
fl.write("Data.Set ZSD:%d %%LE %%Long 0x%d\n" % address, value)
|
|
fl.write("\n")
|
|
|
|
# Show the call stack.
|
|
fl.write("data.view %%sYmbol.long %x\n" % sp)
|
|
fl.write("frame.view /Locals /Caller\n")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
args = parse_args()
|
|
regs = get_regs(args.filename)
|
|
stackvalue = get_stackvalue(args.filename)
|
|
generate_cmm(args.cpu, regs, stackvalue)
|