Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chess changes breakout for upstream #2469

Draft
wants to merge 100 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 50 commits
Commits
Show all changes
100 commits
Select commit Hold shift + click to select a range
7d5b087
Use my capstone dev branch until fixes are merged into next
ekilmer May 8, 2020
f177ce8
Fix aarch64
ekilmer May 8, 2020
5ee1f15
Fix ARM
ekilmer May 8, 2020
10e49bd
Update Capstone commit to fix arm64 LD1 instruction immediates
ekilmer May 10, 2020
4f69dbc
Ignore coverage tracking for defensive assertions and exceptions
ekilmer May 26, 2020
f35744f
Merge branch 'master' into capstone-5-dev
feliam Jul 9, 2020
4b738bf
ENDBR64 as nop
feliam Jul 9, 2020
be9bdd1
Add lacking x86 tests
feliam Jul 14, 2020
6c24f8d
New x86 instrution test
feliam Jul 14, 2020
be00705
Merge branch 'master' into capstone-5-dev
ekilmer Aug 5, 2020
85b3bbb
Merge branch 'master' into capstone-5-dev
ekilmer Aug 11, 2020
4751e11
Disable write back once we hit our stop in Unicorn emulation
ekilmer Aug 3, 2020
3f21e92
Make emulator reinitialize after write backs are disabled
Sep 14, 2020
416b8b8
Merge branch 'master' into fix-emulate-step
Sep 14, 2020
cfafb6d
Fix linting on test_general
Sep 14, 2020
548fe47
Add a Rust/Unicorn resumption test
Sep 22, 2020
255eb70
Make rusticorn binary actually check behavior
Sep 22, 2020
d689bdd
Merge branch 'fix-emulate-step' into chess
ekilmer Sep 25, 2020
3e646f7
Merge branch 'master' into capstone-5-dev
ekilmer Sep 28, 2020
454a65f
Merge branch 'capstone-5-dev' into chess
ekilmer Sep 28, 2020
a21ea0f
Run CI on chess branch
ekilmer Sep 28, 2020
fd4a63d
Support for pread64 syscall
ekilmer Oct 6, 2020
8d6134f
Delete duplicated test method
Oct 14, 2020
fcbc2de
Merge branch 'master' into fix-emulate-step
Oct 14, 2020
565b35c
Fix addresses and improve error handling
Oct 14, 2020
9405a92
Merge branch 'master' into capstone-5-dev
ekilmer Oct 24, 2020
20c1526
Merge branch 'master' into chess
ekilmer Nov 9, 2020
df4baa7
Fix issue with sphinx autodoc
ekilmer Nov 30, 2020
065516f
Add last_executed_pc property to abstract CPU
ekilmer Jan 20, 2021
cceeb1f
Optionally skip publishing mem read/writes in CPU
ekilmer Jan 21, 2021
6079bce
Shallow copy AMD64RegFile but keep concrete register values
ekilmer Jan 21, 2021
0db7011
Merge branch 'master' into chess
ekilmer Mar 29, 2021
d54307c
Remove call to pkg_resources that breaks custom installation
ekilmer Apr 7, 2021
e0d5f3a
Fix mypy
ekilmer Apr 7, 2021
8577543
Merge branch 'master' into chess
ekilmer Apr 7, 2021
a659442
Merge branch 'fix-emulate-step' into chess
ekilmer Apr 8, 2021
c3d7885
Merge branch 'master' into fix-emulate-step
ekilmer Apr 10, 2021
702260c
Fix Unicorn resume
ekilmer Apr 10, 2021
ac9be30
Merge branch 'fix-emulate-step' into chess
ekilmer Apr 14, 2021
dc64f11
Fix test missed during merge
ekilmer Apr 14, 2021
101596e
Fix more tests missed during merge
ekilmer Apr 15, 2021
ba5597c
staticmethods to get syscall info
ekilmer Apr 30, 2021
5fa3f94
Rework some logging
ekilmer May 27, 2021
bb5d00d
Better logging initialization
ekilmer May 27, 2021
5529d86
Remember to set manticore property on state __enter__
ekilmer Jun 4, 2021
f879bfd
Better log message in sys_recvfrom
ekilmer Jun 4, 2021
f9bcc15
Chess heap tracking work (#2458)
sschriner Jun 4, 2021
b3ecaf6
corrected read_arg in hook_malloc_library
sschriner Jun 4, 2021
27e0754
Add location to alloc info and remove some debugging statements (#2463)
sschriner Jun 23, 2021
0fa906d
Kill Manticore if _any_ state encounters unrecoverable exception
ekilmer Jul 9, 2021
98a87e3
Merge branch 'master' into chess
ekilmer Jul 15, 2021
f3b9234
Merge branch 'master' into capstone-5-dev
ekilmer Jul 27, 2021
3811e3b
Merge branch 'master' into chess
ekilmer Sep 1, 2021
dd8af82
Merge branch 'master' into chess
ekilmer Sep 9, 2021
9c74e8d
Formatting
ekilmer Sep 9, 2021
ccebfbc
Mypy fixes
ekilmer Sep 10, 2021
4156aef
Merge branch 'master' into chess
ekilmer Sep 15, 2021
699deba
Remove unneeded sycall stubs helper function
ekilmer Sep 15, 2021
b6e3d05
Remove unneeded workaround for fast_crash option in memory
ekilmer Sep 15, 2021
7fa386d
Add SMT simplifications for bitvec subtraction
Boyan-MILANOV Nov 17, 2021
abbfa01
Replace operator SUB by built-in '-'
Boyan-MILANOV Nov 17, 2021
de3ced3
Merge branch 'dev-bitvecsub-simplifications' into chess
Boyan-MILANOV Nov 17, 2021
9c0a4ee
Add EXPLICIT fork policy (#2514)
Boyan-MILANOV Jan 4, 2022
26ccdd2
Fix `BitVecExtract` simplification for constant folding (#2524)
Boyan-MILANOV Jan 20, 2022
504ec9c
x86 FXSAVE & FXRSTOR support (#2511)
Boyan-MILANOV Feb 4, 2022
d20e777
Also ignore missing unicorn registers in the fallback emulator (#2531)
Boyan-MILANOV Feb 11, 2022
932ed0c
Revert "x86 FXSAVE & FXRSTOR support (#2511)"
Boyan-MILANOV Feb 15, 2022
a16a011
add ENDBR32 as nop (#2532)
lordidiot Feb 15, 2022
7589f48
Merge branch 'master' into capstone-5-dev
ekilmer Mar 3, 2022
b832407
Remove duplicate x86 ENDBR64 instruction
ekilmer Mar 3, 2022
3a7e4ab
Fix test
ekilmer Mar 3, 2022
11bb256
Fix more errors in tests
ekilmer Mar 3, 2022
ab798c7
Use latest tagged capstone==5.0.0rc2
ekilmer Mar 3, 2022
b762f7d
Merge branch 'master' into chess
ekilmer Apr 21, 2022
19ee948
Revert "x86 FXSAVE & FXRSTOR support (#2511)"
Boyan-MILANOV Feb 15, 2022
26e8c96
Merge branch 'capstone-5-dev' into chess
ekilmer Apr 21, 2022
9828f2c
Formatting
ekilmer Apr 22, 2022
634b6a4
Remove duplicate instruction from bad merge
ekilmer Apr 22, 2022
001683f
Fix bug in register_log_callback (#2542)
kokrui Apr 26, 2022
60b728d
add newfstatat syscall
lordidiot May 7, 2022
d13c4ff
add newfstatat syscall tests
lordidiot May 7, 2022
0f24f64
Merge branch 'add-sys-newfstatat' into test-newfstatat
ekilmer May 9, 2022
313dffa
Initial implementation of sys_rseq
ekilmer May 12, 2022
884a0b1
Fixes to CPUID to support latest glibc
ekilmer May 13, 2022
6c6b8d3
Hook CPUID instruction in emulator
ekilmer May 15, 2022
b824ff1
Use a patched version of Unicorn for CPUID hook in Python bindings
ekilmer May 16, 2022
b084d3f
Update unicorn to cpuid commit
ekilmer May 17, 2022
65a7a5b
Run CI on this branch
ekilmer May 17, 2022
33aa6c5
Use upstream merged result of Unicorn for CPUID hook
ekilmer May 17, 2022
9c3f447
Merge branch 'master' into chess
ekilmer May 23, 2022
73fa4e3
Merge branch 'chess' into fix-latest-glibc
ekilmer May 23, 2022
9ee8b4f
Revert CI run on branch
ekilmer May 23, 2022
cd8235b
Fix Docker image for building unicorn
ekilmer May 23, 2022
937ca98
Merge branch 'chess' into fix-latest-glibc
ekilmer May 23, 2022
d8afc95
Merge branch 'master' into chess
ekilmer May 25, 2022
e761932
Merge branch 'master' into chess
ekilmer Jun 1, 2022
33880e6
Use official Unicorn v2.0.0 release
ekilmer Jul 19, 2022
148f4fd
Merge branch 'master' into chess
ekilmer Jul 21, 2022
f514236
Merge branch 'master' into chess
ekilmer Jul 25, 2022
5d712a0
Add boolean simplifications (#2563)
Boyan-MILANOV Jul 27, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@ exclude_lines =

# We don't bother testing code that's explicitly unimplemented
raise NotImplementedError
raise AssertionError
raise Aarch64InvalidInstruction
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These belong to the Capstone PR, but they could probably be submitted as their own (or not 🤷 ) #1701

2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: CI
on:
push:
branches:
- master
- chess
ekilmer marked this conversation as resolved.
Show resolved Hide resolved
pull_request:
schedule:
# run CI every day even if no PRs/merges occur
Expand Down
17 changes: 10 additions & 7 deletions manticore/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ def main() -> None:
"""
Dispatches execution into one of Manticore's engines: evm or native.
"""
# Only print with Manticore's logger
logging.getLogger().handlers = []
log.init_logging()
Comment on lines +32 to +34
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anything messing around with logging is in an unstable state and needs to be discussed/changed to not break all of the tests... The logging changes should include some documentation on how to use Manticore effectively as a component of a larger project and setting the log levels, redirection, etc.

args = parse_arguments()

if args.no_colors:
Expand Down Expand Up @@ -101,13 +104,13 @@ def positive(value):
help=("A folder name for temporaries and results." "(default mcore_?????)"),
)

current_version = pkg_resources.get_distribution("manticore").version
parser.add_argument(
"--version",
action="version",
version=f"Manticore {current_version}",
help="Show program version information",
)
# current_version = pkg_resources.get_distribution("manticore").version
# parser.add_argument(
# "--version",
# action="version",
# version=f"Manticore {current_version}",
# help="Show program version information",
# )
Comment on lines +107 to +113
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is commented because it breaks on "installs" that just naively copy the Manticore source tree into site-packages (due to the pkg_resources.get_distribution("manticore").version call)

parser.add_argument(
"--config",
type=str,
Expand Down
12 changes: 10 additions & 2 deletions manticore/core/smtlib/solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,8 +254,16 @@ def send(self, cmd: str) -> None:
"""
if self._debug:
logger.debug(">%s", cmd)
self._proc.stdout.flush() # type: ignore
self._proc.stdin.write(f"{cmd}\n") # type: ignore
try:
self._proc.stdout.flush() # type: ignore
self._proc.stdin.write(f"{cmd}\n") # type: ignore
except (BrokenPipeError, IOError) as e:
logger.critical(
f"Solver encountered an error trying to send commands: {e}.\n"
f"\tOutput: {self._proc.stdout}\n\n"
f"\tStderr: {self._proc.stderr}"
)
raise e
ekilmer marked this conversation as resolved.
Show resolved Hide resolved

def recv(self, wait=True) -> Optional[str]:
"""Reads the response from the smtlib solver
Expand Down
1 change: 1 addition & 0 deletions manticore/core/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ def __enter__(self):
new_state._input_symbols = list(self._input_symbols)
new_state._context = copy.copy(self._context)
new_state._id = None
new_state.manticore = self.manticore
ekilmer marked this conversation as resolved.
Show resolved Hide resolved
new_state._total_exec = self._total_exec
self.copy_eventful_state(new_state)

Expand Down
3 changes: 3 additions & 0 deletions manticore/core/worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,9 @@ def run(self, *args):
m._kill_state(current_state.id)
m._publish("did_kill_state", current_state, exc)
current_state = None
# Kill Manticore if _any_ state encounters unrecoverable
# exception/assertion
m.kill()
ekilmer marked this conversation as resolved.
Show resolved Hide resolved
break

# Getting out.
Expand Down
81 changes: 19 additions & 62 deletions manticore/native/cpu/aarch64.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import warnings
from typing import NamedTuple
ekilmer marked this conversation as resolved.
Show resolved Hide resolved
from inspect import signature as inspect_signature

import capstone as cs
import collections
Expand All @@ -16,7 +17,6 @@
Operand,
instruction,
)
from .arm import HighBit, Armv7Operand
from .bitwise import SInt, UInt, ASR, LSL, LSR, ROR, Mask, GetNBits
from .register import Register
from ...core.smtlib import Operators
Expand Down Expand Up @@ -299,45 +299,7 @@ def canonicalize_instruction_name(insn):
# work for B.cond. Instead of being set to something like 'b.eq',
# it just returns 'b'.
name = insn.mnemonic.upper()
name = OP_NAME_MAP.get(name, name)
ops = insn.operands
name_list = name.split(".")

# Make sure MOV (bitmask immediate) and MOV (register) go through 'MOV'.
if (
name == "ORR"
and len(ops) == 3
and ops[1].type == cs.arm64.ARM64_OP_REG
and ops[1].reg in ["WZR", "XZR"]
and not ops[2].is_shifted()
):
name = "MOV"
insn._raw.mnemonic = name.lower().encode("ascii")
del ops[1]

# Map all B.cond variants to a single implementation.
elif len(name_list) == 2 and name_list[0] == "B" and insn.cc != cs.arm64.ARM64_CC_INVALID:
name = "B_cond"

# XXX: BFI is only valid when Rn != 11111:
# https://github.com/aquynh/capstone/issues/1441
elif (
name == "BFI"
and len(ops) == 4
and ops[1].type == cs.arm64.ARM64_OP_REG
and ops[1].reg in ["WZR", "XZR"]
):
name = "BFC"
insn._raw.mnemonic = name.lower().encode("ascii")
del ops[1]

# XXX: CMEQ incorrectly sets the type to 'ARM64_OP_FP' for
# 'cmeq v0.16b, v1.16b, #0':
# https://github.com/aquynh/capstone/issues/1443
elif name == "CMEQ" and len(ops) == 3 and ops[2].type == cs.arm64.ARM64_OP_FP:
ops[2]._type = cs.arm64.ARM64_OP_IMM

return name
return OP_NAME_MAP.get(name, name)

@property
def insn_bit_str(self):
Expand Down Expand Up @@ -2366,13 +2328,15 @@ def _CMEQ_zero(cpu, res_op, reg_op, imm_op):
cpu._cmeq(res_op, reg_op, imm_op, register=False)

@instruction
def CMEQ(cpu, res_op, reg_op, reg_imm_op):
def CMEQ(cpu, res_op, reg_op, reg_imm_op, _bug=0):
"""
Combines CMEQ (register) and CMEQ (zero).

:param res_op: destination register.
:param reg_op: source register.
:param reg_imm_op: source register or immediate (zero).

:param bug: Buggy extra operand https://github.com/aquynh/capstone/issues/1629
"""
assert res_op.type is cs.arm64.ARM64_OP_REG
assert reg_op.type is cs.arm64.ARM64_OP_REG
Expand Down Expand Up @@ -3648,17 +3612,6 @@ def _MOV_to_general(cpu, res_op, reg_op):

# XXX: Check if trapped.

# XXX: Capstone doesn't set 'vess' for this alias:
# https://github.com/aquynh/capstone/issues/1452
if res_op.size == 32:
reg_op.op.vess = cs.arm64.ARM64_VESS_S

elif res_op.size == 64:
reg_op.op.vess = cs.arm64.ARM64_VESS_D

else:
raise Aarch64InvalidInstruction

# The 'instruction' decorator advances PC, so call the original
# method.
cpu.UMOV.__wrapped__(cpu, res_op, reg_op)
Expand Down Expand Up @@ -3851,7 +3804,7 @@ def MRS(cpu, res_op, reg_op):
:param reg_op: source system register.
"""
assert res_op.type is cs.arm64.ARM64_OP_REG
assert reg_op.type is cs.arm64.ARM64_OP_REG_MRS
assert reg_op.type is cs.arm64.ARM64_OP_SYS

insn_rx = "1101010100"
insn_rx += "1" # L
Expand All @@ -3877,7 +3830,7 @@ def MSR(cpu, res_op, reg_op):
:param res_op: destination system register.
:param reg_op: source register.
"""
assert res_op.type is cs.arm64.ARM64_OP_REG_MSR
assert res_op.type is cs.arm64.ARM64_OP_SYS
assert reg_op.type is cs.arm64.ARM64_OP_REG

insn_rx = "1101010100"
Expand Down Expand Up @@ -5168,18 +5121,18 @@ def UMOV(cpu, res_op, reg_op):

reg = reg_op.read()
index = reg_op.op.vector_index
vess = reg_op.op.vess
vas = reg_op.op.vas

if vess == cs.arm64.ARM64_VESS_B:
if vas == cs.arm64.ARM64_VAS_1B:
elem_size = 8

elif vess == cs.arm64.ARM64_VESS_H:
elif vas == cs.arm64.ARM64_VAS_1H:
elem_size = 16

elif vess == cs.arm64.ARM64_VESS_S:
elif vas == cs.arm64.ARM64_VAS_1S:
elem_size = 32

elif vess == cs.arm64.ARM64_VESS_D:
elif vas == cs.arm64.ARM64_VAS_1D:
elem_size = 64

else:
Expand Down Expand Up @@ -5302,6 +5255,9 @@ def get_arguments(self):
for address in self.values_from(self._cpu.STACK):
yield address

def get_return_reg(self):
return "X0"

ekilmer marked this conversation as resolved.
Show resolved Hide resolved
def write_result(self, result):
self._cpu.X0 = result

Expand Down Expand Up @@ -5339,6 +5295,7 @@ def __init__(self, cpu, op, **kwargs):
cs.arm64.ARM64_OP_MEM,
cs.arm64.ARM64_OP_IMM,
cs.arm64.ARM64_OP_FP,
cs.arm64.ARM64_OP_SYS,
cs.arm64.ARM64_OP_BARRIER,
):
raise NotImplementedError(f"Unsupported operand type: '{self.op.type}'")
Expand Down Expand Up @@ -5386,7 +5343,7 @@ def is_extended(self):
def read(self):
if self.type == cs.arm64.ARM64_OP_REG:
return self.cpu.regfile.read(self.reg)
elif self.type == cs.arm64.ARM64_OP_REG_MRS:
elif self.type == cs.arm64.ARM64_OP_REG_MRS or self.type == cs.arm64.ARM64_OP_SYS:
name = SYS_REG_MAP.get(self.op.sys)
if not name:
raise NotImplementedError(f"Unsupported system register: '0x{self.op.sys:x}'")
Expand All @@ -5399,7 +5356,7 @@ def read(self):
def write(self, value):
if self.type == cs.arm64.ARM64_OP_REG:
self.cpu.regfile.write(self.reg, value)
elif self.type == cs.arm64.ARM64_OP_REG_MSR:
elif self.type == cs.arm64.ARM64_OP_REG_MSR or cs.arm64.ARM64_OP_SYS:
name = SYS_REG_MAP.get(self.op.sys)
if not name:
raise NotImplementedError(f"Unsupported system register: '0x{self.op.sys:x}'")
Expand Down
35 changes: 30 additions & 5 deletions manticore/native/cpu/abstractcpu.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,15 @@ def get_arguments(self):
"""
raise NotImplementedError

def get_return_reg(self):
"""
Extract the location a return value will be written to. Produces
a string describing a register where the return value is written to.
:return: return register name
:rtype: string
"""
raise NotImplementedError

def write_result(self, result):
"""
Write the result of a model back to the environment.
Expand Down Expand Up @@ -521,6 +530,7 @@ def __init__(self, regfile: RegisterFile, memory: Memory, **kwargs):
self._instruction_cache: Dict[int, Any] = {}
self._icount = 0
self._last_pc = None
self._last_executed_pc = None
ekilmer marked this conversation as resolved.
Show resolved Hide resolved
self._concrete = kwargs.pop("concrete", False)
self.emu = None
self._break_unicorn_at: Optional[int] = None
Expand All @@ -537,6 +547,7 @@ def __getstate__(self):
state["memory"] = self._memory
state["icount"] = self._icount
state["last_pc"] = self._last_pc
state["last_executed_pc"] = self._last_executed_pc
state["disassembler"] = self._disasm
state["concrete"] = self._concrete
state["break_unicorn_at"] = self._break_unicorn_at
Expand All @@ -553,6 +564,7 @@ def __setstate__(self, state):
)
self._icount = state["icount"]
self._last_pc = state["last_pc"]
self._last_executed_pc = state["last_executed_pc"]
self._disasm = state["disassembler"]
self._concrete = state["concrete"]
self._break_unicorn_at = state["break_unicorn_at"]
Expand All @@ -563,6 +575,14 @@ def __setstate__(self, state):
def icount(self):
return self._icount

@property
def last_executed_pc(self) -> Optional[int]:
return self._last_executed_pc

@property
def last_executed_insn(self):
return self.decode_instruction(self.last_executed_pc)

##############################
# Register access
@property
Expand Down Expand Up @@ -723,7 +743,7 @@ def _raw_read(self, where: int, size: int = 1, force: bool = False) -> bytes:
assert len(data) == size, "Raw read resulted in wrong data read which should never happen"
return data

def read_int(self, where, size=None, force=False):
def read_int(self, where, size=None, force=False, publish=True):
ekilmer marked this conversation as resolved.
Show resolved Hide resolved
"""
Reads int from memory

Expand All @@ -736,13 +756,15 @@ def read_int(self, where, size=None, force=False):
if size is None:
size = self.address_bit_size
assert size in SANE_SIZES
self._publish("will_read_memory", where, size)
if publish:
self._publish("will_read_memory", where, size)

data = self._memory.read(where, size // 8, force)
assert (8 * len(data)) == size
value = Operators.CONCAT(size, *map(Operators.ORD, reversed(data)))

self._publish("did_read_memory", where, value, size)
if publish:
self._publish("did_read_memory", where, value, size)
return value

def write_bytes(self, where: int, data, force: bool = False) -> None:
Expand Down Expand Up @@ -777,7 +799,7 @@ def write_bytes(self, where: int, data, force: bool = False) -> None:
for i in range(len(data)):
self.write_int(where + i, Operators.ORD(data[i]), 8, force)

def read_bytes(self, where: int, size: int, force: bool = False):
def read_bytes(self, where: int, size: int, force: bool = False, publish=True):
"""
Read from memory.

Expand All @@ -789,7 +811,7 @@ def read_bytes(self, where: int, size: int, force: bool = False):
"""
result = []
for i in range(size):
result.append(Operators.CHR(self.read_int(where + i, 8, force)))
result.append(Operators.CHR(self.read_int(where + i, 8, force, publish=publish)))
return result

def write_string(
Expand Down Expand Up @@ -976,6 +998,7 @@ def execute(self):
"""
curpc = self.PC
if self._delayed_event:
self._last_executed_pc = self._last_pc
self._icount += 1
self._publish(
"did_execute_instruction",
Expand All @@ -1000,6 +1023,7 @@ def execute(self):
# FIXME (theo) why just return here?
# hook changed PC, so we trust that there is nothing more to do
if insn.address != self.PC:
self._last_executed_pc = self.PC
return

name = self.canonicalize_instruction_name(insn)
Expand Down Expand Up @@ -1047,6 +1071,7 @@ def _publish_instruction_as_executed(self, insn):
"""
Notify listeners that an instruction has been executed.
"""
self._last_executed_pc = self._last_pc
self._icount += 1
self._publish("did_execute_instruction", self._last_pc, self.PC, insn)

Expand Down
Loading