Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Add interactive stack trace #233

Open
wants to merge 22 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
1bb0480
Formatted stack trace and save to file
ryan-doan Sep 27, 2022
2285d9d
code formatting changes
ryan-doan Sep 30, 2022
8581cae
Delete stack_trace.py
ryan-doan Sep 30, 2022
c5d5eb1
Update pros/serial/terminal/terminal.py
ryan-doan Oct 4, 2022
466503e
Update pros/cli/terminal.py
ryan-doan Oct 4, 2022
221ae03
update correct path, prevent addr2line from running if elf file doesn…
ryan-doan Oct 4, 2022
2304312
Merge branch 'add-interactive-stack-trace' of https://github.com/purd…
ryan-doan Oct 4, 2022
3e8c63c
remove project folder
ryan-doan Oct 4, 2022
059b077
added css styling to upload button
ryan-doan Oct 5, 2022
33124e1
Revert "added css styling to upload button"
ryan-doan Oct 5, 2022
efc6095
remove stack_trace.txt
ryan-doan Oct 18, 2022
3125d4a
fix errors with path
ryan-doan Oct 18, 2022
1b9167c
rewrote code to make it functional
ryan-doan Oct 19, 2022
02e98c0
Remove sqlalchemy, add options, string formatting, add colored output.
BennyBot Oct 19, 2022
9e5fcb7
Merge branch 'develop' into add-interactive-stack-trace
ryan-doan Oct 25, 2022
283712e
add shell argument to subprocess open
Andrewtho5942 Feb 24, 2023
f4ae10c
Merging in develop
Ghurfa Mar 1, 2024
7f2ad9d
Changed the addr2line path to use the toolchain
Ghurfa Mar 1, 2024
30f83ab
Merge branch 'develop' into add-interactive-stack-trace
Rocky14683 Jun 11, 2024
5a15963
Finish data abort realtime stack trace functionality
Rocky14683 Jun 11, 2024
afcd1e7
Merge remote-tracking branch 'origin/add-interactive-stack-trace' int…
Rocky14683 Jun 11, 2024
de60210
Work on formatting and color
Rocky14683 Jul 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion pros/cli/terminal.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ def terminal_cli():
help='Specify 2 ports for the "share" backend. The default option deterministically selects ports '
'based on the serial port name')
@click.option('--banner/--no-banner', 'request_banner', default=True)
@click.option('--raw-stack-trace', is_flag=True, default=True, help='Display stack traces as raw data. By default, the terminal will attempt to parse stack traces')
@click.option('--stack-trace-file', type=str, default=None, help='Output stack traces to a file')
@click.option('--output', nargs = 1, type=str, is_eager = True, help='Redirect terminal output to a file', default=None)

def terminal(port: str, backend: str, **kwargs):
Expand Down Expand Up @@ -83,7 +85,29 @@ def terminal(port: str, backend: str, **kwargs):
device = devices.RawStreamDevice(ser)
else:
device = devices.vex.V5UserDevice(ser)
term = Terminal(device, request_banner=kwargs.pop('request_banner', True))
term = Terminal(device, request_banner=kwargs.pop('request_banner', True), auto_stack_trace=(kwargs.pop('raw_stack_trace', False) or kwargs.pop('raw', False)), stack_trace_file=kwargs.pop('stack_trace_file', None))

class TerminalOutput(object):
def __init__(self, file):
self.terminal = sys.stdout
self.log = open(file, 'a')
def write(self, data):
self.terminal.write(data)
self.log.write(data)
def flush(self):
pass
def end(self):
self.log.close()

output = None
if kwargs.get('output', None):
output_file = kwargs['output']
output = TerminalOutput(f'{output_file}')
term.console.output = output
sys.stdout = output
logger(__name__).info(f'Redirecting Terminal Output to File: {output_file}')
else:
sys.stdout = sys.__stdout__

class TerminalOutput(object):
def __init__(self, file):
Expand Down
48 changes: 45 additions & 3 deletions pros/serial/terminal/terminal.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import codecs
import os
import signal
import subprocess
import sys
import threading

import colorama


from pros.common.utils import logger
from pros.serial import decode_bytes_to_str
from pros.serial.devices import StreamDevice
Expand Down Expand Up @@ -165,12 +167,14 @@ def cleanup(self):
'Sorry no implementation for your platform ({})'
' available.'.format(sys.platform))


class Terminal(object):
"""This class is loosely based off of the pyserial miniterm"""
beginStackTrace = False
stackTraceFile = None

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
file = None

Did we ever decide if we needed to do this @ryan-doan ?

def __init__(self, port_instance: StreamDevice, transformations=(),
output_raw: bool = False, request_banner: bool = True):
output_raw: bool = False, request_banner: bool = True,
auto_stack_trace: bool = True, stack_trace_file: str = None):
self.device = port_instance
self.device.subscribe(b'sout')
self.device.subscribe(b'serr')
Expand All @@ -183,6 +187,8 @@ def __init__(self, port_instance: StreamDevice, transformations=(),
self.output_raw = output_raw
self.request_banner = request_banner
self.no_sigint = True # SIGINT flag
self.convert_stack_traces = auto_stack_trace
self.stack_trace_file = stack_trace_file
signal.signal(signal.SIGINT, self.catch_sigint) # SIGINT handler
self.console = Console()
self.console.output = colorama.AnsiToWin32(self.console.output).stream
Expand Down Expand Up @@ -224,7 +230,43 @@ def reader(self):
if data[0] == b'sout':
text = decode_bytes_to_str(data[1])
elif data[0] == b'serr':
text = '{}{}{}'.format(colorama.Fore.RED, decode_bytes_to_str(data[1]), colorama.Style.RESET_ALL)
#print(len(text))
addr = "0x" + decode_bytes_to_str(data[1])[:7]
if self.beginStackTrace and addr.isalnum() and addr[3] != 'x' and self.convert_stack_traces:
def getTrace(s, path):
if not os.path.exists(path):
return ''
temp = subprocess.Popen(['addr2line', '-faps', '-e', path, s],
stdout=subprocess.PIPE).communicate()[0].decode('utf-8')
if (temp.find('?') != -1):
return ''
else:
return temp[12: len(temp) - 2]
trace = ' : {}{}{}'.format(
getTrace(addr, "bin/hot.package.elf"),
getTrace(addr, "bin/cold.package.elf"),
getTrace(addr, "bin/monolith.elf"))
text = '{}{}{}{}{}{}'.format(colorama.Fore.RED, decode_bytes_to_str(data[1]), colorama.Style.RESET_ALL, colorama.Fore.WHITE, trace, colorama.Style.RESET_ALL)
if(self.stack_trace_file):
file.write(addr + trace + '\n')
else:
text = '{}{}{}'.format(colorama.Fore.RED, decode_bytes_to_str(data[1]), colorama.Style.RESET_ALL)

if "BEGIN STACK TRACE" in text:
self.beginStackTrace = True
if(self.convert_stack_traces):
text = '{}{}{}'.format(colorama.Fore.YELLOW, "BEGINNING STACK TRACE\n--------------------------------\n\n", colorama.Style.RESET_ALL)
if(self.stack_trace_file):
file = open(self.stack_trace_file, "w")

if "END OF TRACE" in text:
self.beginStackTrace = False
if(self.convert_stack_traces):
text = '{}{}{}'.format(colorama.Fore.YELLOW, "\n--------------------------------\nEND OF STACK TRACE\n\n", colorama.Style.RESET_ALL)
if(self.stack_trace_file):
file.close()
file = None

elif data[0] == b'kdbg':
text = '{}\n\nKERNEL DEBUG:\t{}{}\n'.format(colorama.Back.GREEN + colorama.Style.BRIGHT,
decode_bytes_to_str(data[1]),
Expand Down