We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Cleanup/optimize break_next_call: compile regex once
The `break_next_call` function which steps through the execution has this functionality that it can stop on a target symbol checked via a regular expression.

However, both the regular expression as well as the string provided to it are constructed on each loop iteration (!). While Python regexes are cached internally, we should not rely on this functionality.

https://github.com/pwndbg/pwndbg/blob/e37591b25d923b1933b7092cacafa51a210d5f5e/pwndbg/gdblib/next.py#L107-L113

Effectively, this issue is just about doing something like:
```py
symbol_re = re.compile(f"{symbol_regex}$")

while ...:
    if ... and symbol_re.match(...): ...
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pwndbg/gdblib/next.py`
Content:
```
1 """
2 Commands for setting temporary breakpoints on the next
3 instruction of some type (call, branch, etc.)
4 """
5 
6 import re
7 from itertools import chain
8 
9 import capstone
10 import gdb
11 
12 import pwndbg.disasm
13 import pwndbg.gdblib.events
14 import pwndbg.gdblib.proc
15 import pwndbg.gdblib.regs
16 from pwndbg.color import message
17 
18 jumps = {capstone.CS_GRP_CALL, capstone.CS_GRP_JUMP, capstone.CS_GRP_RET, capstone.CS_GRP_IRET}
19 
20 interrupts = {capstone.CS_GRP_INT}
21 
22 
23 def clear_temp_breaks() -> None:
24     if not pwndbg.gdblib.proc.alive:
25         for bp in gdb.breakpoints():
26             # visible is used instead of internal because older gdb's don't support internal
27             if bp.temporary and not bp.visible:
28                 bp.delete()
29 
30 
31 def next_int(address=None):
32     """
33     If there is a syscall in the current basic black,
34     return the instruction of the one closest to $PC.
35 
36     Otherwise, return None.
37     """
38     if address is None:
39         ins = pwndbg.disasm.one(pwndbg.gdblib.regs.pc)
40         if not ins:
41             return None
42         address = ins.next
43 
44     ins = pwndbg.disasm.one(address)
45     while ins:
46         ins_groups = set(ins.groups)
47         if ins_groups & jumps:
48             return None
49         elif ins_groups & interrupts:
50             return ins
51         ins = pwndbg.disasm.one(ins.next)
52 
53     return None
54 
55 
56 def next_branch(address=None):
57     if address is None:
58         ins = pwndbg.disasm.one(pwndbg.gdblib.regs.pc)
59         if not ins:
60             return None
61         address = ins.next
62 
63     ins = pwndbg.disasm.one(address)
64     while ins:
65         if set(ins.groups) & jumps:
66             return ins
67         ins = pwndbg.disasm.one(ins.next)
68 
69     return None
70 
71 
72 def next_matching_until_branch(address=None, mnemonic=None, op_str=None):
73     """
74     Finds the next instruction that matches the arguments between the given
75     address and the branch closest to it.
76     """
77     if address is None:
78         address = pwndbg.gdblib.regs.pc
79 
80     ins = pwndbg.disasm.one(address)
81     while ins:
82         # Check whether or not the mnemonic matches if it was specified
83         mnemonic_match = ins.mnemonic.casefold() == mnemonic.casefold() if mnemonic else True
84 
85         # Check whether or not the operands match if they were specified
86         op_str_match = True
87         if op_str is not None:
88             op_str_match = False
89 
90             # Remove whitespace and fold the case of both targets.
91             ops = "".join(ins.op_str.split()).casefold()
92             if isinstance(op_str, str):
93                 op_str = "".join(op_str.split()).casefold()
94             elif isinstance(op_str, list):
95                 op_str = "".join(chain.from_iterable(op.split() for op in op_str)).casefold()
96             else:
97                 raise ValueError("op_str value is of an unsupported type")
98             op_str_match = ops == op_str
99 
100         # If all of the parameters that were specified match, this is the
101         # instruction we want to stop at.
102         if mnemonic_match and op_str_match:
103             return ins
104 
105         if set(ins.groups) & jumps:
106             # No matching instruction until the next branch, and we're
107             # not trying to match the branch instruction itself.
108             return None
109 
110         ins = pwndbg.disasm.one(ins.next)
111     return None
112 
113 
114 def break_next_branch(address=None):
115     ins = next_branch(address)
116 
117     if ins:
118         gdb.Breakpoint("*%#x" % ins.address, internal=True, temporary=True)
119         gdb.execute("continue", from_tty=False, to_string=True)
120         return ins
121 
122 
123 def break_next_interrupt(address=None):
124     ins = next_int(address)
125 
126     if ins:
127         gdb.Breakpoint("*%#x" % ins.address, internal=True, temporary=True)
128         gdb.execute("continue", from_tty=False, to_string=True)
129         return ins
130 
131 
132 def break_next_call(symbol_regex=None):
133     while pwndbg.gdblib.proc.alive:
134         # Break on signal as it may be a segfault
135         if pwndbg.gdblib.proc.stopped_with_signal:
136             return
137 
138         ins = break_next_branch()
139 
140         if not ins:
141             break
142 
143         # continue if not a call
144         if capstone.CS_GRP_CALL not in ins.groups:
145             continue
146 
147         # return call if we don't search for a symbol
148         if not symbol_regex:
149             return ins
150 
151         # return call if we match target address
152         if ins.target_const and re.match(f"{symbol_regex}$", hex(ins.target)):
153             return ins
154 
155         # return call if we match symbol name
156         if ins.symbol and re.match(f"{symbol_regex}$", ins.symbol):
157             return ins
158 
159 
160 def break_next_ret(address=None):
161     while pwndbg.gdblib.proc.alive:
162         # Break on signal as it may be a segfault
163         if pwndbg.gdblib.proc.stopped_with_signal:
164             return
165 
166         ins = break_next_branch(address)
167 
168         if not ins:
169             break
170 
171         if capstone.CS_GRP_RET in ins.groups:
172             return ins
173 
174 
175 def break_on_next_matching_instruction(mnemonic=None, op_str=None) -> bool:
176     """
177     Breaks on next instuction that matches the arguments.
178     """
179     # Make sure we have something to break on.
180     if mnemonic is None and op_str is None:
181         return False
182 
183     while pwndbg.gdblib.proc.alive:
184         # Break on signal as it may be a segfault
185         if pwndbg.gdblib.proc.stopped_with_signal:
186             return False
187 
188         ins = next_matching_until_branch(mnemonic=mnemonic, op_str=op_str)
189         if ins is not None:
190             if ins.address != pwndbg.gdblib.regs.pc:
191                 print("Found instruction")
192                 # Only set breakpoints at a different PC location, otherwise we
193                 # will continue until we hit a breakpoint that's not related to
194                 # this opeeration, or the program halts.
195                 gdb.Breakpoint("*%#x" % ins.address, internal=True, temporary=True)
196                 gdb.execute("continue", from_tty=False, to_string=True)
197                 return ins
198             else:
199                 # We don't want to be spinning in place, nudge execution forward
200                 # and try again.
201                 pass
202         else:
203             # Move to the next branch instruction.
204             print("Moving to next branch")
205             nb = next_branch(pwndbg.gdblib.regs.pc)
206             if nb is not None:
207                 if nb.address != pwndbg.gdblib.regs.pc:
208                     # Stop right at the next branch instruction.
209                     gdb.Breakpoint("*%#x" % nb.address, internal=True, temporary=True)
210                     gdb.execute("continue", from_tty=False, to_string=True)
211                 else:
212                     # Nudge execution so we take the branch we're on top of.
213                     pass
214 
215         if pwndbg.gdblib.proc.alive:
216             gdb.execute("si")
217 
218     return False
219 
220 
221 def break_on_program_code() -> bool:
222     """
223     Breaks on next instruction that belongs to process' objfile code
224 
225     :return: True for success, False when process ended or when pc is not at the code or if a signal occurred
226     """
227     exe = pwndbg.gdblib.proc.exe
228     binary_exec_page_ranges = tuple(
229         (p.start, p.end) for p in pwndbg.gdblib.vmmap.get() if p.objfile == exe and p.execute
230     )
231 
232     pc = pwndbg.gdblib.regs.pc
233     for start, end in binary_exec_page_ranges:
234         if start <= pc < end:
235             print(message.error("The pc is already at the binary objfile code. Not stepping."))
236             return False
237 
238     proc = pwndbg.gdblib.proc
239     regs = pwndbg.gdblib.regs
240 
241     while proc.alive:
242         # Break on signal as it may be a segfault
243         if proc.stopped_with_signal:
244             return False
245 
246         o = gdb.execute("si", from_tty=False, to_string=True)
247 
248         for start, end in binary_exec_page_ranges:
249             if start <= regs.pc < end:
250                 return True
251 
252     return False
253 
254 
255 def break_on_next(address=None) -> None:
256     address = address or pwndbg.gdblib.regs.pc
257     ins = pwndbg.disasm.one(address)
258 
259     gdb.Breakpoint("*%#x" % (ins.address + ins.size), temporary=True)
260     gdb.execute("continue", from_tty=False, to_string=True)
261
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/pwndbg/gdblib/next.py b/pwndbg/gdblib/next.py
--- a/pwndbg/gdblib/next.py
+++ b/pwndbg/gdblib/next.py
@@ -130,6 +130,8 @@
 
 
 def break_next_call(symbol_regex=None):
+    symbol_regex = re.compile(symbol_regex) if symbol_regex else None
+
     while pwndbg.gdblib.proc.alive:
         # Break on signal as it may be a segfault
         if pwndbg.gdblib.proc.stopped_with_signal:
@@ -144,16 +146,15 @@
         if capstone.CS_GRP_CALL not in ins.groups:
             continue
 
-        # return call if we don't search for a symbol
-        if not symbol_regex:
-            return ins
-
-        # return call if we match target address
-        if ins.target_const and re.match(f"{symbol_regex}$", hex(ins.target)):
-            return ins
-
-        # return call if we match symbol name
-        if ins.symbol and re.match(f"{symbol_regex}$", ins.symbol):
+        # return call if we:
+        # 1) don't search for a symbol
+        # 2) match target address
+        # 3) match symbol name
+        if (
+            not symbol_regex
+            or (ins.target_const and symbol_regex.match(hex(ins.target)))
+            or (ins.symbol and symbol_regex.match(ins.symbol))
+        ):
             return ins

{"golden_diff": "diff --git a/pwndbg/gdblib/next.py b/pwndbg/gdblib/next.py\n--- a/pwndbg/gdblib/next.py\n+++ b/pwndbg/gdblib/next.py\n@@ -130,6 +130,8 @@\n \n \n def break_next_call(symbol_regex=None):\n+    symbol_regex = re.compile(symbol_regex) if symbol_regex else None\n+\n     while pwndbg.gdblib.proc.alive:\n         # Break on signal as it may be a segfault\n         if pwndbg.gdblib.proc.stopped_with_signal:\n@@ -144,16 +146,15 @@\n         if capstone.CS_GRP_CALL not in ins.groups:\n             continue\n \n-        # return call if we don't search for a symbol\n-        if not symbol_regex:\n-            return ins\n-\n-        # return call if we match target address\n-        if ins.target_const and re.match(f\"{symbol_regex}$\", hex(ins.target)):\n-            return ins\n-\n-        # return call if we match symbol name\n-        if ins.symbol and re.match(f\"{symbol_regex}$\", ins.symbol):\n+        # return call if we:\n+        # 1) don't search for a symbol\n+        # 2) match target address\n+        # 3) match symbol name\n+        if (\n+            not symbol_regex\n+            or (ins.target_const and symbol_regex.match(hex(ins.target)))\n+            or (ins.symbol and symbol_regex.match(ins.symbol))\n+        ):\n             return ins\n", "issue": "Cleanup/optimize break_next_call: compile regex once\nThe `break_next_call` function which steps through the execution has this functionality that it can stop on a target symbol checked via a regular expression.\r\n\r\nHowever, both the regular expression as well as the string provided to it are constructed on each loop iteration (!). While Python regexes are cached internally, we should not rely on this functionality.\r\n\r\nhttps://github.com/pwndbg/pwndbg/blob/e37591b25d923b1933b7092cacafa51a210d5f5e/pwndbg/gdblib/next.py#L107-L113\r\n\r\nEffectively, this issue is just about doing something like:\r\n```py\r\nsymbol_re = re.compile(f\"{symbol_regex}$\")\r\n\r\nwhile ...:\r\n    if ... and symbol_re.match(...): ...\r\n```\n", "before_files": [{"content": "\"\"\"\nCommands for setting temporary breakpoints on the next\ninstruction of some type (call, branch, etc.)\n\"\"\"\n\nimport re\nfrom itertools import chain\n\nimport capstone\nimport gdb\n\nimport pwndbg.disasm\nimport pwndbg.gdblib.events\nimport pwndbg.gdblib.proc\nimport pwndbg.gdblib.regs\nfrom pwndbg.color import message\n\njumps = {capstone.CS_GRP_CALL, capstone.CS_GRP_JUMP, capstone.CS_GRP_RET, capstone.CS_GRP_IRET}\n\ninterrupts = {capstone.CS_GRP_INT}\n\n\ndef clear_temp_breaks() -> None:\n    if not pwndbg.gdblib.proc.alive:\n        for bp in gdb.breakpoints():\n            # visible is used instead of internal because older gdb's don't support internal\n            if bp.temporary and not bp.visible:\n                bp.delete()\n\n\ndef next_int(address=None):\n    \"\"\"\n    If there is a syscall in the current basic black,\n    return the instruction of the one closest to $PC.\n\n    Otherwise, return None.\n    \"\"\"\n    if address is None:\n        ins = pwndbg.disasm.one(pwndbg.gdblib.regs.pc)\n        if not ins:\n            return None\n        address = ins.next\n\n    ins = pwndbg.disasm.one(address)\n    while ins:\n        ins_groups = set(ins.groups)\n        if ins_groups & jumps:\n            return None\n        elif ins_groups & interrupts:\n            return ins\n        ins = pwndbg.disasm.one(ins.next)\n\n    return None\n\n\ndef next_branch(address=None):\n    if address is None:\n        ins = pwndbg.disasm.one(pwndbg.gdblib.regs.pc)\n        if not ins:\n            return None\n        address = ins.next\n\n    ins = pwndbg.disasm.one(address)\n    while ins:\n        if set(ins.groups) & jumps:\n            return ins\n        ins = pwndbg.disasm.one(ins.next)\n\n    return None\n\n\ndef next_matching_until_branch(address=None, mnemonic=None, op_str=None):\n    \"\"\"\n    Finds the next instruction that matches the arguments between the given\n    address and the branch closest to it.\n    \"\"\"\n    if address is None:\n        address = pwndbg.gdblib.regs.pc\n\n    ins = pwndbg.disasm.one(address)\n    while ins:\n        # Check whether or not the mnemonic matches if it was specified\n        mnemonic_match = ins.mnemonic.casefold() == mnemonic.casefold() if mnemonic else True\n\n        # Check whether or not the operands match if they were specified\n        op_str_match = True\n        if op_str is not None:\n            op_str_match = False\n\n            # Remove whitespace and fold the case of both targets.\n            ops = \"\".join(ins.op_str.split()).casefold()\n            if isinstance(op_str, str):\n                op_str = \"\".join(op_str.split()).casefold()\n            elif isinstance(op_str, list):\n                op_str = \"\".join(chain.from_iterable(op.split() for op in op_str)).casefold()\n            else:\n                raise ValueError(\"op_str value is of an unsupported type\")\n            op_str_match = ops == op_str\n\n        # If all of the parameters that were specified match, this is the\n        # instruction we want to stop at.\n        if mnemonic_match and op_str_match:\n            return ins\n\n        if set(ins.groups) & jumps:\n            # No matching instruction until the next branch, and we're\n            # not trying to match the branch instruction itself.\n            return None\n\n        ins = pwndbg.disasm.one(ins.next)\n    return None\n\n\ndef break_next_branch(address=None):\n    ins = next_branch(address)\n\n    if ins:\n        gdb.Breakpoint(\"*%#x\" % ins.address, internal=True, temporary=True)\n        gdb.execute(\"continue\", from_tty=False, to_string=True)\n        return ins\n\n\ndef break_next_interrupt(address=None):\n    ins = next_int(address)\n\n    if ins:\n        gdb.Breakpoint(\"*%#x\" % ins.address, internal=True, temporary=True)\n        gdb.execute(\"continue\", from_tty=False, to_string=True)\n        return ins\n\n\ndef break_next_call(symbol_regex=None):\n    while pwndbg.gdblib.proc.alive:\n        # Break on signal as it may be a segfault\n        if pwndbg.gdblib.proc.stopped_with_signal:\n            return\n\n        ins = break_next_branch()\n\n        if not ins:\n            break\n\n        # continue if not a call\n        if capstone.CS_GRP_CALL not in ins.groups:\n            continue\n\n        # return call if we don't search for a symbol\n        if not symbol_regex:\n            return ins\n\n        # return call if we match target address\n        if ins.target_const and re.match(f\"{symbol_regex}$\", hex(ins.target)):\n            return ins\n\n        # return call if we match symbol name\n        if ins.symbol and re.match(f\"{symbol_regex}$\", ins.symbol):\n            return ins\n\n\ndef break_next_ret(address=None):\n    while pwndbg.gdblib.proc.alive:\n        # Break on signal as it may be a segfault\n        if pwndbg.gdblib.proc.stopped_with_signal:\n            return\n\n        ins = break_next_branch(address)\n\n        if not ins:\n            break\n\n        if capstone.CS_GRP_RET in ins.groups:\n            return ins\n\n\ndef break_on_next_matching_instruction(mnemonic=None, op_str=None) -> bool:\n    \"\"\"\n    Breaks on next instuction that matches the arguments.\n    \"\"\"\n    # Make sure we have something to break on.\n    if mnemonic is None and op_str is None:\n        return False\n\n    while pwndbg.gdblib.proc.alive:\n        # Break on signal as it may be a segfault\n        if pwndbg.gdblib.proc.stopped_with_signal:\n            return False\n\n        ins = next_matching_until_branch(mnemonic=mnemonic, op_str=op_str)\n        if ins is not None:\n            if ins.address != pwndbg.gdblib.regs.pc:\n                print(\"Found instruction\")\n                # Only set breakpoints at a different PC location, otherwise we\n                # will continue until we hit a breakpoint that's not related to\n                # this opeeration, or the program halts.\n                gdb.Breakpoint(\"*%#x\" % ins.address, internal=True, temporary=True)\n                gdb.execute(\"continue\", from_tty=False, to_string=True)\n                return ins\n            else:\n                # We don't want to be spinning in place, nudge execution forward\n                # and try again.\n                pass\n        else:\n            # Move to the next branch instruction.\n            print(\"Moving to next branch\")\n            nb = next_branch(pwndbg.gdblib.regs.pc)\n            if nb is not None:\n                if nb.address != pwndbg.gdblib.regs.pc:\n                    # Stop right at the next branch instruction.\n                    gdb.Breakpoint(\"*%#x\" % nb.address, internal=True, temporary=True)\n                    gdb.execute(\"continue\", from_tty=False, to_string=True)\n                else:\n                    # Nudge execution so we take the branch we're on top of.\n                    pass\n\n        if pwndbg.gdblib.proc.alive:\n            gdb.execute(\"si\")\n\n    return False\n\n\ndef break_on_program_code() -> bool:\n    \"\"\"\n    Breaks on next instruction that belongs to process' objfile code\n\n    :return: True for success, False when process ended or when pc is not at the code or if a signal occurred\n    \"\"\"\n    exe = pwndbg.gdblib.proc.exe\n    binary_exec_page_ranges = tuple(\n        (p.start, p.end) for p in pwndbg.gdblib.vmmap.get() if p.objfile == exe and p.execute\n    )\n\n    pc = pwndbg.gdblib.regs.pc\n    for start, end in binary_exec_page_ranges:\n        if start <= pc < end:\n            print(message.error(\"The pc is already at the binary objfile code. Not stepping.\"))\n            return False\n\n    proc = pwndbg.gdblib.proc\n    regs = pwndbg.gdblib.regs\n\n    while proc.alive:\n        # Break on signal as it may be a segfault\n        if proc.stopped_with_signal:\n            return False\n\n        o = gdb.execute(\"si\", from_tty=False, to_string=True)\n\n        for start, end in binary_exec_page_ranges:\n            if start <= regs.pc < end:\n                return True\n\n    return False\n\n\ndef break_on_next(address=None) -> None:\n    address = address or pwndbg.gdblib.regs.pc\n    ins = pwndbg.disasm.one(address)\n\n    gdb.Breakpoint(\"*%#x\" % (ins.address + ins.size), temporary=True)\n    gdb.execute(\"continue\", from_tty=False, to_string=True)\n", "path": "pwndbg/gdblib/next.py"}], "after_files": [{"content": "\"\"\"\nCommands for setting temporary breakpoints on the next\ninstruction of some type (call, branch, etc.)\n\"\"\"\n\nimport re\nfrom itertools import chain\n\nimport capstone\nimport gdb\n\nimport pwndbg.disasm\nimport pwndbg.gdblib.events\nimport pwndbg.gdblib.proc\nimport pwndbg.gdblib.regs\nfrom pwndbg.color import message\n\njumps = {capstone.CS_GRP_CALL, capstone.CS_GRP_JUMP, capstone.CS_GRP_RET, capstone.CS_GRP_IRET}\n\ninterrupts = {capstone.CS_GRP_INT}\n\n\ndef clear_temp_breaks() -> None:\n    if not pwndbg.gdblib.proc.alive:\n        for bp in gdb.breakpoints():\n            # visible is used instead of internal because older gdb's don't support internal\n            if bp.temporary and not bp.visible:\n                bp.delete()\n\n\ndef next_int(address=None):\n    \"\"\"\n    If there is a syscall in the current basic black,\n    return the instruction of the one closest to $PC.\n\n    Otherwise, return None.\n    \"\"\"\n    if address is None:\n        ins = pwndbg.disasm.one(pwndbg.gdblib.regs.pc)\n        if not ins:\n            return None\n        address = ins.next\n\n    ins = pwndbg.disasm.one(address)\n    while ins:\n        ins_groups = set(ins.groups)\n        if ins_groups & jumps:\n            return None\n        elif ins_groups & interrupts:\n            return ins\n        ins = pwndbg.disasm.one(ins.next)\n\n    return None\n\n\ndef next_branch(address=None):\n    if address is None:\n        ins = pwndbg.disasm.one(pwndbg.gdblib.regs.pc)\n        if not ins:\n            return None\n        address = ins.next\n\n    ins = pwndbg.disasm.one(address)\n    while ins:\n        if set(ins.groups) & jumps:\n            return ins\n        ins = pwndbg.disasm.one(ins.next)\n\n    return None\n\n\ndef next_matching_until_branch(address=None, mnemonic=None, op_str=None):\n    \"\"\"\n    Finds the next instruction that matches the arguments between the given\n    address and the branch closest to it.\n    \"\"\"\n    if address is None:\n        address = pwndbg.gdblib.regs.pc\n\n    ins = pwndbg.disasm.one(address)\n    while ins:\n        # Check whether or not the mnemonic matches if it was specified\n        mnemonic_match = ins.mnemonic.casefold() == mnemonic.casefold() if mnemonic else True\n\n        # Check whether or not the operands match if they were specified\n        op_str_match = True\n        if op_str is not None:\n            op_str_match = False\n\n            # Remove whitespace and fold the case of both targets.\n            ops = \"\".join(ins.op_str.split()).casefold()\n            if isinstance(op_str, str):\n                op_str = \"\".join(op_str.split()).casefold()\n            elif isinstance(op_str, list):\n                op_str = \"\".join(chain.from_iterable(op.split() for op in op_str)).casefold()\n            else:\n                raise ValueError(\"op_str value is of an unsupported type\")\n            op_str_match = ops == op_str\n\n        # If all of the parameters that were specified match, this is the\n        # instruction we want to stop at.\n        if mnemonic_match and op_str_match:\n            return ins\n\n        if set(ins.groups) & jumps:\n            # No matching instruction until the next branch, and we're\n            # not trying to match the branch instruction itself.\n            return None\n\n        ins = pwndbg.disasm.one(ins.next)\n    return None\n\n\ndef break_next_branch(address=None):\n    ins = next_branch(address)\n\n    if ins:\n        gdb.Breakpoint(\"*%#x\" % ins.address, internal=True, temporary=True)\n        gdb.execute(\"continue\", from_tty=False, to_string=True)\n        return ins\n\n\ndef break_next_interrupt(address=None):\n    ins = next_int(address)\n\n    if ins:\n        gdb.Breakpoint(\"*%#x\" % ins.address, internal=True, temporary=True)\n        gdb.execute(\"continue\", from_tty=False, to_string=True)\n        return ins\n\n\ndef break_next_call(symbol_regex=None):\n    symbol_regex = re.compile(symbol_regex) if symbol_regex else None\n\n    while pwndbg.gdblib.proc.alive:\n        # Break on signal as it may be a segfault\n        if pwndbg.gdblib.proc.stopped_with_signal:\n            return\n\n        ins = break_next_branch()\n\n        if not ins:\n            break\n\n        # continue if not a call\n        if capstone.CS_GRP_CALL not in ins.groups:\n            continue\n\n        # return call if we:\n        # 1) don't search for a symbol\n        # 2) match target address\n        # 3) match symbol name\n        if (\n            not symbol_regex\n            or (ins.target_const and symbol_regex.match(hex(ins.target)))\n            or (ins.symbol and symbol_regex.match(ins.symbol))\n        ):\n            return ins\n\n\ndef break_next_ret(address=None):\n    while pwndbg.gdblib.proc.alive:\n        # Break on signal as it may be a segfault\n        if pwndbg.gdblib.proc.stopped_with_signal:\n            return\n\n        ins = break_next_branch(address)\n\n        if not ins:\n            break\n\n        if capstone.CS_GRP_RET in ins.groups:\n            return ins\n\n\ndef break_on_next_matching_instruction(mnemonic=None, op_str=None) -> bool:\n    \"\"\"\n    Breaks on next instuction that matches the arguments.\n    \"\"\"\n    # Make sure we have something to break on.\n    if mnemonic is None and op_str is None:\n        return False\n\n    while pwndbg.gdblib.proc.alive:\n        # Break on signal as it may be a segfault\n        if pwndbg.gdblib.proc.stopped_with_signal:\n            return False\n\n        ins = next_matching_until_branch(mnemonic=mnemonic, op_str=op_str)\n        if ins is not None:\n            if ins.address != pwndbg.gdblib.regs.pc:\n                print(\"Found instruction\")\n                # Only set breakpoints at a different PC location, otherwise we\n                # will continue until we hit a breakpoint that's not related to\n                # this opeeration, or the program halts.\n                gdb.Breakpoint(\"*%#x\" % ins.address, internal=True, temporary=True)\n                gdb.execute(\"continue\", from_tty=False, to_string=True)\n                return ins\n            else:\n                # We don't want to be spinning in place, nudge execution forward\n                # and try again.\n                pass\n        else:\n            # Move to the next branch instruction.\n            print(\"Moving to next branch\")\n            nb = next_branch(pwndbg.gdblib.regs.pc)\n            if nb is not None:\n                if nb.address != pwndbg.gdblib.regs.pc:\n                    # Stop right at the next branch instruction.\n                    gdb.Breakpoint(\"*%#x\" % nb.address, internal=True, temporary=True)\n                    gdb.execute(\"continue\", from_tty=False, to_string=True)\n                else:\n                    # Nudge execution so we take the branch we're on top of.\n                    pass\n\n        if pwndbg.gdblib.proc.alive:\n            gdb.execute(\"si\")\n\n    return False\n\n\ndef break_on_program_code() -> bool:\n    \"\"\"\n    Breaks on next instruction that belongs to process' objfile code\n\n    :return: True for success, False when process ended or when pc is not at the code or if a signal occurred\n    \"\"\"\n    exe = pwndbg.gdblib.proc.exe\n    binary_exec_page_ranges = tuple(\n        (p.start, p.end) for p in pwndbg.gdblib.vmmap.get() if p.objfile == exe and p.execute\n    )\n\n    pc = pwndbg.gdblib.regs.pc\n    for start, end in binary_exec_page_ranges:\n        if start <= pc < end:\n            print(message.error(\"The pc is already at the binary objfile code. Not stepping.\"))\n            return False\n\n    proc = pwndbg.gdblib.proc\n    regs = pwndbg.gdblib.regs\n\n    while proc.alive:\n        # Break on signal as it may be a segfault\n        if proc.stopped_with_signal:\n            return False\n\n        o = gdb.execute(\"si\", from_tty=False, to_string=True)\n\n        for start, end in binary_exec_page_ranges:\n            if start <= regs.pc < end:\n                return True\n\n    return False\n\n\ndef break_on_next(address=None) -> None:\n    address = address or pwndbg.gdblib.regs.pc\n    ins = pwndbg.disasm.one(address)\n\n    gdb.Breakpoint(\"*%#x\" % (ins.address + ins.size), temporary=True)\n    gdb.execute(\"continue\", from_tty=False, to_string=True)\n", "path": "pwndbg/gdblib/next.py"}]}