angr 9.2.122__py3-none-macosx_11_0_arm64.whl → 9.2.124__py3-none-macosx_11_0_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of angr might be problematic. Click here for more details.

Files changed (96) hide show
  1. angr/__init__.py +1 -1
  2. angr/analyses/calling_convention.py +6 -1
  3. angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py +11 -8
  4. angr/analyses/cfg/indirect_jump_resolvers/mips_elf_got.py +2 -2
  5. angr/analyses/decompiler/ail_simplifier.py +38 -342
  6. angr/analyses/decompiler/callsite_maker.py +8 -7
  7. angr/analyses/decompiler/ccall_rewriters/amd64_ccalls.py +24 -2
  8. angr/analyses/decompiler/clinic.py +30 -3
  9. angr/analyses/decompiler/condition_processor.py +10 -3
  10. angr/analyses/decompiler/decompilation_cache.py +2 -0
  11. angr/analyses/decompiler/decompiler.py +50 -8
  12. angr/analyses/decompiler/dephication/graph_vvar_mapping.py +10 -2
  13. angr/analyses/decompiler/dephication/rewriting_engine.py +65 -2
  14. angr/analyses/decompiler/expression_narrower.py +206 -6
  15. angr/analyses/decompiler/optimization_passes/div_simplifier.py +4 -1
  16. angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +7 -0
  17. angr/analyses/decompiler/optimization_passes/ite_region_converter.py +34 -11
  18. angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +10 -1
  19. angr/analyses/decompiler/optimization_passes/optimization_pass.py +3 -1
  20. angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +8 -5
  21. angr/analyses/decompiler/optimization_passes/return_duplicator_high.py +10 -5
  22. angr/analyses/decompiler/optimization_passes/return_duplicator_low.py +18 -7
  23. angr/analyses/decompiler/optimization_passes/switch_default_case_duplicator.py +6 -0
  24. angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py +2 -0
  25. angr/analyses/decompiler/peephole_optimizations/const_mull_a_shift.py +75 -42
  26. angr/analyses/decompiler/peephole_optimizations/remove_cascading_conversions.py +8 -2
  27. angr/analyses/decompiler/region_identifier.py +36 -0
  28. angr/analyses/decompiler/region_simplifiers/expr_folding.py +4 -0
  29. angr/analyses/decompiler/region_simplifiers/loop.py +2 -8
  30. angr/analyses/decompiler/region_simplifiers/switch_cluster_simplifier.py +9 -3
  31. angr/analyses/decompiler/sequence_walker.py +20 -4
  32. angr/analyses/decompiler/ssailification/rewriting.py +5 -2
  33. angr/analyses/decompiler/ssailification/rewriting_engine.py +151 -25
  34. angr/analyses/decompiler/ssailification/rewriting_state.py +1 -0
  35. angr/analyses/decompiler/ssailification/ssailification.py +17 -9
  36. angr/analyses/decompiler/ssailification/traversal.py +3 -1
  37. angr/analyses/decompiler/ssailification/traversal_engine.py +35 -8
  38. angr/analyses/decompiler/ssailification/traversal_state.py +1 -0
  39. angr/analyses/decompiler/structured_codegen/c.py +42 -4
  40. angr/analyses/decompiler/structuring/phoenix.py +3 -0
  41. angr/analyses/propagator/engine_ail.py +10 -3
  42. angr/analyses/reaching_definitions/engine_ail.py +10 -15
  43. angr/analyses/s_propagator.py +26 -15
  44. angr/analyses/s_reaching_definitions/s_rda_view.py +127 -63
  45. angr/analyses/variable_recovery/engine_ail.py +14 -0
  46. angr/analyses/variable_recovery/engine_base.py +11 -0
  47. angr/calling_conventions.py +2 -2
  48. angr/engines/light/engine.py +24 -2
  49. angr/engines/soot/expressions/instanceOf.py +4 -1
  50. angr/engines/successors.py +1 -1
  51. angr/engines/vex/heavy/concretizers.py +47 -47
  52. angr/engines/vex/heavy/dirty.py +4 -4
  53. angr/knowledge_plugins/__init__.py +2 -0
  54. angr/knowledge_plugins/decompilation.py +45 -0
  55. angr/knowledge_plugins/key_definitions/atoms.py +8 -0
  56. angr/lib/angr_native.dylib +0 -0
  57. angr/procedures/definitions/parse_win32json.py +2 -1
  58. angr/procedures/java_lang/getsimplename.py +4 -1
  59. angr/procedures/linux_kernel/iovec.py +5 -2
  60. angr/sim_type.py +3 -1
  61. angr/storage/memory_mixins/actions_mixin.py +7 -7
  62. angr/storage/memory_mixins/address_concretization_mixin.py +5 -5
  63. angr/storage/memory_mixins/bvv_conversion_mixin.py +1 -1
  64. angr/storage/memory_mixins/clouseau_mixin.py +3 -3
  65. angr/storage/memory_mixins/conditional_store_mixin.py +3 -3
  66. angr/storage/memory_mixins/default_filler_mixin.py +3 -3
  67. angr/storage/memory_mixins/memory_mixin.py +45 -34
  68. angr/storage/memory_mixins/paged_memory/page_backer_mixins.py +15 -14
  69. angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +27 -16
  70. angr/storage/memory_mixins/paged_memory/pages/cooperation.py +18 -9
  71. angr/storage/memory_mixins/paged_memory/pages/ispo_mixin.py +5 -5
  72. angr/storage/memory_mixins/paged_memory/pages/multi_values.py +89 -55
  73. angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +16 -25
  74. angr/storage/memory_mixins/paged_memory/pages/permissions_mixin.py +11 -9
  75. angr/storage/memory_mixins/paged_memory/pages/ultra_page.py +23 -7
  76. angr/storage/memory_mixins/paged_memory/privileged_mixin.py +1 -1
  77. angr/storage/memory_mixins/regioned_memory/region_meta_mixin.py +9 -7
  78. angr/storage/memory_mixins/regioned_memory/regioned_memory_mixin.py +9 -9
  79. angr/storage/memory_mixins/regioned_memory/static_find_mixin.py +1 -0
  80. angr/storage/memory_mixins/simple_interface_mixin.py +2 -2
  81. angr/storage/memory_mixins/simplification_mixin.py +2 -2
  82. angr/storage/memory_mixins/size_resolution_mixin.py +1 -1
  83. angr/storage/memory_mixins/slotted_memory.py +3 -3
  84. angr/storage/memory_mixins/smart_find_mixin.py +1 -0
  85. angr/storage/memory_mixins/underconstrained_mixin.py +5 -5
  86. angr/storage/memory_mixins/unwrapper_mixin.py +4 -4
  87. angr/storage/memory_object.py +4 -3
  88. angr/utils/constants.py +1 -1
  89. angr/utils/graph.py +15 -0
  90. angr/vaults.py +2 -2
  91. {angr-9.2.122.dist-info → angr-9.2.124.dist-info}/METADATA +7 -6
  92. {angr-9.2.122.dist-info → angr-9.2.124.dist-info}/RECORD +96 -95
  93. {angr-9.2.122.dist-info → angr-9.2.124.dist-info}/WHEEL +1 -1
  94. {angr-9.2.122.dist-info → angr-9.2.124.dist-info}/LICENSE +0 -0
  95. {angr-9.2.122.dist-info → angr-9.2.124.dist-info}/entry_points.txt +0 -0
  96. {angr-9.2.122.dist-info → angr-9.2.124.dist-info}/top_level.txt +0 -0
angr/__init__.py CHANGED
@@ -2,7 +2,7 @@
2
2
  # pylint: disable=wrong-import-position
3
3
  from __future__ import annotations
4
4
 
5
- __version__ = "9.2.122"
5
+ __version__ = "9.2.124"
6
6
 
7
7
  if bytes is str:
8
8
  raise Exception(
@@ -356,9 +356,12 @@ class CallingConventionAnalysis(Analysis):
356
356
  caller_block_addr: int,
357
357
  call_insn_addr: int,
358
358
  include_preds: bool = False,
359
- ) -> CallSiteFact:
359
+ ) -> CallSiteFact | None:
360
360
  func = self.kb.functions[caller_addr]
361
361
  subgraph = self._generate_callsite_subgraph(func, caller_block_addr, include_preds=include_preds)
362
+ if subgraph is None:
363
+ # failed to generate a subgraph when the caller block cannot be found in the function graph
364
+ return None
362
365
 
363
366
  observation_points: list = [("insn", call_insn_addr, OP_BEFORE), ("node", caller_block_addr, OP_AFTER)]
364
367
 
@@ -440,6 +443,8 @@ class CallingConventionAnalysis(Analysis):
440
443
  call_insn_addr,
441
444
  include_preds=include_callsite_preds,
442
445
  )
446
+ if fact is None:
447
+ continue
443
448
  facts.append(fact)
444
449
 
445
450
  ctr += 1
@@ -153,6 +153,11 @@ class MipsElfFastResolver(IndirectJumpResolver):
153
153
 
154
154
  def _resolve_case_1(self, addr: int, block: pyvex.IRSB, func_addr: int, gp_value: int, cfg) -> int | None:
155
155
  # lift the block again with the correct setting
