From a1037f74c9cd828e11f662ad279fff452b195c17 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 19 Nov 2019 14:23:41 -0800 Subject: Move to Python 3. The impetus for this was mostly that after my Ubuntu upgrade, pylint suddenly starting to apply python3 rules, and I suppose it's time to adopt python 3 now that it's been released for more than a decade. --- debug/gdbserver.py | 70 +++++++++++++++++++++++++------------------------- debug/pylint.rc | 3 ++- debug/targets.py | 5 ++-- debug/testlib.py | 75 +++++++++++++++++++++++++++--------------------------- 4 files changed, 78 insertions(+), 75 deletions(-) diff --git a/debug/gdbserver.py b/debug/gdbserver.py index 84d3f1d..c34e341 100755 --- a/debug/gdbserver.py +++ b/debug/gdbserver.py @@ -1,8 +1,9 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import argparse import binascii import random +import struct import sys import tempfile import time @@ -11,7 +12,7 @@ import os import targets import testlib from testlib import assertEqual, assertNotEqual, assertIn, assertNotIn -from testlib import assertGreater, assertRegexpMatches, assertLess +from testlib import assertGreater, assertRegex, assertLess from testlib import GdbTest, GdbSingleHartTest, TestFailed from testlib import assertTrue, TestNotApplicable @@ -52,14 +53,14 @@ def ihex_line(address, record_type, data): return line def srec_parse(line): - assert line.startswith('S') + assert line.startswith(b'S') typ = line[:2] count = int(line[2:4], 16) data = "" - if typ == 'S0': + if typ == b'S0': # header return 0, 0, 0 - elif typ == 'S3': + elif typ == b'S3': # data with 32-bit address # Any higher bits were chopped off. address = int(line[4:12], 16) @@ -67,7 +68,7 @@ def srec_parse(line): data += "%c" % int(line[2*i:2*i+2], 16) # Ignore the checksum. return 3, address, data - elif typ == 'S7': + elif typ == b'S7': # ignore execution start field return 7, 0, 0 else: @@ -142,9 +143,9 @@ class SimpleF18Test(SimpleRegisterTest): assertEqual(size, 4) else: output = self.gdb.p_raw("$" + name) - assertRegexpMatches(output, r"void|Could not fetch register.*") + assertRegex(output, r"void|Could not fetch register.*") output = self.gdb.p_raw("$" + alias) - assertRegexpMatches(output, r"void|Could not fetch register.*") + assertRegex(output, r"void|Could not fetch register.*") def test(self): self.check_reg("f18", "fs2") @@ -154,7 +155,7 @@ class CustomRegisterTest(SimpleRegisterTest): return self.target.implements_custom_test def check_custom(self, magic): - regs = {k: v for k, v in self.gdb.info_registers("all").iteritems() + regs = {k: v for k, v in self.gdb.info_registers("all").items() if k.startswith("custom")} assertEqual(set(regs.keys()), set(("custom1", @@ -162,7 +163,7 @@ class CustomRegisterTest(SimpleRegisterTest): "custom12346", "custom12347", "custom12348"))) - for name, value in regs.iteritems(): + for name, value in regs.items(): number = int(name[6:]) if number % 2: expect = number + magic @@ -305,11 +306,12 @@ class MemTestBlock(GdbTest): def write(self, temporary_file): data = "" - for i in range(self.length / self.line_length): + for i in range(self.length // self.line_length): line_data = "".join(["%c" % random.randrange(256) for _ in range(self.line_length)]) data += line_data - temporary_file.write(ihex_line(i * self.line_length, 0, line_data)) + temporary_file.write(ihex_line(i * self.line_length, 0, + line_data).encode()) temporary_file.flush() return data @@ -321,7 +323,7 @@ class MemTestBlock(GdbTest): self.gdb.command("monitor riscv reset_delays 50") self.gdb.command("restore %s 0x%x" % (a.name, self.hart.ram)) increment = 19 * 4 - for offset in range(0, self.length, increment) + [self.length-4]: + for offset in list(range(0, self.length, increment)) + [self.length-4]: value = self.gdb.p("*((int*)0x%x)" % (self.hart.ram + offset)) written = ord(data[offset]) | \ (ord(data[offset+1]) << 8) | \ @@ -335,7 +337,7 @@ class MemTestBlock(GdbTest): self.hart.ram, self.hart.ram + self.length), ops=self.length / 32) self.gdb.command("shell cat %s" % b.name) highest_seen = 0 - for line in b.xreadlines(): + for line in b: record_type, address, line_data = srec_parse(line) if record_type == 3: offset = address - (self.hart.ram & 0xffffffff) @@ -551,7 +553,7 @@ class Hwbp1(DebugTest): for _ in range(2): output = self.gdb.c() self.gdb.p("$pc") - assertRegexpMatches(output, r"[bB]reakpoint") + assertRegex(output, r"[bB]reakpoint") assertIn("rot13 ", output) self.gdb.b("_exit") self.exit() @@ -568,7 +570,7 @@ class Hwbp2(DebugTest): for expected in ("main", "rot13", "rot13"): output = self.gdb.c() self.gdb.p("$pc") - assertRegexpMatches(output, r"[bB]reakpoint") + assertRegex(output, r"[bB]reakpoint") assertIn("%s " % expected, output) self.gdb.command("delete") self.gdb.b("_exit") @@ -598,14 +600,14 @@ class Registers(DebugTest): for reg in ('zero', 'ra', 'sp', 'gp', 'tp'): assertIn(reg, output) for line in output.splitlines(): - assertRegexpMatches(line, r"^\S") + assertRegex(line, r"^\S") #TODO # mcpuid is one of the few registers that should have the high bit set # (for rv64). # Leave this commented out until gdb and spike agree on the encoding of # mcpuid (which is going to be renamed to misa in any case). - #assertRegexpMatches(output, ".*mcpuid *0x80") + #assertRegex(output, ".*mcpuid *0x80") #TODO: # The instret register should always be changing. @@ -884,9 +886,9 @@ class SmpSimultaneousRunHalt(GdbTest): old_mtime.update(mtime_value) mtime_spread = max(mtime_value) - min(mtime_value) - print "mtime_spread:", mtime_spread + print("mtime_spread:", mtime_spread) counter_spread = max(counter) - min(counter) - print "counter_spread:", counter_spread + print("counter_spread:", counter_spread) assertLess(mtime_spread, 101 * (len(self.target.harts) - 1), "Harts don't halt around the same time.") @@ -935,9 +937,9 @@ class JumpHbreak(GdbSingleHartTest): self.gdb.b("read_loop") self.gdb.command("hbreak just_before_read_loop") output = self.gdb.command("jump just_before_read_loop") - assertRegexpMatches(output, r"Breakpoint \d, just_before_read_loop ") + assertRegex(output, r"Breakpoint \d, just_before_read_loop ") output = self.gdb.c() - assertRegexpMatches(output, r"Breakpoint \d, read_loop ") + assertRegex(output, r"Breakpoint \d, read_loop ") class TriggerTest(GdbSingleHartTest): compile_args = ("programs/trigger.S", ) @@ -1131,24 +1133,24 @@ class DownloadTest(GdbTest): length = min(2**14, max(2**10, self.hart.ram_size - 2048)) self.download_c = tempfile.NamedTemporaryFile(prefix="download_", suffix=".c", delete=False) - self.download_c.write("#include \n") + self.download_c.write(b"#include \n") self.download_c.write( - "unsigned int crc32a(uint8_t *message, unsigned int size);\n") - self.download_c.write("uint32_t length = %d;\n" % length) - self.download_c.write("uint8_t d[%d] = {\n" % length) + b"unsigned int crc32a(uint8_t *message, unsigned int size);\n") + self.download_c.write(b"uint32_t length = %d;\n" % length) + self.download_c.write(b"uint8_t d[%d] = {\n" % length) self.crc = 0 assert length % 16 == 0 - for i in range(length / 16): - self.download_c.write(" /* 0x%04x */ " % (i * 16)) + for i in range(length // 16): + self.download_c.write((" /* 0x%04x */ " % (i * 16)).encode()) for _ in range(16): value = random.randrange(1<<8) - self.download_c.write("0x%02x, " % value) - self.crc = binascii.crc32("%c" % value, self.crc) - self.download_c.write("\n") - self.download_c.write("};\n") - self.download_c.write("uint8_t *data = &d[0];\n") + self.download_c.write(("0x%02x, " % value).encode()) + self.crc = binascii.crc32(struct.pack("B", value), self.crc) + self.download_c.write(b"\n") + self.download_c.write(b"};\n") + self.download_c.write(b"uint8_t *data = &d[0];\n") self.download_c.write( - "uint32_t main() { return crc32a(data, length); }\n") + b"uint32_t main() { return crc32a(data, length); }\n") self.download_c.flush() if self.crc < 0: diff --git a/debug/pylint.rc b/debug/pylint.rc index 0d9a640..cf07149 100644 --- a/debug/pylint.rc +++ b/debug/pylint.rc @@ -48,7 +48,8 @@ extension-pkg-whitelist= # no Warning level messages displayed, use"--disable=all --enable=classes # --disable=W" disable=bad-continuation, missing-docstring, invalid-name, locally-disabled, - too-few-public-methods, too-many-arguments, fixme, duplicate-code + too-few-public-methods, too-many-arguments, fixme, duplicate-code, + no-else-return [REPORTS] diff --git a/debug/targets.py b/debug/targets.py index d83e84b..d797f64 100644 --- a/debug/targets.py +++ b/debug/targets.py @@ -5,7 +5,7 @@ import tempfile import testlib -class Hart(object): +class Hart: # XLEN of the hart. May be overridden with --32 or --64 command line # options. xlen = 0 @@ -45,7 +45,7 @@ class Hart(object): return self.misa & (1 << (ord(letter.upper()) - ord('A'))) return False -class Target(object): +class Target: # pylint: disable=too-many-instance-attributes # List of Hart object instances, one for each hart in the target. @@ -117,7 +117,6 @@ class Target(object): def create(self): """Create the target out of thin air, eg. start a simulator.""" - pass def server(self): """Start the debug server that gdb connects to, eg. OpenOCD.""" diff --git a/debug/testlib.py b/debug/testlib.py index 60cb897..1aa0e5b 100644 --- a/debug/testlib.py +++ b/debug/testlib.py @@ -38,17 +38,17 @@ def compile(args): # pylint: disable=redefined-builtin else: cmd.append(arg) header("Compile") - print "+", " ".join(cmd) + print("+", " ".join(cmd)) process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = process.communicate() if process.returncode: - print stdout, - print stderr, + print(stdout, end=" ") + print(stderr, end=" ") header("") raise Exception("Compile failed!") -class Spike(object): +class Spike: # pylint: disable=too-many-instance-attributes # pylint: disable=too-many-locals def __init__(self, target, halted=False, timeout=None, with_jtag_gdb=True, @@ -81,7 +81,7 @@ class Spike(object): self.logname = self.logfile.name if print_log_names: real_stdout.write("Temporary spike log: %s\n" % self.logname) - self.logfile.write("+ %s\n" % " ".join(cmd)) + self.logfile.write(("+ %s\n" % " ".join(cmd)).encode()) self.logfile.flush() self.process = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=self.logfile, stderr=self.logfile) @@ -170,7 +170,7 @@ class Spike(object): def wait(self, *args, **kwargs): return self.process.wait(*args, **kwargs) -class VcsSim(object): +class VcsSim: logfile = tempfile.NamedTemporaryFile(prefix='simv', suffix='.log') logname = logfile.name @@ -223,7 +223,7 @@ class VcsSim(object): except OSError: pass -class Openocd(object): +class Openocd: logfile = tempfile.NamedTemporaryFile(prefix='openocd', suffix='.log') logname = logfile.name @@ -255,7 +255,7 @@ class Openocd(object): if config: self.config_file = find_file(config) if self.config_file is None: - print "Unable to read file " + config + print("Unable to read file", config) exit(1) cmd += ["-f", self.config_file] @@ -306,7 +306,7 @@ class Openocd(object): if not messaged and time.time() - start > 1: messaged = True - print "Waiting for OpenOCD to start..." + print("Waiting for OpenOCD to start...") if (time.time() - start) > self.timeout: raise Exception("Timed out waiting for OpenOCD to " "listen for gdb") @@ -330,12 +330,12 @@ class Openocd(object): def smp(self): """Return true iff OpenOCD internally sees the harts as part of an SMP group.""" - for line in file(self.config_file, "r"): + for line in open(self.config_file, "r"): if "target smp" in line: return True return False -class OpenocdCli(object): +class OpenocdCli: def __init__(self, port=4444): self.child = pexpect.spawn( "sh -c 'telnet localhost %d | tee openocd-cli.log'" % port) @@ -346,7 +346,7 @@ class OpenocdCli(object): self.child.expect(cmd) self.child.expect("\n") self.child.expect("> ") - return self.child.before.strip("\t\r\n \0") + return self.child.before.strip("\t\r\n \0").decode("utf-8") def reg(self, reg=''): output = self.command("reg %s" % reg) @@ -383,7 +383,7 @@ def parse_rhs(text): if all([isinstance(p, dict) for p in parsed]): dictionary = {} for p in parsed: - for k, v in p.iteritems(): + for k, v in p.items(): dictionary[k] = v parsed = dictionary return parsed @@ -394,12 +394,12 @@ def parse_rhs(text): return {lhs: parse_rhs(rhs)} elif re.match(r"-?(\d+\.\d+(e-?\d+)?|inf)", text): return float(text) - elif re.match(r"-nan\(0x[a-f0-9]+\)", text): + elif re.match(r"-?nan\(0x[a-f0-9]+\)", text): return float("nan") else: return int(text, 0) -class Gdb(object): +class Gdb: """A single gdb class which can interact with one or more gdb instances.""" # pylint: disable=too-many-public-methods @@ -428,7 +428,7 @@ class Gdb(object): real_stdout.write("Temporary gdb log: %s\n" % logfile.name) child = pexpect.spawn(cmd) child.logfile = logfile - child.logfile.write("+ %s\n" % cmd) + child.logfile.write(("+ %s\n" % cmd).encode()) self.children.append(child) self.active_child = self.children[0] @@ -468,7 +468,7 @@ class Gdb(object): del child def one_hart_per_gdb(self): - return all(h['solo'] for h in self.harts.itervalues()) + return all(h['solo'] for h in self.harts.values()) def lognames(self): return [logfile.name for logfile in self.logfiles] @@ -504,7 +504,7 @@ class Gdb(object): self.active_child.sendline(command) self.active_child.expect("\n", timeout=timeout) self.active_child.expect(r"\(gdb\)", timeout=timeout) - return self.active_child.before.strip() + return self.active_child.before.strip().decode("utf-8") def global_command(self, command): """Execute this command on every gdb that we control.""" @@ -559,7 +559,7 @@ class Gdb(object): def interrupt(self, ops=1): self.active_child.send("\003") self.active_child.expect(r"\(gdb\)", timeout=self.timeout * ops) - return self.active_child.before.strip() + return self.active_child.before.strip().decode() def interrupt_all(self): for child in self.children: @@ -678,7 +678,7 @@ class Gdb(object): def where(self): return self.command("where 1") -class PrivateState(object): +class PrivateState: def __init__(self, gdb): self.gdb = gdb @@ -706,9 +706,9 @@ def run_all_tests(module, target, parsed): for hart in target.harts: if parsed.misaval: hart.misa = int(parsed.misaval, 16) - print "Using $misa from command line: 0x%x" % hart.misa + print("Using $misa from command line: 0x%x" % hart.misa) elif hart.misa: - print "Using $misa from hart definition: 0x%x" % hart.misa + print("Using $misa from hart definition: 0x%x" % hart.misa) elif not examine_added: todo.append(("ExamineTarget", ExamineTarget, None)) examine_added = True @@ -735,7 +735,7 @@ def run_tests(parsed, target, todo): log_name = os.path.join(parsed.logs, "%s-%s-%s.log" % (time.strftime("%Y%m%d-%H%M%S"), type(target).__name__, name)) log_fd = open(log_name, 'w') - print "[%s] Starting > %s" % (name, log_name) + print("[%s] Starting > %s" % (name, log_name)) instance = definition(target, hart) sys.stdout.flush() log_fd.write("Test: %s\n" % name) @@ -754,7 +754,7 @@ def run_tests(parsed, target, todo): sys.stdout = real_stdout log_fd.write("Time elapsed: %.2fs\n" % (time.time() - start)) log_fd.flush() - print "[%s] %s in %.2fs" % (name, result, time.time() - start) + print("[%s] %s in %.2fs" % (name, result, time.time() - start)) if result not in good_results and parsed.print_failures: sys.stdout.write(open(log_name).read()) sys.stdout.flush() @@ -767,12 +767,12 @@ def run_tests(parsed, target, todo): def print_results(results): result = 0 - for key, value in results.iteritems(): - print "%d tests returned %s" % (len(value), key) + for key, value in results.items(): + print("%d tests returned %s" % (len(value), key)) if key not in good_results: result = 1 for name, log_name in value: - print " %s > %s" % (name, log_name) + print(" %s > %s" % (name, log_name)) return result @@ -797,22 +797,22 @@ def add_test_run_options(parser): def header(title, dash='-', length=78): if title: dashes = dash * (length - 4 - len(title)) - before = dashes[:len(dashes)/2] - after = dashes[len(dashes)/2:] - print "%s[ %s ]%s" % (before, title, after) + before = dashes[:len(dashes)//2] + after = dashes[len(dashes)//2:] + print("%s[ %s ]%s" % (before, title, after)) else: - print dash * length + print(dash * length) def print_log_handle(name, handle): header(name) for l in handle: sys.stdout.write(l) - print + print() def print_log(path): print_log_handle(path, open(path, "r")) -class BaseTest(object): +class BaseTest: compiled = {} def __init__(self, target, hart=None): @@ -893,15 +893,16 @@ class BaseTest(object): else: result = "exception" if isinstance(e, TestFailed): + # pylint: disable=no-member header("Message") - print e.message + print(e.message) header("Traceback") traceback.print_exc(file=sys.stdout) try: self.postMortem() except Exception as e: # pylint: disable=broad-except header("postMortem Exception") - print e + print(e) traceback.print_exc(file=sys.stdout) return result @@ -1007,7 +1008,7 @@ class ExamineTarget(GdbTest): for i in range(26): if hart.misa & (1<