We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
An error occurred while analysis the CFG of the mips program.
An error occurs when I use angr to analyze the CFG of the mips program (net-cgi). 
The error message is shown below.

>  File "/home/user/PycharmProjects/pythonProject/venv/lib/python3.8/site-packages/angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py", line 106, in _resolve
    gp_used = self._is_gp_used_on_slice(project, b)
  File "/home/user/PycharmProjects/pythonProject/venv/lib/python3.8/site-packages/angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py", line 183, in _is_gp_used_on_slice
    stmt = block.vex.statements[block_stmt_idx]
IndexError: list index out of range

The code is shown below.
```
import angr
proj = angr.Project(net-cgi, auto_load_libs=False)
cfg = proj.analyses.CFG()
```

The net-cgi can be found in [net-cgi.zip](https://github.com/angr/angr/files/8160732/net-cgi.zip)




--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py`
Content:
```
1 from typing import Dict, TYPE_CHECKING
2 import logging
3 
4 import pyvex
5 import archinfo
6 
7 
8 from .... import options, BP_BEFORE
9 from ....blade import Blade
10 from ....annocfg import AnnotatedCFG
11 from ....exploration_techniques import Slicecutor
12 
13 from .resolver import IndirectJumpResolver
14 
15 if TYPE_CHECKING:
16     from angr.block import Block
17 
18 
19 l = logging.getLogger(name=__name__)
20 
21 
22 class OverwriteTmpValueCallback:
23     """
24     Overwrites temporary values during resolution
25     """
26     def __init__(self, gp_value):
27         self.gp_value = gp_value
28 
29     def overwrite_tmp_value(self, state):
30         state.inspect.tmp_write_expr = state.solver.BVV(self.gp_value, state.arch.bits)
31 
32 
33 class MipsElfFastResolver(IndirectJumpResolver):
34     """
35     Indirect Jump Resolver for MIPs
36     """
37     def __init__(self, project):
38         super().__init__(project, timeless=True)
39 
40     def filter(self, cfg, addr, func_addr, block, jumpkind):
41         if not isinstance(self.project.arch, (archinfo.ArchMIPS32, archinfo.ArchMIPS64, )):
42             return False
43         return True
44 
45     def resolve(self, cfg, addr, func_addr, block, jumpkind):
46         """
47         Wrapper for _resolve that slowly increments the max_depth used by Blade for finding sources
48         until we can resolve the addr or we reach the default max_depth
49 
50         :param cfg: A CFG instance.
51         :param int addr: IRSB address.
52         :param int func_addr: The function address.
53         :param pyvex.IRSB block: The IRSB.
54         :param str jumpkind: The jumpkind.
55         :return: If it was resolved and targets alongside it
56         :rtype: tuple
57         """
58         for max_level in range(2, 4):
59             resolved, resolved_targets = self._resolve(cfg, addr, func_addr, block, jumpkind, max_level=max_level)
60             if resolved:
61                 return resolved, resolved_targets
62         return False, []
63 
64     def _resolve(self, cfg, addr, func_addr, block, jumpkind, max_level):
65         """
66         Resolves the indirect jump in MIPS ELF binaries where all external function calls are indexed using gp.
67 
68         :param cfg: A CFG instance.
69         :param int addr: IRSB address.
70         :param int func_addr: The function address.
71         :param pyvex.IRSB block: The IRSB.
72         :param str jumpkind: The jumpkind.
73         :param int max_level: maximum level for Blade to resolve when looking for sources
74         :return: If it was resolved and targets alongside it
75         :rtype: tuple
76         """
77 
78         project = self.project
79 
80         b = Blade(cfg.graph, addr, -1, cfg=cfg, project=project, ignore_sp=True, ignore_bp=True,
81                   ignored_regs=('gp',), cross_insn_opt=False, stop_at_calls=True, max_level=max_level
82                   )
83 
84         sources = [n for n in b.slice.nodes() if b.slice.in_degree(n) == 0]
85         if not sources:
86             return False, []
87 
88         source = sources[0]
89         source_addr = source[0]
90         annotated_cfg = AnnotatedCFG(project, None, detect_loops=False)
91         annotated_cfg.from_digraph(b.slice)
92 
93         state = project.factory.blank_state(addr=source_addr, mode="fastpath",
94                                             remove_options=options.refs,
95                                             # suppress unconstrained stack reads for `gp`
96                                             add_options={
97                                                 options.SYMBOL_FILL_UNCONSTRAINED_REGISTERS,
98                                                 options.SYMBOL_FILL_UNCONSTRAINED_MEMORY,
99                                                 options.NO_CROSS_INSN_OPT,
100                                             },
101                                             )
102         state.regs._t9 = func_addr
103         func = cfg.kb.functions.function(addr=func_addr)
104 
105         # see if gp is used on this slice at all
106         gp_used = self._is_gp_used_on_slice(project, b)
107 
108         gp_value = None
109         if gp_used:
110             if 'gp' not in func.info:
111                 # this might a special case: gp is only used once in this function, and it can be initialized right
112                 # before its use site.
113                 # however, it should have been determined in CFGFast
114                 # cannot determine the value of gp. quit
115                 pass
116             else:
117                 gp_value = func.info['gp']
118 
119             if gp_value is None:
120                 l.warning('Failed to determine value of register gp for function %#x.', func.addr)
121                 return False, []
122 
123             # Special handling for cases where `gp` is stored on the stack
124             gp_offset = project.arch.registers['gp'][0]
125             self._set_gp_load_callback(state, b, project, gp_offset, gp_value)
126             state.regs._gp = gp_value
127 
128         simgr = self.project.factory.simulation_manager(state)
129         simgr.use_technique(Slicecutor(annotated_cfg, force_sat=True))
130         simgr.run()
131 
132         if simgr.cut:
133             # pick the successor that is cut right after executing `addr`
134             try:
135                 target_state = next(iter(cut for cut in simgr.cut if cut.history.addr == addr))
136             except StopIteration:
137                 l.info("Indirect jump at %#x cannot be resolved by %s.", addr, repr(self))
138                 return False, [ ]
139             target = target_state.addr
140 
141             if self._is_target_valid(cfg, target) and target != func_addr:
142                 l.debug("Indirect jump at %#x is resolved to target %#x.", addr, target)
143                 return True, [ target ]
144 
145             l.info("Indirect jump at %#x is resolved to target %#x, which seems to be invalid.", addr, target)
146             return False, [ ]
147 
148         l.info("Indirect jump at %#x cannot be resolved by %s.", addr, repr(self))
149         return False, [ ]
150 
151     @staticmethod
152     def _set_gp_load_callback(state, blade, project, gp_offset, gp_value):
153         tmps = {}
154         for block_addr_in_slice in set(slice_node[0] for slice_node in blade.slice.nodes()):
155             for stmt in project.factory.block(block_addr_in_slice, cross_insn_opt=False).vex.statements:
156                 if isinstance(stmt, pyvex.IRStmt.WrTmp) and isinstance(stmt.data, pyvex.IRExpr.Load):
157                     # Load from memory to a tmp - assuming it's loading from the stack
158                     tmps[stmt.tmp] = 'stack'
159                 elif isinstance(stmt, pyvex.IRStmt.Put) and stmt.offset == gp_offset:
160                     if isinstance(stmt.data, pyvex.IRExpr.RdTmp):
161                         tmp_offset = stmt.data.tmp  # pylint:disable=cell-var-from-loop
162                         if tmps.get(tmp_offset, None) == 'stack':
163                             # found the load from stack
164                             # we must make sure value of that temporary variable equals to the correct gp value
165                             state.inspect.make_breakpoint('tmp_write', when=BP_BEFORE,
166                                         condition=lambda s, bbl_addr_=block_addr_in_slice,
167                                                         tmp_offset_=tmp_offset:
168                                         s.scratch.bbl_addr == bbl_addr_ and s.inspect.tmp_write_num == tmp_offset_,
169                                         action=OverwriteTmpValueCallback(
170                                         gp_value).overwrite_tmp_value
171                                         )
172                             break
173 
174     @staticmethod
175     def _is_gp_used_on_slice(project, b: Blade) -> bool:
176         gp_offset = project.arch.registers['gp'][0]
177         blocks_on_slice: Dict[int, 'Block'] = { }
178         for block_addr, block_stmt_idx in b.slice.nodes():
179             if block_addr not in blocks_on_slice:
180                 blocks_on_slice[block_addr] = project.factory.block(block_addr, cross_insn_opt=False)
181             block = blocks_on_slice[block_addr]
182             stmt = block.vex.statements[block_stmt_idx]
183             if isinstance(stmt, pyvex.IRStmt.WrTmp) \
184                     and isinstance(stmt.data, pyvex.IRExpr.Get) \
185                     and stmt.data.offset == gp_offset:
186                 gp_used = True
187                 break
188         else:
189             gp_used = False
190 
191         return gp_used
192
```
--- 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/angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py b/angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py
--- a/angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py
+++ b/angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py
@@ -9,7 +9,7 @@
 from ....blade import Blade
 from ....annocfg import AnnotatedCFG
 from ....exploration_techniques import Slicecutor
-
+from ....utils.constants import DEFAULT_STATEMENT
 from .resolver import IndirectJumpResolver
 
 if TYPE_CHECKING:
@@ -61,7 +61,7 @@
                 return resolved, resolved_targets
         return False, []
 
-    def _resolve(self, cfg, addr, func_addr, block, jumpkind, max_level):
+    def _resolve(self, cfg, addr, func_addr, block, jumpkind, max_level):  # pylint:disable=unused-argument
         """
         Resolves the indirect jump in MIPS ELF binaries where all external function calls are indexed using gp.
 
@@ -179,12 +179,17 @@
             if block_addr not in blocks_on_slice:
                 blocks_on_slice[block_addr] = project.factory.block(block_addr, cross_insn_opt=False)
             block = blocks_on_slice[block_addr]
-            stmt = block.vex.statements[block_stmt_idx]
-            if isinstance(stmt, pyvex.IRStmt.WrTmp) \
-                    and isinstance(stmt.data, pyvex.IRExpr.Get) \
-                    and stmt.data.offset == gp_offset:
-                gp_used = True
-                break
+            if block_stmt_idx == DEFAULT_STATEMENT:
+                if isinstance(block.vex.next, pyvex.IRExpr.Get) and block.vex.next.offset == gp_offset:
+                    gp_used = True
+                    break
+            else:
+                stmt = block.vex.statements[block_stmt_idx]
+                if isinstance(stmt, pyvex.IRStmt.WrTmp) \
+                        and isinstance(stmt.data, pyvex.IRExpr.Get) \
+                        and stmt.data.offset == gp_offset:
+                    gp_used = True
+                    break
         else:
             gp_used = False

{"golden_diff": "diff --git a/angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py b/angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py\n--- a/angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py\n+++ b/angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py\n@@ -9,7 +9,7 @@\n from ....blade import Blade\n from ....annocfg import AnnotatedCFG\n from ....exploration_techniques import Slicecutor\n-\n+from ....utils.constants import DEFAULT_STATEMENT\n from .resolver import IndirectJumpResolver\n \n if TYPE_CHECKING:\n@@ -61,7 +61,7 @@\n                 return resolved, resolved_targets\n         return False, []\n \n-    def _resolve(self, cfg, addr, func_addr, block, jumpkind, max_level):\n+    def _resolve(self, cfg, addr, func_addr, block, jumpkind, max_level):  # pylint:disable=unused-argument\n         \"\"\"\n         Resolves the indirect jump in MIPS ELF binaries where all external function calls are indexed using gp.\n \n@@ -179,12 +179,17 @@\n             if block_addr not in blocks_on_slice:\n                 blocks_on_slice[block_addr] = project.factory.block(block_addr, cross_insn_opt=False)\n             block = blocks_on_slice[block_addr]\n-            stmt = block.vex.statements[block_stmt_idx]\n-            if isinstance(stmt, pyvex.IRStmt.WrTmp) \\\n-                    and isinstance(stmt.data, pyvex.IRExpr.Get) \\\n-                    and stmt.data.offset == gp_offset:\n-                gp_used = True\n-                break\n+            if block_stmt_idx == DEFAULT_STATEMENT:\n+                if isinstance(block.vex.next, pyvex.IRExpr.Get) and block.vex.next.offset == gp_offset:\n+                    gp_used = True\n+                    break\n+            else:\n+                stmt = block.vex.statements[block_stmt_idx]\n+                if isinstance(stmt, pyvex.IRStmt.WrTmp) \\\n+                        and isinstance(stmt.data, pyvex.IRExpr.Get) \\\n+                        and stmt.data.offset == gp_offset:\n+                    gp_used = True\n+                    break\n         else:\n             gp_used = False\n", "issue": "An error occurred while analysis the CFG of the mips program.\nAn error occurs when I use angr to analyze the CFG of the mips program (net-cgi). \r\nThe error message is shown below.\r\n\r\n>  File \"/home/user/PycharmProjects/pythonProject/venv/lib/python3.8/site-packages/angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py\", line 106, in _resolve\r\n    gp_used = self._is_gp_used_on_slice(project, b)\r\n  File \"/home/user/PycharmProjects/pythonProject/venv/lib/python3.8/site-packages/angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py\", line 183, in _is_gp_used_on_slice\r\n    stmt = block.vex.statements[block_stmt_idx]\r\nIndexError: list index out of range\r\n\r\nThe code is shown below.\r\n```\r\nimport angr\r\nproj = angr.Project(net-cgi, auto_load_libs=False)\r\ncfg = proj.analyses.CFG()\r\n```\r\n\r\nThe net-cgi can be found in [net-cgi.zip](https://github.com/angr/angr/files/8160732/net-cgi.zip)\r\n\r\n\r\n\n", "before_files": [{"content": "from typing import Dict, TYPE_CHECKING\nimport logging\n\nimport pyvex\nimport archinfo\n\n\nfrom .... import options, BP_BEFORE\nfrom ....blade import Blade\nfrom ....annocfg import AnnotatedCFG\nfrom ....exploration_techniques import Slicecutor\n\nfrom .resolver import IndirectJumpResolver\n\nif TYPE_CHECKING:\n    from angr.block import Block\n\n\nl = logging.getLogger(name=__name__)\n\n\nclass OverwriteTmpValueCallback:\n    \"\"\"\n    Overwrites temporary values during resolution\n    \"\"\"\n    def __init__(self, gp_value):\n        self.gp_value = gp_value\n\n    def overwrite_tmp_value(self, state):\n        state.inspect.tmp_write_expr = state.solver.BVV(self.gp_value, state.arch.bits)\n\n\nclass MipsElfFastResolver(IndirectJumpResolver):\n    \"\"\"\n    Indirect Jump Resolver for MIPs\n    \"\"\"\n    def __init__(self, project):\n        super().__init__(project, timeless=True)\n\n    def filter(self, cfg, addr, func_addr, block, jumpkind):\n        if not isinstance(self.project.arch, (archinfo.ArchMIPS32, archinfo.ArchMIPS64, )):\n            return False\n        return True\n\n    def resolve(self, cfg, addr, func_addr, block, jumpkind):\n        \"\"\"\n        Wrapper for _resolve that slowly increments the max_depth used by Blade for finding sources\n        until we can resolve the addr or we reach the default max_depth\n\n        :param cfg: A CFG instance.\n        :param int addr: IRSB address.\n        :param int func_addr: The function address.\n        :param pyvex.IRSB block: The IRSB.\n        :param str jumpkind: The jumpkind.\n        :return: If it was resolved and targets alongside it\n        :rtype: tuple\n        \"\"\"\n        for max_level in range(2, 4):\n            resolved, resolved_targets = self._resolve(cfg, addr, func_addr, block, jumpkind, max_level=max_level)\n            if resolved:\n                return resolved, resolved_targets\n        return False, []\n\n    def _resolve(self, cfg, addr, func_addr, block, jumpkind, max_level):\n        \"\"\"\n        Resolves the indirect jump in MIPS ELF binaries where all external function calls are indexed using gp.\n\n        :param cfg: A CFG instance.\n        :param int addr: IRSB address.\n        :param int func_addr: The function address.\n        :param pyvex.IRSB block: The IRSB.\n        :param str jumpkind: The jumpkind.\n        :param int max_level: maximum level for Blade to resolve when looking for sources\n        :return: If it was resolved and targets alongside it\n        :rtype: tuple\n        \"\"\"\n\n        project = self.project\n\n        b = Blade(cfg.graph, addr, -1, cfg=cfg, project=project, ignore_sp=True, ignore_bp=True,\n                  ignored_regs=('gp',), cross_insn_opt=False, stop_at_calls=True, max_level=max_level\n                  )\n\n        sources = [n for n in b.slice.nodes() if b.slice.in_degree(n) == 0]\n        if not sources:\n            return False, []\n\n        source = sources[0]\n        source_addr = source[0]\n        annotated_cfg = AnnotatedCFG(project, None, detect_loops=False)\n        annotated_cfg.from_digraph(b.slice)\n\n        state = project.factory.blank_state(addr=source_addr, mode=\"fastpath\",\n                                            remove_options=options.refs,\n                                            # suppress unconstrained stack reads for `gp`\n                                            add_options={\n                                                options.SYMBOL_FILL_UNCONSTRAINED_REGISTERS,\n                                                options.SYMBOL_FILL_UNCONSTRAINED_MEMORY,\n                                                options.NO_CROSS_INSN_OPT,\n                                            },\n                                            )\n        state.regs._t9 = func_addr\n        func = cfg.kb.functions.function(addr=func_addr)\n\n        # see if gp is used on this slice at all\n        gp_used = self._is_gp_used_on_slice(project, b)\n\n        gp_value = None\n        if gp_used:\n            if 'gp' not in func.info:\n                # this might a special case: gp is only used once in this function, and it can be initialized right\n                # before its use site.\n                # however, it should have been determined in CFGFast\n                # cannot determine the value of gp. quit\n                pass\n            else:\n                gp_value = func.info['gp']\n\n            if gp_value is None:\n                l.warning('Failed to determine value of register gp for function %#x.', func.addr)\n                return False, []\n\n            # Special handling for cases where `gp` is stored on the stack\n            gp_offset = project.arch.registers['gp'][0]\n            self._set_gp_load_callback(state, b, project, gp_offset, gp_value)\n            state.regs._gp = gp_value\n\n        simgr = self.project.factory.simulation_manager(state)\n        simgr.use_technique(Slicecutor(annotated_cfg, force_sat=True))\n        simgr.run()\n\n        if simgr.cut:\n            # pick the successor that is cut right after executing `addr`\n            try:\n                target_state = next(iter(cut for cut in simgr.cut if cut.history.addr == addr))\n            except StopIteration:\n                l.info(\"Indirect jump at %#x cannot be resolved by %s.\", addr, repr(self))\n                return False, [ ]\n            target = target_state.addr\n\n            if self._is_target_valid(cfg, target) and target != func_addr:\n                l.debug(\"Indirect jump at %#x is resolved to target %#x.\", addr, target)\n                return True, [ target ]\n\n            l.info(\"Indirect jump at %#x is resolved to target %#x, which seems to be invalid.\", addr, target)\n            return False, [ ]\n\n        l.info(\"Indirect jump at %#x cannot be resolved by %s.\", addr, repr(self))\n        return False, [ ]\n\n    @staticmethod\n    def _set_gp_load_callback(state, blade, project, gp_offset, gp_value):\n        tmps = {}\n        for block_addr_in_slice in set(slice_node[0] for slice_node in blade.slice.nodes()):\n            for stmt in project.factory.block(block_addr_in_slice, cross_insn_opt=False).vex.statements:\n                if isinstance(stmt, pyvex.IRStmt.WrTmp) and isinstance(stmt.data, pyvex.IRExpr.Load):\n                    # Load from memory to a tmp - assuming it's loading from the stack\n                    tmps[stmt.tmp] = 'stack'\n                elif isinstance(stmt, pyvex.IRStmt.Put) and stmt.offset == gp_offset:\n                    if isinstance(stmt.data, pyvex.IRExpr.RdTmp):\n                        tmp_offset = stmt.data.tmp  # pylint:disable=cell-var-from-loop\n                        if tmps.get(tmp_offset, None) == 'stack':\n                            # found the load from stack\n                            # we must make sure value of that temporary variable equals to the correct gp value\n                            state.inspect.make_breakpoint('tmp_write', when=BP_BEFORE,\n                                        condition=lambda s, bbl_addr_=block_addr_in_slice,\n                                                        tmp_offset_=tmp_offset:\n                                        s.scratch.bbl_addr == bbl_addr_ and s.inspect.tmp_write_num == tmp_offset_,\n                                        action=OverwriteTmpValueCallback(\n                                        gp_value).overwrite_tmp_value\n                                        )\n                            break\n\n    @staticmethod\n    def _is_gp_used_on_slice(project, b: Blade) -> bool:\n        gp_offset = project.arch.registers['gp'][0]\n        blocks_on_slice: Dict[int, 'Block'] = { }\n        for block_addr, block_stmt_idx in b.slice.nodes():\n            if block_addr not in blocks_on_slice:\n                blocks_on_slice[block_addr] = project.factory.block(block_addr, cross_insn_opt=False)\n            block = blocks_on_slice[block_addr]\n            stmt = block.vex.statements[block_stmt_idx]\n            if isinstance(stmt, pyvex.IRStmt.WrTmp) \\\n                    and isinstance(stmt.data, pyvex.IRExpr.Get) \\\n                    and stmt.data.offset == gp_offset:\n                gp_used = True\n                break\n        else:\n            gp_used = False\n\n        return gp_used\n", "path": "angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py"}], "after_files": [{"content": "from typing import Dict, TYPE_CHECKING\nimport logging\n\nimport pyvex\nimport archinfo\n\n\nfrom .... import options, BP_BEFORE\nfrom ....blade import Blade\nfrom ....annocfg import AnnotatedCFG\nfrom ....exploration_techniques import Slicecutor\nfrom ....utils.constants import DEFAULT_STATEMENT\nfrom .resolver import IndirectJumpResolver\n\nif TYPE_CHECKING:\n    from angr.block import Block\n\n\nl = logging.getLogger(name=__name__)\n\n\nclass OverwriteTmpValueCallback:\n    \"\"\"\n    Overwrites temporary values during resolution\n    \"\"\"\n    def __init__(self, gp_value):\n        self.gp_value = gp_value\n\n    def overwrite_tmp_value(self, state):\n        state.inspect.tmp_write_expr = state.solver.BVV(self.gp_value, state.arch.bits)\n\n\nclass MipsElfFastResolver(IndirectJumpResolver):\n    \"\"\"\n    Indirect Jump Resolver for MIPs\n    \"\"\"\n    def __init__(self, project):\n        super().__init__(project, timeless=True)\n\n    def filter(self, cfg, addr, func_addr, block, jumpkind):\n        if not isinstance(self.project.arch, (archinfo.ArchMIPS32, archinfo.ArchMIPS64, )):\n            return False\n        return True\n\n    def resolve(self, cfg, addr, func_addr, block, jumpkind):\n        \"\"\"\n        Wrapper for _resolve that slowly increments the max_depth used by Blade for finding sources\n        until we can resolve the addr or we reach the default max_depth\n\n        :param cfg: A CFG instance.\n        :param int addr: IRSB address.\n        :param int func_addr: The function address.\n        :param pyvex.IRSB block: The IRSB.\n        :param str jumpkind: The jumpkind.\n        :return: If it was resolved and targets alongside it\n        :rtype: tuple\n        \"\"\"\n        for max_level in range(2, 4):\n            resolved, resolved_targets = self._resolve(cfg, addr, func_addr, block, jumpkind, max_level=max_level)\n            if resolved:\n                return resolved, resolved_targets\n        return False, []\n\n    def _resolve(self, cfg, addr, func_addr, block, jumpkind, max_level):  # pylint:disable=unused-argument\n        \"\"\"\n        Resolves the indirect jump in MIPS ELF binaries where all external function calls are indexed using gp.\n\n        :param cfg: A CFG instance.\n        :param int addr: IRSB address.\n        :param int func_addr: The function address.\n        :param pyvex.IRSB block: The IRSB.\n        :param str jumpkind: The jumpkind.\n        :param int max_level: maximum level for Blade to resolve when looking for sources\n        :return: If it was resolved and targets alongside it\n        :rtype: tuple\n        \"\"\"\n\n        project = self.project\n\n        b = Blade(cfg.graph, addr, -1, cfg=cfg, project=project, ignore_sp=True, ignore_bp=True,\n                  ignored_regs=('gp',), cross_insn_opt=False, stop_at_calls=True, max_level=max_level\n                  )\n\n        sources = [n for n in b.slice.nodes() if b.slice.in_degree(n) == 0]\n        if not sources:\n            return False, []\n\n        source = sources[0]\n        source_addr = source[0]\n        annotated_cfg = AnnotatedCFG(project, None, detect_loops=False)\n        annotated_cfg.from_digraph(b.slice)\n\n        state = project.factory.blank_state(addr=source_addr, mode=\"fastpath\",\n                                            remove_options=options.refs,\n                                            # suppress unconstrained stack reads for `gp`\n                                            add_options={\n                                                options.SYMBOL_FILL_UNCONSTRAINED_REGISTERS,\n                                                options.SYMBOL_FILL_UNCONSTRAINED_MEMORY,\n                                                options.NO_CROSS_INSN_OPT,\n                                            },\n                                            )\n        state.regs._t9 = func_addr\n        func = cfg.kb.functions.function(addr=func_addr)\n\n        # see if gp is used on this slice at all\n        gp_used = self._is_gp_used_on_slice(project, b)\n\n        gp_value = None\n        if gp_used:\n            if 'gp' not in func.info:\n                # this might a special case: gp is only used once in this function, and it can be initialized right\n                # before its use site.\n                # however, it should have been determined in CFGFast\n                # cannot determine the value of gp. quit\n                pass\n            else:\n                gp_value = func.info['gp']\n\n            if gp_value is None:\n                l.warning('Failed to determine value of register gp for function %#x.', func.addr)\n                return False, []\n\n            # Special handling for cases where `gp` is stored on the stack\n            gp_offset = project.arch.registers['gp'][0]\n            self._set_gp_load_callback(state, b, project, gp_offset, gp_value)\n            state.regs._gp = gp_value\n\n        simgr = self.project.factory.simulation_manager(state)\n        simgr.use_technique(Slicecutor(annotated_cfg, force_sat=True))\n        simgr.run()\n\n        if simgr.cut:\n            # pick the successor that is cut right after executing `addr`\n            try:\n                target_state = next(iter(cut for cut in simgr.cut if cut.history.addr == addr))\n            except StopIteration:\n                l.info(\"Indirect jump at %#x cannot be resolved by %s.\", addr, repr(self))\n                return False, [ ]\n            target = target_state.addr\n\n            if self._is_target_valid(cfg, target) and target != func_addr:\n                l.debug(\"Indirect jump at %#x is resolved to target %#x.\", addr, target)\n                return True, [ target ]\n\n            l.info(\"Indirect jump at %#x is resolved to target %#x, which seems to be invalid.\", addr, target)\n            return False, [ ]\n\n        l.info(\"Indirect jump at %#x cannot be resolved by %s.\", addr, repr(self))\n        return False, [ ]\n\n    @staticmethod\n    def _set_gp_load_callback(state, blade, project, gp_offset, gp_value):\n        tmps = {}\n        for block_addr_in_slice in set(slice_node[0] for slice_node in blade.slice.nodes()):\n            for stmt in project.factory.block(block_addr_in_slice, cross_insn_opt=False).vex.statements:\n                if isinstance(stmt, pyvex.IRStmt.WrTmp) and isinstance(stmt.data, pyvex.IRExpr.Load):\n                    # Load from memory to a tmp - assuming it's loading from the stack\n                    tmps[stmt.tmp] = 'stack'\n                elif isinstance(stmt, pyvex.IRStmt.Put) and stmt.offset == gp_offset:\n                    if isinstance(stmt.data, pyvex.IRExpr.RdTmp):\n                        tmp_offset = stmt.data.tmp  # pylint:disable=cell-var-from-loop\n                        if tmps.get(tmp_offset, None) == 'stack':\n                            # found the load from stack\n                            # we must make sure value of that temporary variable equals to the correct gp value\n                            state.inspect.make_breakpoint('tmp_write', when=BP_BEFORE,\n                                        condition=lambda s, bbl_addr_=block_addr_in_slice,\n                                                        tmp_offset_=tmp_offset:\n                                        s.scratch.bbl_addr == bbl_addr_ and s.inspect.tmp_write_num == tmp_offset_,\n                                        action=OverwriteTmpValueCallback(\n                                        gp_value).overwrite_tmp_value\n                                        )\n                            break\n\n    @staticmethod\n    def _is_gp_used_on_slice(project, b: Blade) -> bool:\n        gp_offset = project.arch.registers['gp'][0]\n        blocks_on_slice: Dict[int, 'Block'] = { }\n        for block_addr, block_stmt_idx in b.slice.nodes():\n            if block_addr not in blocks_on_slice:\n                blocks_on_slice[block_addr] = project.factory.block(block_addr, cross_insn_opt=False)\n            block = blocks_on_slice[block_addr]\n            if block_stmt_idx == DEFAULT_STATEMENT:\n                if isinstance(block.vex.next, pyvex.IRExpr.Get) and block.vex.next.offset == gp_offset:\n                    gp_used = True\n                    break\n            else:\n                stmt = block.vex.statements[block_stmt_idx]\n                if isinstance(stmt, pyvex.IRStmt.WrTmp) \\\n                        and isinstance(stmt.data, pyvex.IRExpr.Get) \\\n                        and stmt.data.offset == gp_offset:\n                    gp_used = True\n                    break\n        else:\n            gp_used = False\n\n        return gp_used\n", "path": "angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py"}]}