From ed413d1ea904a293ed62bce3d2b32c534c539eed Mon Sep 17 00:00:00 2001 From: theguy147 <37738506+theguy147@users.noreply.github.com> Date: Sun, 10 Oct 2021 17:26:01 +0200 Subject: [PATCH 1/5] feat: measure coverage (#738) --- .gitignore | 2 ++ Makefile | 11 ++++++++++- requirements.txt | 1 + tests/helpers.py | 24 +++++++++++++++++------- 4 files changed, 30 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 19e3cbeaf..628257758 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,5 @@ tests/pylint3.html _build debug.log .pytest_cache +.coverage +htmlcov diff --git a/Makefile b/Makefile index 5b9e87792..06f335e15 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,7 @@ PYLINT_COMMON_PARAMETERS := --jobs=$(PYLINT_JOBS) --suggestion-mode=$(PYLINT_SUG PYLINT_GEF_PARAMETERS := --disable=$(PYLINT_DISABLE) --enable=$(PYLINT_ENABLE) $(PYLINT_COMMON_PARAMETERS) PYLINT_TEST_PARAMETERS := --disable=$(PYLINT_DISABLE) --enable=$(PYLINT_TEST_ENABLE) $(PYLINT_COMMON_PARAMETERS) TARGET := $(shell lscpu | head -1 | sed -e 's/Architecture:\s*//g') +COVERAGE_DIR ?= /tmp/cov GEF_PATH ?= $(shell readlink -f gef.py) TMPDIR ?= /tmp PYTEST_PARAMETERS := --verbose -n $(NB_CORES) @@ -31,12 +32,20 @@ testbins: $(TMPDIR) $(wildcard tests/binaries/*.c) clean: TMPDIR=$(TMPDIR) $(MAKE) -j $(NB_CORES) -C tests/binaries clean - @rm -rf $(TMPDIR) + @rm -rf $(TMPDIR)/gef-* $(TMPDIR)/gef.py || true lint: python3 -m pylint $(PYLINT_GEF_PARAMETERS) $(GEF_PATH) python3 -m pylint $(PYLINT_TEST_PARAMETERS) $(wildcard tests/*.py) +coverage: + @! ( [ -d $(COVERAGE_DIR) ] && echo "COVERAGE_DIR=$(COVERAGE_DIR) exists already") + @mkdir -p $(COVERAGE_DIR) + @COVERAGE_DIR=$(COVERAGE_DIR) $(MAKE) test + @coverage combine $(COVERAGE_DIR)/* + @coverage html --include "*/gef.py" + @rm -rf $(COVERAGE_DIR) + $(TMPDIR): mkdir -p $@ diff --git a/requirements.txt b/requirements.txt index 1b63b5558..22d4a5639 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,3 +5,4 @@ ropper unicorn pytest pytest-xdist +coverage diff --git a/tests/helpers.py b/tests/helpers.py index 55771e534..c7642640e 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -14,6 +14,7 @@ DEFAULT_CONTEXT = "-code -stack" ARCH = (os.getenv("GEF_CI_ARCH") or platform.machine()).lower() CI_VALID_ARCHITECTURES = ("x86_64", "i686", "aarch64", "armv7l") +COVERAGE_DIR = os.getenv("COVERAGE_DIR", "") CommandType = NewType("CommandType", Union[str, Iterable[str]]) @@ -37,16 +38,25 @@ def gdb_run_cmd(cmd: CommandType, before: CommandType = (), after: CommandType = target: Path = DEFAULT_TARGET, strip_ansi: bool = STRIP_ANSI_DEFAULT) -> str: """Execute a command inside GDB. `before` and `after` are lists of commands to be executed before (resp. after) the command to test.""" - command = [ - "gdb", "-q", "-nx", - "-ex", f"source {GEF_PATH}", - "-ex", "gef config gef.debug True" - ] - + command = ["gdb", "-q", "-nx"] + if COVERAGE_DIR: + coverage_file = Path(COVERAGE_DIR) / os.getenv("PYTEST_XDIST_WORKER") + command += _add_command([ + "pi from coverage import Coverage", + f"pi cov = Coverage(data_file=\"{coverage_file}\"," + "auto_data=True, branch=True)", + "pi cov.start()", + ]) + command += _add_command([ + f"source {GEF_PATH}", + "gef config gef.debug True", + ]) command += _add_command(before) command += _add_command(cmd) command += _add_command(after) - command += ["-ex", "quit", "--", target] + if COVERAGE_DIR: + command += _add_command(["pi cov.stop()", "pi cov.save()"]) + command += ["-ex", "quit", "--", str(target)] lines = subprocess.check_output(command, stderr=subprocess.STDOUT).strip().splitlines() output = b"\n".join(lines) From 8719457f67cb8d5c32d9601ffb0adbc9312a52ba Mon Sep 17 00:00:00 2001 From: Zion Date: Wed, 13 Oct 2021 09:15:53 -0700 Subject: [PATCH 2/5] Fix a `max()` call on `None` in `print_guessed_arguments` (#742) --- gef.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gef.py b/gef.py index 904ddf1b8..4ee2dfbdf 100644 --- a/gef.py +++ b/gef.py @@ -8672,7 +8672,9 @@ def __get_current_block_start_address(): pass if not nb_argument: - if is_x86_32(): + if not parameter_set: + nb_argument = 0 + elif is_x86_32(): nb_argument = len(parameter_set) else: nb_argument = max(function_parameters.index(p)+1 for p in parameter_set) From 48ed480c8fb84c52e39d8c7a428c5d9382aa6145 Mon Sep 17 00:00:00 2001 From: Zion Date: Wed, 13 Oct 2021 19:24:24 -0700 Subject: [PATCH 3/5] Resolve Context Trace Symbols (#743) * add symbol resolving for traces --- gef.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/gef.py b/gef.py index 4ee2dfbdf..a6f166136 100644 --- a/gef.py +++ b/gef.py @@ -8832,7 +8832,15 @@ def context_trace(self): insn = next(gef_disassemble(pc, 1)) except gdb.MemoryError: break - items.append(Color.redify("{} {}".format(insn.mnemonic, ", ".join(insn.operands)))) + + # check if the gdb symbol table may know the address + sym_found = gdb_get_location_from_symbol(pc) + symbol = "" + if sym_found: + sym_name, offset = sym_found + symbol = " <{}+{:x}> ".format(sym_name, offset) + + items.append(Color.redify("{}{} {}".format(symbol, insn.mnemonic, ", ".join(insn.operands)))) gef_print("[{}] {}".format(Color.colorify("#{}".format(level), "bold green" if current_frame == orig_frame else "bold pink"), RIGHT_ARROW.join(items))) From 5c2fe285b6bb53acb3ef06fb8409dfba530cfe83 Mon Sep 17 00:00:00 2001 From: Zion Date: Wed, 13 Oct 2021 19:24:46 -0700 Subject: [PATCH 4/5] add thread symbol resolving like traces (#744) --- gef.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/gef.py b/gef.py index a6f166136..a77ab2245 100644 --- a/gef.py +++ b/gef.py @@ -8901,7 +8901,16 @@ def reason(): line += Color.colorify("stopped", "bold red") thread.switch() frame = gdb.selected_frame() - line += " {:s} in {:s} ()".format(Color.colorify("{:#x}".format(frame.pc()), "blue"), Color.colorify(frame.name() or "??", "bold yellow")) + frame_name = frame.name() + + # check if the gdb symbol table may know the address + if not frame_name: + sym_found = gdb_get_location_from_symbol(frame.pc()) + if sym_found: + sym_name, offset = sym_found + frame_name = "<{}+{:x}>".format(sym_name, offset) + + line += " {:s} in {:s} ()".format(Color.colorify("{:#x}".format(frame.pc()), "blue"), Color.colorify(frame_name or "??", "bold yellow")) line += ", reason: {}".format(Color.colorify(reason(), "bold pink")) elif thread.is_exited(): line += Color.colorify("exited", "bold yellow") From 2becf7bea36747b122bd8177ab3100031e2d00ca Mon Sep 17 00:00:00 2001 From: hugsy Date: Thu, 14 Oct 2021 13:01:29 -0700 Subject: [PATCH 5/5] Update `docs/requirements.txt` Fix dependabot security report --- docs/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index baf208dd9..ad4f88966 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1 +1 @@ -mkdocs==1.0.4 \ No newline at end of file +mkdocs>=1.2.3