mirror of
https://github.com/angr/angr
synced 2026-08-17 12:23:11 -04:00
Decompiler: propagate labels through nested statement lists
This commit is contained in:
parent
76b0981a76
commit
e958d1dde4
2 changed files with 47 additions and 4 deletions
|
|
@ -906,21 +906,38 @@ class CStatements(CStatement):
|
|||
self.addr = addr
|
||||
|
||||
def c_repr_chunks(self, indent=0, asexpr=False):
|
||||
yield from self._c_repr_chunks(indent=indent, asexpr=asexpr, terminate_trailing_label=True)
|
||||
|
||||
def _c_repr_chunks(self, indent=0, asexpr=False, *, terminate_trailing_label):
|
||||
indent_str = self.indent_str(indent)
|
||||
if self.codegen.display_block_addrs:
|
||||
yield indent_str, None
|
||||
yield f"/* Block {hex(self.addr) if self.addr is not None else 'unknown'} */", None
|
||||
yield "\n", None
|
||||
for stmt in self.statements:
|
||||
yield from stmt.c_repr_chunks(indent=indent, asexpr=asexpr)
|
||||
if isinstance(stmt, CStatements):
|
||||
# CStatements may be a transparent sequence nested inside another sequence. A label at the end of
|
||||
# the inner sequence still labels the next statement in the outer sequence.
|
||||
yield from stmt._c_repr_chunks(indent=indent, asexpr=asexpr, terminate_trailing_label=False)
|
||||
else:
|
||||
yield from stmt.c_repr_chunks(indent=indent, asexpr=asexpr)
|
||||
if asexpr:
|
||||
yield ", ", None
|
||||
if not asexpr and self.statements and isinstance(self.statements[-1], CLabel):
|
||||
# A C label prefixes a statement; it is not a complete statement itself. Finish a trailing label run
|
||||
# locally so that the next statement in an outer sequence cannot become its labeled statement.
|
||||
if not asexpr and terminate_trailing_label and isinstance(self._last_nonempty_statement(), CLabel):
|
||||
# A C label prefixes a statement; it is not a complete statement itself. Finish it only at the boundary
|
||||
# of the enclosing sequence, after looking through transparent nested sequences.
|
||||
yield indent_str, None
|
||||
yield ";\n", None
|
||||
|
||||
def _last_nonempty_statement(self) -> CStatement | None:
|
||||
for stmt in reversed(self.statements):
|
||||
if isinstance(stmt, CStatements):
|
||||
stmt = stmt._last_nonempty_statement()
|
||||
if stmt is None:
|
||||
continue
|
||||
return stmt
|
||||
return None
|
||||
|
||||
|
||||
class CAILBlock(CStatement):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -57,6 +57,32 @@ def test_trailing_label_run_has_one_null_statement():
|
|||
assert _render(statements, indent=4) == "LABEL_400000:\nLABEL_400010:\n ;\n"
|
||||
|
||||
|
||||
def test_nested_trailing_label_prefixes_next_outer_statement():
|
||||
codegen = _codegen()
|
||||
statements = CStatements(
|
||||
[
|
||||
CStatements([CLabel("LABEL_400000", codegen=codegen)], codegen=codegen),
|
||||
CReturn(None, codegen=codegen),
|
||||
],
|
||||
codegen=codegen,
|
||||
)
|
||||
|
||||
assert _render(statements) == "LABEL_400000:\nreturn;\n"
|
||||
|
||||
|
||||
def test_nested_terminal_label_has_null_statement():
|
||||
codegen = _codegen()
|
||||
statements = CStatements(
|
||||
[
|
||||
CStatements([CLabel("LABEL_400000", codegen=codegen)], codegen=codegen),
|
||||
CStatements([], codegen=codegen),
|
||||
],
|
||||
codegen=codegen,
|
||||
)
|
||||
|
||||
assert _render(statements, indent=4) == "LABEL_400000:\n ;\n"
|
||||
|
||||
|
||||
def test_trailing_label_does_not_capture_outer_statement():
|
||||
codegen = _codegen()
|
||||
conditional = CIfElse(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue