Skip to content

Commit bd0a19c

Browse files
authored
Merge pull request #522 from aap-sc/aap-sc/unavailable_fixup
debug: use TCL-RPC to fetch results of OpenOCD commands instead of parsing log file
2 parents 96403c8 + a4d9f97 commit bd0a19c

File tree

1 file changed

+38
-29
lines changed

1 file changed

+38
-29
lines changed

debug/testlib.py

Lines changed: 38 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import time
1010
import traceback
1111

12+
import tty
1213
import pexpect
1314
import yaml
1415

@@ -308,20 +309,16 @@ def __init__(self, server_cmd=None, config=None, debug=False, timeout=60,
308309
cmd = shlex.split(server_cmd)
309310
else:
310311
cmd = ["openocd"]
311-
if debug:
312-
cmd.append("-d")
313312

314313
# This command needs to come before any config scripts on the command
315314
# line, since they are executed in order.
316315
cmd += [
317316
# Tell OpenOCD to bind gdb to an unused, ephemeral port.
318317
"--command", "gdb_port 0",
319-
# We don't use the TCL server.
320-
"--command", "tcl_port disabled",
321-
# Put the regular command prompt in stdin. Don't listen on a port
322-
# because it will conflict if multiple OpenOCD instances are running
323-
# at the same time.
324-
"--command", "telnet_port pipe",
318+
# We create a socket for OpenOCD command line (TCL-RPC)
319+
"--command", "tcl_port 0",
320+
# don't use telnet
321+
"--command", "telnet_port disabled",
325322
]
326323

327324
if config:
@@ -331,6 +328,7 @@ def __init__(self, server_cmd=None, config=None, debug=False, timeout=60,
331328
sys.exit(1)
332329

333330
cmd += ["-f", self.config_file]
331+
334332
if debug:
335333
cmd.append("-d")
336334

@@ -366,28 +364,47 @@ def __init__(self, server_cmd=None, config=None, debug=False, timeout=60,
366364
logfile.flush()
367365

368366
self.gdb_ports = []
367+
self.tclrpc_port = None
369368
self.start(cmd, logfile, extra_env)
370369

370+
self.openocd_cli = pexpect.spawn(f"nc localhost {self.tclrpc_port}")
371+
# TCL-RPC uses \x1a as a watermark for end of message. We set raw
372+
# pty mode to disable translation of \x1a to EOF
373+
tty.setraw(self.openocd_cli.child_fd)
374+
371375
def start(self, cmd, logfile, extra_env):
372376
combined_env = {**os.environ, **extra_env}
373377
# pylint: disable-next=consider-using-with
374-
self.process = subprocess.Popen(cmd, stdin=subprocess.PIPE,
378+
self.process = subprocess.Popen(cmd, stdin=None,
375379
stdout=logfile, stderr=logfile, env=combined_env)
376380

377381
try:
378382
# Wait for OpenOCD to have made it through riscv_examine(). When
379383
# using OpenOCD to communicate with a simulator this may take a
380384
# long time, and gdb will time out when trying to connect if we
381385
# attempt too early.
382-
383386
while True:
384387
m = self.expect(
385-
rb"(Listening on port (\d+) for gdb connections|"
386-
rb"tcl server disabled)",
388+
rb"Listening on port (?P<port>\d+) for "
389+
rb"(?P<server>(?:gdb)|(?:tcl)) connections",
387390
message="Waiting for OpenOCD to start up...")
388-
if b"gdb" in m.group(1):
389-
self.gdb_ports.append(int(m.group(2)))
390-
else:
391+
if m["server"] == b"gdb":
392+
self.gdb_ports.append(int(m["port"]))
393+
elif m["server"] == b"tcl":
394+
if self.tclrpc_port:
395+
raise TestLibError(
396+
"unexpected re-definition of TCL-RPC port")
397+
self.tclrpc_port = int(m["port"])
398+
# WARNING! WARNING! WARNING!
399+
# The condition below works properly only if OpenOCD reports
400+
# gdb/tcl ports in a specific order. Namely, it requires the
401+
# gdb ports to be reported before the tcl one. At the moment
402+
# this comment was written OpenOCD reports these ports in the
403+
# required order if we have a call to `init` statement in
404+
# either target configuration file or command-line parameter.
405+
# All configuration files used in testing include a call to
406+
# `init`
407+
if self.tclrpc_port and (len(self.gdb_ports) > 0):
391408
break
392409

393410
if self.debug_openocd:
@@ -420,20 +437,12 @@ def smp(self):
420437
return False
421438

422439
def command(self, cmd):
423-
"""Write the command to OpenOCD's stdin. Return the output of the
424-
command, minus the prompt."""
425-
self.process.stdin.write(f"{cmd}\n".encode())
426-
self.process.stdin.flush()
427-
m = self.expect(re.escape(f"{cmd}\n".encode()))
428-
429-
# The prompt isn't flushed to the log, so send a unique command that
430-
# lets us find where output of the last command ends.
431-
magic = f"# {self.command_count}x".encode()
432-
self.command_count += 1
433-
self.process.stdin.write(magic + b"\n")
434-
self.process.stdin.flush()
435-
m = self.expect(rb"(.*)^>\s*" + re.escape(magic))
436-
return m.group(1)
440+
"""Send the command to OpenOCD's TCL-RPC server. Return the output of
441+
the command, minus the prompt."""
442+
self.openocd_cli.write(f"{cmd}\n\x1a")
443+
self.openocd_cli.expect(rb"(.*)\x1a")
444+
m = self.openocd_cli.match.group(1)
445+
return m
437446

438447
def expect(self, regex, message=None):
439448
"""Wait for the regex to match the log, and return the match object. If

0 commit comments

Comments
 (0)