Repository: angr/angr

Issue:
IndexError when creating CFGEmulated on ARM thumb binary
**Describe the bug.**
When running the CFGEmulated analysis on the attached ARM thumb binary, angr crashes with the following backtrace:

```
>>> import angr
>>> p = angr.Project("get")
>>> cfg = p.analyses.CFGEmulated()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/manuel/.virtualenvs/angr/lib/python3.8/site-packages/angr/analyses/analysis.py", line 115, in __call__
    oself.__init__(*args, **kwargs)
  File "/home/manuel/.virtualenvs/angr/lib/python3.8/site-packages/angr/analyses/cfg/cfg_emulated.py", line 306, in __init__
    self._analyze()
  File "/home/manuel/.virtualenvs/angr/lib/python3.8/site-packages/angr/analyses/forward_analysis/forward_analysis.py", line 216, in _analyze
    self._analysis_core_baremetal()
  File "/home/manuel/.virtualenvs/angr/lib/python3.8/site-packages/angr/analyses/forward_analysis/forward_analysis.py", line 368, in _analysis_core_baremetal
    self._process_job_and_get_successors(job_info)
  File "/home/manuel/.virtualenvs/angr/lib/python3.8/site-packages/angr/analyses/forward_analysis/forward_analysis.py", line 386, in _process_job_and_get_successors
    successors = self._get_successors(job)
  File "/home/manuel/.virtualenvs/angr/lib/python3.8/site-packages/angr/analyses/cfg/cfg_emulated.py", line 1295, in _get_successors
    resolved, resolved_targets, ij = self._indirect_jump_encountered(addr, cfg_node, irsb, func_addr,
  File "/home/manuel/.virtualenvs/angr/lib/python3.8/site-packages/angr/analyses/cfg/cfg_base.py", line 2331, in _indirect_jump_encountered
    resolved, resolved_targets = self._resolve_indirect_jump_timelessly(addr, irsb, func_addr, jumpkind)
  File "/home/manuel/.virtualenvs/angr/lib/python3.8/site-packages/angr/analyses/cfg/cfg_base.py", line 2274, in _resolve_indirect_jump_timelessly
    r, resolved_targets = res.resolve(self, addr, func_addr, block, jumpkind)
  File "/home/manuel/.virtualenvs/angr/lib/python3.8/site-packages/angr/analyses/cfg/indirect_jump_resolvers/arm_elf_fast.py", line 60, in resolve
    stmt = block.statements[stmt_idx]
IndexError: list index out of range
```


**Environment Information.**
```% pip show angr
Name: angr
Version: 9.0.5171
% python --version
Python 3.8.5
```


**To Reproduce.**
```
p = angr.Project("get")
cfg = p.analyses.CFGEmulated()
```

[get.zip](https://github.com/angr/angr/files/5754289/get.zip)

Binary is from this reduced test case:
```c
__attribute__((noinline)) int get(void)
{
    volatile int stuff[100] = { 0x1000 };
    return stuff[0];
}

int main(int argc, char **argv)
{
        get();
}
```

compiled with `arm-none-eabi-gcc -mthumb -g -O2 get.c --specs=nosys.specs -o get`.

**Additional context.**
Only breaks with `-mthumb`.  Works with `-marm`.



Discussion:

Resolving patch:
diff --git a/angr/analyses/cfg/cfg_base.py b/angr/analyses/cfg/cfg_base.py
--- a/angr/analyses/cfg/cfg_base.py
+++ b/angr/analyses/cfg/cfg_base.py
@@ -1,4 +1,4 @@
-from typing import Dict
+from typing import Dict, Tuple, List, Optional, Union
 import logging
 from collections import defaultdict
 
@@ -2308,20 +2308,23 @@ def _indirect_jump_unresolved(self, jump):
         # TODO: self.kb._unresolved_indirect_jumps is not processed during normalization. Fix it.
         self.kb.unresolved_indirect_jumps.add(jump.addr)
 
-    def _indirect_jump_encountered(self, addr, cfg_node, irsb, func_addr, stmt_idx=DEFAULT_STATEMENT):
+    def _indirect_jump_encountered(self, addr: int, cfg_node: CFGNode, irsb: pyvex.IRSB, func_addr: int,
+                                   stmt_idx: Union[int,str]=DEFAULT_STATEMENT
+                                   ) -> Tuple[bool,List[int],Optional[IndirectJump]]:
         """
         Called when we encounter an indirect jump. We will try to resolve this indirect jump using timeless (fast)
         indirect jump resolvers. If it cannot be resolved, we will see if this indirect jump has been resolved before.
 
-        :param int addr:                Address of the block containing the indirect jump.
-        :param cfg_node:                The CFGNode instance of the block that contains the indirect jump.
-        :param pyvex.IRSB irsb:         The IRSB instance of the block that contains the indirect jump.
-        :param int func_addr:           Address of the current function.
-        :param int or str stmt_idx:     ID of the source statement.
+        :param addr:        Address of the block containing the indirect jump.
+        :param cfg_node:    The CFGNode instance of the block that contains the indirect jump.
+        :param irsb:        The IRSB instance of the block that contains the indirect jump. It must be lifted with
+                            cross-instruction optimization disabled (cross_insn_opt=True when opt_level=1, or
+                            opt_level=0).
+        :param func_addr:   Address of the current function.
+        :param stmt_idx:    ID of the source statement.
 
         :return:    A 3-tuple of (whether it is resolved or not, all resolved targets, an IndirectJump object
                     if there is one or None otherwise)
-        :rtype:     tuple
         """
 
         jumpkind = irsb.jumpkind
diff --git a/angr/analyses/cfg/cfg_emulated.py b/angr/analyses/cfg/cfg_emulated.py
--- a/angr/analyses/cfg/cfg_emulated.py
+++ b/angr/analyses/cfg/cfg_emulated.py
@@ -1290,7 +1290,7 @@ def _get_successors(self, job):
 
         if is_indirect_jump and self._resolve_indirect_jumps:
             # Try to resolve indirect jumps
-            irsb = input_state.block().vex
+            irsb = input_state.block(cross_insn_opt=False).vex
 
             resolved, resolved_targets, ij = self._indirect_jump_encountered(addr, cfg_node, irsb, func_addr,
                                                                              stmt_idx=DEFAULT_STATEMENT)


Test patch: