dexllm 0.8.2__tar.gz
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.
- dexllm-0.8.2/.claude/dad-reminder.sh +60 -0
- dexllm-0.8.2/.claude/docs-precommit-check.sh +43 -0
- dexllm-0.8.2/.claude/py-quality.sh +44 -0
- dexllm-0.8.2/.claude/review-precommit-check.sh +93 -0
- dexllm-0.8.2/.claude/settings.json +56 -0
- dexllm-0.8.2/.claude/skills/dexkit-bench/SKILL.md +100 -0
- dexllm-0.8.2/.claude/skills/dexkit-build/SKILL.md +26 -0
- dexllm-0.8.2/.claude/skills/dexkit-decompile/SKILL.md +52 -0
- dexllm-0.8.2/.claude/skills/dexkit-diff/SKILL.md +77 -0
- dexllm-0.8.2/.claude/skills/dexkit-sweep/SKILL.md +95 -0
- dexllm-0.8.2/.claude/skills/dexkit-trace/SKILL.md +111 -0
- dexllm-0.8.2/.claude/skills/jadx-diff/SKILL.md +100 -0
- dexllm-0.8.2/.claude/skills/karpathy-guidelines/SKILL.md +67 -0
- dexllm-0.8.2/.github/workflows/ci.yml +77 -0
- dexllm-0.8.2/.github/workflows/release.yml +114 -0
- dexllm-0.8.2/.gitignore +34 -0
- dexllm-0.8.2/CLAUDE.md +559 -0
- dexllm-0.8.2/CMakeLists.txt +104 -0
- dexllm-0.8.2/LICENSE +201 -0
- dexllm-0.8.2/PKG-INFO +382 -0
- dexllm-0.8.2/README.md +348 -0
- dexllm-0.8.2/bench/README.md +26 -0
- dexllm-0.8.2/bench/bench_vs_androguard.py +311 -0
- dexllm-0.8.2/docs/RELEASING.md +107 -0
- dexllm-0.8.2/docs/aosp-oob-divergences.md +134 -0
- dexllm-0.8.2/docs/api.md +790 -0
- dexllm-0.8.2/docs/architecture.md +148 -0
- dexllm-0.8.2/docs/dexkit-vs-art-dex-handling.md +254 -0
- dexllm-0.8.2/docs/sdk.md +287 -0
- dexllm-0.8.2/docs/type-inference-design.md +499 -0
- dexllm-0.8.2/docs/usage.md +782 -0
- dexllm-0.8.2/docs/windows-port-plan.md +209 -0
- dexllm-0.8.2/docs/workflow.md +198 -0
- dexllm-0.8.2/examples/01_overview.py +31 -0
- dexllm-0.8.2/examples/02_decompile.py +45 -0
- dexllm-0.8.2/examples/03_search.py +31 -0
- dexllm-0.8.2/examples/04_decompile_dex.py +55 -0
- dexllm-0.8.2/examples/05_extract_iocs.py +37 -0
- dexllm-0.8.2/examples/README.md +24 -0
- dexllm-0.8.2/examples/_common.py +27 -0
- dexllm-0.8.2/native/binding/module.cpp +972 -0
- dexllm-0.8.2/native/core_ext/analysis.cpp +187 -0
- dexllm-0.8.2/native/core_ext/dex_verifier.cpp +1114 -0
- dexllm-0.8.2/native/core_ext/dexitem_code_source.cpp +702 -0
- dexllm-0.8.2/native/core_ext/dexkit_ext.cpp +2010 -0
- dexllm-0.8.2/native/core_ext/gen/perm_api_data.h +431 -0
- dexllm-0.8.2/native/core_ext/include/analysis.h +51 -0
- dexllm-0.8.2/native/core_ext/include/api_ref.h +128 -0
- dexllm-0.8.2/native/core_ext/include/dex_verifier.h +132 -0
- dexllm-0.8.2/native/core_ext/include/dexitem_code_source.h +64 -0
- dexllm-0.8.2/native/core_ext/include/dexkit_ext.h +411 -0
- dexllm-0.8.2/native/dad_cpp/basic_blocks.cpp +621 -0
- dexllm-0.8.2/native/dad_cpp/control_flow.cpp +776 -0
- dexllm-0.8.2/native/dad_cpp/dast.cpp +1141 -0
- dexllm-0.8.2/native/dad_cpp/dataflow.cpp +2174 -0
- dexllm-0.8.2/native/dad_cpp/decompile.cpp +158 -0
- dexllm-0.8.2/native/dad_cpp/decompiler.cpp +343 -0
- dexllm-0.8.2/native/dad_cpp/graph.cpp +880 -0
- dexllm-0.8.2/native/dad_cpp/include/basic_blocks.h +504 -0
- dexllm-0.8.2/native/dad_cpp/include/control_flow.h +114 -0
- dexllm-0.8.2/native/dad_cpp/include/dast.h +201 -0
- dexllm-0.8.2/native/dad_cpp/include/dataflow.h +284 -0
- dexllm-0.8.2/native/dad_cpp/include/decompile.h +79 -0
- dexllm-0.8.2/native/dad_cpp/include/decompiler.h +118 -0
- dexllm-0.8.2/native/dad_cpp/include/dex_code_source.h +134 -0
- dexllm-0.8.2/native/dad_cpp/include/graph.h +202 -0
- dexllm-0.8.2/native/dad_cpp/include/instruction.h +1119 -0
- dexllm-0.8.2/native/dad_cpp/include/instruction_dispatch.h +35 -0
- dexllm-0.8.2/native/dad_cpp/include/method_snapshot.h +201 -0
- dexllm-0.8.2/native/dad_cpp/include/mock_code_source.h +103 -0
- dexllm-0.8.2/native/dad_cpp/include/mutf8.h +85 -0
- dexllm-0.8.2/native/dad_cpp/include/node.h +168 -0
- dexllm-0.8.2/native/dad_cpp/include/opcode_ins.h +744 -0
- dexllm-0.8.2/native/dad_cpp/include/util.h +86 -0
- dexllm-0.8.2/native/dad_cpp/include/visitor.h +163 -0
- dexllm-0.8.2/native/dad_cpp/include/writer.h +155 -0
- dexllm-0.8.2/native/dad_cpp/instruction.cpp +1656 -0
- dexllm-0.8.2/native/dad_cpp/instruction_accept.cpp +217 -0
- dexllm-0.8.2/native/dad_cpp/instruction_dispatch.cpp +555 -0
- dexllm-0.8.2/native/dad_cpp/method_snapshot_builder.cpp +779 -0
- dexllm-0.8.2/native/dad_cpp/mock_code_source.cpp +194 -0
- dexllm-0.8.2/native/dad_cpp/mutf8.cpp +194 -0
- dexllm-0.8.2/native/dad_cpp/node.cpp +97 -0
- dexllm-0.8.2/native/dad_cpp/opcode_ins.cpp +1203 -0
- dexllm-0.8.2/native/dad_cpp/util.cpp +252 -0
- dexllm-0.8.2/native/dad_cpp/writer.cpp +1264 -0
- dexllm-0.8.2/pyproject.toml +143 -0
- dexllm-0.8.2/scripts/check_dad_boundary.sh +34 -0
- dexllm-0.8.2/scripts/gen_perm_api_data.py +393 -0
- dexllm-0.8.2/scripts/gen_perm_data.py +125 -0
- dexllm-0.8.2/scripts/jadx_parity.py +128 -0
- dexllm-0.8.2/scripts/jadx_ref.py +127 -0
- dexllm-0.8.2/scripts/make_portable_zip.sh +55 -0
- dexllm-0.8.2/src/dexllm/__init__.py +120 -0
- dexllm-0.8.2/src/dexllm/__init__.pyi +169 -0
- dexllm-0.8.2/src/dexllm/_dexkit_core.pyi +917 -0
- dexllm-0.8.2/src/dexllm/_enrich.py +69 -0
- dexllm-0.8.2/src/dexllm/capability.py +119 -0
- dexllm-0.8.2/src/dexllm/dangerous_api.py +629 -0
- dexllm-0.8.2/src/dexllm/data/android_api_map.json +169 -0
- dexllm-0.8.2/src/dexllm/data/content_uris.json +1 -0
- dexllm-0.8.2/src/dexllm/data/perm_api.json +1 -0
- dexllm-0.8.2/src/dexllm/data/perm_levels.json +1 -0
- dexllm-0.8.2/src/dexllm/descriptors.py +214 -0
- dexllm-0.8.2/src/dexllm/filters.py +94 -0
- dexllm-0.8.2/src/dexllm/format.py +122 -0
- dexllm-0.8.2/src/dexllm/ioc.py +410 -0
- dexllm-0.8.2/src/dexllm/mcp_server.py +173 -0
- dexllm-0.8.2/src/dexllm/packer.py +61 -0
- dexllm-0.8.2/src/dexllm/providers.py +98 -0
- dexllm-0.8.2/src/dexllm/py.typed +0 -0
- dexllm-0.8.2/src/dexllm/safe.py +154 -0
- dexllm-0.8.2/src/dexllm/sdk/__init__.py +118 -0
- dexllm-0.8.2/src/dexllm/sdk/adapter.py +850 -0
- dexllm-0.8.2/src/dexllm/sdk/model.py +655 -0
- dexllm-0.8.2/src/dexllm/sdk/ports.py +541 -0
- dexllm-0.8.2/src/dexllm/server.py +356 -0
- dexllm-0.8.2/src/dexllm/tools.py +1432 -0
- dexllm-0.8.2/tests/README.md +46 -0
- dexllm-0.8.2/tests/conftest.py +99 -0
- dexllm-0.8.2/tests/dvclass_parity.py +209 -0
- dexllm-0.8.2/tests/jadx_parity_baseline.json +9 -0
- dexllm-0.8.2/tests/llm_backend_integration.py +217 -0
- dexllm-0.8.2/tests/parity/CMakeLists.txt +28 -0
- dexllm-0.8.2/tests/parity/basic_blocks_parity_test.cpp +251 -0
- dexllm-0.8.2/tests/parity/construct_parity_test.cpp +132 -0
- dexllm-0.8.2/tests/parity/control_flow_parity_test.cpp +122 -0
- dexllm-0.8.2/tests/parity/dast_parity_test.cpp +84 -0
- dexllm-0.8.2/tests/parity/dataflow_parity_test.cpp +532 -0
- dexllm-0.8.2/tests/parity/dex_verifier_parity_test.cpp +136 -0
- dexllm-0.8.2/tests/parity/dispatch_parity_test.cpp +255 -0
- dexllm-0.8.2/tests/parity/graph_parity_test.cpp +225 -0
- dexllm-0.8.2/tests/parity/instr_chunk1_parity_test.cpp +129 -0
- dexllm-0.8.2/tests/parity/instr_chunk2_parity_test.cpp +117 -0
- dexllm-0.8.2/tests/parity/instr_chunk3_parity_test.cpp +147 -0
- dexllm-0.8.2/tests/parity/instr_chunk4_parity_test.cpp +73 -0
- dexllm-0.8.2/tests/parity/instr_chunk5_parity_test.cpp +82 -0
- dexllm-0.8.2/tests/parity/instr_chunk6_parity_test.cpp +55 -0
- dexllm-0.8.2/tests/parity/instr_chunk7_parity_test.cpp +94 -0
- dexllm-0.8.2/tests/parity/instr_chunk8_parity_test.cpp +47 -0
- dexllm-0.8.2/tests/parity/method_snapshot_parity_test.cpp +251 -0
- dexllm-0.8.2/tests/parity/mutf8_parity_test.cpp +231 -0
- dexllm-0.8.2/tests/parity/node_parity_test.cpp +94 -0
- dexllm-0.8.2/tests/parity/opcode_chunkA_parity_test.cpp +113 -0
- dexllm-0.8.2/tests/parity/opcode_chunkB_parity_test.cpp +130 -0
- dexllm-0.8.2/tests/parity/opcode_chunkC_parity_test.cpp +74 -0
- dexllm-0.8.2/tests/parity/opcode_chunkD_parity_test.cpp +99 -0
- dexllm-0.8.2/tests/parity/opcode_chunkE_parity_test.cpp +61 -0
- dexllm-0.8.2/tests/parity/opcode_chunkF_parity_test.cpp +67 -0
- dexllm-0.8.2/tests/parity/return_literal_parity_test.cpp +169 -0
- dexllm-0.8.2/tests/parity/util_parity_test.cpp +119 -0
- dexllm-0.8.2/tests/parity/writer_parity_test.cpp +0 -0
- dexllm-0.8.2/tests/test_access_flags.py +259 -0
- dexllm-0.8.2/tests/test_cascade_type.py +677 -0
- dexllm-0.8.2/tests/test_clinit.py +131 -0
- dexllm-0.8.2/tests/test_clinit_tail_oracle.py +143 -0
- dexllm-0.8.2/tests/test_dangerous_api.py +479 -0
- dexllm-0.8.2/tests/test_dexkit.py +1119 -0
- dexllm-0.8.2/tests/test_ioc.py +308 -0
- dexllm-0.8.2/tests/test_jadx_parity.py +83 -0
- dexllm-0.8.2/tests/test_lenient_verify.py +218 -0
- dexllm-0.8.2/tests/test_mcp_server.py +135 -0
- dexllm-0.8.2/tests/test_multisource.py +99 -0
- dexllm-0.8.2/tests/test_packer.py +104 -0
- dexllm-0.8.2/tests/test_pc_line_map.py +119 -0
- dexllm-0.8.2/tests/test_pc_line_map_headers.py +133 -0
- dexllm-0.8.2/tests/test_pc_map_coverage.py +58 -0
- dexllm-0.8.2/tests/test_permission_callers.py +227 -0
- dexllm-0.8.2/tests/test_return_literals.py +397 -0
- dexllm-0.8.2/tests/test_sdk.py +913 -0
- dexllm-0.8.2/tests/test_stubs.py +104 -0
- dexllm-0.8.2/tests/test_this_reuse.py +298 -0
- dexllm-0.8.2/tests/test_tools.py +610 -0
- dexllm-0.8.2/tests/test_verifier_oob.py +87 -0
- dexllm-0.8.2/tests/test_verify_api.py +208 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/.gitignore +55 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/CMakeLists.txt +65 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/LICENSE +165 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/analyze.cpp +631 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/beans.cpp +193 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/common.cpp +33 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/dex_item.cpp +2495 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/dex_item_batch_find.cpp +253 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/dex_item_find.cpp +427 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/dex_item_matcher.cpp +1976 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/dexkit.cpp +1784 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/include/analyze.h +74 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/include/beans.h +167 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/include/common.h +106 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/include/constant.h +65 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/include/dex_item.h +550 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/include/dexkit.h +181 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/include/dexkit_error.h +50 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/include/dexkit_error_list.h +37 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/include/internal/using_strings_prefilter.h +28 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/include/internal_metrics_config.h +5 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/include/matcher_thread_cache_registry.h +19 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/include/mmap.h +115 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/include/mmap_windows.h +102 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/include/package_trie.h +86 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/include/query_context.h +503 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/include/query_executor.h +133 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/include/query_scheduler.h +622 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/include/schema/encode_value_generated.h +532 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/include/schema/enums_generated.h +339 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/include/schema/matchers_generated.h +2429 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/include/schema/querys_generated.h +681 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/include/schema/ranges_generated.h +142 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/include/schema/results_generated.h +1782 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/include/string_match.h +151 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/include/zip_archive.h +608 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/using_strings_prefilter.cpp +487 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/utils/byte_code_util.h +75 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/utils/dex_descriptor_util.h +92 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/dexkit/utils/opcode_util.h +122 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/main.cpp +1271 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/aho_corasick_trie/acdat/AhoCorasickDoubleArrayTrie.h +317 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/aho_corasick_trie/acdat/Builder.h +261 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/aho_corasick_trie/acdat/State.h +120 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/flatbuffers/include/flatbuffers/allocator.h +68 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/flatbuffers/include/flatbuffers/array.h +256 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/flatbuffers/include/flatbuffers/base.h +495 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/flatbuffers/include/flatbuffers/buffer.h +199 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/flatbuffers/include/flatbuffers/buffer_ref.h +53 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/flatbuffers/include/flatbuffers/code_generator.h +97 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/flatbuffers/include/flatbuffers/code_generators.h +238 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/flatbuffers/include/flatbuffers/default_allocator.h +64 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/flatbuffers/include/flatbuffers/detached_buffer.h +114 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/flatbuffers/include/flatbuffers/file_manager.h +48 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/flatbuffers/include/flatbuffers/flatbuffer_builder.h +1480 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/flatbuffers/include/flatbuffers/flatbuffers.h +284 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/flatbuffers/include/flatbuffers/flatc.h +131 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/flatbuffers/include/flatbuffers/flex_flat_util.h +36 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/flatbuffers/include/flatbuffers/flexbuffers.h +1938 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/flatbuffers/include/flatbuffers/grpc.h +299 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/flatbuffers/include/flatbuffers/hash.h +127 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/flatbuffers/include/flatbuffers/idl.h +1268 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/flatbuffers/include/flatbuffers/minireflect.h +420 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/flatbuffers/include/flatbuffers/pch/flatc_pch.h +39 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/flatbuffers/include/flatbuffers/pch/pch.h +38 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/flatbuffers/include/flatbuffers/reflection.h +523 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/flatbuffers/include/flatbuffers/reflection_generated.h +1487 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/flatbuffers/include/flatbuffers/registry.h +130 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/flatbuffers/include/flatbuffers/stl_emulation.h +513 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/flatbuffers/include/flatbuffers/string.h +64 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/flatbuffers/include/flatbuffers/struct.h +53 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/flatbuffers/include/flatbuffers/table.h +188 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/flatbuffers/include/flatbuffers/util.h +732 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/flatbuffers/include/flatbuffers/vector.h +397 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/flatbuffers/include/flatbuffers/vector_downward.h +289 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/flatbuffers/include/flatbuffers/verifier.h +332 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/parallel_hashmap/parallel_hashmap/btree.h +4076 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/parallel_hashmap/parallel_hashmap/meminfo.h +195 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/parallel_hashmap/parallel_hashmap/phmap.h +5152 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/parallel_hashmap/parallel_hashmap/phmap_base.h +4982 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/parallel_hashmap/parallel_hashmap/phmap_bits.h +664 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/parallel_hashmap/parallel_hashmap/phmap_config.h +767 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/parallel_hashmap/parallel_hashmap/phmap_dump.h +304 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/parallel_hashmap/parallel_hashmap/phmap_fwd_decl.h +186 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/parallel_hashmap/parallel_hashmap/phmap_utils.h +407 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/bytecode_encoder.cc +684 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/code_ir.cc +678 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/common.cc +114 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/control_flow_graph.cc +138 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/debuginfo_encoder.cc +158 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/dex_bytecode.cc +333 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/dex_format.cc +115 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/dex_ir.cc +325 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/dex_ir_builder.cc +229 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/dex_utf8.cc +70 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/export/slicer/arrayview.h +54 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/export/slicer/buffer.h +178 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/export/slicer/bytecode_encoder.h +87 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/export/slicer/chronometer.h +53 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/export/slicer/code_ir.h +514 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/export/slicer/common.h +90 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/export/slicer/control_flow_graph.h +104 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/export/slicer/debuginfo_encoder.h +54 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/export/slicer/dex_bytecode.h +199 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/export/slicer/dex_format.h +366 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/export/slicer/dex_instruction_list.h +318 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/export/slicer/dex_ir.h +490 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/export/slicer/dex_ir_builder.h +86 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/export/slicer/dex_leb128.h +125 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/export/slicer/dex_utf8.h +33 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/export/slicer/hash_table.h +243 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/export/slicer/index_map.h +51 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/export/slicer/instrumentation.h +236 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/export/slicer/intrusive_list.h +142 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/export/slicer/memview.h +49 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/export/slicer/reader.h +156 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/export/slicer/scopeguard.h +77 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/export/slicer/tryblocks_encoder.h +47 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/export/slicer/writer.h +249 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/instrumentation.cc +771 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/reader.cc +1061 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/tryblocks_encoder.cc +114 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/slicer/writer.cc +1195 -0
- dexllm-0.8.2/vendor/dexkit_core/Core/third_party/thread_helper/ThreadPool.h +154 -0
- dexllm-0.8.2/vendor/dexkit_core/LICENSE +201 -0
- dexllm-0.8.2/vendor/dexkit_core/README.md +403 -0
- dexllm-0.8.2/vendor/dexkit_core/README_zh.md +396 -0
- dexllm-0.8.2/vendor/dexkit_core/schema/.gitignore +2 -0
- dexllm-0.8.2/vendor/dexkit_core/schema/README.md +21 -0
- dexllm-0.8.2/vendor/dexkit_core/schema/fbs/encode_value.fbs +41 -0
- dexllm-0.8.2/vendor/dexkit_core/schema/fbs/enums.fbs +75 -0
- dexllm-0.8.2/vendor/dexkit_core/schema/fbs/matchers.fbs +173 -0
- dexllm-0.8.2/vendor/dexkit_core/schema/fbs/querys.fbs +49 -0
- dexllm-0.8.2/vendor/dexkit_core/schema/fbs/ranges.fbs +11 -0
- dexllm-0.8.2/vendor/dexkit_core/schema/fbs/results.fbs +125 -0
- dexllm-0.8.2/vendor/dexkit_core/schema/gen_code.py +47 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Pre-edit hook for DAD-aligned C++ sources.
|
|
3
|
+
# Reads tool_input JSON from stdin (Claude Code hook protocol).
|
|
4
|
+
# Emits a system reminder enforcing DAD-reference development when the target
|
|
5
|
+
# file is under vendor/dexkit_core/Core/, native/binding/, native/dad_cpp/,
|
|
6
|
+
# or native/core_ext/.
|
|
7
|
+
#
|
|
8
|
+
# Removed subsystems (2026-05-26 audit, do NOT reintroduce):
|
|
9
|
+
# - Legacy expr-tree pipeline (Phase 2a/2b/3/4/5/6/8e)
|
|
10
|
+
# - L6_NO_EXPR_TREE / L6_LEGACY_MODE / L6_SSA_MODE env flags
|
|
11
|
+
# - PostInlineSingleUse / PostInlineShortExitTargets / PostStructureForwardGotos
|
|
12
|
+
# - PostEliminateDeadWrites / PostCollapseEmptyBlocks / PostSuppressUnusedLabels
|
|
13
|
+
# - PostSSARename / PostSuppressOrphanGotos (Phase 22)
|
|
14
|
+
# - All text-based regex post-passes on emit output
|
|
15
|
+
# Never block the tool call: any failure (malformed JSON, missing jq, parse
|
|
16
|
+
# error) should silently exit 0 so the user's edit proceeds. The reminder is
|
|
17
|
+
# advisory, not enforced.
|
|
18
|
+
set -u
|
|
19
|
+
|
|
20
|
+
# Local checkout of androguard's DAD reference source. Override per-machine:
|
|
21
|
+
# export DAD_REF=/path/to/androguard-master/androguard/decompiler
|
|
22
|
+
DAD_REF="${DAD_REF:-$HOME/androguard/androguard/decompiler}"
|
|
23
|
+
|
|
24
|
+
path="$(jq -r '.tool_input.file_path // empty' 2>/dev/null || true)"
|
|
25
|
+
if [[ -z "$path" ]]; then
|
|
26
|
+
exit 0
|
|
27
|
+
fi
|
|
28
|
+
if ! [[ "$path" =~ /vendor/dexkit_core/Core/.*\.(cpp|cc|h|hpp)$ ]] && \
|
|
29
|
+
! [[ "$path" =~ /native/binding/.*\.(cpp|cc|h|hpp)$ ]] && \
|
|
30
|
+
! [[ "$path" =~ /native/dad_cpp/.*\.(cpp|cc|h|hpp)$ ]] && \
|
|
31
|
+
! [[ "$path" =~ /native/core_ext/.*\.(cpp|cc|h|hpp)$ ]]; then
|
|
32
|
+
exit 0
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
cat <<MSG
|
|
36
|
+
🔬 DAD-aligned source. Before editing this file:
|
|
37
|
+
|
|
38
|
+
1. Identify the corresponding DAD algorithm in androguard:
|
|
39
|
+
${DAD_REF}/
|
|
40
|
+
basic_blocks.py | control_flow.py | dast.py | dataflow.py
|
|
41
|
+
decompile.py | graph.py | instruction.py | node.py
|
|
42
|
+
opcode_ins.py | util.py | writer.py
|
|
43
|
+
|
|
44
|
+
2. If your change has NO DAD analogue, it is a band-aid. Do not add
|
|
45
|
+
ad-hoc text/regex post-passes, opportunistic pattern matchers, or
|
|
46
|
+
heuristic structural detection. Discuss with the user first.
|
|
47
|
+
|
|
48
|
+
3. Reference the DAD file:lineno in the code comment AND commit message.
|
|
49
|
+
Example: "// DAD: control_flow.py:225 switch_struct"
|
|
50
|
+
|
|
51
|
+
4. Removed in 2026-05-26 audit — DO NOT REINTRODUCE:
|
|
52
|
+
- Legacy expr-tree pipeline (Phase 2a/2b/3/4/5/6/8e)
|
|
53
|
+
- L6_NO_EXPR_TREE / L6_LEGACY_MODE / L6_SSA_MODE flags
|
|
54
|
+
- Post* text regex passes (Inline*, *ForwardGotos, *DeadWrites,
|
|
55
|
+
CollapseEmptyBlocks, SuppressUnusedLabels, SSARename,
|
|
56
|
+
SuppressOrphanGotos (Phase 22))
|
|
57
|
+
|
|
58
|
+
5. After C++ changes, run /dexkit-build (ninja + pip install -e) then
|
|
59
|
+
/dexkit-sweep. Aggregate counts must not regress.
|
|
60
|
+
MSG
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# PreToolUse(Bash) gate — runs before every Bash tool call.
|
|
3
|
+
#
|
|
4
|
+
# Purpose: before `git commit` / `git push`, force a review of the project's
|
|
5
|
+
# docs .md files for drift against the change (and an update of any that are
|
|
6
|
+
# now inaccurate) in the same commit. Docs drift silently — perf numbers, API
|
|
7
|
+
# names, file paths, counts, install/build steps — so this makes the doc pass
|
|
8
|
+
# a conscious step at publish time.
|
|
9
|
+
#
|
|
10
|
+
# The LLM does the actual review; this hook only ensures it happens. Once the
|
|
11
|
+
# docs have been reviewed (and any drift fixed), bypass the gate by prefixing
|
|
12
|
+
# the SAME command with `DOCS_CHECKED=1`, e.g.:
|
|
13
|
+
# DOCS_CHECKED=1 git commit -m "..."
|
|
14
|
+
# DOCS_CHECKED=1 git push origin master
|
|
15
|
+
#
|
|
16
|
+
# Non-git Bash, and git reads (status/log/diff/add/...), pass through untouched.
|
|
17
|
+
set -u
|
|
18
|
+
|
|
19
|
+
cmd="$(jq -r '.tool_input.command // empty' 2>/dev/null || true)"
|
|
20
|
+
[[ -z "$cmd" ]] && exit 0
|
|
21
|
+
|
|
22
|
+
# Only gate git commit / git push.
|
|
23
|
+
grep -qE 'git[^&|;]*\b(commit|push)\b' <<<"$cmd" || exit 0
|
|
24
|
+
|
|
25
|
+
# Already reviewed this turn → allow.
|
|
26
|
+
grep -qE 'DOCS_CHECKED=1|#[[:space:]]*docs-checked' <<<"$cmd" && exit 0
|
|
27
|
+
|
|
28
|
+
root="${CLAUDE_PROJECT_DIR:-.}"
|
|
29
|
+
docs="$(cd "$root" 2>/dev/null && ls README.md CLAUDE.md docs/*.md 2>/dev/null)"
|
|
30
|
+
|
|
31
|
+
{
|
|
32
|
+
echo "📝 Docs gate — before committing/pushing, review these for drift against"
|
|
33
|
+
echo " this change and update any that are now inaccurate (API names, file"
|
|
34
|
+
echo " paths, perf numbers, counts, behavior, install/build steps) IN THIS"
|
|
35
|
+
echo " COMMIT:"
|
|
36
|
+
if [[ -n "$docs" ]]; then
|
|
37
|
+
echo "$docs" | sed 's/^/ - /'
|
|
38
|
+
fi
|
|
39
|
+
echo " Then re-run the SAME command prefixed with DOCS_CHECKED=1, e.g.:"
|
|
40
|
+
echo " DOCS_CHECKED=1 git commit -m \"...\""
|
|
41
|
+
echo " If every doc already matches the new state, just add the prefix."
|
|
42
|
+
} >&2
|
|
43
|
+
exit 2
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# PostToolUse hook: enforce the project's Python standards on every edit to a
|
|
3
|
+
# package source file (PEP 8 / PEP 257 / PEP 484 via Black, Ruff, mypy).
|
|
4
|
+
#
|
|
5
|
+
# Behaviour:
|
|
6
|
+
# 1. Auto-applies Black + `ruff check --fix` in place (formatting + safe fixes).
|
|
7
|
+
# 2. Reports any REMAINING Ruff violations and mypy errors back to Claude
|
|
8
|
+
# (exit 2 surfaces stderr as actionable feedback). Clean → silent exit 0.
|
|
9
|
+
#
|
|
10
|
+
# Scoped to src/dexllm/**.py — the typed public package. Other dirs
|
|
11
|
+
# (examples/bench/tests) are intentionally exempt (see pyproject per-file
|
|
12
|
+
# ignores; mypy is configured for the package only).
|
|
13
|
+
|
|
14
|
+
f="$(jq -r '.tool_input.file_path // empty')"
|
|
15
|
+
[ -z "$f" ] && exit 0
|
|
16
|
+
case "$f" in
|
|
17
|
+
*/src/dexllm/*.py) ;;
|
|
18
|
+
*) exit 0 ;;
|
|
19
|
+
esac
|
|
20
|
+
[ -f "$f" ] || exit 0
|
|
21
|
+
|
|
22
|
+
cd "${CLAUDE_PROJECT_DIR:-.}" || exit 0
|
|
23
|
+
|
|
24
|
+
# 1. Auto-format + auto-fix in place (these mutate the file).
|
|
25
|
+
black -q "$f" 2>/dev/null || true
|
|
26
|
+
ruff check --fix -q "$f" 2>/dev/null || true
|
|
27
|
+
|
|
28
|
+
# 2. Collect what still needs a human/Claude decision.
|
|
29
|
+
issues=""
|
|
30
|
+
ruff_left="$(ruff check "$f" 2>&1)" || issues+="$ruff_left"$'\n'
|
|
31
|
+
mypy_out="$(mypy 2>&1)" || true
|
|
32
|
+
if echo "$mypy_out" | grep -q "error:"; then
|
|
33
|
+
issues+="$mypy_out"$'\n'
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
if [ -n "${issues//[$' \t\n']/}" ]; then
|
|
37
|
+
{
|
|
38
|
+
echo "⚠ Python standards: Black + Ruff auto-fixes applied to $f."
|
|
39
|
+
echo " Remaining issues to fix (PEP 8 / PEP 257 / PEP 484):"
|
|
40
|
+
echo "$issues"
|
|
41
|
+
} >&2
|
|
42
|
+
exit 2
|
|
43
|
+
fi
|
|
44
|
+
exit 0
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# PreToolUse(Bash) gate — runs before every Bash tool call.
|
|
3
|
+
#
|
|
4
|
+
# Purpose: after any FIX (a change to production source), force an ADVERSARIAL
|
|
5
|
+
# CODE REVIEW before the commit/push lands. A decompiler type/dataflow change can
|
|
6
|
+
# be subtly wrong in a way tests don't catch; the project's practice is to spawn
|
|
7
|
+
# independent reviewer agents on the diff, triage their findings, fix the real
|
|
8
|
+
# ones, and re-verify (a/b before-after + parity + 0-crash sweep) BEFORE
|
|
9
|
+
# committing. This gate makes that a mandatory, conscious step at publish time.
|
|
10
|
+
#
|
|
11
|
+
# What "adversarial review" means here (do ALL of it, then commit):
|
|
12
|
+
# 0. HACK SELF-CHECK (root-cause, not output masking). Before reviewing, ask:
|
|
13
|
+
# does this fix address the ROOT of the defect, or does it mask a symptom at
|
|
14
|
+
# the output/late layer? A change that suppresses/rewrites Writer or dast
|
|
15
|
+
# OUTPUT to hide a defect whose true origin is the IR builder / dataflow /
|
|
16
|
+
# control-flow (opcode_ins, instruction, dataflow, graph, control_flow) is a
|
|
17
|
+
# HACK — even when the emitted text looks correct (the AST/other consumers
|
|
18
|
+
# still carry the defect). Precedent: the v0.1.12 void-invoke "fix" masked in
|
|
19
|
+
# Writer::visit_assign, left `this = voidcall` in the AST, and was REWRITTEN
|
|
20
|
+
# at the IR builder (the range invoke handlers). If this is a hack, DO NOT
|
|
21
|
+
# commit — RECONSIDER and redo it at the layer where the defect originates
|
|
22
|
+
# (CLAUDE.md: "structural defects must be fixed at the IR level, not in Writer
|
|
23
|
+
# output"). Only genuine beyond-DAD emit divergences (return-literal, catch-
|
|
24
|
+
# clamp, <clinit> static{}) legitimately live in the Writer; a defect with an
|
|
25
|
+
# earlier structural origin does not.
|
|
26
|
+
# 1. Spawn ≥2 INDEPENDENT reviewer agents on the diff — e.g. the Agent tool with
|
|
27
|
+
# compound-engineering:ce-adversarial-reviewer + ce-correctness-reviewer, or
|
|
28
|
+
# invoke the `code-review` skill. Each must try to CONSTRUCT a breaking input,
|
|
29
|
+
# not just pattern-match.
|
|
30
|
+
# 2. Triage every finding (CONFIRMED / PLAUSIBLE / REFUTED). Fix the real ones.
|
|
31
|
+
# 3. Re-verify: a/b (fix on vs off) shows 0 regression on the relevant axes,
|
|
32
|
+
# parity 28/28, sweep 0-crash. Remove any temporary a/b env-gate.
|
|
33
|
+
# 4. THEN re-run the SAME commit/push command prefixed with REVIEWED=1, e.g.:
|
|
34
|
+
# REVIEWED=1 git commit -m "..."
|
|
35
|
+
# (Combine with the docs gate when both apply: DOCS_CHECKED=1 REVIEWED=1 …)
|
|
36
|
+
#
|
|
37
|
+
# Only gates commits/pushes whose change touches PRODUCTION source (native/**,
|
|
38
|
+
# vendor/dexkit_core/Core/**, src/dexllm/**). Docs-only / test-only / config-only
|
|
39
|
+
# commits, non-git Bash, and git reads pass through untouched.
|
|
40
|
+
set -u
|
|
41
|
+
|
|
42
|
+
cmd="$(jq -r '.tool_input.command // empty' 2>/dev/null || true)"
|
|
43
|
+
[[ -z "$cmd" ]] && exit 0
|
|
44
|
+
|
|
45
|
+
# Only gate git commit / git push.
|
|
46
|
+
grep -qE 'git[^&|;]*\b(commit|push)\b' <<<"$cmd" || exit 0
|
|
47
|
+
|
|
48
|
+
# Already reviewed this turn → allow.
|
|
49
|
+
grep -qE 'REVIEWED=1|#[[:space:]]*reviewed' <<<"$cmd" && exit 0
|
|
50
|
+
|
|
51
|
+
root="${CLAUDE_PROJECT_DIR:-.}"
|
|
52
|
+
cd "$root" 2>/dev/null || exit 0
|
|
53
|
+
|
|
54
|
+
# Collect the files this operation would carry. A COMMIT carries only its own
|
|
55
|
+
# change (staged + unstaged-tracked, covering `git commit -a`); a PUSH carries
|
|
56
|
+
# every commit ahead of upstream. Keeping these separate means a config/docs-only
|
|
57
|
+
# commit is not blocked just because earlier (already-reviewed) code commits are
|
|
58
|
+
# still unpushed — while a push still re-confirms the whole set.
|
|
59
|
+
if grep -qE 'git[^&|;]*\bpush\b' <<<"$cmd"; then
|
|
60
|
+
up="$(git rev-parse --abbrev-ref --symbolic-full-name '@{upstream}' 2>/dev/null || true)"
|
|
61
|
+
changed="$([[ -n "$up" ]] && git diff --name-only "$up"...HEAD 2>/dev/null)"
|
|
62
|
+
else
|
|
63
|
+
changed="$( { git diff --cached --name-only 2>/dev/null
|
|
64
|
+
git diff --name-only 2>/dev/null; } | sort -u )"
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
# Does the change touch PRODUCTION source (a "fix")? If not, pass through.
|
|
68
|
+
grep -qE '^(native/|vendor/dexkit_core/Core/|src/dexllm/).*\.(cpp|cc|h|hpp|py)$' \
|
|
69
|
+
<<<"$changed" || exit 0
|
|
70
|
+
|
|
71
|
+
{
|
|
72
|
+
echo "🔬 Adversarial-review gate — this commit/push changes production source"
|
|
73
|
+
echo " (a fix). Before it lands, run an ADVERSARIAL CODE REVIEW and address"
|
|
74
|
+
echo " the findings:"
|
|
75
|
+
echo " 0. HACK SELF-CHECK (root-cause, not output masking): does this fix"
|
|
76
|
+
echo " the ROOT of the defect, or mask a symptom in Writer/dast OUTPUT"
|
|
77
|
+
echo " while the true origin is the IR builder / dataflow / control-flow?"
|
|
78
|
+
echo " Output-layer suppression that hides an earlier structural defect"
|
|
79
|
+
echo " (AST still carries it) is a HACK — RECONSIDER and redo it at the"
|
|
80
|
+
echo " originating layer (cf. v0.1.12 void-invoke: Writer-hack → IR fix)."
|
|
81
|
+
echo " Only genuine beyond-DAD emit divergences belong in the Writer."
|
|
82
|
+
echo " 1. Spawn ≥2 INDEPENDENT reviewers on the diff (Agent tool:"
|
|
83
|
+
echo " compound-engineering:ce-adversarial-reviewer +"
|
|
84
|
+
echo " ce-correctness-reviewer, or the code-review skill). Each must try"
|
|
85
|
+
echo " to CONSTRUCT a breaking input, not just pattern-match."
|
|
86
|
+
echo " 2. Triage findings; fix the real ones."
|
|
87
|
+
echo " 3. Re-verify: a/b (fix on vs off) 0-regression + parity 28/28 +"
|
|
88
|
+
echo " 0-crash sweep; remove any temp a/b env-gate."
|
|
89
|
+
echo " Then re-run the SAME command prefixed with REVIEWED=1, e.g.:"
|
|
90
|
+
echo " REVIEWED=1 git commit -m \"...\""
|
|
91
|
+
echo " (with the docs gate: DOCS_CHECKED=1 REVIEWED=1 git commit -m \"...\")"
|
|
92
|
+
} >&2
|
|
93
|
+
exit 2
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"availableModels": [
|
|
3
|
+
"opus",
|
|
4
|
+
"claude-fable-5"
|
|
5
|
+
],
|
|
6
|
+
"permissions": {
|
|
7
|
+
"allow": [
|
|
8
|
+
"Bash(*)",
|
|
9
|
+
"WebFetch(domain:github.com)"
|
|
10
|
+
]
|
|
11
|
+
},
|
|
12
|
+
"hooks": {
|
|
13
|
+
"PreToolUse": [
|
|
14
|
+
{
|
|
15
|
+
"matcher": "Edit|Write|MultiEdit",
|
|
16
|
+
"hooks": [
|
|
17
|
+
{
|
|
18
|
+
"type": "command",
|
|
19
|
+
"command": "\"$CLAUDE_PROJECT_DIR/.claude/dad-reminder.sh\""
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"matcher": "Bash",
|
|
25
|
+
"hooks": [
|
|
26
|
+
{
|
|
27
|
+
"type": "command",
|
|
28
|
+
"command": "\"$CLAUDE_PROJECT_DIR/.claude/docs-precommit-check.sh\"",
|
|
29
|
+
"statusMessage": "Docs gate (review docs/*.md before commit/push)"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"type": "command",
|
|
33
|
+
"command": "\"$CLAUDE_PROJECT_DIR/.claude/review-precommit-check.sh\"",
|
|
34
|
+
"statusMessage": "Adversarial-review gate (review a code fix before commit/push)"
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
],
|
|
39
|
+
"PostToolUse": [
|
|
40
|
+
{
|
|
41
|
+
"matcher": "Edit|Write|MultiEdit",
|
|
42
|
+
"hooks": [
|
|
43
|
+
{
|
|
44
|
+
"type": "command",
|
|
45
|
+
"command": "jq -r '.tool_input.file_path // empty' | grep -qE '(/vendor/dexkit_core/Core/|/native/(binding|dad_cpp|core_ext)/).*\\.(cpp|cc|h|hpp)$' && echo '⚠ DexKit C++ source modified — run /dexkit-build before testing or sweeping. The currently-installed .so is now stale.' || true"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"type": "command",
|
|
49
|
+
"command": "\"$CLAUDE_PROJECT_DIR/.claude/py-quality.sh\"",
|
|
50
|
+
"statusMessage": "Enforcing Python standards (Black / Ruff / mypy)"
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dexkit-bench
|
|
3
|
+
description: |
|
|
4
|
+
Head-to-head performance benchmark — androguard DAD (Python reference) vs DexKit-DAD (C++ port).
|
|
5
|
+
Measures wall-clock time per method on the same corpus, verifies parity of output where the
|
|
6
|
+
port is byte-identical to DAD. Use to validate that the C++ port preserves DAD semantics while
|
|
7
|
+
delivering the expected speedup.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## What this measures
|
|
11
|
+
|
|
12
|
+
For a chosen APK, decompile a sample of N methods (default 500) on both implementations:
|
|
13
|
+
|
|
14
|
+
| Metric | DexKit-DAD (C++) | androguard DAD (Python) |
|
|
15
|
+
|---|---|---|
|
|
16
|
+
| Total wall time | sum of `dk.decompile_method()` | sum of `DvMethod(m).process()` + `get_source()` |
|
|
17
|
+
| Per-method mean | ms | ms |
|
|
18
|
+
| Output match rate | byte-identical method count / N | — |
|
|
19
|
+
| Empty rate | external-ref methods (both should agree) | same |
|
|
20
|
+
|
|
21
|
+
A healthy result: DexKit ~50-200× faster, with high byte-identical match rate on non-external
|
|
22
|
+
methods (mismatches are either DAD quirks already deferred in CLAUDE.md or genuine port bugs
|
|
23
|
+
worth investigating via [/dexkit-diff](../dexkit-diff/SKILL.md)).
|
|
24
|
+
|
|
25
|
+
## Execute
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
python << 'EOF'
|
|
29
|
+
import sys, time, random
|
|
30
|
+
sys.stdout.reconfigure(line_buffering=True)
|
|
31
|
+
from loguru import logger; logger.remove()
|
|
32
|
+
import dexllm
|
|
33
|
+
from androguard.misc import AnalyzeAPK
|
|
34
|
+
from androguard.decompiler.decompile import DvMethod
|
|
35
|
+
|
|
36
|
+
APK = "test_apk/APK/com.example.android.tvleanback.apk"
|
|
37
|
+
N = 500
|
|
38
|
+
|
|
39
|
+
dk = dexllm.DexKit(APK)
|
|
40
|
+
_a, _d_list, dx = AnalyzeAPK(APK)
|
|
41
|
+
methods = [m for m in dx.get_methods() if not m.is_external() and m.get_method().get_code() is not None]
|
|
42
|
+
random.seed(42); random.shuffle(methods); sample = methods[:N]
|
|
43
|
+
print(f"Sampling {len(sample)} methods from {APK}", flush=True)
|
|
44
|
+
|
|
45
|
+
def norm(s):
|
|
46
|
+
# androguard DAD emits standalone-method output with class-context 4-space
|
|
47
|
+
# indent; DexKit's decompile_method is true standalone (no indent).
|
|
48
|
+
# Strip leading whitespace per line so byte-match isn't dominated by indent.
|
|
49
|
+
return "\n".join(line.lstrip() for line in s.splitlines()) if s else ""
|
|
50
|
+
|
|
51
|
+
# DexKit-DAD pass
|
|
52
|
+
t0 = time.time(); dk_out = {}
|
|
53
|
+
for m in sample:
|
|
54
|
+
em = m.get_method()
|
|
55
|
+
desc = f"{em.get_class_name()}->{em.get_name()}{em.get_descriptor()}"
|
|
56
|
+
try: dk_out[desc] = dk.decompile_method(desc)
|
|
57
|
+
except Exception as e: dk_out[desc] = f"// CRASH: {type(e).__name__}"
|
|
58
|
+
dk_ms = (time.time() - t0) * 1000
|
|
59
|
+
|
|
60
|
+
# androguard DAD pass
|
|
61
|
+
t0 = time.time(); dad_out = {}
|
|
62
|
+
for m in sample:
|
|
63
|
+
em = m.get_method()
|
|
64
|
+
desc = f"{em.get_class_name()}->{em.get_name()}{em.get_descriptor()}"
|
|
65
|
+
try:
|
|
66
|
+
dv = DvMethod(m); dv.process(); dad_out[desc] = dv.get_source()
|
|
67
|
+
except Exception as e: dad_out[desc] = f"// CRASH: {type(e).__name__}"
|
|
68
|
+
dad_ms = (time.time() - t0) * 1000
|
|
69
|
+
|
|
70
|
+
match = sum(1 for d in dk_out if norm(dk_out[d]) == norm(dad_out.get(d, "")))
|
|
71
|
+
both_nonempty = sum(1 for d in dk_out if dk_out[d] and dad_out.get(d, ""))
|
|
72
|
+
print(f"\n=== Bench result over {N} methods ===")
|
|
73
|
+
print(f" DexKit-DAD : {dk_ms:>8.1f} ms total ({dk_ms/N:.3f} ms/method)")
|
|
74
|
+
print(f" androguard : {dad_ms:>8.1f} ms total ({dad_ms/N:.3f} ms/method)")
|
|
75
|
+
print(f" speedup : {dad_ms/max(dk_ms,0.001):.1f}x")
|
|
76
|
+
print(f" byte-match : {match}/{N} ({match/N*100:.1f}%), both-nonempty: {both_nonempty}")
|
|
77
|
+
EOF
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Interpreting results
|
|
81
|
+
|
|
82
|
+
- **Speedup < 10×**: investigate. The DAD port should be heavily faster — Python interpreter
|
|
83
|
+
+ per-instance object overhead is the dominant cost in androguard DAD.
|
|
84
|
+
- **Match rate < 80% on non-trivial methods**: investigate divergence with `/dexkit-diff` on
|
|
85
|
+
a sample of mismatches. Common legitimate causes (mismatches from DAD bugs we've fixed in
|
|
86
|
+
production — see CLAUDE.md "Upstream DAD bug fixes" section):
|
|
87
|
+
- `get_params_type` quirk (DAD: `IJ p0`, DexKit: `int p0, long p1`)
|
|
88
|
+
- `java/lang/*` char-set strip bug (DAD: `otation.Foo`, DexKit: `annotation.Foo` — fixed)
|
|
89
|
+
- **Match rate ~90%**: port is healthy. The residual mismatch is dominated by `var_naming`
|
|
90
|
+
suffix off-by-N (semantic-equivalent) and other deep-IR categories — see CLAUDE.md
|
|
91
|
+
`project-deferred-decompiler-tasks`.
|
|
92
|
+
|
|
93
|
+
## Caveats
|
|
94
|
+
|
|
95
|
+
- androguard DAD crashes (RecursionError, AttributeError on ExternalMethod, etc.) — caught as
|
|
96
|
+
`// CRASH:` strings in the bench output. These count as legitimate divergence from DexKit
|
|
97
|
+
(which generally doesn't crash on the same input).
|
|
98
|
+
- `random.seed(42)` keeps the sample deterministic across runs for diff-able output.
|
|
99
|
+
- `AnalyzeAPK` load time (~3-5s for tvleanback) is NOT in the per-pass timing; both passes
|
|
100
|
+
reuse the loaded `dx` object.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dexkit-build
|
|
3
|
+
description: Rebuild the DexKit C++ core via ninja and reinstall the editable Python wheel. Run this every time any C++ source under vendor/dexkit_core/Core/, native/binding/, native/dad_cpp/, or native/core_ext/ is modified — the in-memory pip extension does NOT pick up rebuilt .so files automatically.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
DexKit develops natively (C++ static lib + pybind11 module) and Python wraps it. Two directories are involved:
|
|
7
|
+
|
|
8
|
+
- Build artifacts: `<repo>/build/<wheel_tag>` — scikit-build-core names this per platform/Python (e.g. `cp313-cp313-linux_x86_64` on Linux, `cp313-cp313-macosx_14_0_arm64` on macOS). Discover it; never hardcode the name.
|
|
9
|
+
- Package root (for editable install): `<repo>` (the directory with `pyproject.toml`)
|
|
10
|
+
|
|
11
|
+
A correct rebuild ALWAYS runs both steps in this order — running ninja from inside the build dir, then pip install from the package root. Skipping the second step leaves the installed extension stale.
|
|
12
|
+
|
|
13
|
+
## Execute
|
|
14
|
+
|
|
15
|
+
Run this single chained command (platform-agnostic — discovers the build dir by its `build.ninja`; if none exists yet, the `pip install` does a full configure+build):
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
R="$(git rev-parse --show-toplevel)" && B="$(find "$R/build" -maxdepth 2 -name build.ninja -exec dirname {} \; 2>/dev/null | head -1)" && { [ -n "$B" ] && cd "$B" && ninja 2>&1 | tail -5; } ; cd "$R" && pip install -e . --no-build-isolation 2>&1 | tail -3
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Report success only when both `Linking CXX shared module _dexkit_core...so` and `Successfully installed dexllm-0.0.1` appear in output.
|
|
22
|
+
|
|
23
|
+
## Common pitfalls
|
|
24
|
+
|
|
25
|
+
- `pip install -e .` from the build directory FAILS with "does not appear to be a Python project" — always cd to the repo root (`git rev-parse --show-toplevel`) first.
|
|
26
|
+
- If compilation fails, do not retry blindly — read the error and fix the C++ source. Do not work around by reverting changes unless the user asks.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dexkit-decompile
|
|
3
|
+
description: |
|
|
4
|
+
Decompile a single method (or class) via the DAD-aligned C++ pipeline and print the result.
|
|
5
|
+
Argument is a Dalvik method descriptor (e.g. `LX/00D9;->equals(Ljava/lang/Object;)Z`) or a
|
|
6
|
+
class descriptor (`LX/00D9;`), optionally followed by `from <apk_path>`.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
/dexkit-decompile <method-or-class-descriptor> [from <apk-path>]
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
If no APK is given, default to `com.example.android.tvleanback.apk` (~4135 classes, real-world
|
|
16
|
+
Android support library code — good coverage of if/else, try-catch, switch, synchronized).
|
|
17
|
+
|
|
18
|
+
## Execute
|
|
19
|
+
|
|
20
|
+
Single method:
|
|
21
|
+
```bash
|
|
22
|
+
python << 'EOF'
|
|
23
|
+
import dexllm
|
|
24
|
+
APK = "<resolved_apk_path>"
|
|
25
|
+
DESC = "<method_descriptor>"
|
|
26
|
+
dk = dexllm.DexKit(APK)
|
|
27
|
+
try:
|
|
28
|
+
src = dk.decompile_method(DESC)
|
|
29
|
+
print(src if src else "(empty — likely external method ref, no code in this dex)")
|
|
30
|
+
except RuntimeError as e:
|
|
31
|
+
print(f"ERROR: {e}")
|
|
32
|
+
EOF
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Whole class:
|
|
36
|
+
```bash
|
|
37
|
+
python << 'EOF'
|
|
38
|
+
import dexllm
|
|
39
|
+
dk = dexllm.DexKit("<resolved_apk_path>")
|
|
40
|
+
print(dk.decompile_class("<class_descriptor>"))
|
|
41
|
+
EOF
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Notes
|
|
45
|
+
|
|
46
|
+
- Descriptors with `$` for inner classes use Smali form (`LX/0F$Inner;`).
|
|
47
|
+
- Method protos use `(args)Ret` Dalvik shape.
|
|
48
|
+
- `<init>` and `<clinit>` are valid method names.
|
|
49
|
+
- Shell escaping: `$` may need `\$` if passed through bash; prefer Python heredoc.
|
|
50
|
+
- **External method refs** (entries in MethodIds without ClassData in this dex) return empty
|
|
51
|
+
output — DAD-equivalent behavior, not a bug.
|
|
52
|
+
- Multi-dex APKs are fully supported; the descriptor is resolved across all dexes.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dexkit-diff
|
|
3
|
+
description: |
|
|
4
|
+
Side-by-side parity diff between androguard DAD (Python reference) and DexKit-DAD (our C++ port)
|
|
5
|
+
for a given method descriptor. Use when investigating output divergence — confirms whether a
|
|
6
|
+
defect is a port bug or matches DAD's behavior (in which case it's DAD-faithful and out of scope).
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
/dexkit-diff <method-descriptor> [from <apk-path>]
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## When to use
|
|
16
|
+
|
|
17
|
+
When `dk.decompile_method(desc)` produces output that looks wrong, the first question is
|
|
18
|
+
"does DAD produce the same wrong output?" Three outcomes:
|
|
19
|
+
|
|
20
|
+
1. **DAD matches DexKit (both wrong the same way)** — DAD bug we haven't tackled yet. Check
|
|
21
|
+
CLAUDE.md "Deferred DAD quirks" (bug-for-bug faithful by design) or consider promoting to
|
|
22
|
+
"Upstream DAD bug fixes" with a dual-track parity entry.
|
|
23
|
+
2. **DAD wrong, DexKit correct** — we've already fixed it upstream-of-DAD. Look for a
|
|
24
|
+
`*DADFaithful` sibling in `util.cpp` etc.; the mismatch is intentional and counts as
|
|
25
|
+
improvement, not divergence.
|
|
26
|
+
3. **DAD correct, DexKit wrong** — port bug. Use the diverging output region to narrow down
|
|
27
|
+
which pass introduced the regression.
|
|
28
|
+
|
|
29
|
+
## Execute
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
DESC='<method_descriptor>'
|
|
33
|
+
APK='<resolved_apk_path>'
|
|
34
|
+
|
|
35
|
+
# DexKit-DAD output
|
|
36
|
+
python << EOF > /tmp/dexkit.txt 2>&1
|
|
37
|
+
from loguru import logger; logger.remove()
|
|
38
|
+
import dexllm
|
|
39
|
+
dk = dexllm.DexKit("$APK")
|
|
40
|
+
print(dk.decompile_method("$DESC"))
|
|
41
|
+
EOF
|
|
42
|
+
|
|
43
|
+
# androguard DAD reference output
|
|
44
|
+
python << EOF > /tmp/dad.txt 2>&1
|
|
45
|
+
from loguru import logger; logger.remove()
|
|
46
|
+
from androguard.misc import AnalyzeAPK
|
|
47
|
+
from androguard.decompiler.decompile import DvMethod
|
|
48
|
+
_a, _d, dx = AnalyzeAPK("$APK")
|
|
49
|
+
cls, _, name, proto = "$DESC".replace('->', '|').replace('(', '|(', 1).split('|', 2)
|
|
50
|
+
for m in dx.find_methods(classname=cls, methodname=name, descriptor=proto):
|
|
51
|
+
if not m.is_external():
|
|
52
|
+
dv = DvMethod(m); dv.process(); print(dv.get_source())
|
|
53
|
+
EOF
|
|
54
|
+
|
|
55
|
+
diff -u /tmp/dad.txt /tmp/dexkit.txt | head -80
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Interpreting results
|
|
59
|
+
|
|
60
|
+
- **No diff**: byte-identical → port is DAD-faithful. Any "defect" must be addressed at
|
|
61
|
+
DAD's level (a DAD bug) — either deferred (add to CLAUDE.md "Deferred DAD quirks") or
|
|
62
|
+
fixed in production (add to "Upstream DAD bug fixes" with a `*DADFaithful` sibling +
|
|
63
|
+
dual-track parity test). Precedents: `GetType` (fixed), `ParseParamsType` (Writer-side
|
|
64
|
+
alternative to DAD's `GetParamsType`).
|
|
65
|
+
- **Diff present, DexKit looks better**: we already fixed a DAD bug — confirm via
|
|
66
|
+
CLAUDE.md "Upstream DAD bug fixes" section. Not a regression.
|
|
67
|
+
- **Diff present, DexKit looks wrong**: port bug. Use the diverging region to narrow down.
|
|
68
|
+
Common classes: `decompile.cpp` (pass ordering), `writer.cpp` (Java text emission),
|
|
69
|
+
`instruction.cpp` (IR semantics), `dataflow.cpp` (def-use / propagation), `control_flow.cpp`
|
|
70
|
+
(structuring).
|
|
71
|
+
|
|
72
|
+
## Caveats
|
|
73
|
+
|
|
74
|
+
- DAD's output may include surrogate-half MUTF-8 bytes that crash Python's `print()` on
|
|
75
|
+
strict-UTF-8 stdout. Pipe through `iconv -f UTF-8//IGNORE` if needed.
|
|
76
|
+
- ExternalMethod refs: DAD's `DvMethod.__init__` crashes; our port returns empty. The
|
|
77
|
+
"no diff" check should skip external refs (the `is_external()` guard above does that).
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dexkit-sweep
|
|
3
|
+
description: |
|
|
4
|
+
Full-APK regression sweep across every loadable APK in test_apk/APK/. Decompiles every class,
|
|
5
|
+
counts crashes/errors/empties, reports throughput. Use as the primary success gate for any
|
|
6
|
+
decompiler change — a green sweep means no class in the corpus crashes the C++ pipeline.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## What this measures
|
|
10
|
+
|
|
11
|
+
For every method in every loadable APK:
|
|
12
|
+
- **class_crash**: `decompile_class()` raised a Python exception (segfault, runtime_error, etc.)
|
|
13
|
+
- **method_decompile_error / method_method_error**: output starts with `// DECOMPILE ERROR:` or
|
|
14
|
+
`// METHOD ERROR:` (caught in C++ via `try{...}catch(std::exception&)`)
|
|
15
|
+
- **method_empty**: empty output — usually external method ref (no ClassData in this dex),
|
|
16
|
+
matches DAD's effective behavior
|
|
17
|
+
- **method_success**: any other non-empty output
|
|
18
|
+
|
|
19
|
+
The previous L6-era defect categories (orphan goto, brace imbalance, invalid_lhs,
|
|
20
|
+
duplicate_return, self_assign) were text artifacts of the L6 output and are no longer relevant.
|
|
21
|
+
The DAD pipeline produces correct Java by construction; defects manifest as either crashes,
|
|
22
|
+
exceptions, or wrong-but-non-crashing output (which the sweep won't catch — use
|
|
23
|
+
[/dexkit-diff](../dexkit-diff/SKILL.md) for that).
|
|
24
|
+
|
|
25
|
+
## Execute
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
python /tmp/full_sweep.py
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
If `/tmp/full_sweep.py` is missing, recreate it. It must:
|
|
32
|
+
- Glob every `*.apk` in `test_apk/APK/`
|
|
33
|
+
- Skip APKs with `dexllm.identify(apk)["dex_count"] == 0` (resources-only) **before**
|
|
34
|
+
constructing `DexKit(apk)` — the constructor now raises on a container with no
|
|
35
|
+
`classes*.dex` (validated load), so probe with `identify()` first instead of
|
|
36
|
+
loading and checking `dex_count()`
|
|
37
|
+
- For each APK, enumerate classes via `androguard.misc.AnalyzeAPK` (DexKit has no class
|
|
38
|
+
enumeration API)
|
|
39
|
+
- Call `dk.decompile_class(class_descriptor)` for each class
|
|
40
|
+
- Categorize each method block by marker (`// DECOMPILE ERROR`, `// METHOD ERROR`) or empty
|
|
41
|
+
- For APKs >5MB, cap class processing at 200 to keep total time bounded; for true full
|
|
42
|
+
coverage on the cap'd APK, run a focused sweep instead (see below)
|
|
43
|
+
- **`gc.collect()` between APKs** (mandatory). androguard's `AnalyzeAPK` returns a heavy
|
|
44
|
+
`dx`/`d_list` graph held by Python cyclic refs; without explicit GC the working set grows
|
|
45
|
+
monotonically and later APK iterations slow down (~30× slowdown observed at ~17 APKs on
|
|
46
|
+
this corpus, hang-like behavior visible to the user). The dropped refs free both the
|
|
47
|
+
androguard analysis and any DexKit-side caches scoped to the per-APK `DexKit` instance.
|
|
48
|
+
|
|
49
|
+
## Focused full-coverage sweep (no cap)
|
|
50
|
+
|
|
51
|
+
For one APK without the 200-class cap:
|
|
52
|
+
```bash
|
|
53
|
+
python << 'EOF'
|
|
54
|
+
import sys, time; sys.stdout.reconfigure(line_buffering=True)
|
|
55
|
+
from loguru import logger; logger.remove()
|
|
56
|
+
import dexllm; from androguard.misc import AnalyzeAPK
|
|
57
|
+
APK = "test_apk/APK/com.example.android.tvleanback.apk"
|
|
58
|
+
dk = dexllm.DexKit(APK)
|
|
59
|
+
_, d_list, _ = AnalyzeAPK(APK)
|
|
60
|
+
classes = [c.get_name() for dex in d_list for c in dex.get_classes()]
|
|
61
|
+
print(f"{len(classes)} classes", flush=True)
|
|
62
|
+
crashes = 0; t = time.time()
|
|
63
|
+
for c in classes:
|
|
64
|
+
try: dk.decompile_class(c)
|
|
65
|
+
except Exception as e:
|
|
66
|
+
crashes += 1
|
|
67
|
+
print(f"CRASH {c}: {type(e).__name__}: {str(e)[:80]}", flush=True)
|
|
68
|
+
print(f"{crashes} crashes / {len(classes)} classes in {time.time()-t:.1f}s")
|
|
69
|
+
EOF
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Comparing runs
|
|
73
|
+
|
|
74
|
+
When investigating a category, save a baseline before your change:
|
|
75
|
+
```bash
|
|
76
|
+
python /tmp/full_sweep.py > /tmp/sweep_before.txt
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Then patch + `/dexkit-build` + re-sweep, and diff the AGGREGATE block. Per-category deltas
|
|
80
|
+
tell you whether the patch helped, regressed, or was neutral.
|
|
81
|
+
|
|
82
|
+
## Performance reference
|
|
83
|
+
|
|
84
|
+
- Workstation: Ryzen 9 9950X (16C/32T), 128GB DDR5 — single-process sequential.
|
|
85
|
+
- Last reference run (2026-05-27): 22 APKs, 20,221 classes, 159,305 methods, **0 crashes**,
|
|
86
|
+
~17,900 methods/sec.
|
|
87
|
+
- Bottleneck is androguard `AnalyzeAPK` loading (per-APK), not DexKit decompilation.
|
|
88
|
+
- If runtime > 30s on the full sweep, suspect a hang in one specific method — bisect by
|
|
89
|
+
enumerating classes and decompiling per-class until a target hangs.
|
|
90
|
+
|
|
91
|
+
## Multi-process variant (legacy reference)
|
|
92
|
+
|
|
93
|
+
The L6-era multi-process sweep used `ProcessPoolExecutor(max_workers=24)` with class-chunks
|
|
94
|
+
of 200. Currently overkill — single-process sweep finishes in ~10s for the full corpus.
|
|
95
|
+
If sweeping enormous external APK collections (1000+ APKs), revive the multi-process pattern.
|