156
+
157
+ inital_regs = [(self.project.arch.registers["t9"][0], self.project.arch.registers["t9"][1], func_addr)]
158
+ if gp_value is not None:
159
+ inital_regs.append((self.project.arch.registers["gp"][0], self.project.arch.registers["gp"][1], gp_value))
160
+
156
161
  first_irsb = self.project.factory.block(
157
162
  addr,
158
163
  size=block.size,
@@ -160,10 +165,7 @@ class MipsElfFastResolver(IndirectJumpResolver):
160
165
  const_prop=True,
161
166
  cross_insn_opt=False,
162
167
  load_from_ro_regions=True,
163
- initial_regs=[
164
- (self.project.arch.registers["t9"][0], self.project.arch.registers["t9"][1], func_addr),
165
- (self.project.arch.registers["gp"][0], self.project.arch.registers["gp"][1], gp_value),
166
- ],
168
+ initial_regs=inital_regs,
167
169
  ).vex_nostmt
168
170
 
169
171
  if not isinstance(first_irsb.next, pyvex.IRExpr.RdTmp):
@@ -193,6 +195,10 @@ class MipsElfFastResolver(IndirectJumpResolver):
193
195
  # the register (t9) is set in this block - we can resolve the jump target using only the current block
194
196
  return Case2Result.RESUME, None
195
197
 
198
+ inital_regs = [(self.project.arch.registers["t9"][0], self.project.arch.registers["t9"][1], func_addr)]
199
+ if gp_value is not None:
200
+ inital_regs.append((self.project.arch.registers["gp"][0], self.project.arch.registers["gp"][1], gp_value))
201
+
196
202
  # lift the first block again with the correct setting
197
203
  first_irsb = self.project.factory.block(
198
204
  first_block_addr,
@@ -200,10 +206,7 @@ class MipsElfFastResolver(IndirectJumpResolver):
200
206
  collect_data_refs=False,
201
207
  const_prop=True,
202
208
  load_from_ro_regions=True,
203
- initial_regs=[
204
- (self.project.arch.registers["t9"][0], self.project.arch.registers["t9"][1], func_addr),
205
- (self.project.arch.registers["gp"][0], self.project.arch.registers["gp"][1], gp_value),
206
- ],
209
+ initial_regs=inital_regs,
207
210
  ).vex_nostmt
208
211
 
209
212
  last_reg_setting_tmp = self._get_last_reg_setting_tmp(first_irsb, jump_target_reg)
@@ -51,11 +51,11 @@ class MipsElfGotResolver(IndirectJumpResolver):
51
51
  return False, []
52
52
  dynsym_addr = self._find_and_cache_section_addr(obj, ".dynsym")
53
53
  if dynsym_addr is None:
54
- return None
54
+ return False, []
55
55
 
56
56
  dynstr_addr = self._find_and_cache_section_addr(obj, ".dynstr")
57
57
  if dynstr_addr is None:
58
- return None
58
+ return False, []
59
59
 
60
60
  if block.size != 16:
61
61
  return False, []
@@ -22,7 +22,6 @@ from ailment.expression import (
22
22
  Const,
23
23
  BinaryOp,
24
24
  VirtualVariable,
25
- Phi,
26
25
  )
27
26
 
28
27
  from angr.analyses.s_reaching_definitions import SRDAModel
@@ -36,7 +35,7 @@ from angr.knowledge_plugins.key_definitions.constants import OP_BEFORE
36
35
  from angr.errors import AngrRuntimeError
37
36
  from angr.analyses import Analysis, AnalysesHub
38
37
  from .ailgraph_walker import AILGraphWalker
39
- from .expression_narrower import ExpressionNarrowingWalker
38
+ from .expression_narrower import ExprNarrowingInfo, NarrowingInfoExtractor, ExpressionNarrower
40
39
  from .block_simplifier import BlockSimplifier
41
40
  from .ccall_rewriters import CCALL_REWRITERS
42
41
  from .counters.expression_counters import SingleExpressionCounter
@@ -76,26 +75,6 @@ class AILBlockTempCollector(AILBlockWalker):
76
75
  self.temps.add(expr)
77
76
 
78
77
 
79
- class ExprNarrowingInfo:
80
- """
81
- Stores the analysis result of _narrowing_needed().
82
- """
83
-
84
- __slots__ = ("narrowable", "to_size", "use_exprs", "phi_vars")
85
-
86
- def __init__(
87
- self,
88
- narrowable: bool,
89
- to_size: int | None = None,
90
- use_exprs: list[tuple[atoms.VirtualVariable, CodeLocation, tuple[str, tuple[Expression, ...]]]] | None = None,
91
- phi_vars: set[atoms.VirtualVariable] | None = None,
92
- ):
93
- self.narrowable = narrowable
94
- self.to_size = to_size
95
- self.use_exprs = use_exprs
96
- self.phi_vars = phi_vars
97
-
98
-
99
78
  class AILSimplifier(Analysis):
