diff --git a/__init__.py b/__init__.py index ac892a10e771f664dfbef8167c9c9f03025cbb24..c9eda4626988c313115c94025f4047da0339e878 100644 --- a/__init__.py +++ b/__init__.py @@ -173,7 +173,8 @@ class GDB_Output(list): class GDB_Instance: PROMPT = "(gdb) " - + TIMEOUT = 20 # * 0.1 s = 2s before checking for exceptions + CSV_mode = False CSV_header = False CSV_REPEAT = 10 @@ -185,6 +186,7 @@ class GDB_Instance: self.package = package self._fout = None self._fcmd = None + self.src = None def start(self, source, init_hook=None): self.src = source @@ -218,6 +220,12 @@ class GDB_Instance: self.execute("file {}".format(source.binary)) def check_results(self, command, expected, results): + try: + return expected.search(results) is not None + except AttributeError: # not a regex + pass + + if expected.startswith(EXPECTED_FILE_PREFIX): expected_filename = expected[len(EXPECTED_FILE_PREFIX):] with open("{}/{}".format(self.src.src_dir, expected_filename)) as expected_file: @@ -225,34 +233,59 @@ class GDB_Instance: return expected in results + def execute_many(self, commands, *args, **kwargs): if not isinstance(commands, list): commands = [commands] return [self.execute(a_command, *args, **kwargs) for a_command in commands] - - def execute(self, command, expected_results=None, expected_stderr=None, may_fail=False): + + + def test_fail(self, details=""): + print("FAILED {}{}".format(self.last_cmd, " ({})".format(details) if details else "")) + import pdb;pdb.set_trace() + pass + + def test_success(self, details=""): + if self.verbose: + print("PASSED") + + def test_expected_fail(self, details=""): + print("EXPECTED FAILURE {}{}".format(self.last_cmd, "({})".format(details) if details else "")) + + def execute(self, command, expected_results=None, expected_stderr=None, may_fail=False, check_stdout=None, check_stderr=None): if GDB_Instance.CSV_header: return GDB_Output(command, "", "", True) assert not isinstance(command, list) - - out, err = self._read_til_prompt(command) + + self.last_cmd = command + self.last_err = None + self.last_out = None + self.last_out, self.last_err = self._read_til_prompt(command) + + if check_stdout is None: + check_stdout = self.check_results + if check_stderr is None: + check_stderr = self.check_results + correct = all([ - not expected_results or self.check_results(command, expected_results, out), - not expected_stderr or self.check_results(command, expected_results, err)]) + not expected_results or check_stdout(command, expected_results, self.last_out), + not expected_stderr or check_stderr(command, expected_results, self.last_err) + ]) - - if correct: - if self.verbose: print("PASSED") + if not (expected_results or expected_stderr): + pass + elif correct: + self.test_success() elif may_fail: - print("EXPECTED FAILURE ({})".format(command)) + self.test_expected_fail() correct = None else: - print("FAILED {}".format(command)) + self.test_fail() if not correct and not may_fail and self.verbose: - for results, name in (out, "stdout"), (err, "stderr"): + for results, name in (self.last_out, "stdout"), (self.last_err, "stderr"): if not results: continue for line in difflib.context_diff(expected_results.split("\n"), results.split("\n"), fromfile='Expected results', tofile='Actual results ({})'.format(name)): @@ -262,7 +295,7 @@ class GDB_Instance: print(expected_results) #print(levenshtein_distance(expected, results)) - return GDB_Output(command, out, err, correct) + return GDB_Output(command, self.last_out, self.last_err, correct) def set_title(self, title): if GDB_Instance.CSV_header: @@ -317,21 +350,35 @@ class GDB_Instance: def read_utf8_buffer(buff): bs = buff.read() return bs.decode("utf-8") if bs else "" - + + timeout = GDB_Instance.TIMEOUT while not out_buffer.endswith(GDB_Instance.PROMPT): try: self._gdb.poll() if self._gdb.returncode is not None: raise TerminatedError(self._gdb.returncode) - out_buffer += read_utf8_buffer(self._gdb.stdout) - err_buffer += read_utf8_buffer(self._gdb.stderr) + out = read_utf8_buffer(self._gdb.stdout) + out_buffer += out + err = read_utf8_buffer(self._gdb.stderr) + err_buffer += err + + if not err and not out and timeout > 0: + timeout -= 1 except IOError: time.sleep(0.1) except KeyboardInterrupt: import pdb;pdb.set_trace() print(out_buffer) + if timeout <= 0 and "(Pdb)" in out_buffer: + print(err_buffer) + print(out_buffer, end="") + print("FORCE QUITTING PDB") + + self._gdb.stdin.write("import os;os._exit(0)\n".encode('ascii')) + raise TerminatedError(None) + out_buffer = out_buffer[:-(len(GDB_Instance.PROMPT))].strip() self._gdb.stderr.flush() while True: @@ -398,7 +445,16 @@ class GDB_Instance: finally: self._fout.close() self._fcmd.close() - + + def get_location(self, text, src_fname=None): + if src_fname is None: + src_fname = "/".join((self.src.src_dir, self.src.srcname)) + + with open(src_fname) as src_f: + for i, line in enumerate(src_f.readlines()): + if text in line: + return i + ##############################################3 def levenshtein_distance(first, second):