Add 'filteroutput.py' tool to automatically do addr2line lookups on likely hex values

This commit is contained in:
Angus Gratton 2016-03-10 12:28:53 +11:00
parent f9fb0f212c
commit b414e0b946
2 changed files with 109 additions and 1 deletions

View file

@ -75,6 +75,9 @@ FLAVOR ?= release # or debug
# Compiler names, etc. assume gdb # Compiler names, etc. assume gdb
CROSS ?= xtensa-lx106-elf- CROSS ?= xtensa-lx106-elf-
# Path to the filteroutput.py tool
FILTEROUTPUT ?= $(ROOT)/utils/filteroutput.py
AR = $(CROSS)ar AR = $(CROSS)ar
CC = $(CROSS)gcc CC = $(CROSS)gcc
CPP = $(CROSS)cpp CPP = $(CROSS)cpp
@ -385,7 +388,7 @@ size: $(PROGRAM_OUT)
$(Q) $(CROSS)size --format=sysv $(PROGRAM_OUT) $(Q) $(CROSS)size --format=sysv $(PROGRAM_OUT)
test: flash test: flash
screen $(ESPPORT) 115200 $(FILTEROUTPUT) --port $(ESPPORT) --baud 115200 --elf $(PROGRAM_OUT)
# the rebuild target is written like this so it can be run in a parallel build # the rebuild target is written like this so it can be run in a parallel build
# environment without causing weird side effects # environment without causing weird side effects

105
utils/filteroutput.py Executable file
View file

@ -0,0 +1,105 @@
#!/usr/bin/env python
#
# A thin Python wrapper around addr2line, can monitor esp-open-rtos
# output and uses gdb to convert any suitable looking hex numbers
# found in the output into function and line numbers.
#
# Works with a serial port if the --port option is supplied.
# Otherwise waits for input on stdin.
#
import serial
import argparse
import re
import os
import os.path
import subprocess
import termios
import sys
import time
# Try looking up anything in the executable address space
RE_EXECADDR = r"(0x)?40([0-9]|[a-z]){6}"
def find_elf_file():
out_files = []
for top,_,files in os.walk('.', followlinks=False):
for f in files:
if f.endswith(".out"):
out_files.append(os.path.join(top,f))
if len(out_files) == 1:
return out_files[0]
elif len(out_files) > 1:
print("Found multiple .out files: %s. Please specify one with the --elf option." % out_files)
else:
print("No .out file found under current directory. Please specify one with the --elf option.")
sys.exit(1)
def main():
parser = argparse.ArgumentParser(description='esp-open-rtos output filter tool', prog='filteroutput')
parser.add_argument(
'--elf', '-e',
help="ELF file (*.out file) to load symbols from (if not supplied, will search for one)"),
parser.add_argument(
'--port', '-p',
help='Serial port to monitor (will monitor stdin if None)',
default=None)
parser.add_argument(
'--baud', '-b',
help='Baud rate for serial port',
type=int,
default=74880)
parser.add_argument(
'--reset-on-connect', '-r',
help='Reset ESP8266 (via DTR) on serial connect. (Linux resets even if not set, except when using NodeMCU-style auto-reset circuit.)',
action='store_true')
args = parser.parse_args()
if args.elf is None:
args.elf = find_elf_file()
elif not os.path.exists(args.elf):
print("ELF file '%s' not found" % args.elf)
sys.exit(1)
if args.port is not None:
print("Opening %s at %dbps..." % (args.port, args.baud))
port = serial.Serial(args.port, baudrate=args.baud)
if args.reset_on_connect:
print("Resetting...")
port.setDTR(False)
time.sleep(0.1)
port.setDTR(True)
else:
print("Reading from stdin...")
port = sys.stdin
# disable echo
try:
old_attr = termios.tcgetattr(sys.stdin.fileno())
attr = termios.tcgetattr(sys.stdin.fileno())
attr[3] = attr[3] & ~termios.ECHO
termios.tcsetattr(sys.stdin.fileno(), termios.TCSADRAIN, attr)
except termios.error:
pass
try:
while True:
line = port.readline()
if line == '':
break
print(line.strip())
for match in re.finditer(RE_EXECADDR, line, re.IGNORECASE):
addr = match.group(0)
if not addr.startswith("0x"):
addr = "0x"+addr
# keeping addr2line and feeding it addresses on stdin didn't seem to work smoothly
addr2line = subprocess.check_output(["xtensa-lx106-elf-addr2line","-pfia","-e","%s" % args.elf, addr], cwd=".").strip()
if not addr2line.endswith(": ?? ??:0"):
print("\n%s\n" % addr2line.strip())
finally:
if args.port is None:
# restore echo
termios.tcsetattr(sys.stdin.fileno(), termios.TCSADRAIN, old_attr)
if __name__ == "__main__":
main()