100
79
  """
101
80
  Perform function-level simplifications.
@@ -343,309 +322,26 @@ class AILSimplifier(Analysis):
343
322
  if not repeat:
344
323
  break
345
324
 
346
- replaced_vvar_ids = set()
347
-
348
325
  # let's narrow them (finally)
349
- for def_, narrow_info in narrowables:
350
-
351
- # does any uses involve a previously replaced expressions? if so, we have to skip this one because the use
352
- # expression may no longer exist.
353
- should_skip = False
354
- for _, _, (use_type, use_expr_tpl) in narrow_info.use_exprs:
355
- if use_type == "binop-convert" and self._exprs_contain_vvar(use_expr_tpl, replaced_vvar_ids):
356
- should_skip = True
357
- break
358
- if should_skip:
359
- continue
360
-
361
- # replace the definition
362
- if not isinstance(def_.codeloc, ExternalCodeLocation):
363
- old_block = addr_and_idx_to_block.get((def_.codeloc.block_addr, def_.codeloc.block_idx))
364
- if old_block is None:
365
- # this definition might be inside a callee function, which is why the block does not exist
366
- # ignore it
367
- continue
368
-
369
- the_block = self.blocks.get(old_block, old_block)
370
- stmt = the_block.statements[def_.codeloc.stmt_idx]
371
- r, new_block = False, None
372
- replaced_vvar: VirtualVariable | None = None
373
- if is_phi_assignment(stmt):
374
- new_assignment_dst = VirtualVariable(
375
- stmt.dst.idx,
376
- stmt.dst.varid,
377
- narrow_info.to_size * self.project.arch.byte_width,
378
- category=def_.atom.category,
379
- oident=def_.atom.oident,
380
- **stmt.dst.tags,
381
- )
382
- new_src_and_vvars = []
383
- for src, vvar in stmt.src.src_and_vvars:
384
- if vvar is not None and vvar.varid == stmt.dst.varid:
385
- new_vvar = VirtualVariable(
386
- vvar.idx,
387
- vvar.varid,
388
- narrow_info.to_size * self.project.arch.byte_width,
389
- category=vvar.category,
390
- oident=vvar.oident,
391
- **vvar.tags,
392
- )
393
- else:
394
- new_vvar = vvar
395
- new_src_and_vvars.append((src, new_vvar))
396
- new_assignment_src = Phi(
397
- stmt.src.idx,
398
- narrow_info.to_size * self.project.arch.byte_width,
399
- new_src_and_vvars,
400
- **stmt.src.tags,
401
- )
402
- replaced_vvar = stmt.dst
403
- r, new_block = BlockSimplifier._replace_and_build(
404
- the_block,
405
- {
406
- def_.codeloc: {
407
- stmt.dst: new_assignment_dst,
408
- stmt.src: new_assignment_src,
409
- }
410
- },
411
- replace_assignment_dsts=True,
412
- replace_loads=True,
413
- )
414
- elif isinstance(stmt, Assignment) and isinstance(stmt.dst, VirtualVariable) and stmt.dst.was_reg:
415
- new_assignment_dst = VirtualVariable(
416
- stmt.dst.idx,
417
- stmt.dst.varid,
418
- narrow_info.to_size * self.project.arch.byte_width,
419
- category=def_.atom.category,
420
- oident=def_.atom.oident,
421
- **stmt.dst.tags,
422
- )
423
- new_assignment_src = Convert(
424
- stmt.src.idx, # FIXME: This is a hack
425
- stmt.src.bits,
426
- narrow_info.to_size * self.project.arch.byte_width,
427
- False,
428
- stmt.src,
429
- **stmt.src.tags,
430
- )
431
- replaced_vvar = stmt.dst
432
- r, new_block = BlockSimplifier._replace_and_build(
433
- the_block,
434
- {
435
- def_.codeloc: {
436
- stmt.dst: new_assignment_dst,
437
- stmt.src: new_assignment_src,
438
- }
439
- },
440
- replace_assignment_dsts=True,
441
- replace_loads=True,
442
- )
443
- elif isinstance(stmt, Call):
444
- if stmt.ret_expr is not None:
445
- tags = dict(stmt.ret_expr.tags)
446
- tags["reg_name"] = self.project.arch.translate_register_name(
447
- def_.atom.reg_offset, size=narrow_info.to_size
448
- )
449
- replaced_vvar = stmt.ret_expr
450
- new_retexpr = VirtualVariable(
451
- stmt.ret_expr.idx,
452
- stmt.ret_expr.varid,
453
- narrow_info.to_size * self.project.arch.byte_width,
454
- category=def_.atom.category,
455
- oident=def_.atom.oident,
456
- **stmt.ret_expr.tags,
457
- )
458
- r, new_block = BlockSimplifier._replace_and_build(
459
- the_block, {def_.codeloc: {stmt.ret_expr: new_retexpr}}
460
- )
461
- if not r:
462
- # couldn't replace the definition...
463
- continue
326
+ narrower = ExpressionNarrower(self.project, rd, narrowables, addr_and_idx_to_block, self.blocks)
327
+ for old_block in addr_and_idx_to_block.values():
328
+ new_block = self.blocks.get(old_block, old_block)
329
+ new_block = narrower.walk(new_block)
330
+ if narrower.narrowed_any:
331
+ narrowed = True
464
332
  self.blocks[old_block] = new_block
465
- if replaced_vvar is not None:
466
- replaced_vvar_ids.add(replaced_vvar.varid)
467
-
468
- use_exprs = list(narrow_info.use_exprs)
469
- if narrow_info.phi_vars:
470
- for phi_var in narrow_info.phi_vars:
471
- loc = rd.all_vvar_definitions[phi_var]
472
- old_block = addr_and_idx_to_block.get((loc.block_addr, loc.block_idx))
473
- the_block = self.blocks.get(old_block, old_block)
474
- stmt = the_block.statements[loc.stmt_idx]
475
- assert is_phi_assignment(stmt)
476
-
477
- for _, vvar in stmt.src.src_and_vvars:
478
- if vvar is not None and vvar.varid == def_.atom.varid:
479
- use_exprs.append((vvar, loc, ("phi-src-expr", (vvar,))))
480
-
481
- # replace all uses if necessary
482
- for use_atom, use_loc, (use_type, use_expr_tpl) in use_exprs:
483
- if (
484
- isinstance(use_expr_tpl[0], VirtualVariable)
485
- and use_expr_tpl[0].was_reg
486
- and narrow_info.to_size == use_expr_tpl[0].size
487
- ):
488
- # don't replace registers to the same registers
489
- continue
490
- if use_atom.varid != def_.atom.varid:
491
- # don't replace this use - it will be replaced later
492
- continue
493
-
494
- old_block = addr_and_idx_to_block.get((use_loc.block_addr, use_loc.block_idx))
495
- the_block = self.blocks.get(old_block, old_block)
496
-
497
- if use_type in {"expr", "mask", "convert"}:
498
- # the first used expr
499
- use_expr_0 = use_expr_tpl[0]
500
- new_use_expr_0 = VirtualVariable(
501
- use_expr_0.idx,
502
- def_.atom.varid,
503
- narrow_info.to_size * self.project.arch.byte_width,
504
- category=def_.atom.category,
505
- oident=def_.atom.oident,
506
- **use_expr_0.tags,
507
- )
508
- new_use_expr = new_use_expr_0
509
-
510
- # the second used expr (if it exists)
511
- if len(use_expr_tpl) == 2:
512
- use_expr_1 = use_expr_tpl[1]
513
- assert isinstance(use_expr_1, BinaryOp)
514
- con = use_expr_1.operands[1]
515
- assert isinstance(con, Const)
516
- new_use_expr_1 = BinaryOp(
517
- use_expr_1.idx,
518
- use_expr_1.op,
519
- [
520
- new_use_expr_0,
521
- Const(con.idx, con.variable, con.value, new_use_expr_0.bits, **con.tags),
522
- ],
523
- use_expr_1.signed,
524
- floating_point=use_expr_1.floating_point,
525
- rounding_mode=use_expr_1.rounding_mode,
526
- **use_expr_1.tags,
527
- )
528
-
529
- if use_expr_1.size > new_use_expr_1.size:
530
- new_use_expr_1 = Convert(
531
- None,
532
- new_use_expr_1.bits,
533
- use_expr_1.bits,
534
- False,
535
- new_use_expr_1,
536
- **new_use_expr_1.tags,
537
- )
538
-
539
- r, new_block = BlockSimplifier._replace_and_build(
540
- the_block, {use_loc: {use_expr_1: new_use_expr_1}}
541
- )
542
- elif len(use_expr_tpl) == 1:
543
- if use_expr_0.size > new_use_expr_0.size:
544
- new_use_expr_0 = Convert(
545
- None,
546
- new_use_expr_0.bits,
547
- use_expr_0.bits,
548
- False,
549
- new_use_expr_0,
550
- **new_use_expr_0.tags,
551
- )
552
333
 
553
- r, new_block = BlockSimplifier._replace_and_build(
554
- the_block, {use_loc: {use_expr_0: new_use_expr_0}}
555
- )
556
- else:
557
- _l.warning("Nothing to replace at %s.", use_loc)
558
- r = False
559
- new_block = None
560
-
561
- elif use_type == "phi-src-expr":
562
- # the size of the replaced variable will be different from its original size, and it's expected
563
- use_expr = use_expr_tpl[0]
564
- new_use_expr = VirtualVariable(
565
- use_expr.idx,
566
- def_.atom.varid,
567
- narrow_info.to_size * self.project.arch.byte_width,
568
- category=def_.atom.category,
569
- oident=def_.atom.oident,
570
- **use_expr.tags,
571
- )
572
- r, new_block = BlockSimplifier._replace_and_build(the_block, {use_loc: {use_expr: new_use_expr}})
573
-
574
- elif use_type == "binop-convert":
575
- use_expr_0 = use_expr_tpl[0]
576
- new_use_expr_0 = VirtualVariable(
577
- use_expr_0.idx,
578
- def_.atom.varid,
579
- narrow_info.to_size * self.project.arch.byte_width,
580
- category=def_.atom.category,
581
- oident=def_.atom.oident,
582
- **use_expr_0.tags,
583
- )
584
- new_use_expr = new_use_expr_0
585
-
586
- use_expr_1: BinaryOp = use_expr_tpl[1]
587
- # build the new use_expr_1
588
- new_use_expr_1_operands = {}
589
- if use_expr_1.operands[0] is use_expr_0:
590
- new_use_expr_1_operands[0] = new_use_expr_0
591
- other_operand = use_expr_1.operands[1]
592
- else:
593
- new_use_expr_1_operands[1] = new_use_expr_0
594
- other_operand = use_expr_1.operands[0]
595
- use_expr_2: Convert = use_expr_tpl[2]
596
- if other_operand.bits == use_expr_2.from_bits:
597
- new_other_operand = Convert(
598
- None, use_expr_2.from_bits, use_expr_2.to_bits, False, other_operand
599
- )
600
- else:
601
- # Some operations, like Sar and Shl, have operands with different sizes
602
- new_other_operand = other_operand
603
-
604
- if 0 in new_use_expr_1_operands:
605
- new_use_expr_1_operands[1] = new_other_operand
606
- else:
607
- new_use_expr_1_operands[0] = new_other_operand
608
-
609
- # build new use_expr_1
610
- new_use_expr_1 = BinaryOp(
611
- use_expr_1.idx,
612
- use_expr_1.op,
613
- [new_use_expr_1_operands[0], new_use_expr_1_operands[1]],
614
- use_expr_1.signed,
615
- bits=narrow_info.to_size * 8,
616
- floating_point=use_expr_1.floating_point,
617
- rounding_mode=use_expr_1.rounding_mode,
618
- **use_expr_1.tags,
619
- )
620
-
621
- # first remove the old conversion
622
- r, new_block = BlockSimplifier._replace_and_build(
623
- the_block, {use_loc: {use_expr_2: use_expr_2.operand}}
624
- )
625
- # then replace use_expr_1
626
- if r:
627
- r, new_block = BlockSimplifier._replace_and_build(
628
- new_block, {use_loc: {use_expr_1: new_use_expr_1}}
629
- )
630
- else:
631
- raise TypeError(f'Unsupported use_type value "{use_type}"')
632
-
633
- if not r:
634
- _l.warning("Failed to replace use-expr at %s.", use_loc)
635
- else:
636
- # update self._arg_vvars if necessary
637
- if new_use_expr is not None and new_use_expr.was_parameter and self._arg_vvars:
638
- for func_arg_idx in list(self._arg_vvars):
639
- vvar, simvar = self._arg_vvars[func_arg_idx]
640
- if vvar.varid == new_use_expr.varid:
641
- simvar_new = simvar.copy()
642
- simvar_new._hash = None
643
- simvar_new.size = new_use_expr.size
644
- self._arg_vvars[func_arg_idx] = new_use_expr, simvar_new
645
-
646
- self.blocks[old_block] = new_block
647
-
648
- narrowed = True
334
+ # update self._arg_vvars if necessary
335
+ for new_vvars in narrower.replacement_core_vvars.values():
336
+ for new_vvar in new_vvars:
337
+ if new_vvar.was_parameter and self._arg_vvars:
338
+ for func_arg_idx in list(self._arg_vvars):
339
+ vvar, simvar = self._arg_vvars[func_arg_idx]
340
+ if vvar.varid == new_vvar.varid:
341
+ simvar_new = simvar.copy()
342
+ simvar_new._hash = None
343
+ simvar_new.size = new_vvar.size
344
+ self._arg_vvars[func_arg_idx] = new_vvar, simvar_new
649
345
 
650
346
  return narrowed
651
347
 
@@ -669,6 +365,9 @@ class AILSimplifier(Analysis):
669
365
  if len(narrowing_sizes) == 1 and None not in narrowing_sizes:
670
366
  # we can narrow this phi vvar!
671
367
  narrowable_phivarids.add(def_vvarid)
368
+ else:
369
+ # blacklist it for now
370
+ blacklist_varids.add(def_vvarid)
672
371
 
673
372
  # now determine what to narrow!
674
373
  narrowables = []
@@ -834,7 +533,7 @@ class AILSimplifier(Analysis):
834
533
  Determine the effective size of an expression when it's used.
835
534
  """
836
535
 
837
- walker = ExpressionNarrowingWalker(expr)
536
+ walker = NarrowingInfoExtractor(expr)
838
537
  walker.walk_statement(statement)
839
538
  if not walker.operations:
840
539
  if expr is None:
@@ -1617,18 +1316,7 @@ class AILSimplifier(Analysis):
1617
1316
  continue
1618
1317
  uses = rd.get_vvar_uses(def_.atom)
1619
1318
 
1620
- elif def_.atom.was_reg:
1621
- uses = rd.get_vvar_uses(def_.atom)
1622
- if (
1623
- def_.atom.reg_offset in self.project.arch.artificial_registers_offsets
1624
- and len(uses) == 1
1625
- and next(iter(uses)) == def_.codeloc
1626
- ):
1627
- # TODO: Verify if we still need this hack after moving to SSA
1628
- # cc_ndep = amd64g_calculate_condition(..., cc_ndep)
1629
- uses = set()
1630
-
1631
- elif def_.atom.was_parameter:
1319
+ elif def_.atom.was_reg or def_.atom.was_parameter:
1632
1320
  uses = rd.get_vvar_uses(def_.atom)
1633
1321
 
1634
1322
  else:
@@ -1726,9 +1414,17 @@ class AILSimplifier(Analysis):
1726
1414
  simplified = True
1727
1415
  continue
1728
1416
  if isinstance(stmt, Assignment) and isinstance(stmt.dst, VirtualVariable):
1729
- # no one is using the returned virtual variable. replace this assignment statement with
1730
- # a call statement
1731
- stmt = stmt.src
1417
+ # no one is using the returned virtual variable.
1418
+ # now the things are a bit tricky here
1419
+ if isinstance(stmt.src, Call):
1420
+ # replace this assignment statement with a call statement
1421
+ stmt = stmt.src
1422
+ elif isinstance(stmt.src, Convert) and isinstance(stmt.src.operand, Call):
1423
+ # the convert is useless now
1424
+ stmt = stmt.src.operand
1425
+ else:
1426
+ # we can't change this stmt at all because it has an expression with Calls inside
1427
+ pass
1732
1428
  else:
1733
1429
  # no calls. remove it
1734
1430
  simplified = True
@@ -1761,7 +1457,7 @@ class AILSimplifier(Analysis):
1761
1457
  def _find_cyclic_dependent_phis_and_dirty_vvars(self, rd: SRDAModel) -> set[int]:
1762
1458
  blocks_dict = {(bb.addr, bb.idx): bb for bb in self.func_graph}
1763
1459
 
1764
- # find dirty vvars
1460
+ # find dirty vvars and vexccall vvars
1765
1461
  dirty_vvar_ids = set()
