forked from espressif/esp-idf
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgdbhelper.py
132 lines (122 loc) · 5.4 KB
/
gdbhelper.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import os
import re
import subprocess
import sys
import tempfile
from .constants import PANIC_OUTPUT_DECODE_SCRIPT
from .logger import Logger
from .output_helpers import normal_print, red_print, yellow_print
from .web_socket_client import WebSocketClient
class GDBHelper:
def __init__(self, toolchain_prefix, websocket_client, elf_file, port, baud_rate):
# type: (str, WebSocketClient, str, int, int) -> None
self._gdb_buffer = b'' # type: bytes
self._gdb_exit = False # type: bool
self.toolchain_prefix = toolchain_prefix
self.websocket_client = websocket_client
self.elf_file = elf_file
self.port = port
self.baud_rate = baud_rate
@property
def gdb_buffer(self): # type: () -> bytes
return self._gdb_buffer
@gdb_buffer.setter
def gdb_buffer(self, value): # type: (bytes) -> None
self._gdb_buffer = value
@property
def gdb_exit(self): # type: () -> bool
return self._gdb_exit
@gdb_exit.setter
def gdb_exit(self, value): # type: (bool) -> None
self._gdb_exit = value
def run_gdb(self):
# type: () -> None
normal_print('')
try:
cmd = ['%sgdb' % self.toolchain_prefix,
'-ex', 'set serial baud %d' % self.baud_rate,
'-ex', 'target remote %s' % self.port,
self.elf_file]
# Here we handling GDB as a process
# Open GDB process
try:
process = subprocess.Popen(cmd, cwd='.')
except KeyboardInterrupt:
pass
# We ignore Ctrl+C interrupt form external process abd wait response util GDB will be finished.
while True:
try:
process.wait()
break
except KeyboardInterrupt:
pass # We ignore the Ctrl+C
self.gdb_exit = True
except OSError as e:
red_print('%s: %s' % (' '.join(cmd), e))
except KeyboardInterrupt:
pass # happens on Windows, maybe other OSes
finally:
try:
# on Linux, maybe other OSes, gdb sometimes seems to be alive even after wait() returns...
process.terminate()
except Exception: # noqa
pass
try:
# also on Linux, maybe other OSes, gdb sometimes exits uncleanly and breaks the tty mode
subprocess.call(['stty', 'sane'])
except Exception: # noqa
pass # don't care if there's no stty, we tried...
def check_gdb_stub_trigger(self, line):
# type: (bytes) -> bool
line = self.gdb_buffer + line
self.gdb_buffer = b''
m = re.search(b'\\$(T..)#(..)', line) # look for a gdb "reason" for a break
if m is not None:
try:
chsum = sum(ord(bytes([p])) for p in m.group(1)) & 0xFF
calc_chsum = int(m.group(2), 16)
except ValueError: # payload wasn't valid hex digits
return False
if chsum == calc_chsum:
if self.websocket_client:
yellow_print('Communicating through WebSocket')
self.websocket_client.send({'event': 'gdb_stub',
'port': self.port,
'prog': self.elf_file})
yellow_print('Waiting for debug finished event')
self.websocket_client.wait([('event', 'debug_finished')])
yellow_print('Communications through WebSocket is finished')
else:
return True
else:
red_print('Malformed gdb message... calculated checksum %02x received %02x' % (chsum, calc_chsum))
return False
def process_panic_output(self, panic_output, logger, target): # type: (bytes, Logger, str) -> None
panic_output_file = None
try:
# On Windows, the temporary file can't be read unless it is closed.
# Set delete=False and delete the file manually later.
with tempfile.NamedTemporaryFile(mode='wb', delete=False) as panic_output_file:
panic_output_file.write(panic_output)
panic_output_file.flush()
cmd = [self.toolchain_prefix + 'gdb',
'--batch', '-n',
self.elf_file,
'-ex', "target remote | \"{python}\" \"{script}\" --target {target} \"{output_file}\""
.format(python=sys.executable,
script=PANIC_OUTPUT_DECODE_SCRIPT,
target=target,
output_file=panic_output_file.name),
'-ex', 'bt']
output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
yellow_print('\nBacktrace:\n\n')
logger.print(output) # noqa: E999
except subprocess.CalledProcessError as e:
yellow_print('Failed to run gdb_panic_server.py script: {}\n{}\n\n'.format(e, e.output))
logger.print(panic_output)
finally:
if panic_output_file is not None:
try:
os.unlink(panic_output_file.name)
except OSError as e:
yellow_print('Couldn\'t remove temporary panic output file ({})'.format(e))