diff options
Diffstat (limited to 'idatui')
| -rw-r--r-- | idatui/app.py | 23 | ||||
| -rw-r--r-- | idatui/domain.py | 8 |
2 files changed, 30 insertions, 1 deletions
diff --git a/idatui/app.py b/idatui/app.py index 2190643..ff67eef 100644 --- a/idatui/app.py +++ b/idatui/app.py @@ -738,6 +738,7 @@ class ListingView(SearchMixin, NavMixin, ColumnCursor, ScrollView, can_focus=Tru Binding("a", "make_string", "Str", show=False), Binding("p", "define_func", "Func", show=False), Binding("u", "undefine", "Undef", show=False), + Binding("t", "toggle_thumb", "ARM/Thumb", show=False), *SearchMixin.SEARCH_BINDINGS, *NavMixin.NAV_BINDINGS, *ColumnCursor.COL_BINDINGS, @@ -1126,6 +1127,9 @@ class ListingView(SearchMixin, NavMixin, ColumnCursor, ScrollView, can_focus=Tru def action_undefine(self) -> None: self.post_message(EditItemRequested(self, "undef")) + def action_toggle_thumb(self) -> None: + self.post_message(EditItemRequested(self, "thumb")) + def action_make_data(self) -> None: self.post_message(MakeDataRequested(self)) @@ -5150,7 +5154,8 @@ class IdaTui(App): anchor: ViewAnchor | None = None) -> None: # worker context assert self.program is not None verb = {"code": "defined code", "func": "created function", - "undef": "undefined", "string": "made string"}[kind] + "undef": "undefined", "string": "made string", + "thumb": "switched decoding"}[kind] try: if kind == "code": # Keep going until something stops it: one instruction is rarely @@ -5175,6 +5180,22 @@ class IdaTui(App): "limit": "instruction limit"}.get(why, why) verb = (f"defined {n} instruction{'s' if n != 1 else ''} " f"({ea:#x}\u2013{end:#x}) \u2014 {reason}") + elif kind == "thumb": + # Switch the mode, then disassemble in it: flipping T and + # leaving the bytes undefined shows nothing, and the reason you + # flipped it was to read the code. + r = self.program.set_thumb(ea) + run = self.program.define_code_run(ea) + n = int(run.get("count", 0)) + mode = "Thumb" if r.get("thumb") else "ARM" + verb = f"{mode} @ {ea:#x}" + if r.get("forced_32bit"): + verb += " (segment set to 32-bit; Thumb needs ARM32)" + verb += (f" \u2014 {n} instruction{'s' if n != 1 else ''}" + if n else " \u2014 still doesn't decode") + # falls through to the shared reload: same cache bump, same + # anchor restore, same flash. That is the whole point of having + # one path. elif kind == "func": self.program.define_func(ea) elif kind == "string": diff --git a/idatui/domain.py b/idatui/domain.py index 606cf42..8787431 100644 --- a/idatui/domain.py +++ b/idatui/domain.py @@ -1373,6 +1373,14 @@ class Program: if res.get("error"): raise IDAToolError("define_code", f"@ {ea:#x}: {res['error']}") + def set_thumb(self, ea: int, mode: str = "toggle") -> dict: + """Switch ARM/Thumb decoding at ``ea``. Returns the resulting state.""" + r = self.client.call("set_thumb", addr=hex(ea), mode=mode) + if not isinstance(r, dict) or r.get("error"): + raise IDAToolError("set_thumb", + f"@ {ea:#x}: {(r or {}).get('error', 'failed')}") + return r + def define_code_run(self, ea: int, limit: int = 20000) -> dict: """Disassemble consecutively from ``ea`` until something stops it. |