1766
1462
  for bb in self.func_graph:
1767
1463
  for stmt in bb.statements:
@@ -1769,7 +1465,7 @@ class AILSimplifier(Analysis):
1769
1465
  isinstance(stmt, Assignment)
1770
1466
  and isinstance(stmt.dst, VirtualVariable)
1771
1467
  and stmt.dst.was_reg
1772
- and isinstance(stmt.src, DirtyExpression)
1468
+ and isinstance(stmt.src, (DirtyExpression, VEXCCallExpression))
1773
1469
  ):
1774
1470
  dirty_vvar_ids.add(stmt.dst.varid)
1775
1471
 
@@ -1845,8 +1541,8 @@ class AILSimplifier(Analysis):
1845
1541
  v = False
1846
1542
 
1847
1543
  def _handle_expr(expr_idx: int, expr: Expression, stmt_idx: int, stmt: Statement, block) -> Expression | None:
1848
- if isinstance(expr, DirtyExpression) and isinstance(expr.dirty_expr, VEXCCallExpression):
1849
- rewriter = rewriter_cls(expr.dirty_expr, self.project.arch)
1544
+ if isinstance(expr, VEXCCallExpression):
1545
+ rewriter = rewriter_cls(expr, self.project.arch)
1850
1546
  if rewriter.result is not None:
1851
1547
  _any_update.v = True
1852
1548
  return rewriter.result
@@ -143,7 +143,7 @@ class CallSiteMaker(Analysis):
143
143
  if isinstance(arg_loc, SimRegArg):
144
144
  size = arg_loc.size
145
145
  offset = arg_loc.check_offset(cc.arch)
146
- value_and_def = self._resolve_register_argument(call_stmt, arg_loc)
146
+ value_and_def = self._resolve_register_argument(arg_loc)
147
147
  if value_and_def is not None:
148
148
  vvar_def = value_and_def[1]
149
149
  arg_vvars.append(vvar_def)
@@ -283,14 +283,15 @@ class CallSiteMaker(Analysis):
283
283
  l.warning("TODO: Unsupported statement type %s for definitions.", type(stmt))
284
284
  return None
285
285
 
