- def __init__(self,
- cmd=os.path.expandvars("$RISCV/bin/riscv64-unknown-elf-gdb")):
- self.child = pexpect.spawn(cmd)
- self.child.logfile = open("gdb.log", "w")
- self.child.logfile.write("+ %s\n" % cmd)
- self.wait()
- self.command("set confirm off")
- self.command("set width 0")
- self.command("set height 0")
- # Force consistency.
- self.command("set print entry-values no")
+ """A single gdb class which can interact with one or more gdb instances."""
+
+ # pylint: disable=too-many-public-methods
+ # pylint: disable=too-many-instance-attributes
+
+ def __init__(self, ports,
+ cmd=os.path.expandvars("$RISCV/bin/riscv64-unknown-elf-gdb"),
+ timeout=60, binary=None):
+ assert ports
+
+ self.ports = ports
+ self.cmd = cmd
+ self.timeout = timeout
+ self.binary = binary
+
+ self.stack = []
+ self.harts = {}
+
+ self.logfiles = []
+ self.children = []
+ for port in ports:
+ logfile = tempfile.NamedTemporaryFile(prefix="gdb@%d-" % port,
+ suffix=".log")
+ self.logfiles.append(logfile)
+ if print_log_names:
+ real_stdout.write("Temporary gdb log: %s\n" % logfile.name)
+ child = pexpect.spawn(cmd)
+ child.logfile = logfile
+ child.logfile.write("+ %s\n" % cmd)
+ self.children.append(child)
+ self.active_child = self.children[0]
+
+ def connect(self):
+ for port, child in zip(self.ports, self.children):
+ self.select_child(child)
+ self.wait()
+ self.command("set confirm off")
+ self.command("set width 0")
+ self.command("set height 0")
+ # Force consistency.
+ self.command("set print entry-values no")
+ self.command("set remotetimeout %d" % self.timeout)
+ self.command("target extended-remote localhost:%d" % port)
+ if self.binary:
+ self.command("file %s" % self.binary)
+ threads = self.threads()
+ for t in threads:
+ hartid = None
+ if t.name:
+ m = re.search(r"Hart (\d+)", t.name)
+ if m:
+ hartid = int(m.group(1))
+ if hartid is None:
+ if self.harts:
+ hartid = max(self.harts) + 1
+ else:
+ hartid = 0
+ # solo: True iff this is the only thread on this child
+ self.harts[hartid] = {'child': child,
+ 'thread': t,
+ 'solo': len(threads) == 1}
+
+ def __del__(self):
+ for child in self.children:
+ del child
+
+ def one_hart_per_gdb(self):
+ return all(h['solo'] for h in self.harts.itervalues())
+
+ def lognames(self):
+ return [logfile.name for logfile in self.logfiles]
+
+ def select_child(self, child):
+ self.active_child = child
+
+ def select_hart(self, hart):
+ h = self.harts[hart.id]
+ self.select_child(h['child'])
+ if not h['solo']:
+ output = self.command("thread %s" % h['thread'].id, timeout=10)
+ assert "Unknown" not in output
+
+ def push_state(self):
+ self.stack.append({
+ 'active_child': self.active_child
+ })
+
+ def pop_state(self):
+ state = self.stack.pop()
+ self.active_child = state['active_child']