286
- def _resolve_register_argument(self, call_stmt, arg_loc) -> tuple[int | None, Expr.VirtualVariable] | None:
286
+ def _resolve_register_argument(self, arg_loc) -> tuple[int | None, Expr.VirtualVariable] | None:
287
287
  offset = arg_loc.check_offset(self.project.arch)
288
288
 
289
289
  if self._reaching_definitions is not None:
290
290
  # Find its definition
291
- ins_addr = call_stmt.tags["ins_addr"]
292
291
  view = SRDAView(self._reaching_definitions.model)
293
- vvar = view.get_reg_vvar_by_insn(offset, ins_addr, OP_BEFORE, block_idx=self.block.idx)
292
+ vvar = view.get_reg_vvar_by_stmt(
293
+ offset, self.block.addr, self.block.idx, len(self.block.statements) - 1, OP_BEFORE
294
+ )
294
295
 
295
296
  if vvar is not None:
296
297
  vvar_value = view.get_vvar_value(vvar)
@@ -318,8 +319,8 @@ class CallSiteMaker(Analysis):
318
319
  if self._reaching_definitions is not None:
319
320
  # find its definition
320
321
  view = SRDAView(self._reaching_definitions.model)
321
- vvar = view.get_stack_vvar_by_insn(
322
- sp_offset, size, call_stmt.ins_addr, OP_BEFORE, block_idx=self.block.idx
322
+ vvar = view.get_stack_vvar_by_stmt(
323
+ sp_offset, size, self.block.addr, self.block.idx, len(self.block.statements) - 1, OP_BEFORE
323
324
  )
324
325
  if vvar is not None:
325
326
  value = view.get_vvar_value(vvar)
@@ -416,7 +417,7 @@ class CallSiteMaker(Analysis):
416
417
 
417
418
  value = None
418
419
  if isinstance(arg_loc, SimRegArg):
419
- value_and_def = self._resolve_register_argument(call_stmt, arg_loc)
420
+ value_and_def = self._resolve_register_argument(arg_loc)
420
421
  if value_and_def is not None:
421
422
  value = value_and_def[0]
422
423
 
@@ -20,7 +20,7 @@ class AMD64CCallRewriter(CCallRewriterBase):
20
20
  __slots__ = ()
21
21
 
22
22
  def _rewrite(self, ccall: Expr.VEXCCallExpression) -> Expr.Expression | None:
23
- if ccall.cee_name == "amd64g_calculate_condition":
23
+ if ccall.callee == "amd64g_calculate_condition":
24
24
  cond = ccall.operands[0]
25
25
  op = ccall.operands[1]
26
26
  dep_1 = ccall.operands[2]
@@ -288,6 +288,28 @@ class AMD64CCallRewriter(CCallRewriterBase):
288
288
 
289
289
  r = Expr.BinaryOp(ccall.idx, "CmpLT", (dep_1, dep_2), True, **ccall.tags)
290
290
  return Expr.Convert(None, r.bits, ccall.bits, False, r, **ccall.tags)
291
+
292
+ if op_v in {
293
+ AMD64_OpTypes["G_CC_OP_LOGICB"],
294
+ AMD64_OpTypes["G_CC_OP_LOGICW"],
295
+ AMD64_OpTypes["G_CC_OP_LOGICL"],
296
+ AMD64_OpTypes["G_CC_OP_LOGICQ"],
297
+ }:
298
+ # dep_1 is the result, dep_2 is always zero
299
+ # dep_1 <s 0
300
+
301
+ dep_1 = self._fix_size(
302
+ dep_1,
303
+ op_v,
304
+ AMD64_OpTypes["G_CC_OP_LOGICB"],
305
+ AMD64_OpTypes["G_CC_OP_LOGICW"],
306
+ AMD64_OpTypes["G_CC_OP_LOGICL"],
307
+ ccall.tags,
308
+ )
309
+ zero = Expr.Const(None, None, 0, dep_1.bits)
310
+ r = Expr.BinaryOp(ccall.idx, "CmpLT", (dep_1, zero), True, **ccall.tags)
311
+ return Expr.Convert(None, r.bits, ccall.bits, False, r, **ccall.tags)
312
+
291
313
  elif cond_v == AMD64_CondTypes["CondNBE"]:
292
314
  if op_v in {
293
315
  AMD64_OpTypes["G_CC_OP_SUBB"],
@@ -390,7 +412,7 @@ class AMD64CCallRewriter(CCallRewriterBase):
390
412
  )
391
413
  return Expr.Convert(None, r.bits, ccall.bits, False, r, **ccall.tags)
392
414
 
393
- elif ccall.cee_name == "amd64g_calculate_rflags_c":
415
+ elif ccall.callee == "amd64g_calculate_rflags_c":
394
416
  # calculate the carry flag
395
417
  op = ccall.operands[0]
396
418
  dep_1 = ccall.operands[1]