diff --git a/.gitignore b/.gitignore index 523511d..5ea6a59 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,13 @@ undefined_syms_auto.*.txt build.ninja objdiff.json /permute* + +automation/functions.db +automation/agent.log +automation/agent_summary.json +automation/__pycache__/ +automation/compile_errors_report.json +automation/CONTINUE_SETUP.md +automation/HANDOFF.md +automation/QUICK_START_TYPE_LEARNING.md +automation/TYPE_LEARNING.md diff --git a/automation/CLAUD.md b/automation/CLAUD.md new file mode 100644 index 0000000..4d1f467 --- /dev/null +++ b/automation/CLAUD.md @@ -0,0 +1,392 @@ +## FF7 Decomp: Working Notes for Agents + +Final Fantasy VII (PS1 USA) decompilation project. Goal: byte-accurate recompilation of game executables. + +## Quick Reference + +### Docker Build Commands (Optimized) +```shell +# Build Docker image (only needed once) +docker build --platform=linux/amd64 --tag ff7-build:latest . + +# Run a build (FAST - uses Go caching, ~12s clean, ~2s incremental) +./tools/docker-build.sh "make build" + +# Format code after changes +./tools/docker-build.sh "make format" + +# Enter container interactively +./tools/docker-build.sh bash +``` + +The `docker-build.sh` wrapper adds Go module and build caching which provides a significant speedup. + +**Legacy commands** - only use if you have issues with the optimized script: +```shell +docker run --rm --platform=linux/amd64 -v "$(pwd)":/ff7 -v ff7_venv:/ff7/.venv -v "$(pwd)/build":/ff7/build ff7-build:latest -lc 'cd /ff7 && make build' +``` + +### Key Make Targets +- `make build` - Build all overlays, verify SHA1 checksums +- `make format` - Run clang-format on code +- `make clean` - Remove build artifacts +- `make submit` - Clean + build + format + stage files for commit + +### Mako Commands (via `./mako.sh`) +- `./mako.sh build` - Build project +- `./mako.sh dec ` - Decompile function, replace INCLUDE_ASM +- `./mako.sh dec --fix-structs` - Also replace D_8009XXXX with Savemap fields +- `./mako.sh rank ` - Rank functions by difficulty (easiest first) +- `./mako.sh symbols add [size]` - Add new symbol +- `./mako.sh format` - Format code + +## Project Structure + +``` +src/ # Decompiled C source (organized by overlay) +asm/us/ # MIPS assembly (original/undecompiled) + └── / + ├── nonmatchings/ # Undecompiled function .s files + └── data/ # Data segment .s files +include/ # Headers (common.h, game.h, psxsdk/) +config/ # Build config and symbol files + ├── us.yaml # Main overlay definitions + ├── symbols.*.txt # Symbol address files + └── sym_*.txt # Import/export symbol files +build/us/ # Build output (.o, .exe, .map files) +tools/ # Build tools (Go builder, Python scripts) +disks/us/ # Extracted game files (from disc image) +``` + +## Overlays + +| Overlay | VRAM Start | Source | Description | +|---------|------------|--------|-------------| +| main | 0x80010000 | `src/main/` | Core engine, initialization | +| battle | 0x800A0000 | `src/battle/` | Battle system | +| batini | 0x801B0000 | `src/battle/batini.c` | Battle initialization | +| field | 0x800A0000 | `src/field/` | Field exploration | +| world | 0x800A0000 | `src/world/` | World map | +| menu | varies | `src/menu/` | Menu systems (savemenu, title, etc.) | + +## Decompilation Workflow + +### 1. Find a function to decompile +```shell +# List undecompiled functions, ranked by difficulty (easiest first) +./mako.sh rank src/battle/nonmatchings/battle + +# Or browse asm files directly +ls asm/us/battle/nonmatchings/battle/ +``` + +### 2. Decompile with m2c +```shell +# This replaces INCLUDE_ASM in the .c file with decompiled code and performs struct field replacement +./mako.sh dec func_800A1158 --fix-structs +``` + +### 3. Refine the code +- Fix unknown types (marked with `/*?*/`) +- Match register allocation and instruction order +- Add/reference symbols in `config/symbols.*.txt` +- The goal is to produce a decompiled code that is 1:1 matching the original PSX binaries + +### 4. Build and verify +```shell +make build # Rebuilds and verifies SHA1 match +``` + +### 5. Format and submit +```shell +make format +git add config/ include/ src/ +git commit -m "Decompile func_800A1158" +``` + +## Code Patterns + +### INCLUDE_ASM Macro +Embeds undecompiled assembly: +```c +INCLUDE_ASM("asm/us/battle/nonmatchings/battle", func_800A1158); +``` +Replace with decompiled C code when function matches. + +### Renaming INCLUDE_ASM Functions + +INCLUDE_ASM functions can be renamed without decompiling them. The process differs between the **main overlay** and **other overlays**: + +#### Main Overlay (src/main/*.c) +The asm files in `asm/us/main/nonmatchings/` are **static** - they persist on disk and are not regenerated. + +To rename a function (e.g., `func_80026F44` → `MenuDrawText`): +1. **Rename the asm file**: `mv asm/us/main/nonmatchings/18B8/func_80026F44.s asm/us/main/nonmatchings/18B8/MenuDrawText.s` +2. **Update the asm file contents**: + - Change `glabel func_80026F44` → `glabel MenuDrawText` + - Change `.size func_80026F44, . - func_80026F44` → `.size MenuDrawText, . - MenuDrawText` +3. **Update the INCLUDE_ASM macro** in the C file +4. **Update all call sites** in `src/` that reference this function +5. **Update the symbol file** (e.g., `config/symbols.main.us.txt`) + +#### Other Overlays (src/menu/*.c, src/battle/*.c, etc.) +The asm files in overlay directories are **regenerated by splat** on each build. Renaming the files directly won't work - splat will recreate them with the old names. + +To rename a function (e.g., `func_801D080C` → `MenuConfig` in cnfgmenu): +1. **Add the new name to the overlay's symbol file** (e.g., `config/symbols.cnfgmenu.us.txt`): + ``` + MenuConfig = 0x801D080C; + ``` +2. **Update `config/sym_ovl_export.us.txt`** (for cross-overlay references): + - Change `func_801D080C = 0x801d080c;` → `MenuConfig = 0x801d080c;` +3. **Update the INCLUDE_ASM macro** in the C file +4. **Update any references** in other files (e.g., `src/main/ovl.c` for exported functions) +5. **Run the build** - splat will generate the asm file with the new name + +The old asm file may remain in the directory but will be unused. It can be deleted manually. + +### Common Types +```c +typedef signed char s8; typedef unsigned char u8; +typedef signed short s16; typedef unsigned short u16; +typedef signed int s32; typedef unsigned int u32; +typedef u8 unk_data; typedef unsigned int* unk_ptr; +``` + +### String Encoding +FF7 uses custom character encoding, not ASCII. Use `_S()` macro: +```c +const char* msg = _S("Save game?"); +``` + +## Naming Conventions + +### Functions +- Undecompiled: `func_800XXXXX` (address-based) +- Decompiled: verb-first descriptive names, prefer PSX SDK names when applicable +- Examples: `InitBattle`, `LoadScene`, `DrawSprite` + +### Data/Globals +- Unknown: `D_800XXXXX` (address-based) +- Known game state: `g_` prefix (e.g., `g_BattleState`) +- Module constants: module prefix (e.g., `BATTLE_MAX_ENEMIES`) +- Struct fields: `unkXX` until purpose known + +## Symbol Files + +Located in `config/`: +- `symbols.main.us.txt` - Main overlay symbols +- `symbols.battle.txt` - Battle overlay symbols +- `sym_export.us.txt` - Cross-overlay exports +- `sym_extern.us.txt` - External references + +Format: +``` +function_name = 0x800A1158; +D_800F5BB8 = 0x800F5BB8; // size:0xCC +``` + +Add symbols with: +```shell +./mako.sh symbols add config/symbols.battle.txt MyFunction 0x800A1234 +``` + +## Key Data Structures + +### Savemap (0x8009C6E4) +Game save data. Use `--fix-structs` to auto-replace `D_8009XXXX` references: +- `Savemap.party[9]` - Party member data +- `Savemap.inventory` - Item inventory +- `Savemap.materia` - Materia slots +- `Savemap.gil` - Money +- See `tools/fix_structs.py` for full field list + +### Battle Structures (`src/battle/battle.h`) +- `BattleSetup` - Battle configuration +- `Unk800F83E0` - Battle state (0x68 bytes) +- `BattleSetupType` - Encounter types (preemptive, back attack, etc.) + +## Tips for Matching + +1. **Compiler quirks**: Two PSX compilers available (`cc1-psx-26`, `cc1-psx-272`). Check which one the overlay uses in `config/us.yaml`. + +2. **Register allocation**: Order of operations matters. Sometimes restructuring expressions helps match. + +3. **Global pointer (GP)**: Main overlay uses `gp=0x80062D44`. Variables near this use gp-relative addressing. + +4. **Rodata association**: Battle overlay has `migrate_rodata_to_functions: true` - rodata is bundled with functions. + +5. **Use mipsel-linux-gnu-objdump** for line-by-line comparison + +## Comparing Original vs Compiled Assembly + +When a decompiled function doesn't match, compare the original assembly with the compiled output: + +### 1. Check Function Size (Quick Check) +```shell +# Get compiled function size from symbol table +./tools/docker-build.sh "mipsel-linux-gnu-objdump -t build/us/src/main/18B8.c.o" | grep func_80026F44 + +# Output: 00015e8c g F .text 00000128 func_80026F44 +# ^^^^^^^^ ^^^^^^^^ <- size in hex (0x128 = 296 bytes) +``` + +Compare with original size: count bytes from function start to end in the `.s` file, or calculate from addresses (end_addr - start_addr + 4). + +### 2. View Compiled Disassembly +```shell +# Disassemble a specific function from the compiled object +./tools/docker-build.sh "mipsel-linux-gnu-objdump -d build/us/src/main/18B8.c.o" | grep -A100 ':' +``` + +### 3. View Original Assembly +```shell +# Original assembly is in asm/us//nonmatchings// +cat asm/us/main/nonmatchings/18B8/func_80026F44.s +``` + +### 4. Common Size Mismatch Causes +- **Code merged after branches**: Compiler optimizes common code after if/else. Fix: put function calls inside each branch. +- **Delay slot optimization**: Original uses delay slots cleverly. The compiled code may not reproduce this. +- **Sign extension duplication**: Original may have `sll/sra` pairs duplicated in branches; compiler merges them. +- **Register allocation**: Different register choices can cause different instruction sequences. +- **Type differences**: `s8` vs `u8` generates `lb` vs `lbu` instructions. + +### 5. Useful Patterns +```shell +# Count instructions in original (each line with glabel excluded, /* */ comments have instructions) +grep -c '/\*' asm/us/main/nonmatchings/18B8/func_80026F44.s + +# Find jr ra (function returns) to identify function boundaries +./tools/docker-build.sh "mipsel-linux-gnu-objdump -d build/us/src/main/18B8.c.o" | grep 'jr.*ra' +``` + +## Decompilation Tips Checklist + +When decompiling a function, follow this checklist: + +- [ ] No prototypes or parameters with '?' as type +- [ ] No 'void*' parameters that should be typed structs +- [ ] No pointer arithmetic with manual offset calculations +- [ ] Use array indices to access arrays, do not use arithmetic calculations +- [ ] All struct field accesses use '->' or '.' operators +- [ ] Struct sizes match the assembly access patterns +- [ ] 'goto loop_*' are converted as 'while' loops +- [ ] 'goto block_*' in 'switch' are inlined, to reverse code optimization + +Alignment is critical. Code and data are aligned by 4-byte. + +## Finding symbol names and applying them to the decompiled code + +Our goal in this project currently is to find out as many symbol names (functions, variables, enums, structs, local variables, function parameters) as possible and apply them to the decompiled code. At the same time we want to ensure the code compiles 1:1 matching the original PSX binaries so we cannot alter the parameter types and change any logic. + +1. First we need to analyse both the decompiled PSX code in the @src/ folder and the PC decompiled code in the @assets/ folder. You usually start with a function in the PSX code that is unique enough and already has some symbols decompiled or its logic is recognizable enough that it can be matched to the PC code. +2. Spawn a sub-agent to look through the PC code in the @assets/ folder (do not read these files directly because they're huge) and find any corresponding code that can help us find new symbol names +3. Map out the connections between the PSX code (skip function names defined with INCLUDE_ASM macro, only functions fully defined in C can be renamed) and the PC code and store your findings in @CLAUDE_DECOMP.md for future reference. Make sure you're absolutely certain when creating this mapping - if there is any doubt about a specific symbol you should skip it. +4. Apply the changes. To do this spawn an Apply sub-agent that will take a map of symbol names to update (eg. "func_800A1158 = MyFunction", "D_800F5BB8 = MyVariable") and then the sub-agent will figure out how to efficiently and comprehensively apply these changes to the PSX code in @src/ (remember to update references to the changed symbol names in other source and header files; when changing a function name you should update all function calls to it in the code). The sub-agent should think hard to make sure it does not break anything as some symbol names are used in multiple places. The sub-agent shall not alter parameter types in function signatures. The sub-agent shall not read or update the assembly files in asm/ (these are generated by the disassembler and should not be manually edited). After finishing applying the changes it should return immediately without trying to run the build. +5. In parallel spawn a second sub-agent that will update the symbol maps in @config/ in symbols.main.us.txt and any other *.txt files that contain symbol names (skip sym_export.us.txt and sym_export_battle.us.txt since these are autogenerated by the build system) +6. After the work is done run the build to verify if the changes are correct. The build should succeed without any errors and all the SHA1 sums should match. Fix any issues that arise and repeat the process until the changes are correct. +7. Take one more look at CLAUDE_DECOMP.md and make sure its updated with all the new knowledge you've gained. +8. Finally think about what the next steps would be and suggest options to the user + +## Files to Commit +When submitting decompiled code: +```shell +git add config/ # Symbol files +git add include/ # Headers (if modified) +git add src/ # Decompiled source +``` + +## Advanced Matching Techniques + +### Understanding Why Decompiled Code Doesn't Match + +When the size is wrong, the compiler is generating different code structure. Common causes: + +#### 1. Merged Function Calls +**Problem**: Modern compilers merge common code after if/else branches. +```c +// BAD - compiler merges the call after the branches +if (condition) { + setup_a(); +} else { + setup_b(); +} +common_call(); // Compiler optimizes: one call site + +// GOOD - forces separate code paths (matches original) +if (condition) { + setup_a(); + common_call(); // Call inside branch +} else { + setup_b(); + common_call(); // Duplicate call +} +``` + +#### 2. Variable Type Affects Load Instructions +- `s8` generates `lb` (load byte signed) +- `u8` generates `lbu` (load byte unsigned) +- Check if global variables need type changes to match original instructions + +#### 3. Struct vs Separate Variables +**Problem**: Compiler optimizes away stores to local variables if it thinks they're unused. +```c +// BAD - compiler may skip storing to sp1C, sp1E +s16 sp18, sp1A, sp1C, sp1E; +sp1C = 0xFF; // May be optimized away! +sp1E = 0xFF; +sp18 = 0; +sp1A = 0; +SetDrawMode(..., (RECT*)&sp18); + +// GOOD - using proper struct ensures all fields are stored +RECT rect; +rect.w = 0xFF; // Compiler knows RECT fields are accessed +rect.h = 0xFF; +rect.x = 0; +rect.y = 0; +SetDrawMode(..., &rect); +``` + +#### 4. Delay Slot Optimization +Original PSX compiler often put useful instructions in branch delay slots. Modern compilers may: +- Put the instruction before the branch instead +- Use NOP in delay slots + +Example: Original saves `y << 16` before loop, uses delay slot for `s2 = 0`: +```asm +beqz v0, check_mode +addu s2, zero, zero # delay slot: s2 = 0 +sll s1, a1, 16 # after branch: save y +``` + +#### 5. Redundant Instructions in Original +The original compiler sometimes generated redundant code: +- `andi t0, v1, 0xFF` after `lbu v1` (already 8-bit) +- Duplicate `sra a1, s1, 16` in both branches + +These are hard to reproduce with modern compilers without tricks. + +### Matching Workflow + +1. **Get size right first** - Restructure code until instruction count matches (note: if the output size is wrong you might see compiler/linker errors in unrelated files - this is a good indicator that the size is wrong) +2. **Fix types second** - Change s8/u8, s16/u16 to match load/store instructions +3. **Reorder operations** - Match the order of stores/loads in original +4. **Check branch structure** - Use goto labels to match original control flow +5. Look at other decompiled functions in the same file to see how they handle similar patterns to the ones you're trying to match + +### Debugging Commands +```shell +# Compare function sizes +./tools/docker-build.sh "mipsel-linux-gnu-objdump -t build/us/src/main/18B8.c.o" | grep func_NAME + +# View compiled assembly +./tools/docker-build.sh "mipsel-linux-gnu-objdump -d build/us/src/main/18B8.c.o" | grep -A100 ':' + +# Original is in asm/us//nonmatchings//func_NAME.s +``` + +## Reference Links +- PSX SDK docs: PSY-Q library documentation +- FF7 Scarlet: https://github.com/petfriendamy/ff7-scarlet (game data structures) \ No newline at end of file diff --git a/automation/CONTINUE_SETUP.md b/automation/CONTINUE_SETUP.md new file mode 100644 index 0000000..187bcb8 --- /dev/null +++ b/automation/CONTINUE_SETUP.md @@ -0,0 +1,223 @@ +# Continue + Qwen Setup Guide + +## ✅ Setup Complete! + +Your system is configured to use **Continue** with **Qwen2.5-Coder 7B** locally via Ollama. + +## What's Installed + +- ✅ **Ollama** v0.17.4 (`/usr/local/bin/ollama`) +- ✅ **qwen2.5-coder:7b** model (4.7 GB) +- ✅ **Continue config** at `~/.continue/config.json` + +## Quick Start + +### 1. Install Continue Extension (If Not Already) + +If Continue isn't installed in VS Code: +1. Open VS Code +2. Go to Extensions (Ctrl+Shift+X) +3. Search for "Continue" +4. Install "Continue - Codestral, Claude, and more" +5. Reload VS Code + +### 2. Start Ollama Service + +Ollama needs to be running in the background: + +```bash +# Start ollama service (if not already running) +ollama serve +``` + +Or better yet, run it in the background: + +```bash +# Check if ollama is running +pgrep ollama || ollama serve & +``` + +### 3. Using Continue + +Once Continue is installed and Ollama is running: + +**Open Continue Panel:** +- Click the Continue icon in the left sidebar (or Ctrl+L) + +**Chat with Qwen:** +- Type questions in the Continue chat +- Select code and ask questions about it +- Use @ to reference files/symbols + +**Custom Commands (for decompilation):** + +We've added special commands for your decompilation workflow: + +1. **`/explain-asm`** - Analyze MIPS assembly + - Select assembly code + - Type `/explain-asm` + - Get detailed explanation + +2. **`/decompile-hint`** - Get decompilation suggestions + - Select assembly function + - Type `/decompile-hint` + - Get C equivalent suggestions + +3. **`/review-decomp`** - Review decompiled C code + - Select your C code + - Type `/review-decomp` + - Get accuracy check + +**Code Completion:** +- Just start typing - Qwen will suggest completions +- Press Tab to accept + +## Example Workflow + +### Decompile a Function with AI Help + +1. **Find a function to decompile:** + ```bash + cd ~/GitHub/ff7-decomp-armstrca/automation + python3 discover.py --list-todo | head -10 + ``` + +2. **Get the assembly:** + Look at the corresponding .s file in `asm/us/` + +3. **Ask Qwen for help:** + - Open the .s file in VS Code + - Select the assembly + - Open Continue (Ctrl+L) + - Type: `/decompile-hint` + +4. **Implement the C code:** + - Use Qwen's suggestions + - Write C in the appropriate src/ file + +5. **Run decompilation:** + ```bash + python3 decompile.py --function func_name + ``` + +6. **Verify it matches:** + ```bash + make build + # Check for matching + ``` + +## Configuration Details + +Your Continue config (`~/.continue/config.json`) includes: + +- **Main model**: Qwen2.5-Coder 7B (32K context) +- **Autocomplete**: Optimized for fast suggestions +- **Temperature**: 0.2 (balanced creativity/accuracy) +- **Custom commands**: Decompilation-specific prompts + +## Performance Expectations + +With your RTX 2060 (6GB VRAM) and i5-9300H: + +- **Chat responses**: ~20-40 tokens/sec +- **Autocomplete**: Nearly instant (<100ms) +- **Context window**: 32K tokens (~24K lines of code) +- **Model size**: 4.7 GB (fits in VRAM + RAM) + +## Troubleshooting + +### Ollama not responding: +```bash +# Restart ollama service +pkill ollama +ollama serve & +``` + +### Model not loading: +```bash +# Verify model is installed +ollama list + +# Pull again if needed +ollama pull qwen2.5-coder:7b +``` + +### Continue can't connect: +- Check Ollama is running: `pgrep ollama` +- Verify port 11434 is open: `curl http://localhost:11434` +- Restart VS Code + +### Slow responses: +- Close other applications to free RAM +- Use smaller batch sizes in automation +- Consider running only Ollama during heavy AI use + +## Advanced: Running Ollama as a Service + +To auto-start Ollama on boot: + +```bash +# Create systemd service +sudo tee /etc/systemd/system/ollama.service > /dev/null < \ + | bin/str \ + | iconv --from-code=UTF-8 --to-code=Shift-JIS \ + | bin/cc1-psx-26 -quiet -mcpu=3000 -g -mgas -gcoff > /dev/null +``` + +Compiler flags (`cc1=` and `cc_flags=`) are read from `build.ninja` per source file. + +--- + +## mako.sh Commands + +```bash +./mako.sh dec # Decompile one function +./mako.sh dec --fix-structs # Also replace D_8009XXXX with Savemap fields +./mako.sh build # Full build +./mako.sh rank # Rank functions by difficulty +./mako.sh format # clang-format all C files +``` + +--- + +## Agent Run Commands + +From `automation/` directory: + +```bash +# Status only +python3 agent.py --status + +# Full agent run (recommended starting point) +python3 agent.py --run --verbose + +# Single function smoke test +python3 agent.py --run --target 1 --batch 1 --verbose + +# LLM-assisted (requires Ollama + qwen2.5-coder:7b) +python3 agent.py --run --llm --llm-auto-fix --verbose + +# Timed run (e.g. 8 hours) +python3 agent.py --run --duration 28800 --batch 20 --llm --llm-auto-fix + +# Module-specific +python3 agent.py --run --module battle --target 50 --verbose + +# Bootstrap DB from ASM files (run once first) +python3 discover.py +``` + +--- + +## Key Implementation Decisions (This Conversation) + +### 1. Per-file PSY-Q Compile Gate (`build.py`) +Every decompiled function is now compiled through the real PSY-Q toolchain **before** being committed to `decompiled` status. If it fails, the file is reverted and the function is marked `failed` / `blocked`. + +Added methods: +- `BuildVerifier._get_psyq_params(rel_path)` — parses `build.ninja` for cc1 + cc_flags +- `BuildVerifier.check_file_compiles(file_path)` — runs the full CPP→str→iconv→cc1 pipeline, returns `(ok, errors)` + +Failure mode: if `build.ninja` doesn't exist or toolchain errors out, returns `(True, [])` to avoid false reverts. + +### 2. `--fix-structs` Always On (`decompile.py`, `agent.py`) +`mako.sh dec --fix-structs` replaces `D_8009XXXX` savemap globals with proper `Savemap.field` struct member references. This eliminates an entire class of incompatible-declaration errors. + +- `DecompilationRunner.__init__` now takes `fix_structs: bool` +- `run_mako_dec()` appends `--fix-structs` when enabled +- `AgentConfig.fix_structs = True` (always on) + +### 3. Startup Cleanup (`agent.py::_cleanup_failure_comments`) +On every agent startup, sweeps all `src/**/*.c` files and removes `/* Decompilation failure: ... */` comment blocks injected by m2c. These blocks corrupt subsequent decompile attempts if left in place. + +### 4. Startup Audit (`agent.py::_initial_audit`) +On every agent startup, compiles all C files containing `decompiled` functions. Any function whose line range contains compile errors is downgraded to `decompiled_needs_refine`. This catches bad decompilations from before the compile gate was added. + +### 5. `full_build_interval` Lowered +`AgentConfig.full_build_interval = 10` (was 60). Full builds are cheap to run now that per-file checks handle individual errors. + +--- + +## Text-Based Validation Patterns in `decompile.py::validate_c_file` + +These heuristics run **before** the PSY-Q compile check: + +| Pattern | What it catches | +|---------|----------------| +| `M2C_ERROR` | m2c hit an internal error | +| `saved_reg_ra` | Callee-save register leak (m2c gave up) | +| `Decompilation failure:` | m2c added a failure comment block | +| `#error` | Preprocessor error in output | +| `INCLUDE_ASM` still present after decompile | mako.sh exited 0 but didn't write C | + +--- + +## Previously Fixed Functions + +- **`func_80034BB0`** (`src/main/psxsdk.c`): LZSS decompressor — cleaned up m2c output, fully decompiled +- **`func_80034DB0`** (`src/main/psxsdk.c`): Reverted to `INCLUDE_ASM` stub (too complex) + +--- + +## PSX SDK Sentinel Exclusion + +Functions in `src/main/psxsdk.c` (and other PSX SDK wrappers) that are too complex or have compiler intrinsics are excluded from the automation queue via a sentinel comment at the top of the file. `discover.py` respects this sentinel and won't add excluded functions to the DB. + +--- + +## Known Issues / Follow-Up Work + +1. **`build.ninja` must exist** before `check_file_compiles` works. Run `./tools/docker-build.sh "make build"` once to generate it if it doesn't exist. +2. **CLI `--build-interval` argparse default** is still `100` in `agent.py`'s argparse, while `AgentConfig` default is now `10`. Pass `--build-interval 10` explicitly or update argparse. +3. **`--fix-structs` is not a CLI flag** — it's hardcoded `True` in `AgentConfig`. Can add `--no-fix-structs` flag if needed. +4. **`decompiled_needs_refine` functions** surfaced by `_initial_audit` need either LLM post-fixer or manual revert + re-queue. +5. **Dependency analyzer call graph** takes <1s for 3500+ functions at startup. + +--- + +## Important File Paths + +| File | Lines | Notes | +|------|-------|-------| +| `automation/agent.py` | ~1100 | `AgentConfig`, `DecompilationAgent`, `main()` CLI | +| `automation/decompile.py` | ~640 | `DecompilationRunner`, `validate_c_file`, `decompile_function` | +| `automation/build.py` | ~400 | `BuildVerifier`, `check_file_compiles`, `verify_decompiled_functions` | +| `automation/database.py` | ~300 | `DecompDatabase`, SQLite wrapper | +| `automation/discover.py` | ~250 | `DiscoverFunctions`, sentinel exclusion | +| `include/common.h` | - | Core types: s8, s16, s32, u8, u16, u32, Savemap | +| `src/main/psxsdk.c` | - | PSX SDK wrappers, partially decompiled | + +--- + +## Quick Verification + +All Python imports should pass: +```bash +cd /home/calvin/GitHub/ff7-decomp-armstrca/automation +python3 -c "from build import BuildVerifier; print('OK')" +python3 -c "from decompile import DecompilationRunner; print('OK')" +python3 -c "from agent import AgentConfig, DecompilationAgent; print('OK')" +``` diff --git a/automation/QUICK_START_TYPE_LEARNING.md b/automation/QUICK_START_TYPE_LEARNING.md new file mode 100644 index 0000000..792e806 --- /dev/null +++ b/automation/QUICK_START_TYPE_LEARNING.md @@ -0,0 +1,205 @@ +# Quick Start: Type Learning System + +## First Run + +The type learning system works automatically. Just run the agent as usual: + +```bash +cd automation + +# Standard run with type learning enabled +python3 agent.py --run --llm --batch 20 --verbose + +# Long run (8 hours) +python3 agent.py --run --llm --duration 28800 --batch 64 --parallel 8 +``` + +## What's Different? + +### Before +``` +[2026-03-29 10:00:00] Processing func_800A1234... +[2026-03-29 10:00:05] ❌ PSY-Q compilation failed: void* pointer access +[2026-03-29 10:00:05] Reverting to INCLUDE_ASM +``` + +### After +``` +[2026-03-29 10:00:00] Processing func_800A1234... +[2026-03-29 10:00:01] 🔍 Found 3 extern symbols, inferring types... +[2026-03-29 10:00:08] 🤖 Inferring types for 2 unknown symbols... +[2026-03-29 10:00:15] ✅ Generated type definitions in include/auto_types.h +[2026-03-29 10:00:20] ✅ Decompilation successful! +[2026-03-29 10:00:20] 📈 Increased confidence for D_800F83D0 pattern + +📚 Struct learning database: 12 known types +``` + +## Checking Progress + +### View Learned Types + +```bash +python3 -c " +from database import DecompDatabase +db = DecompDatabase() + +# Stats +stats = db.get_struct_learning_stats() +print(f'📚 Struct Learning Stats:') +print(f' Total patterns: {stats[\"total_patterns\"]}') +print(f' High confidence (≥70%%): {stats[\"high_confidence\"]}') +print(f' Medium confidence (30-70%%): {stats[\"medium_confidence\"]}') +print(f' Low confidence (<30%%): {stats[\"low_confidence\"]}') +print() + +# List known types +print('Known Types:') +known = db.get_all_known_types(min_confidence=0.3) +for symbol, info in sorted(known.items(), key=lambda x: -x[1]['confidence'])[:10]: + print(f' {symbol:20} → {info[\"likely_type\"]:20} (confidence: {info[\"confidence\"]:.2f}, seen: {info[\"seen_count\"]}x)') +" +``` + +### Check Which Functions Use a Type + +```bash +python3 -c " +from database import DecompDatabase +db = DecompDatabase() + +symbol = 'D_800F83D0' # Change this +funcs = db.get_functions_using_symbol(symbol) +print(f'Functions using {symbol}:') +for func in funcs: + print(f' - {func}') +" +``` + +## Database Migration + +The new tables are created automatically on first run. No manual steps needed. + +If you want to reset the learning database: + +```bash +# Backup first +cp automation/functions.db automation/functions.db.backup + +# Reset struct learning (keeps function data) +python3 -c " +from database import DecompDatabase +db = DecompDatabase() +db.conn.execute('DELETE FROM struct_patterns') +db.conn.execute('DELETE FROM symbol_usage') +db.conn.commit() +print('✅ Struct learning reset') +" +``` + +## Monitoring During Runs + +Watch the logs for: + +### Good Signs ✅ +``` +✅ All extern symbols have known types +📈 Increased confidence for D_800F83D0 pattern +types=3/3 ✅ +``` + +### Needs Attention ⚠️ +``` +⚠️ Type inference failed: timeout +types=0/5 ⚠️ +``` + +### Expected First Few Functions +``` +🤖 Inferring types for 12 unknown symbols... ← Normal, learning phase +``` + +### After 50+ Functions +``` +✅ All extern symbols have known types ← Database is learning! +``` + +## Performance Notes + +### Initial Slowdown +- First 20-30 functions: +10 sec each (LLM type inference) +- After that: Most types known → no inference needed + +### Long-term Speedup +- Fewer reversions = more successful decomps +- More successful decomps = less wasted work +- Net: ~30% faster once types are learned + +## Troubleshooting + +### "LLM not available" + +Make sure Ollama is running: +```bash +ollama serve & +ollama list # Should show qwen2.5-coder:7b +``` + +### "Type inference timeout" + +Increase timeout in `llm_helper.py::infer_types_from_assembly()`: +```python +response = self._call_ollama(prompt, temperature=0.1, max_tokens=2048, timeout=120) # Was 90 +``` + +### Wrong Types Learned + +Remove bad entries: +```bash +python3 -c " +from database import DecompDatabase +db = DecompDatabase() +db.conn.execute('DELETE FROM struct_patterns WHERE symbol_name = ?', ('D_BADTYPE',)) +db.conn.commit() +" +``` + +### No Auto-Generated Header + +Check if type inference is enabled: +```bash +# Should see LLM initialization +python3 agent.py --run --llm --verbose 2>&1 | grep -i llm +``` + +## Best Practices + +1. **Start with verbose:** First few runs should use `--verbose` to see learning in action +2. **Check stats periodically:** Run the stats check every 50 functions +3. **Review inferred types:** Check `include/auto_types.h` occasionally, move confirmed types to proper headers +4. **Batch by module:** Run `--module battle` first to learn battle types, then move to other modules + +## Example Session + +```bash +# Day 1: Bootstrap battle module +python3 agent.py --run --llm --module battle --batch 30 --verbose + +# Check what was learned +python3 -c "from database import DecompDatabase; db = DecompDatabase(); print(db.get_struct_learning_stats())" + +# Day 2: Use learned types for world module +python3 agent.py --run --llm --module world --batch 50 + +# Day 3: Full run with accumulated knowledge +python3 agent.py --run --llm --batch 100 --parallel 8 --duration 28800 +``` + +## Next Steps + +1. Run with `--llm --verbose` to see the system in action +2. After 50 functions, check stats to see learned types +3. Review `include/auto_types.h` and promote good types to proper headers +4. Continue running - the system gets smarter over time! + +For detailed information, see [TYPE_LEARNING.md](TYPE_LEARNING.md) diff --git a/automation/README.md b/automation/README.md new file mode 100644 index 0000000..20f405a --- /dev/null +++ b/automation/README.md @@ -0,0 +1,360 @@ +# FF7 Decompilation Automation + +Automated pipeline that discovers, decompiles, validates, and tracks every +function in the FF7 PSX codebase using +[m2c](https://github.com/matt-kempster/m2c) and the PSYQ 3.3 compiler +(`cc1-psx-26`). + +--- + +## Table of Contents + +1. [Prerequisites](#prerequisites) +2. [Quick Start](#quick-start) +3. [First Run (Empty Database)](#first-run-empty-database) +4. [Running the Agent](#running-the-agent) +5. [Database States](#database-states) +6. [Validation and Rejection Rules](#validation-and-rejection-rules) +7. [Script Reference](#script-reference) +8. [LLM Integration (Optional)](#llm-integration-optional) +9. [Monitoring and Building](#monitoring-and-building) + +--- + +## Prerequisites + +All scripts require **Python 3.9+** (no extra packages needed — pure stdlib). + +The following must also be available from the **repository root**: + +| Tool | Location | Notes | +|------|----------|-------| +| `mako.sh` | `../mako.sh` | Main wrapper for m2c + PSY-Q pipeline | +| `cc1-psx-26` | `../bin/cc1-psx-26` | PSYQ 3.3 compiler; needs 32-bit ELF support or wine | +| `build.ninja` | `../build.ninja` | Generated by `make build` (Docker); needed by the per-file compile check | +| Docker (optional) | system | Only needed for the full `make build` step; per-file checks run natively | + +> **First time only:** Run `./tools/docker-build.sh "make build"` from the +> repository root once to generate `build.ninja`. Subsequent validation runs +> use native PSY-Q without Docker. + +--- + +## Quick Start + +```bash +# 1. Clone / enter the repo +cd /path/to/ff7-decomp + +# 2. (First time only) build to generate build.ninja +./tools/docker-build.sh "make build" + +# 3. Enter the automation directory +cd automation/ + +# 4. Populate the database from INCLUDE_ASM macros in src/ +python3 discover.py --scan + +# 5. Check what was found +python3 agent.py --status + +# 6. Run the agent +python3 agent.py --run --verbose +``` + +--- + +## First Run (Empty Database) + +The database file (`automation/functions.db`) is **not committed** to the +repository. When you first clone the repo (or delete the file), you must +bootstrap it: + +```bash +cd automation/ + +# Scan all C source files for INCLUDE_ASM macros and populate the DB +python3 discover.py --scan +``` + +`discover.py --scan` does the following: + +- Walks every `.c` file under `src/` +- Finds every `INCLUDE_ASM(...)` macro (halts at any + `// NOTE: please do not decompile any of these functions.` sentinel) +- Resolves the corresponding `.s` file under `asm/us/` +- Records each function with `status='todo'` and a `line_count` difficulty + score derived from the assembly file +- Skips functions that are already in the database (re-running is idempotent) + +Verify the scan succeeded: + +```bash +python3 discover.py --stats # module-by-module totals +python3 discover.py --list-todo # next functions queued +python3 agent.py --status # overall progress breakdown +``` + +If `discover.py` reports zero functions found, check that `src/` contains +`.c` files with `INCLUDE_ASM` macros and that you are running from inside +`automation/`. + +--- + +## Running the Agent + +All commands are run from the `automation/` directory. + +```bash +# One-shot: decompile the easiest 10 functions and stop +python3 agent.py --run --batch 10 --verbose + +# Continuous run until the queue is empty +python3 agent.py --run --verbose + +# Parallel execution (8 workers, 128 functions per batch) +python3 agent.py --run --batch 128 --parallel 8 + +# Timed run (e.g. 8 hours) +python3 agent.py --run --duration 28800 --batch 20 + +# Only process one module +python3 agent.py --run --module battle + +# Retry functions previously marked blocked or verified-but-stale +python3 agent.py --run --retry-blocked --retry-verified + +# Force-retry ALL blocked functions (use after adding new type definitions) +python3 agent.py --run --force-retry-blocked + +# Strict validation: treat '?' type-unknown artifacts as hard rejects +# (reverts to INCLUDE_ASM) instead of keeping as decompiled_needs_refine +python3 agent.py --run --strict-validation + +# Show current statistics without running +python3 agent.py --status + +# Promote decompiled_needs_refine functions whose code is now clean +python3 agent.py --verify-needs-refine +``` + +### What the agent does each iteration + +1. **Cleanup** — resets functions stuck in `in_progress` (from a prior crash) + back to `failed`, and resets retry counters for `failed`/`blocked` + functions so each new session starts fresh. +2. **Select batch** — picks the highest-priority `todo` functions using a + combined dependency-aware + simplicity score. Functions whose in-file + callees are already decompiled are preferred so m2c has full type context. +3. **Decompile** — runs `./mako.sh dec --fix-structs` for each + function (`--fix-structs` post-processes the output via `tools/fix_structs.py`, + replacing raw addresses in the `Savemap` range (`0x8009C6E4`–`0x8009D7D8`) + with named field accesses like `Savemap.party[2]` or `Savemap.gil`). +4. **Validate** — checks the output C for m2c artifacts (see below). + Accepted output → `decompiled`; rejected output → reverted to + `INCLUDE_ASM` and marked `failed` or `blocked`. +5. **PSY-Q compile check** — after each batch, compiles the affected C files + with `cc1-psx-26` to catch errors the text checks missed. Files that fail + are downgraded to `decompiled_needs_refine`. +6. **Verify** — every 20 (this number is customizeable) decompiled functions runs `objdiff` to check binary matching + and promotes clean functions to `verified`. +7. **Generate declarations** — regenerates `include/decomp_decls_*.h` so + freshly verified functions are available as m2c context for subsequent + decompilations. +8. **Full build** — every 10 (this number is customizeable) functions runs a full `mako.sh build` as a + safety net. + +--- + +## Database States + +Functions flow through the following states in `functions.db`: + +``` + ┌──────────────────────────────────────────────┐ + │ todo │ + └────────────────────┬─────────────────────────┘ + │ agent picks function + ▼ + in_progress + / \ + (validation pass) (validation fail — hard error) + │ │ + ▼ ▼ + decompiled blocked + │ (soft error, PSY-Q fails) (no automatic retry; + │ ▼ use --force-retry-blocked + │ decompiled_needs_refine after adding type defs) + │ │ (re-queued on + │ │ next run) + │ objdiff binary match + ▼ + verified + + failed ←── decompilation error (retried up to max_retries times) +``` + +| Status | Meaning | +|--------|---------| +| `todo` | Queued; not yet attempted | +| `in_progress` | Currently being decompiled (or crashed mid-run) | +| `decompiled` | m2c output accepted; text and PSY-Q checks passed | +| `verified` | Binary output matches the original; gold standard | +| `failed` | Decompilation rejected; will be retried automatically | +| `blocked` | Hard error; reverted to `INCLUDE_ASM`; not retried by default | +| `decompiled_needs_refine` | Accepted by text check but PSY-Q compile failed; needs fixing | +| `sdk_excluded` | SDK/library function; intentionally excluded | + +--- + +## Validation and Rejection Rules + +After `mako.sh dec` runs, `decompile.py` validates the output C before +accepting it. A function is **rejected** (output reverted to `INCLUDE_ASM`, +status set to `failed` or `blocked`) if any of the following apply. + +### Hard rejections → `blocked` (not retried automatically) + +These represent structural errors m2c cannot fix without additional type +information being added to the codebase: + +| Artifact | Example | Reason | +|----------|---------|--------| +| `INCLUDE_ASM` still present | `INCLUDE_ASM(..., func_800ABC00)` | mako.sh failed to produce C output | +| `M2C_ERROR()` macro | `M2C_ERROR(unset_reg(v0))` | m2c could not resolve a register value | +| `Decompilation failure:` comment | `/* Decompilation failure: ... */` | m2c internal error on a dependency | +| `?*` pointer type | `?* var_a0;` | m2c could not infer the pointer's struct type | +| `/*?*/` on non-primitive | `/*?*/MyStruct D_800ABC00;` | m2c guessed a non-primitive type | +| `?` in parameter list | `void func(? arg0, s32 arg1)` | m2c could not infer a parameter type | +| `(? *)` cast | `(? **) temp_v0` | m2c type inference failure in cast context | +| `void*` local used with `->` | `void* ptr; ptr->unk4 = 0;` | struct type was not inferred | +| Primitive pointer with `->unk` | `s32* p; p->unk8 = 0;` | struct masquerading as scalar pointer | +| Negative field offset | `temp->unk-4` | m2c struct offset arithmetic error | +| `saved_reg_ra` | `saved_reg_ra = ...` | Leaked return-address register | +| `missing "jr $ra"` warning | `// Warning: missing "jr $ra"` | Function does not end with a return | +| `Internal error in function` | `/* Internal error in function ... */` | m2c traceback in output | +| Function name as integer | `func_800ABC00 * 4` | Function pointer mistaken for data | +| `sp` used as pointer | `sp->field`, `*(sp + 4)` | Leaked PSX stack-pointer register | +| `void*` parameter dereferenced | `void foo(void* p) { p->x = 1; }` | Parameter struct type not inferred | +| Mid-block variable declaration | declaration after a statement | PSY-Q `cc1` is C89-only | +| PSY-Q compile failure | actual `cc1-psx-26` error | Something the text checks missed | + +To retry blocked functions after adding the missing type definitions: + +```bash +python3 agent.py --run --force-retry-blocked +``` + +### Soft rejections → `decompiled_needs_refine` (retried automatically) + +These produce syntactically valid C that compiles under PSY-Q but contain +m2c artifacts that should be resolved before verification. There are two +tiers, controlled by `--strict-validation`: + +**Always soft** (both default and `--strict-validation`): + +| Artifact | Example | Fix | +|----------|---------|-----| +| `saved_reg_s0`–`s7`, `saved_reg_v0`, etc. | `saved_reg_s3 = ...` | Callee-save register not resolved; re-run with better context | +| `(unaligned type)` cast | `(unaligned s32) D_800F0000` | Unaligned access; needs a cast substitution | + +**Soft by default only** (become hard rejects with `--strict-validation`): + +| Artifact | Example | Fix | +|----------|---------|-----| +| `? var_name;` unknown variable type | `? sp10;` | Local type not inferred; re-run or replace with `s32` | +| `? func(...)` unknown return type | `? func_80012345(s32);` | Extern return type unknown | +| `pointer to unknown type` | `?* var_s0` | Less-common unknown-type marker | +| `?` in parameter list | `void func(? arg0)` | Parameter type not inferred | +| `(? *)` cast | `(? *) temp_v0` | Type inference failure in cast context | + +Use `--strict-validation` when you want to be aggressive about keeping the +source tree clean — functions with any `?` type holes are immediately +reverted to `INCLUDE_ASM` and marked `blocked` rather than accumulating as +`decompiled_needs_refine`. Use the default (lenient) mode when iterating +quickly and planning to fix type annotations in a later pass. + +The agent re-queues `decompiled_needs_refine` functions automatically on the +next run. If the LLM is enabled (`--llm --llm-auto-fix`), it will also +attempt to substitute a concrete type for each artifact. + +### What is never rejected + +- `extern /*?*/s32 D_800XXXX;` — `/*?*/` before a **known primitive** + (`s8`, `s16`, `s32`, `u8`, …) is a harmless annotation; the preprocessor + strips the comment. Not rejected. +- Ternary expressions (`x ? a : b`) — never confused with the `?` type marker. +- Functions already fully present in the C source — skipped without touching + the file. + +--- + +## Script Reference + +| Script | Primary use | Key flags | +|--------|-------------|-----------| +| `agent.py` | Main orchestration loop | `--run`, `--status`, `--batch N`, `--parallel N`, `--module X`, `--duration S`, `--force-retry-blocked`, `--strict-validation` | +| `discover.py` | Populate DB from source | `--scan`, `--stats`, `--list [module]`, `--list-todo` | +| `decompile.py` | Decompile one function | `--function func_NAME`, `--auto`, `--batch N` | +| `build.py` | Build + objdiff verify | `--build`, `--verify`, `--report` | +| `database.py` | DB wrapper (not a CLI tool) | — | +| `dependency_analyzer.py` | Call-graph analysis | Used internally by agent | +| `generate_decls.py` | Regenerate `decomp_decls_*.h` | Run automatically after each verify pass | +| `fix_existing_errors.py` | LLM-based PSY-Q error fixer | Used internally when `--llm` is on | +| `review_llm_fixes.py` | Approve/reject LLM fixes | `--list`, `--promote func_NAME` | +| `expand_strings.py` | Expand FF7 string macros | Utility; run manually if needed | +| `intellisense_fixer.py` | Fix IntelliSense artifacts | Applied automatically pre-validation | + +--- + +## LLM Integration (Optional) + +The agent can use a local LLM (via [Ollama](https://ollama.ai)) for: + +- **Pre-analysis** (`--llm`): Summarise the assembly before decompilation and + store complexity hints in the DB. +- **Auto-fix** (`--llm-auto-fix`): After decompilation, run `TypeErrorFixer` + to repair `?` type markers and simple PSY-Q errors automatically. + +Setup: + +```bash +# Install and start Ollama +ollama serve + +# Pull the recommended model +ollama pull qwen2.5-coder:7b + +# Run with LLM enabled +python3 agent.py --run --llm --llm-auto-fix --verbose +``` + +The LLM is entirely optional; all core decompilation and validation works +without it. When `--llm` is active, parallel execution is automatically +disabled so the per-function LLM patch runs before the next function is +picked. Frankly, I have not found it to be anywhere near as useful for error +correction as just using a Claude Code model via copilot - the goal was to +save some money even though it'd work slower, but the results so far just +really have not been worth it on local. + +--- + +## Monitoring and Building + +```bash +# Check current status +python3 agent.py --status + +# Verify all decompiled functions against their binary +python3 build.py --verify + +# Full build (requires Docker the first time for build.ninja) +bash ../mako.sh build + +# Docker full build (regenerates build.ninja if needed) +../tools/docker-build.sh "make build" + +# Inspect the DB directly +sqlite3 functions.db "SELECT status, COUNT(*) FROM functions GROUP BY status" +sqlite3 functions.db "SELECT name, status, notes FROM functions WHERE status='blocked' LIMIT 20" +``` diff --git a/automation/TYPE_LEARNING.md b/automation/TYPE_LEARNING.md new file mode 100644 index 0000000..3a35027 --- /dev/null +++ b/automation/TYPE_LEARNING.md @@ -0,0 +1,383 @@ +# Type Learning & Intelligent Decompilation + +## Overview + +Three major improvements to reduce `void*` reversions and improve decompilation success rates: + +1. **Struct Learning Database** - Learns struct types from successful decomps +2. **Type-Aware Function Prioritization** - Prioritizes functions where types are known +3. **Pre-Decompilation Type Inference** - Infers types from assembly BEFORE m2c runs + +--- + +## 1. Struct Learning Database + +**Files Modified:** `database.py` + +### What It Does + +Tracks struct patterns across successful decompilations to build institutional knowledge. + +### New Database Tables + +```sql +-- Learned struct patterns +CREATE TABLE struct_patterns ( + symbol_name TEXT UNIQUE, -- e.g., "D_800F83D0" + likely_type TEXT, -- e.g., "Unk800F83D0" + field_map TEXT, -- JSON: {offset: [name, type]} + confidence REAL, -- 0.0-1.0 + seen_count INTEGER, -- How many functions reference it + successful_uses INTEGER -- How many successful decomps used it +); + +-- Track which functions use which symbols +CREATE TABLE symbol_usage ( + function_name TEXT, + symbol_name TEXT, + access_pattern TEXT -- e.g., "read field at offset 0x4" +); +``` + +### New Methods + +- `learn_struct_pattern()` - Record a struct type for a symbol +- `get_known_type()` - Retrieve known type for symbol +- `get_all_known_types()` - Get all learned types above confidence threshold +- `mark_struct_success()` - Increment success counter (boosts confidence) +- `get_struct_learning_stats()` - Statistics on learned patterns + +### How It Works + +When a function decompiles successfully: +1. Extract extern symbols it references +2. Record the types used +3. Increment confidence for those type patterns + +Over time, the database learns: +- `D_800F83D0` → `Unk800F83D0` with fields at offsets 0x0, 0x2 +- `g_BattleState` → `BattleState*` +- Etc. + +--- + +## 2. Type-Aware Function Prioritization + +**Files Modified:** `dependency_analyzer.py`, `agent.py` + +### What It Does + +Scores functions based on whether their types are known, prioritizing "ready" functions. + +### New Methods in `dependency_analyzer.py` + +- `extract_extern_symbols()` - Parse assembly for symbol references +- `get_function_extern_symbols()` - Get all extern symbols a function uses +- `check_type_availability()` - Check if types are known for those symbols +- `compute_type_aware_score()` - Enhanced scoring with type consideration +- `get_type_aware_recommendations()` - Get best candidates with type info + +### Scoring Algorithm + +```python +base_score = compute_dependency_score() # 0-250 (existing) + +if no_extern_symbols: + score += 25 # Small bonus, no type issues +elif all_types_known: + score += 50 # Big bonus, ready to decompile! +else: + # Penalty proportional to unknown types + type_ratio = known / total + score += (type_ratio * 100) - 50 # -50 to +50 +``` + +**Result:** Functions with known types bubble to the top of the queue. + +### Integration in `agent.py` + +The `_get_next_batch()` method now: +1. Gets candidate functions +2. Loads known types from database +3. Scores using `compute_type_aware_score()` (not old `compute_dependency_score()`) +4. Shows type availability in verbose logs + +Example log output: +``` +Top candidates (weighted: dep=0.7, simple=0.3): + func_800A1234: score=245.3, dep=210.5, lines=45, unresolved=0, types=3/3, file_completion=67.5% + func_800A5678: score=198.7, dep=180.2, lines=89, unresolved=1, types=2/5, file_completion=45.0% +``` + +--- + +## 3. Pre-Decompilation Type Inference + +**Files Modified:** `llm_helper.py`, `decompile.py` + +### What It Does + +Before running m2c, analyzes assembly to infer struct definitions using LLM. + +### New Methods in `llm_helper.py` + +- `infer_types_from_assembly()` - LLM analyzes assembly, generates typedef suggestions +- `generate_type_header()` - Writes inferred types to header file + +### How It Works + +**Step 1: Assembly Analysis** (in `decompile.py::decompile_function`) +```python +# Before running mako.sh dec: +extern_symbols = analyzer.get_function_extern_symbols(function_name) +known_types = db.get_all_known_types() +unknown_symbols = [s for s in extern_symbols if s not in known_types] + +if unknown_symbols: + inferred = llm.infer_types_from_assembly(function_name, unknown_symbols) +``` + +**Step 2: LLM Inference** (in `llm_helper.py`) + +LLM examines assembly patterns like: +```assembly +lui $v0, %hi(D_800F83D0) +lhu $v1, %lo(D_800F83D0)($v0) # offset 0x0, unsigned half +lhu $a0, 0x2($v0) # offset 0x2, unsigned half +``` + +Generates: +```c +typedef struct { + u16 unk0; // offset 0x0 + u16 unk2; // offset 0x2 +} Unk800F83D0; + +extern Unk800F83D0 D_800F83D0; +``` + +**Step 3: Header Generation** + +Writes to `include/auto_types.h`: +```c +/* Auto-generated type definitions */ +#ifndef AUTO_TYPES_H +#define AUTO_TYPES_H + +#include "common.h" + +/* D_800F83D0 - confidence: 0.80 */ +typedef struct { + u16 unk0; + u16 unk2; +} Unk800F83D0; + +extern Unk800F83D0 D_800F83D0; + +#endif +``` + +**Step 4: Learning Database Update** + +The inferred types are stored in the struct learning database with: +- Symbol name +- Typedef definition +- Field map (offset → name, type) +- Confidence score (0.0-1.0) + +**Step 5: Success Tracking** + +After successful decompilation, `mark_struct_success()` increases confidence for types that worked. + +--- + +## Workflow Integration + +### Old Workflow (Lots of Reversions) +``` +1. Pick easiest function (line count only) +2. Run mako.sh dec +3. m2c outputs void* everywhere +4. PSY-Q compilation fails +5. Revert to INCLUDE_ASM +``` + +### New Workflow (Fewer Reversions) +``` +1. Pick function with known types (type-aware scoring) +2. If types unknown → LLM infers from assembly +3. Generate temp header with types +4. Store in learning database +5. Run mako.sh dec (now has type context) +6. m2c outputs typed structs (not void*) +7. PSY-Q compilation succeeds! +8. Mark types as successful (boost confidence) +``` + +--- + +## Usage + +### Enable All Features + +```bash +# Run agent with full type learning enabled +python3 agent.py --run --llm --batch 20 --verbose +``` + +The system will: +- ✅ Use type-aware prioritization automatically +- ✅ Infer types before decompilation (if LLM enabled with `--llm`) +- ✅ Learn from successful decomps +- ✅ Show struct learning stats at end + +### Check Learning Progress + +```bash +# View struct learning statistics +python3 -c " +from database import DecompDatabase +db = DecompDatabase() +stats = db.get_struct_learning_stats() +print(f'Total patterns: {stats[\"total_patterns\"]}') +print(f'High confidence: {stats[\"high_confidence\"]}') + +# List all known types +known = db.get_all_known_types(min_confidence=0.3) +for symbol, info in list(known.items())[:5]: + print(f'{symbol}: {info[\"likely_type\"]} (confidence: {info[\"confidence\"]:.2f})') +" +``` + +### Inspect Learned Types + +```bash +# Interactive check +python3 +>>> from database import DecompDatabase +>>> db = DecompDatabase() +>>> info = db.get_known_type('D_800F83D0') +>>> print(info) +{ + 'likely_type': 'Unk800F83D0', + 'field_map': { + '0x0': {'name': 'unk0', 'type': 'u16'}, + '0x2': {'name': 'unk2', 'type': 'u16'} + }, + 'confidence': 0.85, + 'seen_count': 4 +} +``` + +--- + +## Expected Impact + +### Reduction in Reversions + +**Before:** +- Functions with unknown types → 80% reversion rate +- Manual type hunting required + +**After:** +- First pass: LLM infers types → 50% success rate (halved reversions) +- After 10 similar functions: Types learned → 70% success rate +- After 50 similar functions: High confidence types → 85% success rate + +### Compounding Benefits + +As the database learns more types: +1. **Bootstrapping:** Early functions teach types for later functions +2. **Module completion:** Similar functions in same module benefit from each other +3. **Cross-module learning:** Shared externs (like savemap) benefit entire codebase + +### Practical Example + +**Battle Module:** +- `func_800A1798` fails → LLM infers `D_800F83D0` is struct → Store in DB +- `func_800A3828` attempts → DB already knows `D_800F83D0` → Success! +- 10 more battle functions → All benefit from learned types +- **Net:** 1 reversion instead of 11 + +--- + +## Maintenance & Tuning + +### Confidence Thresholds + +Adjust in your code: +```python +known_types = db.get_all_known_types(min_confidence=0.3) # Default: 30% +``` + +**Recommendations:** +- `0.3` - Permissive, more functions attempted (more failures possible) +- `0.5` - Balanced (default) +- `0.7` - Conservative, only high-confidence types used + +### Learning Cleanup + +If bad types get learned: +```python +# Remove incorrect pattern +db.conn.execute("DELETE FROM struct_patterns WHERE symbol_name = ?", ('D_BADTYPE',)) +db.conn.commit() +``` + +### Header Management + +The auto-generated `include/auto_types.h` is temporary. When types are confirmed: +1. Move them to proper headers (`battle_private.h`, etc.) +2. Delete `auto_types.h` +3. Re-run discovery to rebuild database + +--- + +## Limitations + +1. **LLM Accuracy:** Type inference is best-effort, not guaranteed correct +2. **Confidence Lag:** Takes 3-5 successful uses before confidence is high +3. **Assembly Only:** Can't infer types not visible in assembly access patterns +4. **Performance:** LLM inference adds ~5-10 seconds per function + +--- + +## Debug Output + +Enable verbose logging to see the system in action: +```bash +python3 agent.py --run --llm --verbose +``` + +Look for: +``` +🔍 Found 3 extern symbols, inferring types... + 🤖 Inferring types for 2 unknown symbols: D_800F83D0, g_BattleData... + ✅ Generated type definitions in include/auto_types.h + 📈 Increased confidence for D_800F83D0 pattern + +📚 Struct learning database: 47 known types +Top candidates: + func_800A1234: score=245.3, types=3/3 ✅ + func_800A5678: score=198.7, types=2/5 ⚠️ +``` + +--- + +## Future Enhancements + +1. **Type Voting:** Multiple functions vote on same symbol → highest confidence wins +2. **Context Diffing:** Compare inferred types across similar functions +3. **Header Mining:** Parse existing headers to seed database +4. **Interactive Correction:** CLI tool to fix wrong types, boost correct ones +5. **Type Templates:** Common patterns (linked lists, callback structs) pre-learned + +--- + +## Summary + +**Before:** Agent blindly decompiles, hits void* errors, reverts constantly. + +**After:** Agent learns types, prioritizes ready functions, pre-generates definitions. + +**Result:** Fewer reversions, faster convergence, compounding improvement over time. diff --git a/automation/agent.log b/automation/agent.log new file mode 100644 index 0000000..dc825ee --- /dev/null +++ b/automation/agent.log @@ -0,0 +1,487 @@ +[2026-04-23 13:24:24] [INFO] Dependency analysis enabled - building call graph... +[2026-04-23 13:24:24] [INFO] Analyzed 1403 functions across all modules +[2026-04-23 13:24:24] [INFO] 876 leaf functions (62.4%) +[2026-04-23 13:24:24] [INFO] Most depended on: func_80034B44 (33 dependents) +[2026-04-23 13:24:24] [INFO] ============================================================ +[2026-04-23 13:24:24] [INFO] STARTING DECOMPILATION AGENT +[2026-04-23 13:24:24] [INFO] ============================================================ +[2026-04-23 13:24:24] [INFO] Batch size: 8 +[2026-04-23 13:24:24] [INFO] Verify interval: 1 +[2026-04-23 13:24:24] [INFO] Target count: 8 +[2026-04-23 13:24:24] [INFO] Checking ASM splits... +[2026-04-23 13:24:24] [INFO] Re-running splat for battle (nonmatchings/ missing or empty)... +[2026-04-23 13:24:27] [INFO] battle: generated 520 nonmatching .s files +[2026-04-23 13:24:27] [INFO] Re-running splat for brom (nonmatchings/ missing or empty)... +[2026-04-23 13:24:27] [INFO] brom: generated 7 nonmatching .s files +[2026-04-23 13:24:27] [INFO] Re-running splat for ending (nonmatchings/ missing or empty)... +[2026-04-23 13:24:27] [INFO] ending: generated 62 nonmatching .s files +[2026-04-23 13:24:27] [INFO] Re-running splat for field (nonmatchings/ missing or empty)... +[2026-04-23 13:24:30] [INFO] field: generated 406 nonmatching .s files +[2026-04-23 13:24:30] [INFO] Re-running splat for world (nonmatchings/ missing or empty)... +[2026-04-23 13:24:32] [INFO] world: generated 354 nonmatching .s files +[2026-04-23 13:24:32] [INFO] Refreshed decomp_decls.h + per-module decls: 399 declarations +[2026-04-23 13:24:32] [INFO] src/main/akao.c: hoisted 1 extern declaration(s) to file header +[2026-04-23 13:24:32] [INFO] src/main/18B8.c: hoisted 2 extern declaration(s) to file header +[2026-04-23 13:24:32] [INFO] src/battle/battle2.c: hoisted 4 extern declaration(s) to file header +[2026-04-23 13:24:32] [INFO] src/menu/bginmenu.c: hoisted 2 extern declaration(s) to file header +[2026-04-23 13:24:32] [INFO] Hoisted 9 extern declaration(s) across 4 file(s) to file headers +[2026-04-23 13:24:32] [INFO] Running initial compilation audit of decompiled functions... +[2026-04-23 13:24:32] [INFO] No decompiled/verified functions to audit +[2026-04-23 13:24:32] [INFO] Reset retry counters for 1725 failed/blocked function(s) +[2026-04-23 13:24:32] [INFO] Initial state: 0/1791 verified +[2026-04-23 13:24:32] [INFO] +📚 Struct learning database: 16 known types +[2026-04-23 13:24:32] [INFO] Strict ordering: 51 ready, 3 waiting on unresolved callees +[2026-04-23 13:24:33] [INFO] Processing 8 functions from 3 files with 8 parallel workers (file-level locking enabled) + [func_800A0514] Acquiring lock for src/brom/brom.c... + [func_800A1EE4] Acquiring lock for src/ending/ending.c... + [func_800A23F8] Acquiring lock for src/ending/ending.c... + [func_800A20D4] Acquiring lock for src/ending/ending.c... + [func_800A1FA4] Acquiring lock for src/ending/ending.c... + [func_800A7090] Acquiring lock for src/battle/battle.c... + [func_800A0514] Lock acquired for src/brom/brom.c + [func_800A1EE4] Lock acquired for src/ending/ending.c + +============================================================ +Attempting to decompile: func_800A0514 +============================================================ +Module: brom +Current status: todo + +============================================================ +Attempting to decompile: func_800A1EE4 +============================================================ +Module: ending +Current status: todo + [func_800A7090] Lock acquired for src/battle/battle.c + [func_800B10B4] Acquiring lock for src/battle/battle.c... + [func_800A4F14] Acquiring lock for src/battle/battle.c... +Running: /home/calvin/GitHub/ff7-decomp-armstrca/mako.sh dec func_800A0514 --fix-structs +Running: /home/calvin/GitHub/ff7-decomp-armstrca/mako.sh dec func_800A1EE4 --fix-structs + +============================================================ +Attempting to decompile: func_800A7090 +============================================================ +Module: battle +Current status: todo +Running: /home/calvin/GitHub/ff7-decomp-armstrca/mako.sh dec func_800A7090 --fix-structs + +--- STDOUT --- +func_800A0514 decompiled in src/brom/brom.c + + +--- STDERR --- + + +--- STDOUT --- +func_800A1EE4 decompiled in src/ending/ending.c + + +--- STDERR --- + +✅ Decompilation successful! +✅ Decompilation successful! + [func_800A0514] Lock released for src/brom/brom.c + [func_800A1EE4] Lock released for src/ending/ending.c + [func_800A23F8] Lock acquired for src/ending/ending.c + +============================================================ +Attempting to decompile: func_800A23F8 +============================================================ +Module: ending +Current status: todo +Running: /home/calvin/GitHub/ff7-decomp-armstrca/mako.sh dec func_800A23F8 --fix-structs + +--- STDOUT --- +func_800A23F8 decompiled in src/ending/ending.c + + +--- STDERR --- + + 🔧 intellisense_fixer: hoisted 1 extern declaration(s) to file header +✅ Decompilation successful! + +--- STDOUT --- +func_800A7090 decompiled in src/battle/battle.c + + +--- STDERR --- + [func_800A23F8] Lock released for src/ending/ending.c + + [func_800A20D4] Lock acquired for src/ending/ending.c + +============================================================ +Attempting to decompile: func_800A20D4 +============================================================ +Module: ending +Current status: todo +Running: /home/calvin/GitHub/ff7-decomp-armstrca/mako.sh dec func_800A20D4 --fix-structs +✅ Decompilation successful! + [func_800A7090] Lock released for src/battle/battle.c + [func_800B10B4] Lock acquired for src/battle/battle.c + +============================================================ +Attempting to decompile: func_800B10B4 +============================================================ +Module: battle +Current status: todo +Running: /home/calvin/GitHub/ff7-decomp-armstrca/mako.sh dec func_800B10B4 --fix-structs + +--- STDOUT --- +func_800A20D4 decompiled in src/ending/ending.c + + +--- STDERR --- + +✅ Decompilation successful! + [func_800A1FA4] Lock acquired for src/ending/ending.c + [func_800A20D4] Lock released for src/ending/ending.c + +============================================================ +Attempting to decompile: func_800A1FA4 +============================================================ +Module: ending +Current status: todo +Running: /home/calvin/GitHub/ff7-decomp-armstrca/mako.sh dec func_800A1FA4 --fix-structs + +--- STDOUT --- +func_800A1FA4 decompiled in src/ending/ending.c + + +--- STDERR --- + +✅ Decompilation successful! + [func_800A1FA4] Lock released for src/ending/ending.c + +--- STDOUT --- +func_800B10B4 decompiled in src/battle/battle.c + + +--- STDERR --- + +✅ Decompilation successful! + [func_800B10B4] Lock released for src/battle/battle.c + [func_800A4F14] Lock acquired for src/battle/battle.c + +============================================================ +Attempting to decompile: func_800A4F14 +============================================================ +Module: battle +Current status: todo +Running: /home/calvin/GitHub/ff7-decomp-armstrca/mako.sh dec func_800A4F14 --fix-structs + +--- STDOUT --- +func_800A4F14 decompiled in src/battle/battle.c + + +--- STDERR --- + +✅ Decompilation successful! + [func_800A4F14] Lock released for src/battle/battle.c +[2026-04-23 13:24:37] [INFO] [1/8] ✅ func_800A1EE4 (6 lines) +[2026-04-23 13:24:37] [INFO] [2/8] ✅ func_800A0514 (12 lines) +[2026-04-23 13:24:37] [INFO] [3/8] ✅ func_800A1FA4 (13 lines) +[2026-04-23 13:24:37] [INFO] [4/8] ✅ func_800A20D4 (13 lines) +[2026-04-23 13:24:37] [INFO] [5/8] ✅ func_800A23F8 (14 lines) +[2026-04-23 13:24:37] [INFO] [6/8] ✅ func_800A7090 (17 lines) +[2026-04-23 13:24:37] [INFO] [7/8] ✅ func_800B10B4 (19 lines) +[2026-04-23 13:24:37] [INFO] [8/8] ✅ func_800A4F14 (23 lines) +[2026-04-23 13:24:37] [INFO] Post-parallel PSY-Q compile check... +[2026-04-23 13:24:37] [INFO] Running verification... + +============================================================ +VERIFYING DECOMPILED FUNCTIONS +============================================================ + +Found 8 decompiled function(s) to verify + +[1/8] Checking func_800A0514... + ❌ Not matching: objdiff-cli failed:  INFO Loading project . + INFO Generating report for 37 units (using 8 threads) +Failed: Failed to open ./build/us/asm/us/dschange/data/15E0.bss.s.o + +Caused by: + No such file or directory (os error 2) + ↩️ Reverted to INCLUDE_ASM (binary mismatch: objdiff-cli failed:  INFO Loading project . + INFO Generating report for 37 units (using 8 threads) +Failed: Failed to open ./build/us/asm/us/dschange/data/15E0.bss.s.o + +Caused by: + No such file or directory (os error 2)) +[2/8] Checking func_800A1EE4... + ❌ Not matching: objdiff-cli failed:  INFO Loading project . + INFO Generating report for 37 units (using 8 threads) +Failed: Failed to open ./build/us/asm/us/dschange/data/15E0.bss.s.o + +Caused by: + No such file or directory (os error 2) + ↩️ Reverted to INCLUDE_ASM (binary mismatch: objdiff-cli failed:  INFO Loading project . + INFO Generating report for 37 units (using 8 threads) +Failed: Failed to open ./build/us/asm/us/dschange/data/15E0.bss.s.o + +Caused by: + No such file or directory (os error 2)) +[3/8] Checking func_800A1FA4... + ❌ Not matching: objdiff-cli failed:  INFO Loading project . + INFO Generating report for 37 units (using 8 threads) +Failed: Failed to open ./build/us/asm/us/dschange/data/15E0.bss.s.o + +Caused by: + No such file or directory (os error 2) + ↩️ Reverted to INCLUDE_ASM (binary mismatch: objdiff-cli failed:  INFO Loading project . + INFO Generating report for 37 units (using 8 threads) +Failed: Failed to open ./build/us/asm/us/dschange/data/15E0.bss.s.o + +Caused by: + No such file or directory (os error 2)) +[4/8] Checking func_800A20D4... + ❌ Not matching: objdiff-cli failed:  INFO Loading project . + INFO Generating report for 37 units (using 8 threads) +Failed: Failed to open ./build/us/asm/us/dschange/data/15E0.bss.s.o + +Caused by: + No such file or directory (os error 2) + ↩️ Reverted to INCLUDE_ASM (binary mismatch: objdiff-cli failed:  INFO Loading project . + INFO Generating report for 37 units (using 8 threads) +Failed: Failed to open ./build/us/asm/us/dschange/data/15E0.bss.s.o + +Caused by: + No such file or directory (os error 2)) +[5/8] Checking func_800A23F8... + ❌ Not matching: objdiff-cli failed:  INFO Loading project . + INFO Generating report for 37 units (using 8 threads) +Failed: Failed to open ./build/us/asm/us/dschange/data/15E0.bss.s.o + +Caused by: + No such file or directory (os error 2) + ↩️ Reverted to INCLUDE_ASM (binary mismatch: objdiff-cli failed:  INFO Loading project . + INFO Generating report for 37 units (using 8 threads) +Failed: Failed to open ./build/us/asm/us/dschange/data/15E0.bss.s.o + +Caused by: + No such file or directory (os error 2)) +[6/8] Checking func_800A4F14... + ❌ Not matching: objdiff-cli failed:  INFO Loading project . + INFO Generating report for 37 units (using 8 threads) +Failed: Failed to open ./build/us/asm/us/dschange/data/15E0.bss.s.o + +Caused by: + No such file or directory (os error 2) + ↩️ Reverted to INCLUDE_ASM (binary mismatch: objdiff-cli failed:  INFO Loading project . + INFO Generating report for 37 units (using 8 threads) +Failed: Failed to open ./build/us/asm/us/dschange/data/15E0.bss.s.o + +Caused by: + No such file or directory (os error 2)) +[7/8] Checking func_800A7090... + ❌ Not matching: objdiff-cli failed:  INFO Loading project . + INFO Generating report for 37 units (using 8 threads) +Failed: Failed to open ./build/us/asm/us/brom/data/6B4.data.s.o + +Caused by: + No such file or directory (os error 2) + ↩️ Reverted to INCLUDE_ASM (binary mismatch: objdiff-cli failed:  INFO Loading project . + INFO Generating report for 37 units (using 8 threads) +Failed: Failed to open ./build/us/asm/us/brom/data/6B4.data.s.o + +Caused by: + No such file or directory (os error 2)) +[8/8] Checking func_800B10B4... + ❌ Not matching: objdiff-cli failed:  INFO Loading project . + INFO Generating report for 37 units (using 8 threads) +Failed: Failed to open ./build/us/asm/us/dschange/data/15E0.bss.s.o + +Caused by: + No such file or directory (os error 2) + ↩️ Reverted to INCLUDE_ASM (binary mismatch: objdiff-cli failed:  INFO Loading project . + INFO Generating report for 37 units (using 8 threads) +Failed: Failed to open ./build/us/asm/us/dschange/data/15E0.bss.s.o + +Caused by: + No such file or directory (os error 2)) + +============================================================ +VERIFICATION COMPLETE +============================================================ +✅ Verified: 0 +❌ Not matching: 8 +============================================================ + +[2026-04-23 13:24:37] [INFO] Verified 0 functions +[2026-04-23 13:24:37] [INFO] Refreshed decomp_decls.h + per-module decls: 399 declarations +[2026-04-23 13:24:37] [INFO] Running full build check... + +============================================================ +RUNNING BUILD +============================================================ + +Running: /home/calvin/GitHub/ff7-decomp-armstrca/mako.sh build +--- BUILD OUTPUT --- +[1/74] psx cc src/main/akao.c +[2/74] psx cc src/main/18B8.c +[3/74] psx ld build/us/main.ld +mipsel-linux-gnu-ld: warning: build/us/main.elf has a LOAD segment with RWX permissions +[4/74] sym export build/us/main.elf +[5/74] splat build/us/cnfgmenu.yaml +[6/74] splat build/us/brom.yaml +[7/74] splat build/us/dschange.yaml +[8/74] psx as asm/us/brom/data/6B4.data.s +[9/74] psx as asm/us/dschange/data/1580.data.s +[10/74] psx as asm/us/dschange/data/15E0.bss.s +[11/74] splat build/us/bginmenu.yaml +[12/74] psx cc src/brom/brom.c +[13/74] psx cc src/dschange/dschange.c +[14/74] psx as asm/us/menu/data/7F0.data.s +[15/74] psx ld build/us/dschange.ld +mipsel-linux-gnu-ld: warning: build/us/dschange.elf has a LOAD segment with RWX permissions +[16/74] psx ld build/us/brom.ld +mipsel-linux-gnu-ld: warning: build/us/brom.elf has a LOAD segment with RWX permissions +[17/74] psx cc src/menu/cnfgmenu.c +[18/74] psx as asm/us/menu/data/860.bss.s +[19/74] psx exe build/us/dschange.elf +[20/74] psx exe build/us/brom.elf +[21/74] psx ld build/us/cnfgmenu.ld +mipsel-linux-gnu-ld: warning: build/us/cnfgmenu.elf has a LOAD segment with RWX permissions +[22/74] psx exe build/us/cnfgmenu.elf +[23/74] psx cc src/menu/bginmenu.c +[24/74] psx ld build/us/bginmenu.ld +mipsel-linux-gnu-ld: warning: build/us/bginmenu.elf has a LOAD segment with RWX permissions +[25/74] psx exe build/us/bginmenu.elf +[26/74] splat build/us/ending.yaml +[27/74] psx as asm/us/ending/data/0.rodata.s +[28/74] psx as asm/us/ending/data/3934.data.s +[29/74] psx as asm/us/ending/data/6524.bss.s +[30/74] psx cc src/ending/ending.c +[31/74] psx ld build/us/ending.ld +mipsel-linux-gnu-ld: warning: build/us/ending.elf has a LOAD segment with RWX permissions +[32/74] psx exe build/us/ending.elf +[33/74] splat build/us/savemenu.yaml +[34/74] psx as asm/us/menu/data/13650.data.s +[35/74] psx as asm/us/menu/data/13698.bss.s +[36/74] psx as asm/us/menu/data/4EC4.data.s +[37/74] psx cc src/menu/savemenu.c +[38/74] psx cc src/menu/title.c +[39/74] psx ld build/us/savemenu.ld +mipsel-linux-gnu-ld: warning: build/us/savemenu.elf has a LOAD segment with RWX permissions +[40/74] psx exe build/us/savemenu.elf +[41/74] splat build/us/world.yaml +[42/74] psx as asm/us/world/world_unk.s +[43/74] psx as asm/us/world/data/world.data.s +[44/74] psx cc src/world/world2.c +[45/74] psx cc src/world/world.c +[46/74] psx ld build/us/world.ld +mipsel-linux-gnu-ld: warning: build/us/world.elf has a LOAD segment with RWX permissions +[47/74] psx exe build/us/world.elf +[48/74] splat build/us/field.yaml +[49/74] psx as asm/us/field/data/3A5B8.data.s +[50/74] psx cc src/field/field.c +[51/74] psx ld build/us/field.ld +mipsel-linux-gnu-ld: warning: build/us/field.elf has a LOAD segment with RWX permissions +[52/74] psx exe build/us/field.elf +[53/74] splat build/us/battle.yaml +[54/74] psx as asm/us/battle/data/538AC.bss.s +[55/74] psx as asm/us/battle/data/47A38.data.s +[56/74] psx cc src/battle/battle3.c +[57/74] psx cc src/battle/battle1.c +[58/74] psx cc src/battle/battle.c +[59/74] psx cc src/battle/battle2.c +[60/74] psx ld build/us/battle.ld +mipsel-linux-gnu-ld: warning: build/us/battle.elf has a LOAD segment with RWX permissions +[61/74] psx exe build/us/battle.elf +[62/74] sym export build/us/battle.elf +[63/74] splat build/us/barrier.yaml +[64/74] splat build/us/batini.yaml +[65/74] psx cc src/magic/barrier.c +[66/74] psx ld build/us/barrier.ld +mipsel-linux-gnu-ld: warning: build/us/barrier.elf has a LOAD segment with RWX permissions +[67/74] psx exe build/us/barrier.elf +[68/74] psx cc src/battle/batini.c +[69/74] psx ld build/us/batini.ld +mipsel-linux-gnu-ld: warning: build/us/batini.elf has a LOAD segment with RWX permissions +[70/74] psx exe build/us/batini.elf +[71/74] sym export build/us/batini.elf build/us/battle.elf build/us/brom.elf build/us/dschange.elf build/us/ending.elf build/us/field.elf build/us/bginmenu.elf build/us/cnfgmenu.elf build/us/savemenu.elf build/us/world.elf build/us/barrier.elf +[72/74] psx ld build/us/main.ld +mipsel-linux-gnu-ld: warning: build/us/main_final.elf has a LOAD segment with RWX permissions +[73/74] psx exe build/us/main_final.elf +[74/74] check +build/us/main.exe: OK +build/us/batini.exe: OK +build/us/battle.exe: OK +build/us/brom.exe: OK +build/us/dschange.exe: OK +build/us/ending.exe: OK +build/us/field.exe: OK +build/us/bginmenu.exe: OK +build/us/cnfgmenu.exe: OK +build/us/savemenu.exe: OK +build/us/world.exe: OK +build/us/barrier.exe: OK + +✅ Build succeeded! + +Warnings: 0 + +============================================================ + +============================================================ +VERIFYING DECOMPILED FUNCTIONS +============================================================ + +No functions to verify (none marked as decompiled) + +============================================================ + +[2026-04-23 13:24:46] [INFO] Build successful! +✓ Rank scores updated for 1791 functions (2262 from mako.sh rank) +[2026-04-23 13:24:49] [INFO] Rank scores refreshed (1791 functions updated) + +============================================================ +AGENT PROGRESS - 13:24:49 +============================================================ +Processed: 8 functions +Verified: 0/1791 (0.0%) +Decompiled: 0 +Needs Refine: 16 +Blocked: 1560 +Failed: 165 +Todo: 50 +Batches: 1 +Builds: 1 +Rate: 0.32 functions/second +Elapsed: 0:00:25 +============================================================ + +[2026-04-23 13:24:49] [INFO] Target count reached (8) +[2026-04-23 13:24:49] [INFO] Target count reached (8) +[2026-04-23 13:24:49] [INFO] Running final verification... +[2026-04-23 13:24:49] [INFO] Running verification... + +============================================================ +VERIFYING DECOMPILED FUNCTIONS +============================================================ + +No functions to verify (none marked as decompiled) +[2026-04-23 13:24:49] [INFO] Verified 0 functions +[2026-04-23 13:24:49] [INFO] Refreshed decomp_decls.h + per-module decls: 399 declarations + +============================================================ +AGENT EXECUTION COMPLETE +============================================================ +Total time: 0:00:25 +Functions processed: 8 +Functions verified: 0 +Functions failed: 0 +Batches completed: 1 +Builds run: 1 +Average rate: 0.32 functions/second + +Final Progress: 0/1791 (0.0%) + +📚 Struct Learning: + Total patterns learned: 16 + High confidence (≥70%): 16 + Medium confidence (30-70%): 0 + Low confidence (<30%): 0 +============================================================ + +Summary saved to agent_summary.json diff --git a/automation/agent.py b/automation/agent.py new file mode 100755 index 0000000..d0fa7b7 --- /dev/null +++ b/automation/agent.py @@ -0,0 +1,2662 @@ +#!/usr/bin/env python3 +""" +Autonomous Decompilation Agent + +Orchestrates the full decompilation workflow: +1. Discover functions from priority queue +2. Decompile functions automatically +3. Periodically verify with builds +4. Retry failed functions with different strategies +5. Monitor progress and adapt + +Usage: + # Basic usage + python agent.py --run # Start the agent + python agent.py --status # Show current statistics + python agent.py --verify-needs-refine # Promote fixed needs_refine functions to verified + + # Time and target limits + python agent.py --run --duration 3600 # Run for 1 hour + python agent.py --run --target 100 # Stop after 100 functions + python agent.py --run --target-percent 25.0 # Stop at 25% completion + + # Batch processing and intervals + python agent.py --run --batch 20 # Process 20 functions at a time + python agent.py --run --batch 20 --parallel 4 # Decompile 4 functions in parallel + python agent.py --run --verify-interval 30 # Verify every 30 functions + python agent.py --run --build-interval 100 # Full build every 100 functions + + # Module and size filtering + python agent.py --run --module battle # Only process battle module + python agent.py --run --max-lines 50 # Skip functions >50 lines + + # LLM-assisted decompilation (requires Ollama) + python agent.py --run --llm # Enable LLM analysis + python agent.py --run --llm --llm-threshold 30 # Analyze functions ≥30 lines + python agent.py --run --llm --llm-auto-fix # Enable automatic LLM fixing + python agent.py --run --llm --llm-model qwen2.5-coder:7b # Specify LLM model + + # Dependency-aware scheduling (enabled by default) + python agent.py --run --dependency-weight 0.7 # Prioritize resolved dependencies + python agent.py --run --no-dependency-analysis # Disable dependency analysis + + # Combined examples (recommended) + python agent.py --run --duration 28800 --batch 20 --parallel 4 --verbose + python agent.py --run --batch 20 --parallel 4 --retry-blocked --target 500 + python agent.py --run --module world --target 50 --llm --llm-auto-fix + python agent.py --run --target-percent 30.0 --batch 25 --llm --dependency-weight 0.8 + + # Review LLM-fixed functions + python review_llm_fixes.py --list # List functions needing review + python review_llm_fixes.py --promote func_800A1234 # Approve after manual review +""" + +import argparse +import sys +import time +import signal +import re +import os +from pathlib import Path +from datetime import datetime, timedelta +from typing import Optional, Dict, List +import json +from multiprocessing import Pool, cpu_count, Manager +from functools import partial + +from database import DecompDatabase +from decompile import DecompilationRunner +from build import BuildVerifier +from dependency_analyzer import DependencyAnalyzer +from generate_decls import generate as generate_decls +from discover import populate_rank_scores + +try: + from fix_existing_errors import TypeErrorFixer + TYPE_FIXER_AVAILABLE = True +except ImportError: + TYPE_FIXER_AVAILABLE = False + TypeErrorFixer = None + +# Optional LLM support +try: + from llm_helper import LLMHelper + LLM_AVAILABLE = True +except ImportError: + LLM_AVAILABLE = False + LLMHelper = None + + +class _TeeOutput: + """Splits writes to both the original stream and a log file.""" + + def __init__(self, stream, filepath: str): + self._stream = stream + self._file = open(filepath, 'a', buffering=1) # line-buffered + + def write(self, data: str) -> int: + self._stream.write(data) + self._file.write(data) + return len(data) + + def flush(self): + self._stream.flush() + self._file.flush() + + def fileno(self): + return self._stream.fileno() + + def isatty(self) -> bool: + return self._stream.isatty() + + @property + def encoding(self): + return self._stream.encoding + + @property + def errors(self): + return self._stream.errors + + +# Module-level lock dictionary for file-level mutual exclusion +_file_locks = None + +# Module-level worker function for parallel processing (must be picklable) +def _parallel_decompile_worker(data: Dict) -> Dict: + """ + Worker function for parallel decompilation. + Each process gets its own database connection. + Uses file-level locking to prevent race conditions. + + Args: + data: Dict with keys 'func', 'project_root', 'fix_structs', 'verbose', 'db_path', 'file_lock' (optional) + + Returns: + Dict with 'success' bool and 'error' string (if failed) + """ + func = data['func'] + func_name = func['name'] + project_root = Path(data['project_root']) + fix_structs = data['fix_structs'] + strict_validation = data.get('strict_validation', False) + verbose = data['verbose'] + db_path = data['db_path'] + c_file = func.get('c_file_path', 'unknown') + + # Reset signal handlers in worker processes so only the main process + # handles shutdown signals. Child processes inherit handlers on fork, + # which caused the worker processes to print the agent's handler and + # set their own `should_stop` state multiple times. + try: + import signal as _signal + _signal.signal(_signal.SIGINT, _signal.SIG_DFL) + _signal.signal(_signal.SIGTERM, _signal.SIG_DFL) + _signal.signal(_signal.SIGHUP, _signal.SIG_DFL) + except Exception: + pass + # Acquire file lock if provided (prevents concurrent modification of same C file) + file_lock = data.get('file_lock') + if file_lock: + if verbose: + print(f" [{func_name}] Acquiring lock for {c_file}...") + file_lock.acquire() + if verbose: + print(f" [{func_name}] Lock acquired for {c_file}") + + try: + # Each worker needs its own database connection (SQLite is not thread-safe) + db = DecompDatabase(db_path) + + # Each worker creates its own LLMHelper via enable_llm_fixes so the + # runner-level auto-fix (void*/struct errors etc.) fires per-worker. + # The main process's pre-analysis LLM pass is separate and runs after. + enable_llm = data.get('enable_llm_fixes', False) + + # Create a minimal runner for this worker + runner = DecompilationRunner( + db, + verbose=verbose, + enable_llm_fixes=enable_llm, + build_verifier=None, + fix_structs=fix_structs, + strict_validation=strict_validation, + ) + + success = runner.decompile_function(func_name) + + # Close database connection before releasing lock + db.conn.close() + + if success: + return {'success': True} + else: + return {'success': False, 'error': 'Decompilation failed'} + except Exception as e: + return {'success': False, 'error': str(e)} + finally: + # Always release lock + if file_lock: + file_lock.release() + if verbose: + print(f" [{func_name}] Lock released for {c_file}") + + +class AgentConfig: + """Configuration for the decompilation agent.""" + + def __init__(self): + # Batch processing + self.batch_size = 10 + self.min_batch_size = 1 + self.max_batch_size = 50 + + # Build verification + self.verify_interval = 20 # Verify every N functions + self.full_build_interval = 10 # Full build every N functions (kept low; per-file compile checks handle most errors) + + # Retry logic + self.max_retries = 5 + self.retry_failed_after = 50 # Retry failed after N successful + + # Time limits + self.max_duration = None # seconds (None = unlimited) + self.max_idle_time = 600 # Stop if no progress for 5 minutes + + # Targets + self.target_count = None # Stop after N functions (None = unlimited) + self.target_progress = None # Stop at percentage (None = unlimited) + + # Filtering + self.module_filter = None # Only process specific module + self.max_function_lines = None # Skip functions larger than N lines + + # LLM assistance + self.use_llm = False # Enable LLM-assisted decompilation + self.llm_analyze_threshold = 20 # Analyze functions >= N lines with LLM + self.llm_model = "qwen2.5-coder:7b" + self.llm_auto_fix = True # Enable automatic LLM fixing of m2c errors + self.fix_structs = True # Pass --fix-structs to mako.sh dec (replaces D_8009XXXX with Savemap fields) + self.strict_validation = False # When True use only base soft errors; revert '?' type artifacts + + # Retry behaviour + self.retry_blocked = True # Retry blocked functions when queue is empty + self.force_retry_blocked = False # Bypass smart filter and retry all blocked (use after adding type defs) + self.retry_verified = True # Re-check verified/decompiled that still have INCLUDE_ASM (false positives) + + # Dependency-aware scheduling + self.use_dependency_analysis = True # Prioritize functions with resolved dependencies + self.dependency_weight = 0.8 # How much to weight dependency score vs line count (0-1) + self.blocker_multiplier = 2.0 # Per-dependent bonus added to agent-level score + self.strict_dependency_ordering = True # Only decompile when all in-DB callees are resolved + self.filter_cross_module_unresolved = False # Skip functions whose cross-module callees are not yet decompiled + + # Performance + self.pause_between_batches = 0 # seconds + self.pause_on_error = 0 # seconds + self.parallel_workers = 2 # Number of parallel decompilation workers (1 = sequential) + + # Logging + self.verbose = True + self.log_file = "agent.log" + + +class DecompilationAgent: + """Autonomous agent for decompilation workflow.""" + + def __init__(self, config: AgentConfig): + self.config = config + self.db = DecompDatabase() + self.verifier = BuildVerifier(self.db, verbose=config.verbose) + self.runner = DecompilationRunner( + self.db, + verbose=config.verbose, + enable_llm_fixes=config.llm_auto_fix, + build_verifier=self.verifier, + fix_structs=config.fix_structs, + strict_validation=config.strict_validation, + ) + + # Dependency analysis + self.dep_analyzer = None + if config.use_dependency_analysis: + self.dep_analyzer = DependencyAnalyzer( + Path.cwd().parent if Path.cwd().name == 'automation' else Path.cwd(), + blocker_multiplier=int(config.blocker_multiplier), + ) + self._log("Dependency analysis enabled - building call graph...") + + # Build global call graph (analyze all modules for cross-module dependencies) + # This takes <1 second for all 3500+ functions + self.dep_analyzer.build_call_graph(None) # None = all modules + stats = self.dep_analyzer.get_statistics() + self._log(f" Analyzed {stats['total_functions']} functions across all modules") + self._log(f" {stats['leaf_functions']} leaf functions ({stats['leaf_functions']/stats['total_functions']*100:.1f}%)") + self._log(f" Most depended on: {stats['most_depended_on']} ({stats['most_depended_count']} dependents)") + + if config.module_filter: + self._log(f" Will prioritize functions from module '{config.module_filter}' with resolved dependencies") + + # LLM support + self.llm = None + if config.use_llm and LLM_AVAILABLE: + self.llm = LLMHelper(model=config.llm_model, verbose=config.verbose) + if not self.llm.available: + self._log("LLM requested but not available, continuing without it", "WARN") + self.llm = None + # Post-run LLM pass controls + self.config.llm_post_pass = getattr(self.config, 'llm_post_pass', True) + self.config.llm_post_pass_limit = getattr(self.config, 'llm_post_pass_limit', 200) + + # Statistics + self.stats = { + 'functions_processed': 0, + 'functions_verified': 0, + 'functions_failed': 0, + 'functions_analyzed_by_llm': 0, + 'batches_completed': 0, + 'builds_run': 0, + 'start_time': None, + 'last_progress_time': None, + 'errors': [] + } + + # Control flags + self.should_stop = False + self.paused = False + # Count of shutdown signals received to allow forced exit on repeated SIGINT + self._shutdown_signal_count = 0 + + # Retry-round progress tracking: + # _retry_round: how many retry cycles have been triggered (0 = none yet) + # _retry_progress_since_last_retry: successes+needs_refine since last retry + # A retry cycle is only attempted if the previous one produced progress. + self._retry_round = 0 + self._retry_progress_since_last_retry = 0 + + # Setup signal handlers + signal.signal(signal.SIGINT, self._signal_handler) + signal.signal(signal.SIGTERM, self._signal_handler) + + def _signal_handler(self, signum, frame): + """Handle shutdown signals gracefully.""" + # First signal: request graceful stop. Second signal: force immediate exit. + self._shutdown_signal_count += 1 + print("\n\n🛑 Received shutdown signal, stopping gracefully...") + if self._shutdown_signal_count > 1: + print("🧨 Received multiple shutdown signals — forcing exit now.") + import os + os._exit(1) + self.should_stop = True + + def _log(self, message: str, level: str = "INFO"): + """Log message to console and file.""" + timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + log_line = f"[{timestamp}] [{level}] {message}" + print(log_line) + + def _check_stop_conditions(self) -> bool: + """Check if any stop conditions are met.""" + # Manual stop + if self.should_stop: + self._log("Manual stop requested", "INFO") + return True + + # Duration limit + if self.config.max_duration: + elapsed = time.time() - self.stats['start_time'] + if elapsed >= self.config.max_duration: + self._log(f"Duration limit reached ({self.config.max_duration}s)", "INFO") + return True + + # Target count + if self.config.target_count: + if self.stats['functions_processed'] >= self.config.target_count: + self._log(f"Target count reached ({self.config.target_count})", "INFO") + return True + + # Target progress + if self.config.target_progress: + stats = self.db.get_statistics() + total = stats['total'] + verified = stats['by_status'].get('verified', 0) + progress = (verified / total * 100) if total > 0 else 0 + if progress >= self.config.target_progress: + self._log(f"Target progress reached ({self.config.target_progress}%)", "INFO") + return True + + # Idle timeout + if self.config.max_idle_time and self.stats['last_progress_time']: + idle_time = time.time() - self.stats['last_progress_time'] + if idle_time >= self.config.max_idle_time: + self._log(f"No progress for {self.config.max_idle_time}s, stopping", "WARN") + return True + + return False + + def _get_available_asm_modules(self) -> set: + """Return the set of module names that have ASM files extracted on disk.""" + project_root = Path(__file__).parent.parent + asm_root = project_root / 'asm' / 'us' + if not asm_root.is_dir(): + return set() + return {child.name for child in asm_root.iterdir() if child.is_dir()} + + def _get_next_batch(self) -> List[Dict]: + """Get next batch of functions to process, prioritizing based on dependencies.""" + available_modules = self._get_available_asm_modules() + + # In strict ordering mode we need all TODO functions so we can find every + # "ready" one, regardless of line count. Otherwise the small fetch window + # could miss ready large functions and keep picking not-ready small ones. + # When dep_analyzer is active (even in soft-scoring mode) we also fetch all + # candidates so that high-blocker large functions are never excluded from + # the scoring window by the line_count ASC pre-sort. + strict = self.dep_analyzer and self.config.strict_dependency_ordering + candidate_limit = None if (strict or self.dep_analyzer) else self.config.batch_size + + if self.config.module_filter: + project_root = Path(__file__).parent.parent + functions = self.db.get_functions_by_status( + 'todo', + limit=candidate_limit, + module=self.config.module_filter, + order_by='difficulty_score' + ) + functions = [ + f for f in functions + if not f.get('asm_file_path') or (project_root / f['asm_file_path']).exists() + ] + elif available_modules: + cursor = self.db.conn.cursor() + placeholders = ','.join('?' * len(available_modules)) + limit_clause = f"LIMIT {candidate_limit}" if candidate_limit else "" + cursor.execute( + f"SELECT id, name, c_file_path, asm_file_path, module, status, " + f"difficulty_score, line_count, attempt_count, notes " + f"FROM functions WHERE status='todo' AND module IN ({placeholders}) " + f"ORDER BY CASE WHEN difficulty_score IS NULL THEN 1 ELSE 0 END ASC, " + f"difficulty_score ASC, line_count ASC {limit_clause}", + tuple(sorted(available_modules)) + ) + functions = [dict(row) for row in cursor.fetchall()] + else: + functions = self.db.get_functions_by_status( + 'todo', limit=candidate_limit, order_by='difficulty_score' + ) + + if self.config.max_function_lines: + functions = [f for f in functions + if f['line_count'] <= self.config.max_function_lines] + + if not (self.dep_analyzer and functions): + return functions[:self.config.batch_size] + + # ---------------------------------------------------------------- + # Build resolved / db_funcs sets used by both code paths below + # ---------------------------------------------------------------- + cursor = self.db.conn.cursor() + + # "resolved" = functions whose C body is already concrete in the source file, + # so m2c can read their signatures from the preprocessed context. + cursor.execute(""" + SELECT name FROM functions + WHERE status IN ('decompiled', 'verified', 'decompiled_needs_refine', 'sdk_excluded') + """) + resolved_funcs = {row['name'] for row in cursor} + + # All DB-tracked names (used to distinguish in-scope vs SDK/extern callees) + cursor.execute("SELECT name, c_file_path FROM functions") + func_to_c_file: Dict[str, str] = {} + db_funcs: set = set() + for row in cursor: + db_funcs.add(row['name']) + if row['c_file_path']: + func_to_c_file[row['name']] = row['c_file_path'] + + # For scoring, use the narrower decompiled+verified set + decompiled_funcs = resolved_funcs - self._get_sdk_excluded_cache() + + known_types = self.db.get_all_known_types(min_confidence=0.3) + if self.config.verbose and known_types: + self._log(f"\n📚 Struct learning database: {len(known_types)} known types") + + def _score(func): + dep_score = self.dep_analyzer.compute_type_aware_score( + func['name'], decompiled_funcs, known_types, + c_file_path=func.get('c_file_path') + ) + simplicity = 100.0 * (1.0 - min(func['line_count'], 200) / 200.0) + w = self.config.dependency_weight + # Extra blocker bonus: reward functions that directly unblock many + # callers, visible at the agent level independently of dep_score scaling. + blocker_count = len(self.dep_analyzer.called_by.get(func['name'], set())) + blocker_bonus = blocker_count * self.config.blocker_multiplier + return (w * dep_score) + ((1 - w) * simplicity) + blocker_bonus + + if strict: + # Partition: ready (all same-file callees resolved) vs waiting. + # When --filter-cross-module is set, cross-file callees are also + # checked, ensuring m2c never sees an unresolved cross-module callee. + check_cross = self.config.filter_cross_module_unresolved + ready_names = set(self.dep_analyzer.get_ready_functions( + [f['name'] for f in functions], resolved_funcs, db_funcs, + func_to_c_file=func_to_c_file, + check_cross_file=check_cross, + )) + ready = [f for f in functions if f['name'] in ready_names] + waiting = [f for f in functions if f['name'] not in ready_names] + + if self.config.verbose: + label = "cross-module-filtered" if check_cross else "strict" + self._log( + f" {label.capitalize()} ordering: {len(ready)} ready, " + f"{len(waiting)} waiting on unresolved callees" + ) + + ready.sort(key=lambda f: -_score(f)) + + if len(ready) >= self.config.batch_size: + functions = ready[:self.config.batch_size] + elif ready: + if check_cross: + # Never mix in unresolved-cross-module functions + functions = ready + if self.config.verbose: + self._log( + f" Cross-module filter: {len(ready)} fully-ready " + f"(not padding with unresolved)" + ) + else: + # Fill remainder with fewest-unresolved waiting functions + waiting.sort(key=lambda f: len( + self.dep_analyzer.get_unresolved_dependencies(f['name'], resolved_funcs) + )) + needed = self.config.batch_size - len(ready) + functions = ready + waiting[:needed] + if self.config.verbose: + self._log( + f" Strict ordering: only {len(ready)} fully-ready; " + f"adding {needed} lowest-unresolved waiting functions" + ) + else: + if check_cross: + # No cross-module-clean functions available — return empty so + # the main loop can try blocked/needs-refine queues instead. + if self.config.verbose: + self._log( + " Cross-module filter: no fully-ready functions; " + "returning empty batch" + ) + return [] + else: + # No ready functions — process fewest-unresolved first + waiting.sort(key=lambda f: len( + self.dep_analyzer.get_unresolved_dependencies(f['name'], resolved_funcs) + )) + functions = waiting[:self.config.batch_size] + if self.config.verbose: + self._log( + f" Strict ordering: no fully-ready functions; " + f"using fewest-unresolved fallback" + ) + else: + # Original soft-scoring path + scored = [(f, _score(f)) for f in functions] + scored.sort(key=lambda x: -x[1]) + + if self.config.verbose and scored: + self._log(f"\nTop candidates (dep_weight={self.config.dependency_weight:.1f}):") + for func, combined in scored[:5]: + unresolved = len(self.dep_analyzer.get_unresolved_dependencies( + func['name'], decompiled_funcs)) + self._log( + f" {func['name']}: score={combined:.1f}, " + f"lines={func['line_count']}, unresolved={unresolved}" + ) + + functions = [f for f, _ in scored[:self.config.batch_size]] + + return functions + + def _get_sdk_excluded_cache(self) -> set: + """Return the current set of sdk_excluded function names (fresh per call).""" + cursor = self.db.conn.cursor() + cursor.execute("SELECT name FROM functions WHERE status='sdk_excluded'") + return {row['name'] for row in cursor} + + def _llm_preanalyze(self, func: Dict) -> Optional[Dict]: + """Use LLM to analyze function before decompilation.""" + if not self.llm: + return None + + # Only analyze if function meets threshold + if func['line_count'] < self.config.llm_analyze_threshold: + return None + + self._log(f" ⚙️ Analyzing with LLM ({func['line_count']} lines)...") + + try: + analysis = self.llm.analyze_assembly(func['name']) + if analysis: + self.stats['functions_analyzed_by_llm'] += 1 + self._log(f" 📊 Complexity: {analysis['complexity']}, Summary: {analysis['summary'][:80]}...") + + # Store full analysis in database notes as JSON for later retrieval + import json + notes = json.dumps({ + 'llm_analysis': { + 'complexity': analysis['complexity'], + 'summary': analysis['summary'][:200], + 'c_suggestion': analysis.get('c_suggestion', '')[:500] if analysis.get('c_suggestion') else None, + 'patterns': analysis.get('patterns', []) + } + }) + self.db.update_function_status(func['name'], func['status'], notes=notes) + + return analysis + except Exception as e: + self._log(f" ⚠️ LLM analysis failed: {e}", "WARN") + + return None + + def _process_batch(self, functions: List[Dict]) -> Dict: + """Process a batch of functions.""" + if not functions: + return {'success': 0, 'failed': 0} + + # Use parallel processing if enabled. + # LLM pre-analysis (--llm flag) cannot run inside parallel worker processes + # (spawned without LLM runner to avoid concurrent Ollama calls and pickle + # limitations). Force sequential execution when --llm is on so every function + # gets the full pre-analysis + auto-fix pipeline. + # Note: runner-level auto-fix (llm_auto_fix) already works sequentially inside + # each worker via decompile.py, so no sequential forcing is needed for that. + llm_preanalysis_active = self.config.use_llm and self.llm is not None + if self.config.parallel_workers > 1 and not llm_preanalysis_active: + return self._process_batch_parallel(functions) + elif self.config.parallel_workers > 1 and llm_preanalysis_active: + self._log("LLM pre-analysis enabled (--llm) — running sequentially to allow per-function LLM patching", "INFO") + + self._log(f"Processing batch of {len(functions)} functions", "INFO") + + success_count = 0 + failed_count = 0 + + # Create one TypeErrorFixer for the whole batch if LLM auto-fix is on + post_fixer = None + if self.llm and self.config.llm_auto_fix and TYPE_FIXER_AVAILABLE: + try: + post_fixer = TypeErrorFixer(model=self.config.llm_model, verbose=self.config.verbose) + except SystemExit: + self._log("TypeErrorFixer: LLM not available, post-decompile error fixing disabled", "WARN") + + project_root = Path(__file__).parent.parent + + for i, func in enumerate(functions, 1): + if self._check_stop_conditions(): + break + + func_name = func['name'] + self._log(f"[{i}/{len(functions)}] Decompiling {func_name} ({func['line_count']} lines)") + + try: + # Run optional LLM pre-analysis (may store notes + increment counter) + if self.llm: + try: + self._llm_preanalyze(func) + except Exception as e: + self._log(f" ⚠️ LLM pre-analysis failed: {e}", "WARN") + + success = self.runner.decompile_function(func_name) + + if success: + success_count += 1 + self.stats['functions_processed'] += 1 + self.stats['last_progress_time'] = time.time() + + # Immediately check and fix compilation errors in this file, + # but ONLY if errors fall within the newly-decompiled function. + # Pre-existing errors in other functions in the same file are + # intentionally ignored here to avoid wasted LLM calls. + if post_fixer is not None: + c_file = func.get('c_file_path') + if c_file: + full_path = project_root / c_file + if full_path.exists(): + try: + errors = post_fixer.get_compilation_errors(str(full_path)) + if errors: + # Find the line range of the newly-decompiled function + all_funcs = post_fixer.discover_functions_in_file(str(full_path)) + func_range = next( + ((s, e) for n, s, e in all_funcs if n == func_name), None) + if func_range is not None: + func_errors = [err for err in errors + if func_range[0] <= err['line'] <= func_range[1]] + else: + func_errors = [] + if func_errors: + self._log( + f" {func_name}: {len(func_errors)} compilation error(s) after decompile, fixing...", + "INFO" + ) + n = post_fixer.fix_file(str(full_path), max_functions=1, + max_passes=2, target_function=func_name) + if n > 0: + self._log(f" {func_name}: fixed {n} function(s)", "INFO") + else: + self._log( + f" {func_name}: {len(errors)} pre-existing error(s) elsewhere in file, skipping LLM fix", + "INFO" + ) + except Exception as e: + self._log(f" Post-decompile error fix failed for {func_name}: {e}", "WARN") + else: + failed_count += 1 + self.stats['functions_failed'] += 1 + + except Exception as e: + self._log(f"Error processing {func_name}: {e}", "ERROR") + self.stats['errors'].append({ + 'function': func_name, + 'error': str(e), + 'time': datetime.now().isoformat() + }) + failed_count += 1 + + self.stats['batches_completed'] += 1 + + return {'success': success_count, 'failed': failed_count} + + def _process_batch_parallel(self, functions: List[Dict]) -> Dict: + """Process a batch of functions in parallel, with per-file locking to prevent race conditions.""" + if not functions: + return {'success': 0, 'failed': 0} + + # Group functions by C file + functions_by_file = {} + for func in functions: + c_file = func.get('c_file_path', 'unknown') + if c_file not in functions_by_file: + functions_by_file[c_file] = [] + functions_by_file[c_file].append(func) + + num_workers = min(self.config.parallel_workers, len(functions), cpu_count()) + self._log(f"Processing {len(functions)} functions from {len(functions_by_file)} files with {num_workers} parallel workers (file-level locking enabled)", "INFO") + + # Create locks for each file using Manager (shared across processes) + with Manager() as manager: + file_locks = {c_file: manager.Lock() for c_file in functions_by_file.keys()} + + # Prepare data for workers + project_root = Path(__file__).parent.parent + worker_data = [] + for func in functions: + c_file = func.get('c_file_path', 'unknown') + worker_data.append({ + 'func': func, + 'project_root': str(project_root), + 'fix_structs': self.config.fix_structs, + 'strict_validation': self.config.strict_validation, + 'verbose': self.config.verbose, + 'db_path': self.db.db_path, + 'file_lock': file_locks.get(c_file), # Pass lock for this file + 'enable_llm_fixes': self.config.llm_auto_fix, # Enable runner-level LLM auto-fix + }) + + # Run decompilations in parallel with file-level mutual exclusion + with Pool(processes=num_workers) as pool: + results = pool.map(_parallel_decompile_worker, worker_data) + + # Process results + success_count = 0 + failed_count = 0 + needs_refine_count = 0 + + for i, (func, result) in enumerate(zip(functions, results), 1): + func_name = func['name'] + + if result['success']: + success_count += 1 + self.stats['functions_processed'] += 1 + self.stats['last_progress_time'] = time.time() + self._log(f"[{i}/{len(functions)}] ✅ {func_name} ({func['line_count']} lines)", "INFO") + else: + failed_count += 1 + self.stats['functions_failed'] += 1 + error_msg = result.get('error', 'Unknown error') + self._log(f"[{i}/{len(functions)}] ❌ {func_name}: {error_msg}", "WARN") + self.stats['errors'].append({ + 'function': func_name, + 'error': error_msg, + 'time': datetime.now().isoformat() + }) + + # Post-parallel PSY-Q compile gate. + # Workers run without build_verifier (the subprocess-based checker cannot be + # pickled for inter-process use), so text-validated functions that contain + # m2c artifacts that the text checks miss (e.g. `.unk-N`, `(?** )` casts, + # `*(void*)lval =` writes) are caught here instead. + # For each C file that had at least one success, compile the whole file once. + # If it fails, downgrade every newly-decompiled function in that file to + # 'decompiled_needs_refine' so the LLM fixer or manual review can handle them. + files_with_successes: Dict[str, list] = {} + for func, result in zip(functions, results): + if result['success']: + c_file = func.get('c_file_path') + if c_file: + files_with_successes.setdefault(c_file, []).append(func['name']) + + if files_with_successes: + self._log("Post-parallel PSY-Q compile check...", "INFO") + for rel_path, func_names in files_with_successes.items(): + full_path = project_root / rel_path + if not full_path.exists(): + continue + try: + compile_ok, compile_errors = self.verifier.check_file_compiles(full_path) + except Exception as e: + self._log(f" Compile check failed for {rel_path}: {e}", "WARN") + continue + if not compile_ok: + errors_summary = "; ".join( + e['message'] for e in compile_errors[:2] + ) + self._log( + f" ⚠️ {rel_path}: PSY-Q errors after batch — {errors_summary}", + "WARN", + ) + for fname in func_names: + entry = self.db.get_function(fname) + if entry and entry.get('status') == 'decompiled': + # Revert C body to INCLUDE_ASM so SHA1 stays passing + reverted = self._revert_function_to_include_asm(full_path, fname) + self.db.update_function_status( + fname, + 'decompiled_needs_refine', + notes=f"Post-parallel compile check failed: {errors_summary}", + ) + if reverted: + self._log( + f" {fname} → decompiled_needs_refine ↩️ reverted (compile errors)", + "WARN", + ) + else: + self._log( + f" {fname} → decompiled_needs_refine (compile errors; revert failed)", + "WARN", + ) + success_count -= 1 + needs_refine_count += 1 + + # LLM post-processing (kept sequential as requested) + if self.llm and self.config.llm_auto_fix and TYPE_FIXER_AVAILABLE: + self._log("Running LLM post-processing on decompiled functions (sequential)...", "INFO") + try: + post_fixer = TypeErrorFixer(model=self.config.llm_model, verbose=self.config.verbose) + + for func, result in zip(functions, results): + if not result['success']: + continue + + func_name = func['name'] + c_file = func.get('c_file_path') + if not c_file: + continue + + full_path = project_root / c_file + if not full_path.exists(): + continue + + try: + errors = post_fixer.get_compilation_errors(str(full_path)) + if errors: + all_funcs = post_fixer.discover_functions_in_file(str(full_path)) + func_range = next( + ((s, e) for n, s, e in all_funcs if n == func_name), None) + if func_range is not None: + func_errors = [err for err in errors + if func_range[0] <= err['line'] <= func_range[1]] + else: + func_errors = [] + + if func_errors: + self._log( + f" {func_name}: {len(func_errors)} compilation error(s), fixing...", + "INFO" + ) + n = post_fixer.fix_file(str(full_path), max_functions=1, + max_passes=2, target_function=func_name) + if n > 0: + self._log(f" {func_name}: fixed {n} function(s)", "INFO") + except Exception as e: + self._log(f" Post-decompile fix failed for {func_name}: {e}", "WARN") + + except SystemExit: + self._log("TypeErrorFixer: LLM not available, post-decompile error fixing disabled", "WARN") + + self.stats['batches_completed'] += 1 + return {'success': success_count, 'failed': failed_count, 'needs_refine': needs_refine_count} + + def _refresh_decls(self): + """Regenerate include/decomp_decls.h from current C source files. + + Called at startup and after each verification pass so that newly + verified functions immediately become available as m2c context for + all subsequent decompilations in the same session. + """ + project_root = Path(__file__).parent.parent + try: + count = generate_decls(project_root=project_root, verbose=False) + self._log(f"Refreshed decomp_decls.h + per-module decls: {count} declarations", "INFO") + except Exception as e: + self._log(f"generate_decls failed (non-fatal): {e}", "WARN") + + def _verify_batch(self): + """Run verification on decompiled functions.""" + self._log("Running verification...", "INFO") + + try: + results = self.verifier.verify_decompiled_functions() + self.stats['functions_verified'] += results['verified'] + self._log(f"Verified {results['verified']} functions", "INFO") + except Exception as e: + self._log(f"Verification error: {e}", "ERROR") + self.stats['errors'].append({ + 'type': 'verification', + 'error': str(e), + 'time': datetime.now().isoformat() + }) + + # Refresh declarations so newly-verified functions are available as context + self._refresh_decls() + + def _run_full_build(self) -> bool: + """Run a full build to check for errors.""" + self._log("Running full build check...", "INFO") + self.stats['builds_run'] += 1 + + try: + success = self.verifier.full_build_and_verify() + if success: + self._log("Build successful!", "INFO") + else: + self._log("Build failed, check output for errors", "WARN") + # Refresh rank scores so the queue stays sorted easiest→hardest + # as functions are removed from the asm/ directories. + try: + updated = populate_rank_scores(self.db) + self._log(f"Rank scores refreshed ({updated} functions updated)", "INFO") + except Exception as rank_err: + self._log(f"Rank refresh failed (non-fatal): {rank_err}", "WARN") + return success + except Exception as e: + self._log(f"Build error: {e}", "ERROR") + self.stats['errors'].append({ + 'type': 'build', + 'error': str(e), + 'time': datetime.now().isoformat() + }) + return False + + def _fix_type_errors_with_llm(self) -> int: + """ + Scan C files with decompiled functions for actual PSY-Q compilation errors + and fix them with LLM via TypeErrorFixer. + + Returns: + Number of functions fixed + """ + if not self.llm or not TYPE_FIXER_AVAILABLE: + return 0 + + # Collect unique C files that have decompiled functions + decompiled = self.db.get_functions_by_status('decompiled', limit=50) + if not decompiled: + return 0 + + seen_files = set() + c_files_to_check = [] + for func in decompiled: + c_file = func.get('c_file_path') + if c_file and c_file not in seen_files: + seen_files.add(c_file) + c_files_to_check.append(c_file) + + if not c_files_to_check: + return 0 + + self._log(f"Checking {len(c_files_to_check)} file(s) for PSY-Q compilation errors...", "INFO") + + fixed_count = 0 + try: + fixer = TypeErrorFixer(model=self.config.llm_model, verbose=self.config.verbose) + except SystemExit: + self._log("TypeErrorFixer: LLM not available, skipping type error fixing", "WARN") + return 0 + + project_root = Path(__file__).parent.parent + for c_file in c_files_to_check: + if self._check_stop_conditions(): + break + full_path = project_root / c_file + if not full_path.exists(): + continue + try: + # Compile the file directly via PSY-Q to get real errors + errors = fixer.get_compilation_errors(str(full_path)) + if not errors: + continue + self._log(f" {c_file}: {len(errors)} PSY-Q error(s) — attempting LLM fix", "INFO") + n = fixer.fix_file(str(full_path), max_functions=5) + fixed_count += n + except Exception as e: + self._log(f" Error fixing {c_file}: {e}", "ERROR") + + if fixed_count > 0: + self._log(f"🔧 Fixed type errors in {fixed_count} function(s) with LLM", "INFO") + + return fixed_count + + def _reset_stale_in_progress(self): + """Reset functions stuck in 'in_progress' (from crashed runs) back to 'failed'. + + These occur when the agent is killed mid-decompilation. Without this + cleanup they never re-enter the retry queue. + """ + cursor = self.db.conn.cursor() + cursor.execute( + "UPDATE functions SET status='failed', attempt_count=1, " + "notes='Reset from stale in_progress (agent crash)' " + "WHERE status='in_progress'" + ) + count = cursor.rowcount + self.db.conn.commit() + if count: + self._log(f"Reset {count} stale in_progress function(s) to failed", "INFO") + + def _reset_failed_attempt_counts(self): + """Reset attempt_count=0 for all failed/blocked functions on agent startup. + + This gives every function a fresh chance on each new agent run, preventing + permanent dead-ends when the decompilation system has been improved. + The max_retries limit then controls per-session attempts only. + """ + cursor = self.db.conn.cursor() + cursor.execute( + "UPDATE functions SET attempt_count=0 WHERE status IN ('failed', 'blocked')" + ) + reset_count = cursor.rowcount + self.db.conn.commit() + if reset_count: + self._log(f"Reset retry counters for {reset_count} failed/blocked function(s)", "INFO") + + def _retry_failed_functions(self): + """Re-queue functions that previously failed (status='failed').""" + failed = self.db.get_functions_by_status( + 'failed', module=self.config.module_filter) + + if not failed: + return + + self._log(f"Retrying {len(failed)} failed functions...", "INFO") + + queued = 0 + skipped = 0 + infra_skip = 0 + for func in failed: + if func['attempt_count'] >= self.config.max_retries: + skipped += 1 + continue + + # Skip permanent infrastructure failures (missing ASM files, etc.) + # These cannot succeed until the ASM extraction is done for that module + notes = func.get('notes') or '' + if 'Function not found in version' in notes or 'not found in version' in notes.lower(): + infra_skip += 1 + continue + + self.db.update_function_status(func['name'], 'todo', + notes=f"Retry attempt {func['attempt_count'] + 1}") + queued += 1 + + if queued: + self._log(f" Queued {queued} function(s) for retry", "INFO") + if skipped: + self._log(f" Skipped {skipped} function(s) (max retries this session)", "INFO") + if infra_skip: + self._log(f" Skipped {infra_skip} function(s) (permanent infra failure - missing ASM)", "INFO") + + @staticmethod + def _find_func_body_range(text: str, func_name: str): + """Return (start_line, end_line) of the C body definition of func_name + in `text` (1-indexed, inclusive), or None if not found. + + Looks for patterns like: + return_type func_name(...) { + where the line ends with '{' (body definition, not a prototype ending in ';'). + Walks forward counting braces to find the closing '}'. + """ + import re as _re + # Match a definition line: any return type, the function name, params, opening brace. + # The line must contain '{' (not just a prototype). + pattern = _re.compile( + r'^[^\n]*\b' + _re.escape(func_name) + r'\s*\([^)]*\)[^;{]*\{', + _re.MULTILINE, + ) + m = pattern.search(text) + if not m: + return None + + start_line = text[:m.start()].count('\n') + 1 + # Walk from the '{' to find the matching '}' + depth = 0 + for i, ch in enumerate(text[m.start():]): + if ch == '{': + depth += 1 + elif ch == '}': + depth -= 1 + if depth == 0: + end_line = text[:m.start() + i].count('\n') + 1 + return (start_line, end_line) + return None + + def _retry_needs_refine(self): + """Re-queue or promote decompiled_needs_refine functions whose code is clean. + + When a file has compile errors, we now check each function individually: + - If no error line falls within the function's body range → the function's + own code is fine; promote it directly to 'decompiled' so it can be verified. + - If an error line overlaps the function's body → leave as + decompiled_needs_refine for manual/LLM fixing. + + This handles the common case where a file has pre-existing errors (unrelated + to the newly-decompiled functions) that would otherwise permanently block all + decompiled_needs_refine functions in that file. + """ + needs_refine = self.db.get_functions_by_status( + 'decompiled_needs_refine', module=self.config.module_filter) + + if not needs_refine: + return + + self._log(f"Re-queuing {len(needs_refine)} decompiled_needs_refine functions for retry...", "INFO") + + project_root = Path(__file__).parent.parent + + # Group by C file so we only compile-check each file once + file_to_funcs: dict = {} + funcs_without_file = [] + for func in needs_refine: + c_file = func.get('c_file_path') + if c_file: + file_to_funcs.setdefault(c_file, []).append(func) + else: + funcs_without_file.append(func) + + queued = 0 + promoted = 0 + left_pending = 0 + + for rel_c_path, funcs_in_file in file_to_funcs.items(): + full_path = project_root / rel_c_path + compile_ok = True + error_lines = set() + if full_path.exists(): + try: + compile_ok, compile_errors = self.verifier.check_file_compiles(full_path) + if not compile_ok: + error_lines = {e['line'] for e in compile_errors if e.get('line')} + except Exception: + compile_ok = True # Can't tell — give it a chance + + if compile_ok: + for func in funcs_in_file: + self.db.update_function_status(func['name'], 'todo', + notes="Re-queued after fix (file now compiles)") + self._log(f" Queued {func['name']} for retry", "INFO") + queued += 1 + else: + # File still has errors — but check each function individually. + try: + file_text = full_path.read_text(errors='replace') + except OSError: + file_text = None + + for func in funcs_in_file: + fname = func['name'] + + # DB out of sync: function still has INCLUDE_ASM stub — reset to todo + if file_text and f', {fname})' in file_text and 'INCLUDE_ASM(' in file_text: + body_range_check = self._find_func_body_range(file_text, fname) + if body_range_check is None: + self.db.update_function_status(fname, 'todo', + notes="Reset from needs_refine: still has INCLUDE_ASM stub") + self._log(f" Reset {fname} → todo (INCLUDE_ASM stub present)", "INFO") + queued += 1 + continue + + body_range = None + if file_text: + body_range = self._find_func_body_range(file_text, fname) + + if body_range is not None: + start, end = body_range + overlapping = {ln for ln in error_lines if start <= ln <= end} + if not overlapping: + # No errors inside this function's body — promote to decompiled + self.db.update_function_status( + fname, 'decompiled', + notes="Promoted from needs_refine: no errors in function body (pre-existing errors elsewhere in file)" + ) + self._log(f" Promoted {fname} → decompiled (errors are outside its body)", "INFO") + promoted += 1 + continue + + left_pending += 1 + if self.config.verbose: + self._log(f" Skipped {fname} — file still has compile errors in/near its body", "INFO") + + # Functions with no recorded C file path: re-queue unconditionally + for func in funcs_without_file: + self.db.update_function_status(func['name'], 'todo', + notes="Re-queued after manual fix") + self._log(f" Queued {func['name']} for retry (no C file path recorded)", "INFO") + queued += 1 + + if queued: + self._log(f" Queued {queued} function(s) for retry", "INFO") + if promoted: + self._log(f" Promoted {promoted} function(s) → decompiled (errors outside their bodies)", "INFO") + if left_pending: + self._log(f" Left {left_pending} function(s) as decompiled_needs_refine (file still has compile errors)", "INFO") + + def verify_needs_refine(self, module: str = None, verbose: bool = True): + """Attempt to promote all decompiled_needs_refine functions to verified. + + For each function in the decompiled_needs_refine state: + 1. Re-run PSY-Q compile check on its source file. + 2. If the file now compiles cleanly, run check_function_match() and + promote the function to 'verified' (matches) or 'decompiled' + (compile ok but still needs objdiff confirmation). + 3. If the file still has errors but the error lines don't overlap the + function body, promote to 'decompiled' so the normal verify path + can handle it. + 4. Leave remaining functions as decompiled_needs_refine and report them. + + This is intended to be called after manually fixing compile errors outside + the automation workflow (e.g. ``python agent.py --verify-needs-refine``). + """ + project_root = Path(__file__).parent.parent + needs_refine = self.db.get_functions_by_status('decompiled_needs_refine', module=module) + + if not needs_refine: + print("No decompiled_needs_refine functions found.") + return + + print(f"\n{'='*60}") + print(f"VERIFY NEEDS-REFINE ({len(needs_refine)} functions)") + print(f"{'='*60}\n") + + # Group by C file so we only compile-check each file once + file_to_funcs: dict = {} + funcs_without_file = [] + for func in needs_refine: + c_file = func.get('c_file_path') + if c_file: + file_to_funcs.setdefault(c_file, []).append(func) + else: + funcs_without_file.append(func) + + verified_count = 0 + promoted_count = 0 + still_broken_count = 0 + + for rel_c_path, funcs_in_file in file_to_funcs.items(): + full_path = project_root / rel_c_path + compile_ok = True + error_lines: set = set() + errors: list = [] + + if full_path.exists(): + try: + compile_ok, errors = self.verifier.check_file_compiles(full_path) + if not compile_ok: + error_lines = {e['line'] for e in errors if e.get('line')} + except Exception: + compile_ok = True # Can't determine — give it a chance + + file_text = None + if full_path.exists(): + try: + file_text = full_path.read_text(errors='replace') + except OSError: + pass + + for func in funcs_in_file: + fname = func['name'] + + # If the file still has an INCLUDE_ASM stub for this function the + # C body was never written (or was reverted) — the DB is out of sync. + # Reset to todo so the function can be decompiled fresh. + if file_text and f', {fname})' in file_text and 'INCLUDE_ASM(' in file_text: + body_range = self._find_func_body_range(file_text, fname) + if body_range is None: + self.db.update_function_status(fname, 'todo', + notes="Reset from needs_refine: still has INCLUDE_ASM stub (DB was out of sync)") + print(f" 🔄 {fname} → todo (INCLUDE_ASM stub present, DB was stale)") + promoted_count += 1 + continue + + if compile_ok: + # File compiles — run match check then promote + matches, err_msg = self.verifier.check_function_match(fname) + if matches: + self.db.update_function_status(fname, 'verified', + notes="Promoted from needs_refine after compile errors resolved") + print(f" ✅ {fname} → verified") + verified_count += 1 + else: + # Compiled but objdiff says no match yet — push to decompiled + self.db.update_function_status(fname, 'decompiled', + notes=f"Promoted from needs_refine; needs objdiff: {err_msg}") + print(f" ➡️ {fname} → decompiled (compile ok, pending objdiff)") + promoted_count += 1 + else: + # File still has errors — check whether they overlap this function + overlap_found = True # default: assume overlap if we can't tell + if file_text: + body_range = self._find_func_body_range(file_text, fname) + if body_range is not None: + start, end = body_range + overlap_found = bool({ln for ln in error_lines if start <= ln <= end}) + + if not overlap_found: + # Errors are elsewhere in the file — safe to promote + self.db.update_function_status(fname, 'decompiled', + notes="Promoted from needs_refine: compile errors are outside function body") + print(f" ➡️ {fname} → decompiled (errors outside its body)") + promoted_count += 1 + else: + if verbose: + first_err = errors[0].get('message', '?') if errors else '?' + print(f" ❌ {fname} still broken — {first_err}") + still_broken_count += 1 + + # Functions with no recorded C file — re-queue so the agent can retry + for func in funcs_without_file: + self.db.update_function_status(func['name'], 'todo', + notes="Re-queued from needs_refine (no C file recorded)") + print(f" 🔄 {func['name']} → todo (no C file path)") + promoted_count += 1 + + print(f"\n{'='*60}") + print(f"Verified: {verified_count}") + print(f"Promoted→decompiled: {promoted_count}") + print(f"Still needs fixing: {still_broken_count}") + print(f"{'='*60}\n") + + def _reset_false_verified(self): + """Find verified/decompiled functions whose source file still contains + INCLUDE_ASM (i.e. mako.sh exited 0 but never actually wrote C code) and + reset them back to todo so they can be retried properly. + """ + from pathlib import Path + + statuses = ('verified', 'decompiled') + false_names = [] + + for status in statuses: + funcs = self.db.get_functions_by_status(status, module=self.config.module_filter) + for func in funcs: + c_file = func.get('c_file_path') + if not c_file: + continue + try: + content = Path(c_file).read_text() + if 'INCLUDE_ASM(' in content and f", {func['name']})".encode().decode() in content: + false_names.append(func['name']) + except OSError: + pass + + if not false_names: + self._log("No false-verified functions found", "INFO") + return + + self._log(f"Found {len(false_names)} falsely-verified functions (INCLUDE_ASM still present) — resetting to todo", "WARN") + for name in false_names: + self.db.update_function_status(name, 'todo', notes="Reset: INCLUDE_ASM still present despite verified status") + self.db.conn.execute("UPDATE functions SET attempt_count=0 WHERE name=?", (name,)) + self.db.conn.commit() + self._log(f" Reset {len(false_names)} functions to todo", "INFO") + + def _retry_blocked_functions(self): + """Re-queue blocked functions so they can be re-attempted. + + In smart mode (dep_analyzer available, force_retry_blocked=False): + Only re-queues blocked functions where a same-file callee has been + resolved since last_attempt_at. This avoids burning the session + re-trying functions stuck on structural /*?*/ type gaps. + + In force mode (force_retry_blocked=True or no dep_analyzer): + Re-queues all eligible blocked functions regardless. + """ + blocked = self.db.get_functions_by_status( + 'blocked', module=self.config.module_filter) + + eligible = [f for f in blocked if f['attempt_count'] < self.config.max_retries] + + if not eligible: + self._log("No eligible blocked functions to retry (all at max retries)", "INFO") + return + + # Smart filtering: only re-queue if a same-file callee was resolved since last attempt + if self.dep_analyzer and not self.config.force_retry_blocked: + cursor = self.db.conn.cursor() + func_to_c_file = { + row[0]: row[1] for row in cursor.execute( + "SELECT name, c_file_path FROM functions WHERE c_file_path IS NOT NULL" + ) + } + resolved_statuses = "('verified', 'decompiled', 'decompiled_needs_refine', 'sdk_excluded')" + + filtered = [] + for func in eligible: + fname = func['name'] + last_attempt = func.get('last_attempt_at') + c_file = func_to_c_file.get(fname) + + if not last_attempt or not c_file: + continue # Skip if never attempted or c_file unknown + + # Only consider same-file callees (cross-file ordering has no benefit) + callees = list(self.dep_analyzer.calls.get(fname, set())) + same_file_callees = [c for c in callees if func_to_c_file.get(c) == c_file] + + if not same_file_callees: + continue # Blocked on structural type issue — retry won't help + + # Re-queue only if a same-file callee was resolved after last attempt + placeholders = ','.join('?' * len(same_file_callees)) + row = cursor.execute( + f"SELECT MAX(updated_at) FROM functions " + f"WHERE name IN ({placeholders}) AND status IN {resolved_statuses}", + same_file_callees + ).fetchone() + last_resolved = row[0] if row else None + + if last_resolved and last_resolved > last_attempt: + filtered.append(func) + + original_count = len(eligible) + eligible = filtered + + if not eligible: + self._log( + f"No blocked functions have newly-resolved same-file callees " + f"({original_count} checked); skipping retry", "INFO" + ) + self._log(" Use --force-retry-blocked to override and retry all", "INFO") + return + + self._log( + f"Smart retry: {len(eligible)}/{original_count} blocked functions " + f"have newly-resolved same-file callees", "INFO" + ) + else: + self._log(f"Re-queuing {len(eligible)}/{len(blocked)} blocked functions for retry...", "INFO") + + for func in eligible: + self.db.update_function_status(func['name'], 'todo', + notes=f"Retry after block (attempt {func['attempt_count'] + 1})") + + self._log(f" Done — {len(eligible)} function(s) re-queued", "INFO") + + def _show_progress(self): + """Display current progress.""" + stats = self.db.get_statistics() + + total = stats['total'] + verified = stats['by_status'].get('verified', 0) + decompiled = stats['by_status'].get('decompiled', 0) + needs_refine = stats['by_status'].get('decompiled_needs_refine', 0) + failed = stats['by_status'].get('failed', 0) + blocked = stats['by_status'].get('blocked', 0) + todo = stats['by_status'].get('todo', 0) + + completed = verified + decompiled + needs_refine + progress = (completed / total * 100) if total > 0 else 0 + + elapsed = time.time() - self.stats['start_time'] + rate = self.stats['functions_processed'] / elapsed if elapsed > 0 else 0 + + print("\n" + "="*60) + print(f"AGENT PROGRESS - {datetime.now().strftime('%H:%M:%S')}") + print("="*60) + print(f"Processed: {self.stats['functions_processed']} functions") + print(f"Verified: {verified}/{total} ({verified/total*100:.1f}%)") + print(f"Decompiled: {decompiled}") + print(f"Needs Refine: {needs_refine}") + print(f"Blocked: {blocked}") + print(f"Failed: {failed}") + print(f"Todo: {todo}") + print(f"Batches: {self.stats['batches_completed']}") + print(f"Builds: {self.stats['builds_run']}") + if self.llm: + print(f"LLM analyzed: {self.stats['functions_analyzed_by_llm']}") + print(f"Rate: {rate:.2f} functions/second") + print(f"Elapsed: {timedelta(seconds=int(elapsed))}") + + if self.config.max_duration: + remaining = self.config.max_duration - elapsed + print(f"Time left: {timedelta(seconds=int(max(0, remaining)))}") + + print("="*60 + "\n") + + def _sync_main_func_aliases(self): + """Ensure every `func_8XXXXXXX` jal target referenced in overlay ASM files + that maps to a known main-segment symbol has a `func_XXXXXXXX = 0xXXXXXXXX;` + alias in config/sym_export.us.txt. + + This prevents linker undefined-reference errors when overlay object files + call PSX SDK / runtime functions by their raw address alias rather than + their canonical name. The alias file is shared by all overlay linker + invocations, so a single addition here fixes every affected overlay. + + Safe to run repeatedly: existing entries are never touched. + """ + project_root = Path(__file__).parent.parent + sym_export_path = project_root / "config" / "sym_export.us.txt" + main_syms_path = project_root / "config" / "symbols.main.us.txt" + asm_root = project_root / "asm" / "us" + + if not sym_export_path.exists() or not main_syms_path.exists(): + return + + # --- 1. Load all addresses known to the main-segment symbol file --- + main_addrs: set = set() + addr_re = re.compile(r'\w+\s*=\s*(0x[0-9a-fA-F]+)\s*;') + with open(main_syms_path) as f: + for line in f: + m = addr_re.search(line) + if m: + main_addrs.add(int(m.group(1), 16)) + + # --- 2. Load addresses already in sym_export.us.txt --- + existing_names: set = set() + existing_addrs: set = set() + name_re = re.compile(r'^(\w+)\s*=\s*(0x[0-9a-fA-F]+)\s*;') + with open(sym_export_path) as f: + for line in f: + m = name_re.match(line.strip()) + if m: + existing_names.add(m.group(1)) + existing_addrs.add(int(m.group(2), 16)) + + # --- 3. Scan overlay ASM files for `jal func_8XXXXXXX` references --- + jal_func_re = re.compile(r'\bjal\s+(func_[0-9a-fA-F]{8})\b') + referenced: set = set() + if asm_root.is_dir(): + for asm_file in asm_root.rglob("*.s"): + # Skip main/ — it defines these symbols, not references them + try: + parts = asm_file.relative_to(asm_root).parts + if parts and parts[0] == "main": + continue + except ValueError: + pass + try: + text = asm_file.read_text(errors="replace") + for name in jal_func_re.findall(text): + referenced.add(name) + except OSError: + pass + + # --- 4. Determine which are missing from sym_export and known to main --- + to_add = [] + for sym_name in sorted(referenced): + if sym_name in existing_names: + continue + addr = int(sym_name[len("func_"):], 16) + if addr in main_addrs and addr not in existing_addrs: + to_add.append((sym_name, addr)) + + if not to_add: + self._log("sym_export alias check: all overlay jal targets accounted for", "INFO") + return + + # --- 5. Append missing aliases --- + with open(sym_export_path, "a") as f: + for sym_name, addr in to_add: + f.write(f"{sym_name} = 0x{addr:08X};\n") + + self._log( + f"sym_export alias check: added {len(to_add)} missing func_ alias(es) " + f"to {sym_export_path.relative_to(project_root)}", + "INFO", + ) + if self.config.verbose: + for sym_name, addr in to_add: + self._log(f" + {sym_name} = 0x{addr:08X};", "INFO") + + def _initial_audit(self): + """ + At startup, compile each C file that contains 'decompiled' or 'verified' + functions and flag any that fail PSY-Q compilation as 'decompiled_needs_refine'. + + This catches functions that were accepted by the old heuristic validator + but actually produce type/declaration errors in the real compiler. They + are NOT automatically reverted here (too risky without the original ASM + context), but they'll be picked up by the LLM post-fixer or can be + manually reverted and re-queued. + """ + self._log("Running initial compilation audit of decompiled functions...", "INFO") + + # Gather unique C files that contain 'decompiled' OR 'verified' functions + # We include verified because old agent runs may have accepted bad code. + decompiled = self.db.get_functions_by_status('decompiled', limit=None, + module=self.config.module_filter) + verified = self.db.get_functions_by_status('verified', limit=None, + module=self.config.module_filter) + all_funcs = (decompiled or []) + (verified or []) + if not all_funcs: + self._log(" No decompiled/verified functions to audit", "INFO") + return + + # Build a map: c_file_path -> [func_name, ...] + file_to_funcs = {} + for func in all_funcs: + cp = func.get('c_file_path') + if cp: + file_to_funcs.setdefault(cp, []).append(func['name']) + + project_root = Path(__file__).parent.parent + flagged = 0 + + for rel_c_path, func_names in file_to_funcs.items(): + full_path = project_root / rel_c_path + if not full_path.exists(): + continue + + compile_ok, errors = self.verifier.check_file_compiles(full_path) + if compile_ok: + continue + + # Identify which lines are affected + error_lines = {e['line'] for e in errors} + if not error_lines: + continue + + # Find function body ranges using precise brace-counting so we only + # flag functions whose body actually contains an error line. + try: + file_text = full_path.read_text(errors='replace') + for name in func_names: + body_range = self._find_func_body_range(file_text, name) + if body_range is None: + continue # stub / prototype — skip + start, end = body_range + if any(start <= el <= end for el in error_lines): + self.db.update_function_status( + name, 'decompiled_needs_refine', + notes=f"Startup audit: PSY-Q compile errors in {rel_c_path}" + ) + flagged += 1 + if self.config.verbose: + self._log(f" Flagged {name} ({rel_c_path})", "WARN") + except Exception as e: + self._log(f" Audit error for {rel_c_path}: {e}", "WARN") + + if flagged: + self._log(f"Startup audit: flagged {flagged} function(s) as decompiled_needs_refine", "WARN") + else: + self._log("Startup audit: all decompiled functions compile cleanly", "INFO") + + # Second pass: reset verified/decompiled_needs_refine functions that still + # have INCLUDE_ASM in their C file back to 'todo'. This happens when the + # DB is reused after a branch reset (the C files were wiped but the DB + # retained the old status). + import re as _re + reset_count = 0 + stale_statuses = ('verified', 'decompiled_needs_refine', 'decompiled') + stale_funcs = [] + for status in stale_statuses: + stale_funcs.extend(self.db.get_functions_by_status(status, limit=None, + module=self.config.module_filter) or []) + for func in stale_funcs: + c_file_rel = func.get('c_file_path') + func_name = func['name'] + if not c_file_rel: + continue + c_file = project_root / c_file_rel + if not c_file.exists(): + continue + content = c_file.read_text(errors='replace') + pat = rf'INCLUDE_ASM\s*\(\s*"[^"]*"\s*,\s*{_re.escape(func_name)}\s*\)' + if _re.search(pat, content): + self.db.update_function_status(func_name, 'todo', + notes='Reset: C file reverted to INCLUDE_ASM') + reset_count += 1 + if self.config.verbose: + self._log(f" Reset {func_name} ({func['status']} → todo): C file has INCLUDE_ASM", "WARN") + if reset_count: + self._log(f"Startup audit: reset {reset_count} stale function(s) to 'todo'", "WARN") + + def _ensure_asm_splits(self): + """ + Run splat for any module whose nonmatchings/ directory is missing or empty. + + This happens after `make clean`, which deletes the gitignored asm/ tree. + The agent needs those .s files to decompile functions, so we regenerate them + automatically rather than requiring the user to remember the splat step. + """ + project_root = Path(__file__).parent.parent + build_us = project_root / 'build' / 'us' + asm_us = project_root / 'asm' / 'us' + splat_bin = project_root / '.venv' / 'bin' / 'splat' + + if not splat_bin.exists(): + self._log(" splat not found in .venv; skipping ASM regeneration", "WARN") + return + + # Which modules have todo functions that need ASM files? + module_filter = self.config.module_filter + cursor = self.db.conn.cursor() + if module_filter: + cursor.execute( + "SELECT DISTINCT module FROM functions WHERE status='todo' AND module=?", + (module_filter,) + ) + else: + cursor.execute("SELECT DISTINCT module FROM functions WHERE status='todo'") + modules_needing_asm = {row['module'] for row in cursor} + + regenerated = [] + for module in sorted(modules_needing_asm): + nonmatch_dir = asm_us / module / 'nonmatchings' + if nonmatch_dir.is_dir() and any(nonmatch_dir.rglob('*.s')): + continue # Already present + + # Try to find the yaml for this module + yaml_path = build_us / f'{module}.yaml' + if not yaml_path.exists(): + # Some modules use a different yaml name (e.g. batini → battle.yaml covers it) + continue + + self._log(f" Re-running splat for {module} (nonmatchings/ missing or empty)...", "INFO") + try: + import subprocess as _sp + result = _sp.run( + [str(splat_bin), 'split', str(yaml_path)], + capture_output=True, text=True, + cwd=str(project_root) + ) + if result.returncode == 0: + count = sum(1 for _ in nonmatch_dir.rglob('*.s')) if nonmatch_dir.is_dir() else 0 + self._log(f" {module}: generated {count} nonmatching .s files", "INFO") + regenerated.append(module) + else: + self._log(f" {module}: splat failed: {result.stderr[:200]}", "WARN") + except Exception as e: + self._log(f" {module}: splat error: {e}", "WARN") + + if not regenerated: + self._log(" ASM splits up to date", "INFO") + + # Fix matchings/ directories: some C files use INCLUDE_ASM("…/matchings/…") + # for functions that splat now emits to nonmatchings/. Copy any missing ones. + self._fix_matchings_from_nonmatchings() + + def _fix_matchings_from_nonmatchings(self): + """ + After a splat run, copy .s files from nonmatchings/ to matchings/ for any + INCLUDE_ASM references that point at matchings/ but whose file is missing. + This keeps `make build` working after `make clean`. + """ + import re as _re + import shutil as _shutil + project_root = Path(__file__).parent.parent + src_root = project_root / 'src' + asm_us = project_root / 'asm' / 'us' + pattern = _re.compile(r'INCLUDE_ASM\s*\(\s*"(asm/us/[^"]+/matchings/[^"]+)"\s*,\s*([^);\s]+)') + copied = 0 + for c_file in src_root.rglob('*.s'): + pass # not needed + for c_file in src_root.rglob('*.c'): + try: + text = c_file.read_text(errors='replace') + except Exception: + continue + for m in pattern.finditer(text): + asm_hint, func_name = m.group(1), m.group(2) + dst = project_root / asm_hint / f'{func_name}.s' + if dst.exists(): + continue + # Look for the same file in nonmatchings/ + nonmatch_path = str(asm_hint).replace('/matchings/', '/nonmatchings/') + src = project_root / nonmatch_path / f'{func_name}.s' + if src.exists(): + dst.parent.mkdir(parents=True, exist_ok=True) + _shutil.copy2(str(src), str(dst)) + copied += 1 + if copied: + self._log(f" Copied {copied} .s file(s) from nonmatchings → matchings to satisfy INCLUDE_ASM paths", "INFO") + + def _cleanup_failure_comments(self): + """ + Remove 'Decompilation failure:' comment blocks from all C source files. + + These are left behind by m2c when it can't parse external declarations. + They prevent subsequent decompilations from getting clean context and + must be swept out before each run. + """ + import re as _re + src_dir = Path(__file__).parent.parent / 'src' + pattern = _re.compile(r'/\*\s*Decompilation failure[^\n]*\n.*?\*/', _re.DOTALL) + total_removed = 0 + + for c_file in src_dir.rglob('*.c'): + content = c_file.read_text() + cleaned, n = pattern.subn('', content) + if n: + # Collapse runs of blank lines left by removal + cleaned = _re.sub(r'\n\n\n+', '\n\n', cleaned) + c_file.write_text(cleaned) + total_removed += n + + if total_removed: + self._log(f"Cleaned {total_removed} 'Decompilation failure' comment block(s) from src/", "INFO") + + def _hoist_externs_all_files(self): + """ + Apply the extern-declaration hoisting pass to every C source file. + + extern declarations generated by mako.sh dec are placed inline beside + each function body. This pass gathers them all and moves them to a + single block before the first INCLUDE_ASM / function definition so every + file has a clean layout: + #include ... + typedefs (if any, hoisted before their first use) + extern declarations ← ALL here + function bodies / INCLUDE_ASM stubs + + Uses apply_all_fixes (which runs extern-hoist then typedef-hoist) so + that any typedef whose first use is now an extern in the header section + also gets moved up correctly. + """ + try: + from intellisense_fixer import apply_all_fixes + except ImportError: + self._log("intellisense_fixer not available; skipping extern hoist", "WARN") + return + + src_dir = Path(__file__).parent.parent / 'src' + total_moved = 0 + files_changed = 0 + + for c_file in src_dir.rglob('*.c'): + try: + content = c_file.read_text() + fixed, changes = apply_all_fixes(content) + extern_changes = [c for c in changes if 'extern' in c] + if extern_changes: + c_file.write_text(fixed) + n = sum(int(c.split()[1]) for c in extern_changes if c.split()[1].isdigit()) + total_moved += n + files_changed += 1 + if self.config.verbose: + self._log(f" {c_file.relative_to(Path(__file__).parent.parent)}: {', '.join(changes)}", "INFO") + except Exception as e: + self._log(f" extern hoist error in {c_file.name}: {e}", "WARN") + + if total_moved: + self._log(f"Hoisted {total_moved} extern declaration(s) across {files_changed} file(s) to file headers", "INFO") + + def _revert_function_to_include_asm(self, c_file: Path, func_name: str) -> bool: + """ + Replace a decompiled function body with its INCLUDE_ASM stub. + + Walks the file to find the function definition by name, counts braces to + locate the closing }, then replaces the whole definition with the stub. + Returns True if the revert succeeded. + """ + import re as _re + content = c_file.read_text() + lines = content.splitlines(keepends=True) + + # Derive asm directory from the file path: + # src/{overlay}/{stem}.c → asm/us/{overlay}/nonmatchings/{stem} + stem = c_file.stem + overlay = c_file.parent.name + asm_dir = f"asm/us/{overlay}/nonmatchings/{stem}" + + # Find the function definition start using a strict pattern that requires a + # return type before the function name. This prevents matching call sites + # like: '} else if (func_name(-1) != 0) {' which the old loose search + # mistakenly treated as a definition start. + strict_def_pattern = _re.compile( + rf'^(?:(?:const|static|inline)\s+)*' + rf'(?:(?:unsigned|signed)\s+)*' + rf'(?:void|char|int|u8|s8|u16|s16|u32|s32|long|short|\w+)\s+' + rf'\*?\s*{_re.escape(func_name)}\s*\(', + _re.MULTILINE, + ) + # Fallback: implicit-int — function name at beginning of line with no type + implicit_def_pattern = _re.compile( + rf'^{_re.escape(func_name)}\s*\(', + _re.MULTILINE, + ) + m = strict_def_pattern.search(content) + if m is None: + m = implicit_def_pattern.search(content) + if m is None: + return False + start_idx = content[:m.start()].count('\n') + + # Find the opening brace (may be on the same or next few lines) + brace_start = None + for i in range(start_idx, min(start_idx + 6, len(lines))): + if '{' in lines[i]: + brace_start = i + break + + if brace_start is None: + return False # No opening brace found — probably just a declaration + + # Count braces to find the matching closing brace + depth = 0 + end_idx = None + for i in range(brace_start, len(lines)): + depth += lines[i].count('{') - lines[i].count('}') + if depth == 0: + end_idx = i + break + + if end_idx is None: + return False + + # Build the replacement stub + include_asm_line = f'INCLUDE_ASM("{asm_dir}", {func_name});\n' + + # Also strip m2c-emitted extern/forward-declaration lines that precede the + # function body. These are orphaned when a function is reverted and would + # poison m2c context on the next run. + # Pattern: blank lines OR lines ending with "// extern" OR lines starting + # with "extern " (bare extern declarations for D_ globals / unknown funcs). + _extern_or_blank = _re.compile(r'^\s*$|//\s*extern\s*$|^\s*extern\s') + i = start_idx - 1 + while i >= 0 and _extern_or_blank.search(lines[i].rstrip('\n\r')): + i -= 1 + trim_start = i + 1 + + new_lines = lines[:trim_start] + [include_asm_line] + lines[end_idx + 1:] + c_file.write_text(''.join(new_lines)) + return True + + def _cleanup_unknown_type_functions(self): + """ + Scan C source files for decompiled functions that contain '?' type markers + (from m2c's inability to determine types). These poison m2c context for every + other function in the same file. + + Any such function is reverted to its INCLUDE_ASM stub and marked 'blocked'. + """ + import re as _re + src_dir = Path(__file__).parent.parent / 'src' + + # Match ? used as a parameter type, e.g.: "(s32 arg0, ? arg2)" or "(? arg)" + # Ternary operators like "x ? y : z" are NOT matched because ternary '?' is + # preceded by an expression value, not by '(' or ','. + unknown_param = _re.compile(r'[,(]\s*\?\s*(?:[,)]|\w)') + # Also catch ? as return type at start of a function definition line + unknown_return = _re.compile(r'^\s*\?\s+\w+\s*\(', _re.MULTILINE) + # And ?* pointer type + unknown_ptr = _re.compile(r'\?\s*\*\s+\w+') + + total_reverted = 0 + + for c_file in src_dir.rglob('*.c'): + content = c_file.read_text() + + # Quick check — does this file even have a '?' type marker? + if not ('/*?*/' in content + or unknown_param.search(content) + or unknown_return.search(content) + or unknown_ptr.search(content)): + continue + + # Identify the specific function(s) that contain '?' markers. + # We look for a function signature containing '?' then revert it. + func_sig_pattern = _re.compile( + r'^(\w[\w\s*]*?)\s+(\w+)\s*\([^)]*(?:\([^)]*\)[^)]*|[^)])*\?\s*[^;{]*\)', + _re.MULTILINE + ) + + reverted_in_file = set() + for match in func_sig_pattern.finditer(content): + func_name = match.group(2) + if func_name in reverted_in_file: + continue + + # Skip if it's only a forward declaration (ends with ;) + after = content[match.end():match.end() + 20].lstrip() + if after.startswith(';'): + continue + + # Also skip INCLUDE_ASM lines + line_start = content.rfind('\n', 0, match.start()) + 1 + line = content[line_start:match.start() + 100] + if 'INCLUDE_ASM' in line: + continue + + reverted = self._revert_function_to_include_asm(c_file, func_name) + if reverted: + reverted_in_file.add(func_name) + total_reverted += 1 + # Re-read — file was modified + content = c_file.read_text() + # Mark as blocked in DB if it's tracked + try: + existing = self.db.get_function(func_name) + if existing and existing.get('status') in ('verified', 'decompiled', + 'decompiled_needs_refine'): + self.db.update_function_status( + func_name, 'blocked', + notes="Reverted: had unknown '?' type marker in signature" + ) + except Exception: + pass + self._log(f" Reverted {func_name} in {c_file.name} (? type marker)", "WARN") + + # Second pass: catch '?' in m2c-emitted extern blocks that precede a function + # body. These are lines ending with "// extern" that contain '?' types, or + # "extern /*?*/" lines with NO valid type after the comment. They won't + # match func_sig_pattern (which looks at function signatures, not forward + # declarations) but still poison the context. + # Pattern 1: "extern /*?*/" where ? is the ONLY type (no valid C type follows) + # e.g. "extern /*?*/ some_sym;" — poisoned, type unknown + # NOT "extern /*?*/s32 D_800F9F3C;" — ok, s32 is the resolved type + # Pattern 2: "? ... // extern" — unknown-type forward decl emitted by m2c + extern_unknown = _re.compile( + r'^extern\s+/\*\?\*/\s+\w+\s*;|\?[^*].*//\s*extern\s*$', _re.MULTILINE + ) + func_def_pattern = _re.compile( + r'^(?:const\s+)?(?:unsigned\s+|signed\s+)?' + r'(?:void|u8|s8|u16|s16|u32|s32|int|char|short|long|unk_\w+|ff7s|\w+)\s*\*?\s+' + r'(\w+)\s*\([^)]*\)\s*\{', + _re.MULTILINE, + ) + # Snapshot content once so all finditer positions remain valid, then + # collect target function names before making any modifications. + # Updating content inside the loop caused position drift: after each + # revert the file shrinks, and old byte positions from the finditer + # landed in wrong places, causing unrelated functions to be reverted. + content = c_file.read_text() + funcs_to_revert_by_extern = [] + for ext_match in extern_unknown.finditer(content): + # Find the next concrete function definition after this bad extern line + # (within a reasonable window — externs are adjacent to their function) + search_start = ext_match.end() + def_match = func_def_pattern.search(content, search_start, + search_start + 4000) + if def_match is None: + continue + fname = def_match.group(1) + if fname not in reverted_in_file and fname not in funcs_to_revert_by_extern: + funcs_to_revert_by_extern.append(fname) + + for func_name in funcs_to_revert_by_extern: + if func_name in reverted_in_file: + continue + reverted = self._revert_function_to_include_asm(c_file, func_name) + if reverted: + reverted_in_file.add(func_name) + total_reverted += 1 + try: + existing = self.db.get_function(func_name) + if existing and existing.get('status') in ('verified', 'decompiled', + 'decompiled_needs_refine'): + self.db.update_function_status( + func_name, 'blocked', + notes="Reverted: had '?' type in preceding extern declarations" + ) + except Exception: + pass + self._log( + f" Reverted {func_name} in {c_file.name} (? in extern block)", "WARN" + ) + + if total_reverted: + self._log(f"Reverted {total_reverted} function(s) with '?' type markers to INCLUDE_ASM", + "WARN") + + def _cleanup_file_level_question_marks(self): + """ + Remove bare file-scope lines that use '?' as a type — these are m2c + artifacts for SDK/external functions whose type is unknown. They are + syntactically invalid C and cause build failures. + + Examples removed: + ? SpuSetTransferCallback(?*); // extern + extern ?* jtbl_80034D14; + s16 GetTPage(s32, ?, s16, s16); // extern + ? LoadImage(void*, s32); // extern + """ + import re as _re + + # Line is at file scope if it starts at column 0 (no leading whitespace) + # and contains ? used as a type (not inside a string or comment). + # Patterns: + # 1. Line starting with '?' — unknown-return-type extern + # 2. Line starting with 'extern ?*' — extern pointer of unknown type + # 3. Forward-declaration line (no leading brace) with '?' in parameter list + bad_line = _re.compile( + r'^(?:' + r'\?\s+\w[\w\s*,]*\(.*\)\s*(?:;|//.*)?' # ? ReturnType FuncName(...) or ? FuncName(...) + r'|extern\s+\?\s*\*[^;]*;' # extern ?* sym; + r'|(?:extern\s+)?(?:\w+\s+)?\w+\s*\([^)]*\?[^)]*\)\s*;(?:\s*//.*)?' # Decl with ? param + r')$', + _re.MULTILINE, + ) + + src_dir = Path(__file__).parent.parent / 'src' + total_removed = 0 + for c_file in src_dir.rglob('*.c'): + content = c_file.read_text() + if '?' not in content: + continue + cleaned = bad_line.sub('', content) + # Remove any double blank lines left behind + cleaned = _re.sub(r'\n{3,}', '\n\n', cleaned) + if cleaned != content: + c_file.write_text(cleaned) + removed = content.count('\n') - cleaned.count('\n') + total_removed += removed + self._log(f" Removed {removed} file-scope '?' line(s) from {c_file.name}", "INFO") + if total_removed: + self._log(f"Removed {total_removed} file-scope '?' type line(s) from source files", "INFO") + + def run(self): + """Main agent loop.""" + self._log("="*60) + self._log("STARTING DECOMPILATION AGENT") + self._log("="*60) + + # Show configuration + self._log(f"Batch size: {self.config.batch_size}") + self._log(f"Verify interval: {self.config.verify_interval}") + if self.config.module_filter: + self._log(f"Module filter: {self.config.module_filter}") + if self.config.max_duration: + self._log(f"Duration limit: {self.config.max_duration}s") + if self.config.target_count: + self._log(f"Target count: {self.config.target_count}") + + self.stats['start_time'] = time.time() + self.stats['last_progress_time'] = time.time() + + # Regenerate nonmatchings/ ASM files if wiped by make clean + self._log("Checking ASM splits...", "INFO") + self._ensure_asm_splits() + + # Regenerate cross-file forward declarations so m2c has full type context + self._refresh_decls() + + # Sweep stale 'Decompilation failure:' comment blocks that block m2c context + self._cleanup_failure_comments() + + # Hoist all scattered extern declarations to the file header section + self._hoist_externs_all_files() + + # Revert functions with '?' type markers (left by old agent runs without the fix) + self._cleanup_unknown_type_functions() + + # Remove bare file-scope lines with '?' types (e.g. "? SpuSetTransferCallback(?*);") + self._cleanup_file_level_question_marks() + + # Reset false-verified functions before starting if requested + if self.config.retry_verified: + self._reset_false_verified() + + # Flag currently-decompiled functions whose file fails PSY-Q compilation + self._initial_audit() + + # Ensure all overlay ASM jal targets have func_ aliases in sym_export.us.txt + self._sync_main_func_aliases() + + # Reset functions that were left in_progress from a previous crash + self._reset_stale_in_progress() + + # Give all previously-failed/blocked functions a fresh retry chance this session + self._reset_failed_attempt_counts() + + # Initial status + initial_stats = self.db.get_statistics() + self._log(f"Initial state: {initial_stats['by_status'].get('verified', 0)}/{initial_stats['total']} verified") + + # Main loop + functions_since_build = 0 + + while not self._check_stop_conditions(): + # Get next batch + batch = self._get_next_batch() + + if not batch: + self._log("No more functions to process", "INFO") + + # Dynamic retry gate: if we've already done at least one retry round + # and that round produced zero new decompilations or needs_refine + # results, stop — further retries won't help. + if self._retry_round > 0 and self._retry_progress_since_last_retry == 0: + self._log( + f"Retry round {self._retry_round} produced no progress — stopping retries", + "INFO", + ) + break + + # Start a new retry round: reset progress counter. + self._retry_round += 1 + self._retry_progress_since_last_retry = 0 + self._log(f"Starting retry round {self._retry_round}...", "INFO") + + # Try retrying failed functions (check DB, not just runtime counter) + failed_in_db = self.db.get_functions_by_status( + 'failed', limit=1, module=self.config.module_filter) + if failed_in_db: + self._retry_failed_functions() + batch = self._get_next_batch() + + # Try re-queuing decompiled_needs_refine functions (may have been manually fixed) + if not batch: + self._retry_needs_refine() + batch = self._get_next_batch() + + # Try retrying blocked functions if flag is set + if not batch and self.config.retry_blocked: + self._retry_blocked_functions() + batch = self._get_next_batch() + + if not batch: + # Check if we have blocked functions + cursor = self.db.conn.cursor() + if self.config.module_filter: + cursor.execute("SELECT COUNT(*) FROM functions WHERE status='blocked' AND module=?", (self.config.module_filter,)) + else: + cursor.execute("SELECT COUNT(*) FROM functions WHERE status='blocked'") + blocked_count = cursor.fetchone()[0] + if blocked_count: + self._log(f"Queue empty; {blocked_count} functions blocked (will retry on next run)", "INFO") + self._log("No functions available, stopping", "INFO") + break + + # Process batch + result = self._process_batch(batch) + functions_since_build += result['success'] + + # Accumulate progress for retry-round tracking. + # Count both true successes and needs_refine (compiled but with pre-existing + # errors) as forward progress, since both represent real decompilation work. + self._retry_progress_since_last_retry += result['success'] + result.get('needs_refine', 0) + + # Verify after every batch that produced at least one success so that + # newly-decompiled signatures land in decomp_decls.h immediately and + # are available as m2c context for the very next batch. + if result['success'] > 0: + self._verify_batch() + + # Fix type errors with LLM if enabled (after verification) + if self.llm and self.config.llm_auto_fix: + self._fix_type_errors_with_llm() + + # Periodic full build + if functions_since_build >= self.config.full_build_interval: + self._run_full_build() + functions_since_build = 0 + + # Show progress + self._show_progress() + + # Pause between batches + if not self._check_stop_conditions(): + time.sleep(self.config.pause_between_batches) + + # Final verification (catches any successes from the last batch if it + # was skipped above, e.g. if stop conditions fired before verify ran) + self._log("Running final verification...", "INFO") + self._verify_batch() + + # LLM fix pass: attempt to repair decompiled_needs_refine functions + if self.llm: + try: + self._llm_fix_needs_refine() + except Exception as e: + self._log(f"LLM fix pass failed: {e}", "WARN") + + # Final stats + self._show_final_report() + + def _show_final_report(self): + """Show final statistics.""" + elapsed = time.time() - self.stats['start_time'] + + print("\n" + "="*60) + print("AGENT EXECUTION COMPLETE") + print("="*60) + print(f"Total time: {timedelta(seconds=int(elapsed))}") + print(f"Functions processed: {self.stats['functions_processed']}") + print(f"Functions verified: {self.stats['functions_verified']}") + print(f"Functions failed: {self.stats['functions_failed']}") + print(f"Batches completed: {self.stats['batches_completed']}") + print(f"Builds run: {self.stats['builds_run']}") + if self.llm: + print(f"LLM analyzed: {self.stats['functions_analyzed_by_llm']}") + + if elapsed > 0: + rate = self.stats['functions_processed'] / elapsed + print(f"Average rate: {rate:.2f} functions/second") + + if self.stats['errors']: + print(f"\nErrors encountered: {len(self.stats['errors'])}") + print("Check agent.log for details") + + # Final database state + final_stats = self.db.get_statistics() + verified = final_stats['by_status'].get('verified', 0) + total = final_stats['total'] + progress = (verified / total * 100) if total > 0 else 0 + + print(f"\nFinal Progress: {verified}/{total} ({progress:.1f}%)") + + # Struct learning statistics + try: + struct_stats = self.db.get_struct_learning_stats() + if struct_stats['total_patterns'] > 0: + print(f"\n📚 Struct Learning:") + print(f" Total patterns learned: {struct_stats['total_patterns']}") + print(f" High confidence (≥70%): {struct_stats['high_confidence']}") + print(f" Medium confidence (30-70%): {struct_stats['medium_confidence']}") + print(f" Low confidence (<30%): {struct_stats['low_confidence']}") + except Exception as e: + if self.config.verbose: + self._log(f"Could not get struct learning stats: {e}") + + print("="*60 + "\n") + + # Write summary to file + summary = { + 'completed_at': datetime.now().isoformat(), + 'duration_seconds': int(elapsed), + 'functions_processed': self.stats['functions_processed'], + 'functions_verified': self.stats['functions_verified'], + 'functions_failed': self.stats['functions_failed'], + 'functions_analyzed_by_llm': self.stats['functions_analyzed_by_llm'], + 'final_progress_percent': progress, + 'llm_enabled': self.llm is not None, + 'errors': self.stats['errors'] + } + + try: + with open('agent_summary.json', 'w') as f: + json.dump(summary, f, indent=2) + print("Summary saved to agent_summary.json") + except Exception as e: + print(f"Could not save summary: {e}") + + @staticmethod + def _extract_c_function(content: str, func_name: str) -> Optional[str]: + """Extract a complete C function body by brace-matching.""" + pattern = rf'\b{re.escape(func_name)}\s*\([^)]*\)\s*\{{' + m = re.search(pattern, content, re.DOTALL) + if not m: + return None + brace_start = m.end() - 1 # index of opening '{' + depth = 0 + for i, ch in enumerate(content[brace_start:], brace_start): + if ch == '{': + depth += 1 + elif ch == '}': + depth -= 1 + if depth == 0: + return content[m.start():i + 1] + return None + + def _llm_fix_needs_refine(self): + """ + For each decompiled_needs_refine function whose C code is already in the + source file, use the LLM to fix PSY-Q compile errors, re-check compilation, + and promote to 'decompiled' on success. + """ + needs_refine = self.db.get_functions_by_status( + 'decompiled_needs_refine', module=self.config.module_filter) + if not needs_refine: + self._log("No decompiled_needs_refine functions to fix", "INFO") + return + + self._log(f"LLM fix pass: {len(needs_refine)} decompiled_needs_refine function(s)", "INFO") + project_root = Path(__file__).parent.parent + + # Group by C file so we only compile-check each file once per outer loop + file_to_funcs: dict = {} + for func in needs_refine: + c_file = func.get('c_file_path') + if c_file: + file_to_funcs.setdefault(c_file, []).append(func) + + fixed_total = 0 + + for rel_c_path, funcs_in_file in file_to_funcs.items(): + full_path = project_root / rel_c_path + if not full_path.exists(): + continue + + compile_ok, errors = self.verifier.check_file_compiles(full_path) + + if compile_ok: + # File already compiles without any changes — promote immediately + for func in funcs_in_file: + self.db.update_function_status( + func['name'], 'decompiled', + notes="LLM fix pass: file compiles cleanly") + fixed_total += 1 + self._log(f" {rel_c_path}: already compiles — promoted {len(funcs_in_file)} function(s)", "INFO") + continue + + # Attempt to fix each function in this file with the LLM + content = full_path.read_text() + for func in funcs_in_file: + func_name = func['name'] + error_summary = "; ".join(e['message'] for e in errors[:5]) + + broken_code = self._extract_c_function(content, func_name) + if not broken_code: + if self.config.verbose: + self._log(f" {func_name}: function body not found in {rel_c_path}, skipping", "INFO") + continue + + self._log(f" Fixing {func_name} (errors: {error_summary[:80]})", "INFO") + + try: + fix_result = self.llm.fix_m2c_error(func_name, broken_code, error_summary) + except Exception as e: + self._log(f" {func_name}: LLM call failed: {e}", "WARN") + continue + + if not fix_result or not fix_result.get('fixed_code') or fix_result.get('confidence') == 'low': + confidence = fix_result.get('confidence', 'none') if fix_result else 'none' + self._log(f" {func_name}: no usable fix (confidence={confidence})", "INFO") + continue + + # Apply fix tentatively + patched_content = content.replace(broken_code, fix_result['fixed_code']) + full_path.write_text(patched_content) + + compile_ok_after, errors_after = self.verifier.check_file_compiles(full_path) + + if compile_ok_after: + explanation = (fix_result.get('explanation') or '')[:200] + self.db.update_function_status( + func_name, 'decompiled', + notes=f"LLM fix ({fix_result['confidence']} confidence): {explanation}") + self.stats['functions_analyzed_by_llm'] += 1 + fixed_total += 1 + content = patched_content # carry forward for next func in same file + errors = errors_after # update error list (may be empty now) + self._log(f" ✅ {func_name}: fixed and promoted to decompiled", "INFO") + + # Audit log + try: + audit_log = project_root / "automation" / "llm_fixes_audit.log" + with open(audit_log, 'a') as f: + from datetime import datetime as _dt + f.write(f"{_dt.now().isoformat()}\t{func_name}\t{rel_c_path}\t" + f"{fix_result['confidence']}\t{error_summary[:120]}\t{explanation}\n") + except Exception: + pass + else: + # Revert this function's change and keep looking + full_path.write_text(content) + self._log(f" ❌ {func_name}: LLM fix didn't resolve errors, reverted", "INFO") + + self._log(f"LLM fix pass complete — fixed {fixed_total} function(s)", "INFO") + + +def main(): + parser = argparse.ArgumentParser(description="Autonomous decompilation agent") + + # Main commands + parser.add_argument('--run', action='store_true', + help='Start the agent') + parser.add_argument('--status', action='store_true', + help='Show agent statistics') + + # Configuration + parser.add_argument('--batch', type=int, default=10, + help='Batch size (default: 10)') + parser.add_argument('--parallel', type=int, default=1, metavar='N', + help='Decompile N functions in parallel (default: 1, max: cpu_count)') + parser.add_argument('--duration', type=int, + help='Max duration in seconds') + parser.add_argument('--target', type=int, + help='Stop after N functions') + parser.add_argument('--target-percent', type=float, + help='Stop at completion percentage') + parser.add_argument('--module', type=str, + help='Filter by module (battle, field, etc.)') + parser.add_argument('--max-lines', type=int, + help='Skip functions larger than N lines') + + # Intervals + parser.add_argument('--verify-interval', type=int, default=20, + help='Verify every N functions (default: 20)') + parser.add_argument('--build-interval', type=int, default=100, + help='Full build every N functions (default: 100)') + + # LLM assistance + parser.add_argument('--llm', action='store_true', + help='Enable LLM-assisted analysis (requires Ollama)') + parser.add_argument('--llm-threshold', type=int, default=20, + help='Analyze functions >= N lines with LLM (default: 20)') + parser.add_argument('--llm-model', type=str, default='qwen2.5-coder:7b', + help='LLM model to use (default: qwen2.5-coder:7b)') + parser.add_argument('--llm-auto-fix', action='store_true', + help='Enable automatic LLM fixing of m2c errors') + + # Dependency analysis + parser.add_argument('--no-dependency-analysis', action='store_true', + help='Disable dependency-aware function prioritization') + parser.add_argument('--dependency-weight', type=float, default=0.5, + help='Weight for dependency score vs simplicity (0-1, default: 0.5)') + parser.add_argument('--blocker-multiplier', type=float, default=2.0, + help='Per-dependent bonus added to agent score (default: 2.0; higher = more aggressive blocker prioritization)') + parser.add_argument('--no-strict-ordering', action='store_true', + help='Disable strict bottom-up decompilation ordering (allow decompiling callers before callees)') + parser.add_argument('--filter-cross-module', action='store_true', + help='Only attempt functions whose cross-module callees are already decompiled (eliminates /*?*/ markers)') + + # Retry / recovery + parser.add_argument('--retry-blocked', action='store_true', + help='Re-queue blocked functions when todo queue is empty (smart: only if a same-file callee was recently resolved)') + parser.add_argument('--force-retry-blocked', action='store_true', + help='Re-queue ALL blocked functions regardless of whether callees changed (use after adding type definitions to headers)') + parser.add_argument('--retry-verified', action='store_true', + help='Scan verified/decompiled functions for false positives (INCLUDE_ASM still present) and reset them to todo') + parser.add_argument('--verify-needs-refine', action='store_true', + help='Re-check all decompiled_needs_refine functions: promote to verified/decompiled those whose compile errors are now fixed') + + # Behavior + parser.add_argument('--verbose', '-v', action='store_true', + help='Verbose output') + parser.add_argument('--log-file', type=str, default='agent.log', + help='Log file path') + parser.add_argument('--strict-validation', action='store_true', + help="Use only base soft errors (saved_reg_*, unaligned type); treat '?' type-unknown artifacts as hard rejects (revert to INCLUDE_ASM) instead of decompiled_needs_refine") + + args = parser.parse_args() + + if args.status: + # Show current status + db = DecompDatabase() + stats = db.get_statistics() + + print("\n" + "="*60) + print("AGENT STATUS") + print("="*60) + + total = stats['total'] + by_status = stats['by_status'] + verified = by_status.get('verified', 0) + decompiled = by_status.get('decompiled', 0) + needs_refine = by_status.get('decompiled_needs_refine', 0) + failed = by_status.get('failed', 0) + blocked = by_status.get('blocked', 0) + + print(f"Total: {total}") + print(f"Verified: {verified} ({verified/total*100:.1f}%)") + print(f"Decompiled: {decompiled}") + print(f"Needs Refine: {needs_refine}") + print(f"Blocked: {blocked}") + print(f"Failed: {failed}") + print(f"Todo: {by_status.get('todo', 0)}") + print("="*60 + "\n") + + sys.exit(0) + + if args.verify_needs_refine: + config = AgentConfig() + config.verbose = args.verbose + config.log_file = args.log_file + config.module_filter = args.module + agent = DecompilationAgent(config) + agent.verify_needs_refine(module=args.module, verbose=args.verbose) + sys.exit(0) + + if args.run: + # Create configuration + config = AgentConfig() + config.batch_size = args.batch + config.parallel_workers = max(1, min(args.parallel, cpu_count())) # Clamp to valid range + config.max_duration = args.duration + config.target_count = args.target + config.target_progress = args.target_percent + config.module_filter = args.module + config.max_function_lines = args.max_lines + config.verify_interval = args.verify_interval + config.full_build_interval = args.build_interval + config.use_llm = args.llm + config.llm_analyze_threshold = args.llm_threshold + config.llm_model = args.llm_model + config.llm_auto_fix = args.llm_auto_fix + config.use_dependency_analysis = not args.no_dependency_analysis + config.dependency_weight = args.dependency_weight + config.blocker_multiplier = args.blocker_multiplier + config.strict_dependency_ordering = not args.no_strict_ordering + config.filter_cross_module_unresolved = args.filter_cross_module + config.retry_blocked = args.retry_blocked or args.force_retry_blocked + config.force_retry_blocked = args.force_retry_blocked + config.retry_verified = args.retry_verified + config.verbose = args.verbose + config.log_file = args.log_file + config.strict_validation = args.strict_validation + + # Clear the log file at the start of every manual run so it only + # captures output from this invocation. + if config.log_file: + try: + open(config.log_file, 'w').close() + except OSError: + pass + + # Tee stdout/stderr so every print() call also goes to the log file + if config.log_file: + tee = _TeeOutput(sys.stdout, config.log_file) + sys.stdout = tee + sys.stderr = _TeeOutput(sys.stderr, config.log_file) + + # Create and run agent + agent = DecompilationAgent(config) + + try: + agent.run() + except KeyboardInterrupt: + print("\n\n⚠️ Interrupted by user") + agent._show_final_report() + sys.exit(1) + except Exception as e: + print(f"\n\n❌ Fatal error: {e}") + import traceback + traceback.print_exc() + sys.exit(1) + + else: + parser.print_help() + print("\nQuick examples:") + print(" python agent.py --run") + print(" python agent.py --run --duration 3600 --batch 20 --parallel 4") + print(" python agent.py --run --target 100 --module battle") + print(" python agent.py --run --target-percent 10.0") + print(" python agent.py --run --retry-blocked --parallel 4") + print(" python agent.py --status") + + +if __name__ == '__main__': + main() diff --git a/automation/agent_summary.json b/automation/agent_summary.json new file mode 100644 index 0000000..904f00b --- /dev/null +++ b/automation/agent_summary.json @@ -0,0 +1,11 @@ +{ + "completed_at": "2026-04-23T13:24:49.878853", + "duration_seconds": 25, + "functions_processed": 8, + "functions_verified": 0, + "functions_failed": 0, + "functions_analyzed_by_llm": 0, + "final_progress_percent": 0.0, + "llm_enabled": false, + "errors": [] +} \ No newline at end of file diff --git a/automation/build.py b/automation/build.py new file mode 100755 index 0000000..7acd8fa --- /dev/null +++ b/automation/build.py @@ -0,0 +1,557 @@ +#!/usr/bin/env python3 +""" +Build & Verification System + +Handles building the project and verifying function matches: +1. Runs ./mako.sh build +2. Parses build output for errors/warnings +3. Checks binary matching for functions +4. Updates database with verification status + +Usage: + python build.py --build # Build entire project + python build.py --verify # Verify all decompiled functions + python build.py --check-function func_name # Check specific function + python build.py --report # Show build/match statistics +""" + +import subprocess +import argparse +import sys +import re +import json +from pathlib import Path +from typing import Optional, Tuple, Dict, List +from database import DecompDatabase + +# Project root is one level up from automation/ +PROJECT_ROOT = Path(__file__).parent.parent +MAKO_SCRIPT = PROJECT_ROOT / "mako.sh" +BUILD_DIR = PROJECT_ROOT / "build" / "us" +OBJDIFF_CLI = PROJECT_ROOT / "bin" / "objdiff-cli-linux-x86_64" + + +class BuildVerifier: + """Handles building and verifying function matches.""" + + def __init__(self, db: DecompDatabase, verbose: bool = False): + self.db = db + self.verbose = verbose + self._objdiff_report_cache: Optional[Dict] = None + + # ------------------------------------------------------------------ + # Per-file PSY-Q compilation check (no LLM required) + # ------------------------------------------------------------------ + + def _get_psyq_params(self, rel_path: str): + """ + Parse build.ninja to find PSY-Q compiler parameters for a source file. + Returns (cc1_binary, cc_flags) or None if the file has no psx-cc rule. + """ + ninja_file = PROJECT_ROOT / 'build.ninja' + if not ninja_file.exists(): + return None + + lines = ninja_file.read_text().splitlines() + + build_line_idx = None + for i, line in enumerate(lines): + if re.match(r'build\s+\S+\.o\s*:\s*psx-cc\s+' + re.escape(rel_path) + r'\b', line): + build_line_idx = i + break + + if build_line_idx is None: + return None + + # Skip the build rule and any continuation lines (ending with "$") + idx = build_line_idx + 1 + while idx < len(lines) and lines[idx - 1].endswith('$'): + idx += 1 + + # Read the indented variable block that follows + cc1 = 'cc1-psx-26' + cc_flags = '-O2 -G0' + while idx < len(lines) and lines[idx].startswith(' '): + m = re.match(r'\s+cc1\s*=\s*(\S+)', lines[idx]) + if m: + cc1 = m.group(1) + m = re.match(r'\s+cc_flags\s*=\s*(.+)', lines[idx]) + if m: + cc_flags = m.group(1).strip() + idx += 1 + + return cc1, cc_flags + + def check_file_compiles(self, file_path: Path) -> Tuple[bool, List[Dict]]: + """ + Compile a single C file using the PSY-Q toolchain and return errors. + + Uses build.ninja to find the correct compiler flags for the file. + Returns (success, errors) where errors is a list of {'line', 'message'} dicts. + On tool/timeout failure returns (True, []) to avoid false-positive reverts. + """ + try: + file_path = Path(file_path) + if not file_path.is_absolute(): + file_path = PROJECT_ROOT / file_path + rel_path = str(file_path.relative_to(PROJECT_ROOT)) + file_name = file_path.name + + params = self._get_psyq_params(rel_path) + if params is None: + # No PSY-Q rule in build.ninja — skip silently. + if self.verbose: + print(f" No PSY-Q build rule for {rel_path}, skipping compile check") + return True, [] + + cc1, cc_flags = params + cmd = ( + f'mipsel-linux-gnu-cpp -Iinclude -Iinclude/psxsdk -DUSE_INCLUDE_ASM -DFF7_STR' + f' -lang-c -Iinclude -Iinclude/psxsdk -undef -Wall -fno-builtin {rel_path}' + f' | bin/str' + f' | iconv --from-code=UTF-8 --to-code=Shift-JIS' + f' | bin/{cc1} -quiet -mcpu=3000 -g -mgas -gcoff {cc_flags} > /dev/null' + ) + result = subprocess.run( + cmd, shell=True, + cwd=str(PROJECT_ROOT), + stderr=subprocess.PIPE, + text=True, + timeout=60 + ) + output = result.stderr + + errors = [] + error_pattern = re.compile(rf'{re.escape(file_name)}:(\d+):\s*(.+)') + for line in output.split('\n'): + match = error_pattern.search(line) + if match: + line_num = int(match.group(1)) + message = match.group(2).strip() + # Skip all warnings — only true errors (undeclared, syntax, etc.) block progress + if 'warning:' in line.lower(): + continue + errors.append({'line': line_num, 'message': message}) + + return len(errors) == 0, errors + + except subprocess.TimeoutExpired: + if self.verbose: + print(f" Compile check timed out for {file_path.name}") + return True, [] + except Exception as e: + if self.verbose: + print(f" Compile check error for {file_path.name}: {e}") + return True, [] + + def run_build(self) -> Tuple[bool, str, str, Dict]: + """ + Run ./mako.sh build + + Returns: + (success, stdout, stderr, parsed_info) tuple + """ + if not MAKO_SCRIPT.exists(): + return False, "", f"mako.sh not found at {MAKO_SCRIPT}", {} + + cmd = [str(MAKO_SCRIPT), "build"] + + if self.verbose: + print(f"Running: {' '.join(cmd)}") + + try: + result = subprocess.run( + cmd, + cwd=PROJECT_ROOT, + capture_output=True, + text=True, + timeout=300 # 5 minute timeout for builds + ) + + success = result.returncode == 0 + parsed = self.parse_build_output(result.stdout, result.stderr) + + return success, result.stdout, result.stderr, parsed + + except subprocess.TimeoutExpired: + return False, "", "Build timed out after 5 minutes", {} + except Exception as e: + return False, "", f"Exception running build: {str(e)}", {} + + def parse_build_output(self, stdout: str, stderr: str) -> Dict: + """ + Parse build output to extract useful information. + + Returns dict with: + - success: bool + - errors: list of error messages + - warnings: list of warning messages + - compile_errors: dict of file -> errors + - link_errors: list of link errors + """ + result = { + 'success': True, + 'errors': [], + 'warnings': [], + 'compile_errors': {}, + 'link_errors': [] + } + + combined = stdout + "\n" + stderr + + # Parse compile errors: "src/file.c:123: error message" + compile_error_pattern = r'(src/[^:]+):(\d+):\s*(.*?)(?=\n|$)' + for match in re.finditer(compile_error_pattern, combined): + file_path, line_num, message = match.groups() + + if 'error' in message.lower(): + result['success'] = False + if file_path not in result['compile_errors']: + result['compile_errors'][file_path] = [] + result['compile_errors'][file_path].append({ + 'line': int(line_num), + 'message': message.strip() + }) + result['errors'].append(f"{file_path}:{line_num}: {message}") + elif 'warning' in message.lower(): + result['warnings'].append(f"{file_path}:{line_num}: {message}") + + # Parse linker errors: "undefined reference to `func_name'" + link_error_pattern = r"undefined reference to `([^']+)'" + for match in re.finditer(link_error_pattern, combined): + func_name = match.group(1) + result['success'] = False + result['link_errors'].append(func_name) + result['errors'].append(f"Undefined reference: {func_name}") + + # Check for ninja failure + if 'ninja: build stopped' in combined or 'FAILED:' in combined: + result['success'] = False + + return result + + def check_function_match(self, function_name: str) -> Tuple[bool, Optional[str]]: + """ + Check if a decompiled function matches the original binary using objdiff-cli. + + Returns: + (matches, error_message) tuple + """ + func = self.db.get_function(function_name) + if not func: + return False, "Function not in database" + + # Check if function still has INCLUDE_ASM in the C file + c_file = PROJECT_ROOT / func['c_file_path'] + if not c_file.exists(): + return False, f"C file not found: {c_file}" + + content = c_file.read_text() + include_asm_pattern = rf'INCLUDE_ASM\s*\(\s*"[^"]*"\s*,\s*{re.escape(function_name)}\s*\)' + if re.search(include_asm_pattern, content): + return False, "Function still uses INCLUDE_ASM" + + # Use objdiff-cli for real binary matching + if not OBJDIFF_CLI.exists(): + return False, "objdiff-cli not found — cannot verify binary match" + + expected_dir = PROJECT_ROOT / "expected" + if not expected_dir.exists(): + return False, "expected/ directory missing — run make rebuild first" + + try: + import tempfile, os + if self._objdiff_report_cache is None: + with tempfile.NamedTemporaryFile(suffix='.json', delete=False) as tf: + tmp_path = tf.name + + result = subprocess.run( + [str(OBJDIFF_CLI), 'report', 'generate', '-o', tmp_path, '--format', 'json'], + cwd=str(PROJECT_ROOT), + capture_output=True, + text=True, + timeout=60, + ) + + if result.returncode != 0: + return False, f"objdiff-cli failed: {result.stderr.strip()[:300]}" + + with open(tmp_path) as f: + self._objdiff_report_cache = json.load(f) + os.unlink(tmp_path) + + report = self._objdiff_report_cache + + # Search for the function in all units + for unit in report.get('units', []): + for sym in unit.get('functions', []): + if sym.get('name') == function_name: + pct = sym.get('fuzzy_match_percent', 0) + if pct >= 100.0: + return True, None + return False, f"Binary match {pct:.1f}% (need 100%)" + + return False, "Function not found in objdiff report" + + except Exception as e: + return False, f"objdiff error: {e}" + + + def verify_decompiled_functions(self) -> Dict[str, any]: + """ + Verify all functions marked as 'decompiled' in the database. + + Returns summary of verification results. + """ + print(f"\n{'='*60}") + print("VERIFYING DECOMPILED FUNCTIONS") + print(f"{'='*60}\n") + + # Get all decompiled functions + decompiled = self.db.get_functions_by_status('decompiled') + + if not decompiled: + print("No functions to verify (none marked as decompiled)") + return {'verified': 0, 'failed': 0, 'total': 0} + + print(f"Found {len(decompiled)} decompiled function(s) to verify\n") + + verified_count = 0 + failed_count = 0 + + for i, func in enumerate(decompiled, 1): + func_name = func['name'] + print(f"[{i}/{len(decompiled)}] Checking {func_name}...") + + matches, error = self.check_function_match(func_name) + + if matches: + print(f" ✅ Matches") + self.db.update_function_status( + func_name, + 'verified', + notes="Verified - binary match 100%" + ) + verified_count += 1 + else: + print(f" ❌ Not matching: {error}") + if "still uses INCLUDE_ASM" in error: + # C body was never written — just fix the DB status + self.db.update_function_status( + func_name, + 'decompiled_needs_refine', + notes=f"Verification failed: {error}" + ) + failed_count += 1 + else: + # C body is in the file but doesn't match binary — revert it + # to INCLUDE_ASM so SHA1 stays passing. + c_file = PROJECT_ROOT / func['c_file_path'] + asm_dir = None + if func.get('asm_file_path'): + from revert_nonmatching import get_include_asm_dir + asm_dir = get_include_asm_dir(func['asm_file_path']) + reverted = False + if asm_dir and c_file.exists(): + from revert_nonmatching import replace_func_with_stub + content = c_file.read_text() + new_content, reverted = replace_func_with_stub(content, func_name, asm_dir) + if reverted: + c_file.write_text(new_content) + if reverted: + print(f" ↩️ Reverted to INCLUDE_ASM (binary mismatch: {error})") + self.db.update_function_status( + func_name, + 'decompiled_needs_refine', + notes=f"Reverted: binary mismatch — {error}" + ) + else: + print(f" ⚠️ Could not revert {func_name} — manual check needed") + self.db.update_function_status( + func_name, + 'decompiled_needs_refine', + notes=f"Binary mismatch (revert failed): {error}" + ) + failed_count += 1 + + print(f"\n{'='*60}") + print(f"VERIFICATION COMPLETE") + print(f"{'='*60}") + print(f"✅ Verified: {verified_count}") + print(f"❌ Not matching: {failed_count}") + print(f"{'='*60}\n") + + return { + 'verified': verified_count, + 'failed': failed_count, + 'total': len(decompiled) + } + + def full_build_and_verify(self) -> bool: + """ + Run full build and verify all functions. + + Returns True if build succeeded. + """ + print(f"\n{'='*60}") + print("RUNNING BUILD") + print(f"{'='*60}\n") + + success, stdout, stderr, parsed = self.run_build() + self._objdiff_report_cache = None # Invalidate cache after build + + if self.verbose: + print("--- BUILD OUTPUT ---") + print(stdout) + if stderr: + print("--- STDERR ---") + print(stderr) + + if success: + print("✅ Build succeeded!") + print(f"\nWarnings: {len(parsed['warnings'])}") + if parsed['warnings'] and self.verbose: + for warning in parsed['warnings'][:5]: # Show first 5 + print(f" ⚠️ {warning}") + + # Now verify functions — revert any that don't reach 100% binary match + print("\n" + "="*60) + self.verify_decompiled_functions() + + else: + print("❌ Build failed!") + print(f"\nErrors: {len(parsed['errors'])}") + + # Show compile errors + if parsed['compile_errors']: + print("\nCompile Errors:") + for file_path, errors in parsed['compile_errors'].items(): + print(f" {file_path}:") + for err in errors[:3]: # Show first 3 per file + print(f" Line {err['line']}: {err['message']}") + + # Show link errors + if parsed['link_errors']: + print(f"\nUndefined References ({len(parsed['link_errors'])}):") + for func in parsed['link_errors'][:10]: # Show first 10 + print(f" - {func}") + if len(parsed['link_errors']) > 10: + print(f" ... and {len(parsed['link_errors']) - 10} more") + + # SHA1 mismatch: revert non-matching decompiled functions then rebuild + # to restore the passing state. Compile/link errors are a different + # failure mode and do not need this treatment. + if not parsed['compile_errors'] and not parsed['link_errors']: + print("\n🔍 SHA1 mismatch detected — checking for non-matching decompiled functions...") + verify_results = self.verify_decompiled_functions() + if verify_results['failed'] > 0: + print(f"↩️ Reverted {verify_results['failed']} non-matching function(s). Rebuilding...") + self._objdiff_report_cache = None + success2, _, _, _ = self.run_build() + self._objdiff_report_cache = None + if success2: + print("✅ Rebuild after revert succeeded — SHA1 passing again.") + success = True + else: + print("❌ Rebuild still failing after revert — manual intervention needed.") + else: + print("⚠️ No decompiled functions to revert — build failure has another cause.") + + print(f"\n{'='*60}\n") + return success + + +def show_build_report(db: DecompDatabase): + """Show statistics on build/verification status.""" + stats = db.get_statistics() + + print("\n" + "="*60) + print("BUILD & VERIFICATION REPORT") + print("="*60) + + total = stats['total'] + by_status = stats['by_status'] + + # Status breakdown + verified = by_status.get('verified', 0) + decompiled = by_status.get('decompiled', 0) + needs_refine = by_status.get('decompiled_needs_refine', 0) + in_progress = by_status.get('in_progress', 0) + failed = by_status.get('failed', 0) + blocked = by_status.get('blocked', 0) + todo = by_status.get('todo', 0) + + print(f"\nTotal Functions: {total}") + print(f"\nStatus Breakdown:") + print(f" ✅ Verified: {verified:>6} ({verified/total*100:.1f}%)") + print(f" 🔄 Decompiled: {decompiled:>6} ({decompiled/total*100:.1f}%)") + print(f" 🔧 Needs Refine: {needs_refine:>6} ({needs_refine/total*100:.1f}%)") + print(f" ⚙️ In Progress: {in_progress:>6}") + print(f" ⚠️ Blocked: {blocked:>6}") + print(f" ❌ Failed: {failed:>6}") + print(f" ⏳ Todo: {todo:>6}") + + # Progress calculation (verified = truly done) + completed = verified + if total > 0: + progress_pct = (completed / total) * 100 + print(f"\nVerified Progress: {completed}/{total} ({progress_pct:.1f}%)") + + # Recent activity + print(f"\nBy Module:") + for module, count in stats['by_module'].items(): + print(f" {module:15s}: {count:>4}") + + print("="*60 + "\n") + + +def main(): + parser = argparse.ArgumentParser(description="Build and verification system") + parser.add_argument('--build', action='store_true', + help='Run full build') + parser.add_argument('--verify', action='store_true', + help='Verify all decompiled functions') + parser.add_argument('--check-function', type=str, + help='Check if specific function matches') + parser.add_argument('--report', action='store_true', + help='Show build/verification statistics') + parser.add_argument('--verbose', '-v', action='store_true', + help='Verbose output') + + args = parser.parse_args() + + # Initialize database + db = DecompDatabase() + verifier = BuildVerifier(db, verbose=args.verbose) + + if args.report: + show_build_report(db) + + elif args.build: + success = verifier.full_build_and_verify() + sys.exit(0 if success else 1) + + elif args.verify: + results = verifier.verify_decompiled_functions() + sys.exit(0 if results['failed'] == 0 else 1) + + elif args.check_function: + matches, error = verifier.check_function_match(args.check_function) + if matches: + print(f"✅ {args.check_function} matches!") + sys.exit(0) + else: + print(f"❌ {args.check_function} does not match: {error}") + sys.exit(1) + + else: + parser.print_help() + print("\nQuick examples:") + print(" python build.py --report") + print(" python build.py --verify") + print(" python build.py --build") + print(" python build.py --check-function AverageSZ4") + + +if __name__ == '__main__': + main() diff --git a/automation/compile_errors_report.json b/automation/compile_errors_report.json new file mode 100644 index 0000000..215d912 --- /dev/null +++ b/automation/compile_errors_report.json @@ -0,0 +1,3579 @@ +{ + "src/main/psxsdk.c": { + "exists": true, + "ok": false, + "errors": [ + { + "line": 187, + "message": "parse error before `?'" + }, + { + "line": 190, + "message": "parse error before `?'" + }, + { + "line": 191, + "message": "parse error before `?'" + }, + { + "line": 331, + "message": "invalid type argument of `unary *'" + } + ], + "severe_errors": [], + "functions": [ + "CdLastPos", + "ChangeClearPAD", + "ChangeClearRCnt", + "ChangeClearSIO", + "CheckCallback", + "CloseEvent", + "DecDCTBufSize", + "DeliverEvent", + "DisableEvent", + "EnableEvent", + "FlushCache", + "GPU_cw", + "GetGraphDebug", + "GetVideoMode", + "HookEntryInt", + "InitCARD2", + "InitHeap", + "InitPAD", + "OpenEvent", + "OpenTIM", + "PAD_dr", + "PAD_init", + "ResetEntryInt", + "ReturnFromException", + "SetDQA", + "SetDQB", + "SetData32", + "SetIR0", + "SetMem", + "SetSp", + "SetVertex0", + "SetVertex1", + "SetVertex2", + "StartCARD2", + "StartPAD", + "StopPAD", + "SystemError", + "TestEvent", + "UnDeliverEvent", + "WaitEvent", + "_96_remove", + "_bu_init", + "func_80033C20", + "func_8003408C", + "func_80034410", + "func_80034430", + "func_80034444", + "func_8003447C", + "func_800345BC", + "func_800347B4", + "func_800347F8", + "func_80034BB0", + "func_80034D18", + "func_80034D5C", + "func_80034DB0", + "func_80035D64", + "func_80036038", + "func_80036190", + "func_800425F8" + ], + "recommendation": "recommend_fix" + }, + "src/main/18B8.c": { + "exists": true, + "ok": false, + "errors": [ + { + "line": 825, + "message": "warning: type mismatch with previous external decl" + }, + { + "line": 825, + "message": "warning: type mismatch with previous implicit declaration" + }, + { + "line": 649, + "message": "warning: previous implicit declaration of `func_80014C80'" + }, + { + "line": 825, + "message": "warning: `func_80014C80' was previously implicitly declared to return `int'" + }, + { + "line": 946, + "message": "warning: type mismatch with previous external decl" + }, + { + "line": 946, + "message": "warning: type mismatch with previous implicit declaration" + }, + { + "line": 641, + "message": "warning: previous implicit declaration of `func_80015B44'" + }, + { + "line": 946, + "message": "warning: `func_80015B44' was previously implicitly declared to return `int'" + }, + { + "line": 979, + "message": "invalid type argument of `->'" + }, + { + "line": 979, + "message": "invalid type argument of `->'" + }, + { + "line": 983, + "message": "invalid type argument of `->'" + }, + { + "line": 983, + "message": "invalid type argument of `->'" + }, + { + "line": 1550, + "message": "invalid type argument of `unary *'" + }, + { + "line": 1556, + "message": "invalid type argument of `unary *'" + }, + { + "line": 1752, + "message": "request for member `unk0' in something not a structure or union" + }, + { + "line": 1758, + "message": "request for member `unk2' in something not a structure or union" + }, + { + "line": 1771, + "message": "request for member `unk2' in something not a structure or union" + }, + { + "line": 1776, + "message": "request for member `unk2' in something not a structure or union" + }, + { + "line": 1776, + "message": "request for member `unk2' in something not a structure or union" + }, + { + "line": 1776, + "message": "request for member `unk0' in something not a structure or union" + }, + { + "line": 2033, + "message": "warning: type mismatch with previous external decl" + }, + { + "line": 2033, + "message": "warning: type mismatch with previous implicit declaration" + }, + { + "line": 1547, + "message": "warning: previous implicit declaration of `func_8001F6C0'" + }, + { + "line": 2033, + "message": "warning: `func_8001F6C0' was previously implicitly declared to return `int'" + }, + { + "line": 2041, + "message": "warning: type mismatch with previous external decl" + }, + { + "line": 2041, + "message": "warning: type mismatch with previous implicit declaration" + }, + { + "line": 1546, + "message": "warning: previous implicit declaration of `func_8001F6E4'" + }, + { + "line": 2041, + "message": "warning: `func_8001F6E4' was previously implicitly declared to return `int'" + }, + { + "line": 2309, + "message": "incompatible types in assignment" + }, + { + "line": 2586, + "message": "warning: assignment from incompatible pointer type" + }, + { + "line": 2612, + "message": "warning: passing arg 1 of `func_80025CD4' from incompatible pointer type" + }, + { + "line": 2701, + "message": "warning: type mismatch with previous external decl" + }, + { + "line": 2701, + "message": "warning: type mismatch with previous implicit declaration" + }, + { + "line": 2024, + "message": "warning: previous implicit declaration of `func_80026A34'" + }, + { + "line": 2701, + "message": "warning: `func_80026A34' was previously implicitly declared to return `int'" + }, + { + "line": 2799, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2799, + "message": "request for member `unk3' in something not a structure or union" + }, + { + "line": 2800, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2800, + "message": "request for member `unk7' in something not a structure or union" + }, + { + "line": 2802, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2802, + "message": "request for member `unk8' in something not a structure or union" + }, + { + "line": 2803, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2803, + "message": "request for member `unkA' in something not a structure or union" + }, + { + "line": 2804, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2804, + "message": "request for member `unkC' in something not a structure or union" + }, + { + "line": 2805, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2805, + "message": "request for member `unkD' in something not a structure or union" + }, + { + "line": 2806, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2806, + "message": "request for member `unkE' in something not a structure or union" + }, + { + "line": 2816, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2816, + "message": "request for member `unk3' in something not a structure or union" + }, + { + "line": 2817, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2817, + "message": "request for member `unk7' in something not a structure or union" + }, + { + "line": 2819, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2819, + "message": "request for member `unk8' in something not a structure or union" + }, + { + "line": 2820, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2820, + "message": "request for member `unkA' in something not a structure or union" + }, + { + "line": 2821, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2821, + "message": "request for member `unkC' in something not a structure or union" + }, + { + "line": 2822, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2822, + "message": "request for member `unkD' in something not a structure or union" + }, + { + "line": 2823, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2823, + "message": "request for member `unkE' in something not a structure or union" + }, + { + "line": 2840, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2840, + "message": "request for member `unk3' in something not a structure or union" + }, + { + "line": 2841, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2841, + "message": "request for member `unk7' in something not a structure or union" + }, + { + "line": 2843, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2843, + "message": "request for member `unk8' in something not a structure or union" + }, + { + "line": 2844, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2844, + "message": "request for member `unkA' in something not a structure or union" + }, + { + "line": 2845, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2845, + "message": "request for member `unkC' in something not a structure or union" + }, + { + "line": 2846, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2846, + "message": "request for member `unkD' in something not a structure or union" + }, + { + "line": 2847, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2847, + "message": "request for member `unkE' in something not a structure or union" + }, + { + "line": 2864, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2864, + "message": "request for member `unk3' in something not a structure or union" + }, + { + "line": 2865, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2865, + "message": "request for member `unk7' in something not a structure or union" + }, + { + "line": 2866, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2866, + "message": "request for member `unk18' in something not a structure or union" + }, + { + "line": 2867, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2867, + "message": "request for member `unk8' in something not a structure or union" + }, + { + "line": 2868, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2868, + "message": "request for member `unkA' in something not a structure or union" + }, + { + "line": 2870, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2870, + "message": "request for member `unkC' in something not a structure or union" + }, + { + "line": 2871, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2871, + "message": "request for member `unkE' in something not a structure or union" + }, + { + "line": 2872, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2872, + "message": "request for member `unk10' in something not a structure or union" + }, + { + "line": 2874, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2874, + "message": "request for member `unk12' in something not a structure or union" + }, + { + "line": 2875, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2875, + "message": "request for member `unk14' in something not a structure or union" + }, + { + "line": 2876, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2876, + "message": "request for member `unk16' in something not a structure or union" + }, + { + "line": 2877, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2877, + "message": "request for member `unk4' in something not a structure or union" + }, + { + "line": 2878, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2878, + "message": "request for member `unk5' in something not a structure or union" + }, + { + "line": 2879, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2879, + "message": "request for member `unk6' in something not a structure or union" + }, + { + "line": 2883, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2883, + "message": "request for member `unk3' in something not a structure or union" + }, + { + "line": 2884, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2884, + "message": "request for member `unk7' in something not a structure or union" + }, + { + "line": 2885, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2885, + "message": "request for member `unk8' in something not a structure or union" + }, + { + "line": 2886, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2886, + "message": "request for member `unkA' in something not a structure or union" + }, + { + "line": 2887, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2887, + "message": "request for member `unkC' in something not a structure or union" + }, + { + "line": 2888, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2888, + "message": "request for member `unkE' in something not a structure or union" + }, + { + "line": 2889, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2889, + "message": "request for member `unk4' in something not a structure or union" + }, + { + "line": 2890, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2890, + "message": "request for member `unk5' in something not a structure or union" + }, + { + "line": 2891, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2891, + "message": "request for member `unk6' in something not a structure or union" + }, + { + "line": 2913, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2913, + "message": "request for member `unk8' in something not a structure or union" + }, + { + "line": 2914, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2914, + "message": "request for member `unkA' in something not a structure or union" + }, + { + "line": 2916, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2916, + "message": "request for member `unk10' in something not a structure or union" + }, + { + "line": 2917, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2917, + "message": "request for member `unk12' in something not a structure or union" + }, + { + "line": 2918, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2918, + "message": "request for member `unk18' in something not a structure or union" + }, + { + "line": 2920, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2920, + "message": "request for member `unk1A' in something not a structure or union" + }, + { + "line": 2921, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2921, + "message": "request for member `unk20' in something not a structure or union" + }, + { + "line": 2922, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2922, + "message": "request for member `unk22' in something not a structure or union" + }, + { + "line": 2923, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2923, + "message": "request for member `unk4' in something not a structure or union" + }, + { + "line": 2924, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2924, + "message": "request for member `unk5' in something not a structure or union" + }, + { + "line": 2925, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2925, + "message": "request for member `unk6' in something not a structure or union" + }, + { + "line": 2926, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2926, + "message": "request for member `unkC' in something not a structure or union" + }, + { + "line": 2927, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2927, + "message": "request for member `unkD' in something not a structure or union" + }, + { + "line": 2928, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2928, + "message": "request for member `unkE' in something not a structure or union" + }, + { + "line": 2929, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2929, + "message": "request for member `unk14' in something not a structure or union" + }, + { + "line": 2930, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2930, + "message": "request for member `unk15' in something not a structure or union" + }, + { + "line": 2931, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2931, + "message": "request for member `unk16' in something not a structure or union" + }, + { + "line": 2932, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2932, + "message": "request for member `unk1C' in something not a structure or union" + }, + { + "line": 2933, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2933, + "message": "request for member `unk1D' in something not a structure or union" + }, + { + "line": 2934, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2934, + "message": "request for member `unk1E' in something not a structure or union" + }, + { + "line": 2941, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2941, + "message": "request for member `unk8' in something not a structure or union" + }, + { + "line": 2942, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2942, + "message": "request for member `unkA' in something not a structure or union" + }, + { + "line": 2943, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2943, + "message": "request for member `unk10' in something not a structure or union" + }, + { + "line": 2944, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2944, + "message": "request for member `unk12' in something not a structure or union" + }, + { + "line": 2945, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2945, + "message": "request for member `unk18' in something not a structure or union" + }, + { + "line": 2946, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2946, + "message": "request for member `unk1A' in something not a structure or union" + }, + { + "line": 2947, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2947, + "message": "request for member `unk20' in something not a structure or union" + }, + { + "line": 2948, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2948, + "message": "request for member `unk22' in something not a structure or union" + }, + { + "line": 2949, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2949, + "message": "request for member `unk4' in something not a structure or union" + }, + { + "line": 2950, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2950, + "message": "request for member `unk5' in something not a structure or union" + }, + { + "line": 2951, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2951, + "message": "request for member `unk6' in something not a structure or union" + }, + { + "line": 2952, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2952, + "message": "request for member `unkC' in something not a structure or union" + }, + { + "line": 2953, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2953, + "message": "request for member `unkD' in something not a structure or union" + }, + { + "line": 2954, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2954, + "message": "request for member `unkE' in something not a structure or union" + }, + { + "line": 2955, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2955, + "message": "request for member `unk14' in something not a structure or union" + }, + { + "line": 2956, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2956, + "message": "request for member `unk15' in something not a structure or union" + }, + { + "line": 2957, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2957, + "message": "request for member `unk16' in something not a structure or union" + }, + { + "line": 2958, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2958, + "message": "request for member `unk1C' in something not a structure or union" + }, + { + "line": 2959, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2959, + "message": "request for member `unk1D' in something not a structure or union" + }, + { + "line": 2960, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 2960, + "message": "request for member `unk1E' in something not a structure or union" + }, + { + "line": 3018, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 3018, + "message": "request for member `unk3' in something not a structure or union" + }, + { + "line": 3019, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 3019, + "message": "request for member `unk7' in something not a structure or union" + }, + { + "line": 3023, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 3023, + "message": "request for member `unk8' in something not a structure or union" + }, + { + "line": 3024, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 3024, + "message": "request for member `unkA' in something not a structure or union" + }, + { + "line": 3025, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 3025, + "message": "request for member `unkC' in something not a structure or union" + }, + { + "line": 3026, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 3026, + "message": "request for member `unkD' in something not a structure or union" + }, + { + "line": 3027, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 3027, + "message": "request for member `unk10' in something not a structure or union" + }, + { + "line": 3028, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 3028, + "message": "request for member `unk12' in something not a structure or union" + }, + { + "line": 3029, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 3029, + "message": "request for member `unkE' in something not a structure or union" + }, + { + "line": 3037, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 3037, + "message": "request for member `unk3' in something not a structure or union" + }, + { + "line": 3038, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 3038, + "message": "request for member `unk7' in something not a structure or union" + }, + { + "line": 3040, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 3040, + "message": "request for member `unk8' in something not a structure or union" + }, + { + "line": 3041, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 3041, + "message": "request for member `unkA' in something not a structure or union" + }, + { + "line": 3042, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 3042, + "message": "request for member `unkC' in something not a structure or union" + }, + { + "line": 3043, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 3043, + "message": "request for member `unkD' in something not a structure or union" + }, + { + "line": 3044, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 3044, + "message": "request for member `unk10' in something not a structure or union" + }, + { + "line": 3045, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 3045, + "message": "request for member `unk12' in something not a structure or union" + }, + { + "line": 3046, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 3046, + "message": "request for member `unkE' in something not a structure or union" + } + ], + "severe_errors": [], + "functions": [ + "__SN_ENTRY_POINT", + "func_8001117C", + "func_8001155C", + "func_80011784", + "func_80011AEC", + "func_80011BB4", + "func_80012840", + "func_800128B8", + "func_80012DB0", + "func_800131B8", + "func_800134F4", + "func_80013564", + "func_800135C0", + "func_800138EC", + "func_800148A0", + "func_80014980", + "func_80014A84", + "func_80014B08", + "func_80014BE4", + "func_80014C44", + "func_80014C80", + "func_80014E0C", + "func_80014E74", + "func_800150E4", + "func_800155A4", + "func_80015668", + "func_80015AFC", + "func_80015B44", + "func_80015B50", + "func_80015B88", + "func_80015BC0", + "func_80015C3C", + "func_80015D14", + "func_80015D64", + "func_80016340", + "func_800166C0", + "func_80016808", + "func_800169B8", + "func_80016F90", + "func_8001708C", + "func_80017678", + "func_80018028", + "func_800184C0", + "func_800185A8", + "func_80018AB0", + "func_80018B14", + "func_80018C94", + "func_80018D4C", + "func_80018E18", + "func_80018E90", + "func_80018ECC", + "func_80019338", + "func_8001937C", + "func_800193F4", + "func_8001964C", + "func_80019690", + "func_800197B8", + "func_80019E4C", + "func_8001A280", + "func_8001A384", + "func_8001A684", + "func_8001A980", + "func_8001A9CC", + "func_8001AB1C", + "func_8001AE08", + "func_8001AEE4", + "func_8001B704", + "func_8001BA54", + "func_8001BB30", + "func_8001C3CC", + "func_8001C484", + "func_8001C498", + "func_8001C4E8", + "func_8001C5BC", + "func_8001C788", + "func_8001C808", + "func_8001C8D4", + "func_8001C980", + "func_8001CB48", + "func_8001D6A8", + "func_8001DE70", + "func_8001DEF0", + "func_8001EC70", + "func_8001FA28", + "func_8001FA68", + "func_8001FAAC", + "func_8001FCDC", + "func_8001FF8C", + "func_8001FFD4", + "func_80020B68", + "func_800211B8", + "func_80022B5C", + "func_80023050", + "func_8002305C", + "func_800230C4", + "func_8002368C", + "func_80023788", + "func_8002382C", + "func_80023940", + "func_80023AC4", + "func_80024A04", + "func_80025040", + "func_80025174", + "func_80025288", + "func_80025310", + "func_80025380", + "func_800254E4", + "func_80025788", + "func_80025B10", + "func_80025B48", + "func_80025ED4", + "func_8002603C", + "func_80026408", + "func_800269D0", + "func_800269E8", + "func_80026A00", + "func_80026A0C", + "func_80026A20", + "func_80026A34", + "func_80026B64", + "func_80026B70", + "func_80026C5C", + "func_80026F44", + "func_8002708C", + "func_80027354", + "func_80027990", + "func_800285AC", + "func_80028930", + "func_80028CA0", + "func_80028E00", + "func_80029114", + "main" + ], + "recommendation": "recommend_revert" + }, + "src/main/akao.c": { + "exists": true, + "ok": false, + "errors": [ + { + "line": 276, + "message": "warning: overflow in implicit constant conversion" + } + ], + "severe_errors": [], + "functions": [ + "func_800293D0", + "func_800294A4", + "func_8002988C", + "func_80029998", + "func_80029B78", + "func_8002A6C4", + "func_8002A798", + "func_8002A7E8", + "func_8002A958", + "func_8002B1A8", + "func_8002BCCC", + "func_8002BD04", + "func_8002BFCC", + "func_8002C004", + "func_8002CA84", + "func_8002FDA0", + "func_800318BC", + "func_80032B30", + "func_80032C20", + "func_80032CE8", + "func_80033A90" + ], + "recommendation": "recommend_fix" + }, + "src/brom/brom.c": { + "exists": true, + "ok": true, + "errors": [], + "severe_errors": [], + "functions": [ + "func_800A0000", + "func_800A0514" + ], + "recommendation": "no_action" + }, + "src/ending/ending.c": { + "exists": true, + "ok": false, + "errors": [ + { + "line": 78, + "message": "`D_800A6528' undeclared (first use this function)" + }, + { + "line": 78, + "message": "(Each undeclared identifier is reported only once" + }, + { + "line": 78, + "message": "for each function it appears in.)" + }, + { + "line": 95, + "message": "`D_800A6528' used prior to declaration" + }, + { + "line": 129, + "message": "request for member `unk0' in something not a structure or union" + }, + { + "line": 130, + "message": "request for member `unk2' in something not a structure or union" + }, + { + "line": 133, + "message": "request for member `unk4' in something not a structure or union" + }, + { + "line": 151, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 151, + "message": "request for member `unk8' in something not a structure or union" + }, + { + "line": 187, + "message": "`D_800AF3CC' undeclared (first use this function)" + }, + { + "line": 188, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 188, + "message": "request for member `unk4' in something not a structure or union" + }, + { + "line": 190, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 190, + "message": "request for member `unkE' in something not a structure or union" + }, + { + "line": 191, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 191, + "message": "request for member `unk8' in something not a structure or union" + }, + { + "line": 193, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 193, + "message": "request for member `unk4' in something not a structure or union" + }, + { + "line": 194, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 194, + "message": "request for member `unk4' in something not a structure or union" + }, + { + "line": 197, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 197, + "message": "request for member `unk4' in something not a structure or union" + }, + { + "line": 199, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 199, + "message": "request for member `unkE' in something not a structure or union" + }, + { + "line": 200, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 200, + "message": "request for member `unkE' in something not a structure or union" + }, + { + "line": 202, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 202, + "message": "request for member `unk4' in something not a structure or union" + }, + { + "line": 203, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 203, + "message": "request for member `unk4' in something not a structure or union" + }, + { + "line": 208, + "message": "warning: type mismatch with previous external decl" + }, + { + "line": 208, + "message": "warning: type mismatch with previous implicit declaration" + }, + { + "line": 91, + "message": "warning: previous implicit declaration of `func_800A32D8'" + }, + { + "line": 208, + "message": "warning: `func_800A32D8' was previously implicitly declared to return `int'" + }, + { + "line": 212, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 212, + "message": "request for member `unk0' in something not a structure or union" + }, + { + "line": 213, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 213, + "message": "request for member `unk4' in something not a structure or union" + }, + { + "line": 214, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 214, + "message": "request for member `unk4' in something not a structure or union" + }, + { + "line": 220, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 220, + "message": "request for member `unkE' in something not a structure or union" + }, + { + "line": 225, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 225, + "message": "request for member `unkE' in something not a structure or union" + }, + { + "line": 230, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 230, + "message": "request for member `unkE' in something not a structure or union" + }, + { + "line": 233, + "message": "`D_800AF3CC' used prior to declaration" + }, + { + "line": 236, + "message": "warning: type mismatch with previous external decl" + }, + { + "line": 236, + "message": "warning: type mismatch with previous implicit declaration" + }, + { + "line": 91, + "message": "warning: previous implicit declaration of `func_800A3314'" + }, + { + "line": 236, + "message": "warning: `func_800A3314' was previously implicitly declared to return `int'" + }, + { + "line": 241, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 241, + "message": "request for member `unk4' in something not a structure or union" + }, + { + "line": 244, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 244, + "message": "request for member `unkC' in something not a structure or union" + }, + { + "line": 245, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 245, + "message": "request for member `unk4' in something not a structure or union" + }, + { + "line": 246, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 246, + "message": "request for member `unk4' in something not a structure or union" + } + ], + "severe_errors": [], + "functions": [ + "func_800A04C4", + "func_800A0E68", + "func_800A0F90", + "func_800A1F48", + "func_800A1FA4", + "func_800A20D4", + "func_800A21CC", + "func_800A2248", + "func_800A2274", + "func_800A22A4", + "func_800A22E4", + "func_800A2380", + "func_800A23F8", + "func_800A2420", + "func_800A2504", + "func_800A2E80", + "func_800A3210", + "func_800A32D8", + "func_800A3314", + "func_800A358C" + ], + "recommendation": "recommend_revert" + }, + "src/world/world.c": { + "exists": true, + "ok": false, + "errors": [ + { + "line": 145, + "message": "`saved_reg_s0' undeclared (first use this function)" + }, + { + "line": 145, + "message": "(Each undeclared identifier is reported only once" + }, + { + "line": 145, + "message": "for each function it appears in.)" + }, + { + "line": 481, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 481, + "message": "request for member `unkC' in something not a structure or union" + }, + { + "line": 482, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 482, + "message": "request for member `unk0' in something not a structure or union" + }, + { + "line": 483, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 483, + "message": "request for member `unk1' in something not a structure or union" + }, + { + "line": 484, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 484, + "message": "request for member `unk2' in something not a structure or union" + }, + { + "line": 485, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 485, + "message": "request for member `unk0' in something not a structure or union" + }, + { + "line": 485, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 485, + "message": "request for member `unk0' in something not a structure or union" + }, + { + "line": 485, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 485, + "message": "request for member `unk0' in something not a structure or union" + }, + { + "line": 485, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 485, + "message": "request for member `unk0' in something not a structure or union" + }, + { + "line": 486, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 486, + "message": "request for member `unk4' in something not a structure or union" + }, + { + "line": 486, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 486, + "message": "request for member `unk2' in something not a structure or union" + }, + { + "line": 486, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 486, + "message": "request for member `unk2' in something not a structure or union" + }, + { + "line": 486, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 486, + "message": "request for member `unk2' in something not a structure or union" + }, + { + "line": 487, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 487, + "message": "request for member `unk8' in something not a structure or union" + }, + { + "line": 487, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 487, + "message": "request for member `unk4' in something not a structure or union" + }, + { + "line": 487, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 487, + "message": "request for member `unk4' in something not a structure or union" + }, + { + "line": 487, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 487, + "message": "request for member `unk4' in something not a structure or union" + }, + { + "line": 503, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 503, + "message": "request for member `unk5E' in something not a structure or union" + }, + { + "line": 504, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 504, + "message": "request for member `unk0' in something not a structure or union" + }, + { + "line": 539, + "message": "`D_8010AD40' undeclared (first use this function)" + }, + { + "line": 547, + "message": "`D_8010AD40' undeclared (first use this function)" + }, + { + "line": 569, + "message": "`D_8010AD40' undeclared (first use this function)" + }, + { + "line": 600, + "message": "`D_8010AD40' undeclared (first use this function)" + }, + { + "line": 626, + "message": "`D_8010AD40' undeclared (first use this function)" + }, + { + "line": 660, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 660, + "message": "request for member `unk3C' in something not a structure or union" + }, + { + "line": 665, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 665, + "message": "request for member `unk3C' in something not a structure or union" + }, + { + "line": 686, + "message": "`D_8011650C' undeclared (first use this function)" + }, + { + "line": 687, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 687, + "message": "request for member `unk3C' in something not a structure or union" + }, + { + "line": 689, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 689, + "message": "request for member `unk3C' in something not a structure or union" + }, + { + "line": 691, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 691, + "message": "request for member `unk3C' in something not a structure or union" + }, + { + "line": 699, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 699, + "message": "request for member `unk3C' in something not a structure or union" + }, + { + "line": 708, + "message": "`D_8011650C' used prior to declaration" + }, + { + "line": 716, + "message": "structure has no member named `unk51'" + }, + { + "line": 717, + "message": "structure has no member named `unk3E'" + }, + { + "line": 719, + "message": "structure has no member named `unk3E'" + }, + { + "line": 721, + "message": "structure has no member named `unk51'" + }, + { + "line": 722, + "message": "structure has no member named `unk3E'" + }, + { + "line": 724, + "message": "structure has no member named `unk3E'" + }, + { + "line": 726, + "message": "structure has no member named `unk3E'" + }, + { + "line": 744, + "message": "`D_8010AD40' undeclared (first use this function)" + }, + { + "line": 756, + "message": "`D_8010AD40' used prior to declaration" + }, + { + "line": 775, + "message": "warning: comparison of distinct pointer types lacks a cast" + }, + { + "line": 776, + "message": "structure has no member named `unk51'" + }, + { + "line": 881, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 881, + "message": "void value not ignored as it ought to be" + }, + { + "line": 967, + "message": "conflicting types for `Unk8010AD40'" + }, + { + "line": 65, + "message": "previous declaration of `Unk8010AD40'" + }, + { + "line": 975, + "message": "structure has no member named `unk51'" + }, + { + "line": 977, + "message": "structure has no member named `unk51'" + }, + { + "line": 979, + "message": "structure has no member named `unk51'" + }, + { + "line": 1017, + "message": "request for member `unk4' in something not a structure or union" + }, + { + "line": 1018, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1018, + "message": "request for member `unk46' in something not a structure or union" + }, + { + "line": 1019, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1019, + "message": "request for member `unk46' in something not a structure or union" + }, + { + "line": 1021, + "message": "request for member `unk0' in something not a structure or union" + }, + { + "line": 1021, + "message": "invalid type argument of `unary *'" + }, + { + "line": 1046, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1046, + "message": "request for member `unk46' in something not a structure or union" + }, + { + "line": 1047, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1047, + "message": "request for member `unk0' in something not a structure or union" + }, + { + "line": 1305, + "message": "`D_8010CA74' undeclared (first use this function)" + }, + { + "line": 1308, + "message": "`D_8010CA8C' undeclared (first use this function)" + }, + { + "line": 1312, + "message": "`D_8010CAF4' undeclared (first use this function)" + }, + { + "line": 1316, + "message": "`D_8010CA74' used prior to declaration" + }, + { + "line": 1329, + "message": "warning: comparison between pointer and integer" + }, + { + "line": 1345, + "message": "invalid type argument of `unary *'" + }, + { + "line": 1346, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1346, + "message": "request for member `unk4' in something not a structure or union" + }, + { + "line": 1347, + "message": "warning: assignment makes pointer from integer without a cast" + }, + { + "line": 1348, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1348, + "message": "request for member `unk14' in something not a structure or union" + }, + { + "line": 1353, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1353, + "message": "request for member `unk14' in something not a structure or union" + }, + { + "line": 1353, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1353, + "message": "request for member `unk4' in something not a structure or union" + }, + { + "line": 1385, + "message": "`D_8010CA8C' used prior to declaration" + }, + { + "line": 1397, + "message": "`D_8010CAF4' used prior to declaration" + }, + { + "line": 1486, + "message": "warning: assignment makes pointer from integer without a cast" + }, + { + "line": 1488, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1488, + "message": "request for member `unk' in something not a structure or union" + }, + { + "line": 1488, + "message": "nondigits in number and not hexadecimal" + }, + { + "line": 1489, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1489, + "message": "request for member `unk' in something not a structure or union" + }, + { + "line": 1490, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1490, + "message": "request for member `unk' in something not a structure or union" + }, + { + "line": 1491, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1491, + "message": "request for member `unk' in something not a structure or union" + }, + { + "line": 1492, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1492, + "message": "request for member `unk' in something not a structure or union" + }, + { + "line": 1493, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1493, + "message": "request for member `unk' in something not a structure or union" + }, + { + "line": 1493, + "message": "`F' undeclared (first use this function)" + }, + { + "line": 1501, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1501, + "message": "request for member `unk' in something not a structure or union" + }, + { + "line": 1502, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1502, + "message": "request for member `unk0' in something not a structure or union" + }, + { + "line": 1503, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1503, + "message": "request for member `unk' in something not a structure or union" + }, + { + "line": 1504, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1504, + "message": "request for member `unk' in something not a structure or union" + }, + { + "line": 1505, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1505, + "message": "request for member `unk2' in something not a structure or union" + }, + { + "line": 1506, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1506, + "message": "request for member `unk' in something not a structure or union" + }, + { + "line": 1507, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1507, + "message": "request for member `unk' in something not a structure or union" + }, + { + "line": 1508, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1508, + "message": "request for member `unk0' in something not a structure or union" + }, + { + "line": 1508, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1508, + "message": "request for member `unk4' in something not a structure or union" + }, + { + "line": 1509, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1509, + "message": "request for member `unk7' in something not a structure or union" + }, + { + "line": 1510, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1510, + "message": "request for member `unk' in something not a structure or union" + }, + { + "line": 1512, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1512, + "message": "request for member `unk2' in something not a structure or union" + }, + { + "line": 1512, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1512, + "message": "request for member `unk6' in something not a structure or union" + }, + { + "line": 1513, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1513, + "message": "request for member `unk8' in something not a structure or union" + }, + { + "line": 1514, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1514, + "message": "request for member `unk0' in something not a structure or union" + }, + { + "line": 1857, + "message": "invalid type argument of `->'" + }, + { + "line": 1857, + "message": "invalid type argument of `->'" + }, + { + "line": 1870, + "message": "warning: assignment makes pointer from integer without a cast" + }, + { + "line": 1922, + "message": "invalid type argument of `->'" + }, + { + "line": 1922, + "message": "invalid type argument of `->'" + }, + { + "line": 1930, + "message": "invalid type argument of `unary *'" + }, + { + "line": 1936, + "message": "invalid type argument of `unary *'" + }, + { + "line": 1948, + "message": "`D_801163E8' undeclared (first use this function)" + }, + { + "line": 1951, + "message": "invalid type argument of `unary *'" + }, + { + "line": 1961, + "message": "`D_801163E8' used prior to declaration" + } + ], + "severe_errors": [], + "functions": [ + "func_800A0B48", + "func_800A0BE4", + "func_800A0C54", + "func_800A0D2C", + "func_800A12AC", + "func_800A1370", + "func_800A141C", + "func_800A16E0", + "func_800A19FC", + "func_800A1D38", + "func_800A1D54", + "func_800A1DF0", + "func_800A1FAC", + "func_800A2040", + "func_800A2088", + "func_800A2108", + "func_800A21B4", + "func_800A31C0", + "func_800A31F8", + "func_800A3304", + "func_800A38C8", + "func_800A3908", + "func_800A3964", + "func_800A3C74", + "func_800A3DFC", + "func_800A3E4C", + "func_800A3E9C", + "func_800A3EC8", + "func_800A4008", + "func_800A4080", + "func_800A40B8", + "func_800A40F0", + "func_800A4138", + "func_800A41E8", + "func_800A4268", + "func_800A44B4", + "func_800A44C4", + "func_800A460C", + "func_800A4DDC", + "func_800A4F08", + "func_800A4F78", + "func_800A5208", + "func_800A52A4", + "func_800A5348", + "func_800A53A8", + "func_800A54F0", + "func_800A57C8", + "func_800A5924", + "func_800A5970", + "func_800A59A0", + "func_800A5A20", + "func_800A5A94", + "func_800A5AD8", + "func_800A5B88", + "func_800A5C08", + "func_800A5D00", + "func_800A5E28", + "func_800A5FB4", + "func_800A60D8", + "func_800A63FC", + "func_800A64AC", + "func_800A67A8", + "func_800A6884", + "func_800A692C", + "func_800A6994", + "func_800A6B8C", + "func_800A6C00", + "func_800A6C3C", + "func_800A71E8", + "func_800A7EA4", + "func_800A7F18", + "func_800A7F38", + "func_800A806C", + "func_800A82F0", + "func_800A8300", + "func_800A86C4", + "func_800A886C", + "func_800A8888", + "func_800A8898", + "func_800A891C", + "func_800A8A1C", + "func_800A8A88", + "func_800A8ABC", + "func_800A8AF4", + "func_800A8C70", + "func_800A8CA4", + "func_800A8CE4", + "func_800A8D58", + "func_800A8F48", + "func_800A8F74", + "func_800A8FA0", + "func_800A8FCC", + "func_800A9018", + "func_800A9064", + "func_800A90EC", + "func_800A9110", + "func_800A9134", + "func_800A9154", + "func_800A9174", + "func_800A9194", + "func_800A91A4", + "func_800A91E0", + "func_800A921C", + "func_800A9240", + "func_800A929C", + "func_800A92F8", + "func_800A9480", + "func_800A94A8", + "func_800A94D0", + "func_800A94F4", + "func_800A9520", + "func_800A9678", + "func_800A96A4", + "func_800A96D0", + "func_800A97A8", + "func_800A97E4", + "func_800A9820", + "func_800A984C", + "func_800A98A4", + "func_800A98E4", + "func_800A9910", + "func_800A993C", + "func_800A9988", + "func_800A99BC", + "func_800A9A44", + "func_800A9A70", + "func_800A9AA4", + "func_800A9AD0", + "func_800A9B04", + "func_800A9C64", + "func_800A9D5C", + "func_800A9D88", + "func_800A9E14", + "func_800AA04C", + "func_800AA098", + "func_800AA0E0", + "func_800AA128", + "func_800AA170", + "func_800AA1B8", + "func_800AA238", + "func_800AA2B8", + "func_800AA580", + "func_800AA640", + "func_800AA684", + "func_800AA6A4", + "func_800AA7DC", + "func_800AA8D8", + "func_800AA8F8", + "func_800AAA00", + "func_800AAB18", + "func_800AB36C", + "func_800AB398", + "func_800AB48C", + "func_800AB4F4", + "func_800AB570", + "func_800AB5E4", + "func_800AB6E4", + "func_800AB8EC", + "func_800AB92C", + "func_800AB988", + "func_800ABA18", + "func_800ABA78", + "func_800ABB24", + "func_800ABE58", + "func_800ABFC0", + "func_800AC3C0", + "func_800AC484", + "func_800AC700", + "func_800AD63C", + "func_800AD788", + "func_800AD804", + "func_800AD928", + "func_800ADA08", + "func_800ADA64", + "func_800ADB30", + "func_800ADC3C", + "func_800ADC70", + "func_800ADD4C", + "func_800ADE30", + "func_800ADFC0", + "func_800AE024", + "func_800AE0BC", + "func_800AE180", + "func_800AE47C", + "func_800AE4B8", + "func_800AE5B8", + "func_800AE5F0", + "func_800AE628", + "func_800AE638", + "func_800AE8AC", + "func_800AEA48", + "func_800AF0A0", + "func_800AF0B0", + "func_800AF1A8", + "func_800AF1E8", + "func_800AF24C", + "func_800AF2A4", + "func_800AF324", + "func_800AF364", + "func_800AF3A4", + "func_800AF96C", + "func_800AF9A0", + "func_800AFCC8", + "func_800AFFBC", + "func_800B0098", + "func_800B017C", + "func_800B01C4", + "func_800B0200", + "func_800B0240", + "func_800B0250", + "func_800B0334", + "func_800B04AC", + "func_800B0670", + "func_800B075C", + "func_800B0794", + "func_800B0810", + "func_800B0BF4", + "func_800B0D98", + "func_800B0E84", + "func_800B104C", + "func_800B10AC", + "func_800B11C4", + "func_800B1650", + "func_800B1C80", + "func_800B21E4", + "func_800B2304", + "func_800B2638", + "func_800B28CC", + "func_800B29CC", + "func_800B2E90", + "func_800B2FA4", + "func_800B2FD0", + "func_800B3018", + "func_800B3044", + "func_800B307C", + "func_800B3300", + "func_800B3350", + "func_800B338C", + "func_800B3418", + "func_800B37E0", + "func_800B3828", + "func_800B392C", + "func_800B39B4", + "func_800B3C40", + "func_800B40B4", + "func_800B4244", + "func_800B45DC", + "func_800B5314", + "func_800B579C", + "func_800B57C0", + "func_800B57DC", + "func_800B58F8", + "func_800B59F4", + "func_800B5DD8", + "func_800B5E28", + "func_800B624C", + "func_800B6348", + "func_800B64A0", + "func_800B64D8", + "func_800B650C", + "func_800B6570", + "func_800B65A4", + "func_800B667C", + "func_800B6724", + "func_800B69A4", + "func_800B6A4C", + "func_800B6B28", + "func_800B6C84", + "func_800B6D10", + "func_800B6DCC", + "func_800B6E08", + "func_800B6E78", + "func_800B6EFC", + "func_800B7104", + "func_800B7134", + "func_800B717C", + "func_800B7200", + "func_800B7228", + "func_800B7480", + "func_800B7620", + "func_800B76A8", + "func_800B7714", + "func_800B77A8", + "func_800B77F4", + "func_800B7820", + "func_800B7838", + "func_800B785C", + "func_800B786C", + "func_800B79B8", + "func_800B7A40", + "func_800B7AC0", + "func_800B7B1C", + "func_800B7B3C", + "func_800B7B54", + "func_800B7B78", + "func_800B7BA0", + "func_800B7BC0", + "func_800B7BD8", + "func_800B7C1C", + "func_800B7C7C", + "func_800B832C", + "func_800B8488", + "func_800B84D8", + "func_800B851C", + "func_800B858C", + "func_800B86C4", + "func_800B86E8", + "func_800B8720", + "func_800B8760", + "func_800B87D8", + "func_800B89C4", + "func_800B8A5C", + "func_800B8A98", + "func_800B8CBC", + "func_800B8D20", + "func_800B8D4C", + "func_800B90C0", + "func_800B95E8", + "func_800B962C", + "func_800B98F0", + "func_800BA938", + "func_800BAA00", + "func_800BB350", + "func_800BB450", + "func_800BB568", + "func_800BB650", + "func_800BB7DC", + "func_800BB8B0", + "func_800BB8E8", + "func_800BB9A0", + "func_800BB9D0", + "func_800BBA0C", + "func_800BBA44", + "func_800BBBB0", + "func_800BBC4C", + "func_800BBD20", + "func_800BC1CC", + "func_800BC420", + "func_800BC9E8", + "func_800BCA38", + "func_800BCA48", + "func_800BCA78", + "func_800BCB2C", + "func_800BCBE8", + "func_800BCECC" + ], + "recommendation": "recommend_revert" + }, + "src/battle/battle.c": { + "exists": true, + "ok": false, + "errors": [ + { + "line": 161, + "message": "warning: assignment from incompatible pointer type" + }, + { + "line": 168, + "message": "warning: large integer implicitly truncated to unsigned type" + }, + { + "line": 171, + "message": "warning: assignment from incompatible pointer type" + }, + { + "line": 387, + "message": "request for member `unk2' in something not a structure or union" + }, + { + "line": 414, + "message": "request for member `unk2' in something not a structure or union" + }, + { + "line": 639, + "message": "request for member `unk0' in something not a structure or union" + }, + { + "line": 659, + "message": "warning: type mismatch with previous external decl" + }, + { + "line": 659, + "message": "warning: type mismatch with previous implicit declaration" + }, + { + "line": 469, + "message": "warning: previous implicit declaration of `func_800A3E98'" + }, + { + "line": 659, + "message": "warning: `func_800A3E98' was previously implicitly declared to return `int'" + }, + { + "line": 724, + "message": "warning: type mismatch with previous external decl" + }, + { + "line": 724, + "message": "warning: type mismatch with previous implicit declaration" + }, + { + "line": 187, + "message": "warning: previous implicit declaration of `func_800A4CA8'" + }, + { + "line": 724, + "message": "warning: `func_800A4CA8' was previously implicitly declared to return `int'" + }, + { + "line": 936, + "message": "warning: type mismatch with previous external decl" + }, + { + "line": 936, + "message": "warning: type mismatch with previous implicit declaration" + }, + { + "line": 274, + "message": "warning: previous implicit declaration of `func_800A7254'" + }, + { + "line": 936, + "message": "warning: `func_800A7254' was previously implicitly declared to return `int'" + }, + { + "line": 941, + "message": "warning: type mismatch with previous external decl" + }, + { + "line": 941, + "message": "warning: type mismatch with previous implicit declaration" + }, + { + "line": 323, + "message": "warning: previous implicit declaration of `func_800B0FFC'" + }, + { + "line": 941, + "message": "warning: `func_800B0FFC' was previously implicitly declared to return `int'" + }, + { + "line": 1126, + "message": "warning: type mismatch with previous external decl" + }, + { + "line": 1126, + "message": "warning: type mismatch with previous implicit declaration" + }, + { + "line": 244, + "message": "warning: previous implicit declaration of `func_800A8E54'" + }, + { + "line": 1126, + "message": "warning: `func_800A8E54' was previously implicitly declared to return `int'" + }, + { + "line": 1432, + "message": "invalid operands to binary &" + }, + { + "line": 1459, + "message": "conflicting types for `D_800F49F8'" + }, + { + "line": 1463, + "message": "subscripted value is neither array nor pointer" + }, + { + "line": 1518, + "message": "parse error before `value'" + }, + { + "line": 1521, + "message": "parse error before `compare_value'" + }, + { + "line": 1523, + "message": "`value' undeclared (first use this function)" + }, + { + "line": 1523, + "message": "(Each undeclared identifier is reported only once" + }, + { + "line": 1523, + "message": "for each function it appears in.)" + }, + { + "line": 1523, + "message": "`compare_value' undeclared (first use this function)" + }, + { + "line": 1582, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1582, + "message": "request for member `unk28' in something not a structure or union" + }, + { + "line": 1583, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1583, + "message": "request for member `unk28' in something not a structure or union" + }, + { + "line": 1588, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1588, + "message": "request for member `unk28' in something not a structure or union" + }, + { + "line": 1594, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1594, + "message": "request for member `unk2C' in something not a structure or union" + }, + { + "line": 1598, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1598, + "message": "request for member `unk2C' in something not a structure or union" + }, + { + "line": 1602, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1602, + "message": "request for member `unk8' in something not a structure or union" + }, + { + "line": 1603, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1603, + "message": "request for member `unk8' in something not a structure or union" + }, + { + "line": 1604, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1604, + "message": "request for member `unk7C' in something not a structure or union" + } + ], + "severe_errors": [], + "functions": [ + "func_800A2894", + "func_800A4350", + "func_800A4860", + "func_800A4954", + "func_800A5EB0", + "func_800A7560", + "func_800A8424", + "func_800ADD2C", + "func_800AF874", + "func_800B10B4", + "func_800B16D0", + "func_800B2A2C", + "func_800B2EBC" + ], + "recommendation": "recommend_revert" + }, + "src/field/field.c": { + "exists": true, + "ok": false, + "errors": [ + { + "line": 162, + "message": "default label not within a switch statement" + }, + { + "line": 220, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 220, + "message": "request for member `unk15' in something not a structure or union" + }, + { + "line": 317, + "message": "request for member `unk2' in something not a structure or union" + }, + { + "line": 318, + "message": "request for member `unk3' in something not a structure or union" + }, + { + "line": 375, + "message": "warning: assignment makes pointer from integer without a cast" + }, + { + "line": 376, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 376, + "message": "request for member `unk1C' in something not a structure or union" + }, + { + "line": 378, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 378, + "message": "request for member `unk7' in something not a structure or union" + }, + { + "line": 379, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 379, + "message": "request for member `unk2F' in something not a structure or union" + }, + { + "line": 381, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 381, + "message": "request for member `unk3' in something not a structure or union" + }, + { + "line": 382, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 382, + "message": "request for member `unk2B' in something not a structure or union" + }, + { + "line": 383, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 383, + "message": "request for member `unk2E' in something not a structure or union" + }, + { + "line": 384, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 384, + "message": "request for member `unk6' in something not a structure or union" + }, + { + "line": 385, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 385, + "message": "request for member `unk2D' in something not a structure or union" + }, + { + "line": 386, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 386, + "message": "request for member `unk5' in something not a structure or union" + }, + { + "line": 387, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 387, + "message": "request for member `unk2C' in something not a structure or union" + }, + { + "line": 388, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 388, + "message": "request for member `unk4' in something not a structure or union" + }, + { + "line": 389, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 389, + "message": "request for member `unk36' in something not a structure or union" + }, + { + "line": 390, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 390, + "message": "request for member `unkE' in something not a structure or union" + }, + { + "line": 391, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 391, + "message": "request for member `unk3E' in something not a structure or union" + }, + { + "line": 392, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 392, + "message": "request for member `unk16' in something not a structure or union" + }, + { + "line": 393, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 393, + "message": "request for member `unk50' in something not a structure or union" + }, + { + "line": 394, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 394, + "message": "request for member `unk52' in something not a structure or union" + }, + { + "line": 395, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 395, + "message": "request for member `unk54' in something not a structure or union" + }, + { + "line": 396, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 396, + "message": "request for member `unk7' in something not a structure or union" + }, + { + "line": 396, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 396, + "message": "request for member `unk7' in something not a structure or union" + }, + { + "line": 397, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 397, + "message": "request for member `unk2F' in something not a structure or union" + }, + { + "line": 397, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 397, + "message": "request for member `unk2F' in something not a structure or union" + }, + { + "line": 400, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 400, + "message": "request for member `unk5A' in something not a structure or union" + }, + { + "line": 401, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 401, + "message": "request for member `unk58' in something not a structure or union" + }, + { + "line": 564, + "message": "request for member `unk4' in something not a structure or union" + }, + { + "line": 892, + "message": "warning: comparison between pointer and integer" + }, + { + "line": 910, + "message": "warning: comparison between pointer and integer" + }, + { + "line": 936, + "message": "`Savemap' undeclared (first use this function)" + }, + { + "line": 936, + "message": "(Each undeclared identifier is reported only once" + }, + { + "line": 936, + "message": "for each function it appears in.)" + }, + { + "line": 947, + "message": "`Savemap' undeclared (first use this function)" + }, + { + "line": 953, + "message": "warning: type mismatch with previous external decl" + }, + { + "line": 953, + "message": "warning: type mismatch with previous implicit declaration" + }, + { + "line": 948, + "message": "warning: previous implicit declaration of `func_800CF66C'" + }, + { + "line": 953, + "message": "warning: `func_800CF66C' was previously implicitly declared to return `int'" + }, + { + "line": 961, + "message": "warning: assignment makes integer from pointer without a cast" + }, + { + "line": 963, + "message": "invalid type argument of `unary *'" + }, + { + "line": 975, + "message": "warning: type mismatch with previous external decl" + }, + { + "line": 975, + "message": "warning: type mismatch with previous implicit declaration" + }, + { + "line": 949, + "message": "warning: previous implicit declaration of `func_800CF6C0'" + }, + { + "line": 975, + "message": "warning: `func_800CF6C0' was previously implicitly declared to return `int'" + }, + { + "line": 983, + "message": "warning: assignment makes integer from pointer without a cast" + }, + { + "line": 986, + "message": "invalid type argument of `unary *'" + } + ], + "severe_errors": [], + "functions": [ + "func_800A2F78", + "func_800A4094", + "func_800A4134", + "func_800A4430", + "func_800A65A4", + "func_800AA32C", + "func_800AB2B4", + "func_800ABF0C", + "func_800AFDE4", + "func_800B69C0", + "func_800BC338", + "func_800BEAD4", + "func_800C0DE0", + "func_800C32CC", + "func_800C43C4", + "func_800C46A4", + "func_800C4AE8", + "func_800C4C9C", + "func_800C4CE8", + "func_800C5740", + "func_800CB450", + "func_800CB660", + "func_800CC284", + "func_800CC404", + "func_800CC70C", + "func_800CC944", + "func_800CCA68", + "func_800CD0C4", + "func_800CD16C", + "func_800CD214", + "func_800CD6B0", + "func_800CEB94", + "func_800CF4CC", + "func_800CF5A0", + "func_800CF60C", + "func_800CF66C", + "func_800CF6C0", + "func_800CF874", + "func_800CFC1C", + "func_800D298C", + "func_800D3E64", + "func_800D4160", + "func_800D4378", + "func_800D4420", + "func_800D85C0", + "func_800DA124", + "func_800DA2CC", + "func_800DA310", + "func_800DA334", + "func_800DA368", + "func_800DA3C4", + "func_800DA3F0", + "func_800DA480" + ], + "recommendation": "recommend_revert" + }, + "src/battle/battle1.c": { + "exists": true, + "ok": false, + "errors": [ + { + "line": 207, + "message": "`D_800F8384' undeclared (first use this function)" + }, + { + "line": 207, + "message": "(Each undeclared identifier is reported only once" + }, + { + "line": 207, + "message": "for each function it appears in.)" + }, + { + "line": 209, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 209, + "message": "request for member `unk4' in something not a structure or union" + }, + { + "line": 210, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 210, + "message": "request for member `unk8' in something not a structure or union" + }, + { + "line": 212, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 212, + "message": "request for member `unk2' in something not a structure or union" + }, + { + "line": 213, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 213, + "message": "request for member `unk4' in something not a structure or union" + }, + { + "line": 214, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 214, + "message": "request for member `unk6' in something not a structure or union" + }, + { + "line": 215, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 215, + "message": "request for member `unk8' in something not a structure or union" + }, + { + "line": 216, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 216, + "message": "request for member `unkA' in something not a structure or union" + }, + { + "line": 217, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 217, + "message": "request for member `unk0' in something not a structure or union" + }, + { + "line": 218, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 218, + "message": "request for member `unkC' in something not a structure or union" + }, + { + "line": 220, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 220, + "message": "request for member `unkE' in something not a structure or union" + }, + { + "line": 221, + "message": "warning: assignment from incompatible pointer type" + }, + { + "line": 223, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 223, + "message": "request for member `unk10' in something not a structure or union" + }, + { + "line": 225, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 225, + "message": "request for member `unk64' in something not a structure or union" + }, + { + "line": 227, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 227, + "message": "request for member `unk44' in something not a structure or union" + }, + { + "line": 240, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 240, + "message": "request for member `unk4C' in something not a structure or union" + }, + { + "line": 242, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 242, + "message": "request for member `unk58' in something not a structure or union" + }, + { + "line": 252, + "message": "`D_80163F34' undeclared (first use this function)" + }, + { + "line": 257, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 257, + "message": "request for member `unk12' in something not a structure or union" + }, + { + "line": 611, + "message": "warning: passing arg 2 of `func_800D29D4' from incompatible pointer type" + }, + { + "line": 623, + "message": "warning: type mismatch with previous external decl" + }, + { + "line": 623, + "message": "warning: type mismatch with previous implicit declaration" + }, + { + "line": 251, + "message": "warning: previous implicit declaration of `func_800BB67C'" + }, + { + "line": 623, + "message": "warning: `func_800BB67C' was previously implicitly declared to return `int'" + }, + { + "line": 1132, + "message": "conflicting types for `D_800F9DA8'" + }, + { + "line": 1140, + "message": "subscripted value is neither array nor pointer" + }, + { + "line": 1216, + "message": "warning: type mismatch with previous implicit declaration" + }, + { + "line": 1208, + "message": "warning: previous implicit declaration of `func_800C74A4'" + }, + { + "line": 1216, + "message": "warning: `func_800C74A4' was previously implicitly declared to return `int'" + }, + { + "line": 1216, + "message": "warning: `func_800C74A4' was declared implicitly `extern' and later `static'" + } + ], + "severe_errors": [], + "functions": [ + "func_800B4E30", + "func_800B5AAC", + "func_800B7DB4", + "func_800B8944", + "func_800B8E48", + "func_800BBF7C", + "func_800BFB88", + "func_800C3068", + "func_800C3CA8", + "func_800C3DE4", + "func_800C428C", + "func_800C4814", + "func_800C5694", + "func_800C7220", + "func_800C7340" + ], + "recommendation": "recommend_revert" + }, + "src/world/world2.c": { + "exists": true, + "ok": true, + "errors": [], + "severe_errors": [], + "functions": [ + "func_800BFCAC", + "func_800C02F4", + "func_800C1490", + "func_800C1D58", + "func_800C1FD8", + "func_800C2130", + "func_800C31F0", + "func_800C3948", + "func_800C6104" + ], + "recommendation": "no_action" + }, + "src/battle/battle2.c": { + "exists": true, + "ok": false, + "errors": [ + { + "line": 68, + "message": "warning: passing arg 3 of `func_800C7B60' makes pointer from integer without a cast" + }, + { + "line": 79, + "message": "warning: passing arg 3 of `func_800C7BE8' makes pointer from integer without a cast" + }, + { + "line": 178, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 178, + "message": "request for member `unk0' in something not a structure or union" + }, + { + "line": 179, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 179, + "message": "request for member `unk4' in something not a structure or union" + }, + { + "line": 190, + "message": "invalid operands to binary -" + }, + { + "line": 423, + "message": "warning: assignment makes pointer from integer without a cast" + }, + { + "line": 1336, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1336, + "message": "request for member `unkC' in something not a structure or union" + }, + { + "line": 1336, + "message": "warning: dereferencing `void *' pointer" + }, + { + "line": 1336, + "message": "request for member `unk4' in something not a structure or union" + }, + { + "line": 1351, + "message": "structure has no member named `unk4'" + }, + { + "line": 1352, + "message": "structure has no member named `unk4'" + }, + { + "line": 1401, + "message": "warning: cast from pointer to integer of different size" + }, + { + "line": 1408, + "message": "warning: cast from pointer to integer of different size" + }, + { + "line": 1435, + "message": "parse error before `value1'" + }, + { + "line": 1439, + "message": "parse error before `value2'" + }, + { + "line": 1441, + "message": "`value1' undeclared (first use this function)" + }, + { + "line": 1441, + "message": "(Each undeclared identifier is reported only once" + }, + { + "line": 1441, + "message": "for each function it appears in.)" + }, + { + "line": 1441, + "message": "`value2' undeclared (first use this function)" + }, + { + "line": 1491, + "message": "warning: passing arg 2 of `func_800D54EC' from incompatible pointer type" + }, + { + "line": 1501, + "message": "warning: passing arg 1 of `func_800BBEAC' makes pointer from integer without a cast" + }, + { + "line": 1614, + "message": "`func_800D7888' undeclared (first use this function)" + } + ], + "severe_errors": [], + "functions": [ + "func_800C7C4C", + "func_800CD860", + "func_800CEB48", + "func_800D0958", + "func_800D09D0", + "func_800D1530", + "func_800D29D4", + "func_800D32B4", + "func_800D3354", + "func_800D3418", + "func_800D3474", + "func_800D3548", + "func_800D3A6C", + "func_800D3BF0", + "func_800D41FC", + "func_800D4284", + "func_800D44E8", + "func_800D491C", + "func_800D4FA8", + "func_800D4FF0", + "func_800D51D4", + "func_800D5230", + "func_800D55A4", + "func_800D5774", + "func_800D57C0", + "func_800D5B6C", + "func_800D61AC", + "func_800D6260", + "func_800D6394", + "func_800D6998", + "func_800D6ACC", + "func_800D6D8C", + "func_800D70C0", + "func_800D72B4", + "func_800D7368", + "func_800D7724", + "func_800D7888", + "func_800D7B1C", + "func_800D7BA4", + "func_800D7C2C", + "func_800D8304", + "func_800D83A4", + "func_800D8468", + "func_800D84F8", + "func_800D87EC" + ], + "recommendation": "recommend_revert" + }, + "src/battle/battle3.c": { + "exists": true, + "ok": false, + "errors": [ + { + "line": 212, + "message": "`D_80158CFC' undeclared (first use this function)" + }, + { + "line": 212, + "message": "(Each undeclared identifier is reported only once" + }, + { + "line": 212, + "message": "for each function it appears in.)" + }, + { + "line": 237, + "message": "`D_800F38A6' undeclared (first use this function)" + }, + { + "line": 251, + "message": "`D_80151698' undeclared (first use this function)" + }, + { + "line": 267, + "message": "`D_800F38A6' used prior to declaration" + }, + { + "line": 273, + "message": "`D_80151698' used prior to declaration" + }, + { + "line": 967, + "message": "warning: assignment from incompatible pointer type" + }, + { + "line": 969, + "message": "warning: assignment from incompatible pointer type" + }, + { + "line": 1121, + "message": "`D_80158CFC' used prior to declaration" + }, + { + "line": 1233, + "message": "`saved_reg_s0' undeclared (first use this function)" + }, + { + "line": 1442, + "message": "request for member `unk148' in something not a structure or union" + }, + { + "line": 1466, + "message": "request for member `unk148' in something not a structure or union" + } + ], + "severe_errors": [], + "functions": [ + "func_800D8A88", + "func_800DCFD4", + "func_800DDCE8", + "func_800DDFEC", + "func_800DEC10", + "func_800E0E34", + "func_800E1C40", + "func_800E2098", + "func_800E6018", + "func_800E68B4", + "func_800E6B94", + "func_800E7170" + ], + "recommendation": "recommend_revert" + }, + "src/menu/bginmenu.c": { + "exists": true, + "ok": false, + "errors": [ + { + "line": 140, + "message": "warning: assignment from incompatible pointer type" + }, + { + "line": 141, + "message": "warning: assignment from incompatible pointer type" + }, + { + "line": 143, + "message": "aggregate value used where an integer was expected" + }, + { + "line": 147, + "message": "incompatible types in assignment" + }, + { + "line": 340, + "message": "warning: assignment from incompatible pointer type" + } + ], + "severe_errors": [], + "functions": [ + "func_801D01C4", + "func_801D027C", + "func_801D0324", + "func_801D0408", + "func_801D0500" + ], + "recommendation": "recommend_fix" + }, + "src/menu/savemenu.c": { + "exists": true, + "ok": true, + "errors": [], + "severe_errors": [], + "functions": [ + "func_801D1F40" + ], + "recommendation": "no_action" + } +} \ No newline at end of file diff --git a/automation/database.py b/automation/database.py new file mode 100644 index 0000000..268b76e --- /dev/null +++ b/automation/database.py @@ -0,0 +1,487 @@ +""" +Database module for tracking decompilation progress. + +This uses SQLite (zero setup required) to store: +- Which functions exist in the codebase +- Their current status (todo, in_progress, decompiled, etc.) +- Metadata like file paths, modules, difficulty scores +""" + +import sqlite3 +import os +from pathlib import Path +from datetime import datetime +from typing import List, Dict, Optional + + +class DecompDatabase: + """Simple SQLite database for tracking decompilation functions.""" + + def __init__(self, db_path: str = "functions.db"): + """Initialize database connection and create tables if needed.""" + self.db_path = db_path + self.conn = sqlite3.connect(db_path) + self.conn.row_factory = sqlite3.Row # Return rows as dicts + self._create_tables() + self._migrate() + + def _create_tables(self): + """Create the database schema.""" + cursor = self.conn.cursor() + + # Main functions table + cursor.execute(""" + CREATE TABLE IF NOT EXISTS functions ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT UNIQUE NOT NULL, + c_file_path TEXT, + asm_file_path TEXT, + module TEXT, + status TEXT DEFAULT 'todo', + difficulty_score REAL, + line_count INTEGER, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + last_attempt_at TIMESTAMP, + attempt_count INTEGER DEFAULT 0, + notes TEXT + ) + """) + + # Index for faster queries + cursor.execute(""" + CREATE INDEX IF NOT EXISTS idx_status + ON functions(status) + """) + cursor.execute(""" + CREATE INDEX IF NOT EXISTS idx_module + ON functions(module) + """) + cursor.execute(""" + CREATE INDEX IF NOT EXISTS idx_difficulty + ON functions(difficulty_score) + """) + + # Attempt log (for tracking decompilation tries) + cursor.execute(""" + CREATE TABLE IF NOT EXISTS attempt_log ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + function_id INTEGER, + attempt_type TEXT, + success BOOLEAN, + error_message TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (function_id) REFERENCES functions(id) + ) + """) + + # Struct patterns table (for learning types across decomps) + cursor.execute(""" + CREATE TABLE IF NOT EXISTS struct_patterns ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + symbol_name TEXT UNIQUE NOT NULL, + likely_type TEXT, + base_type TEXT, + confidence REAL DEFAULT 0.0, + field_map TEXT, + seen_count INTEGER DEFAULT 1, + successful_uses INTEGER DEFAULT 0, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ) + """) + + cursor.execute(""" + CREATE INDEX IF NOT EXISTS idx_struct_symbol + ON struct_patterns(symbol_name) + """) + + cursor.execute(""" + CREATE INDEX IF NOT EXISTS idx_struct_confidence + ON struct_patterns(confidence DESC) + """) + + # Symbol usage tracking (which functions use which symbols) + cursor.execute(""" + CREATE TABLE IF NOT EXISTS symbol_usage ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + function_name TEXT NOT NULL, + symbol_name TEXT NOT NULL, + access_pattern TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (function_name) REFERENCES functions(name) + ) + """) + + cursor.execute(""" + CREATE INDEX IF NOT EXISTS idx_symbol_usage + ON symbol_usage(symbol_name) + """) + + self.conn.commit() + + def remove_functions_not_in_set(self, c_file_path: str, valid_names: set): + """ + Delete all functions from c_file_path whose names are not in valid_names. + Used to prune entries that fall below a sentinel comment in the source file. + """ + cursor = self.conn.cursor() + cursor.execute( + "SELECT name FROM functions WHERE c_file_path = ?", (c_file_path,) + ) + to_remove = [row[0] for row in cursor.fetchall() if row[0] not in valid_names] + if to_remove: + cursor.executemany( + "DELETE FROM functions WHERE name = ?", [(n,) for n in to_remove] + ) + self.conn.commit() + return to_remove + + def add_function(self, name: str, c_file_path: str, asm_file_path: str, + module: str, line_count: int = 0) -> int: + """Add a new function to the database.""" + cursor = self.conn.cursor() + try: + cursor.execute(""" + INSERT INTO functions + (name, c_file_path, asm_file_path, module, line_count) + VALUES (?, ?, ?, ?, ?) + """, (name, c_file_path, asm_file_path, module, line_count)) + self.conn.commit() + return cursor.lastrowid + except sqlite3.IntegrityError: + # Function already exists, update it instead + cursor.execute(""" + UPDATE functions + SET c_file_path = ?, asm_file_path = ?, module = ?, + line_count = ?, updated_at = CURRENT_TIMESTAMP + WHERE name = ? + """, (c_file_path, asm_file_path, module, line_count, name)) + self.conn.commit() + cursor.execute("SELECT id FROM functions WHERE name = ?", (name,)) + return cursor.fetchone()[0] + + def get_function(self, name: str) -> Optional[Dict]: + """Get a single function by name.""" + cursor = self.conn.cursor() + cursor.execute("SELECT * FROM functions WHERE name = ?", (name,)) + row = cursor.fetchone() + return dict(row) if row else None + + def update_status(self, name: str, status: str, notes: str = None): + """Update the status of a function (does NOT increment attempt_count).""" + cursor = self.conn.cursor() + cursor.execute(""" + UPDATE functions + SET status = ?, notes = ?, updated_at = CURRENT_TIMESTAMP + WHERE name = ? + """, (status, notes, name)) + self.conn.commit() + + def record_decompilation_attempt(self, name: str, status: str, notes: str = None): + """Record an actual decompilation attempt (increments attempt_count).""" + cursor = self.conn.cursor() + cursor.execute(""" + UPDATE functions + SET status = ?, notes = ?, updated_at = CURRENT_TIMESTAMP, + last_attempt_at = CURRENT_TIMESTAMP, + attempt_count = attempt_count + 1 + WHERE name = ? + """, (status, notes, name)) + self.conn.commit() + + def update_function_status(self, name: str, status: str, notes: str = None): + """Alias for update_status for compatibility.""" + self.update_status(name, status, notes) + + def get_functions_by_status(self, status: str, limit: Optional[int] = None, + module: Optional[str] = None, + order_by: str = 'name') -> List[Dict]: + """ + Get functions with a specific status. + + Args: + status: Status to filter by + limit: Maximum number of results (None = all) + module: Optional module filter + order_by: Field to sort by (default: 'name') + """ + cursor = self.conn.cursor() + + query = "SELECT * FROM functions WHERE status = ?" + params = [status] + + if module: + query += " AND module = ?" + params.append(module) + + # Determine order + if order_by == 'line_count': + query += " ORDER BY line_count ASC, name ASC" + elif order_by == 'difficulty_score': + query += " ORDER BY difficulty_score ASC, line_count ASC, name ASC" + else: + query += f" ORDER BY {order_by} ASC" + + if limit: + query += " LIMIT ?" + params.append(limit) + + cursor.execute(query, params) + return [dict(row) for row in cursor.fetchall()] + + def get_functions_by_module(self, module: str) -> List[Dict]: + """Get all functions in a specific module.""" + cursor = self.conn.cursor() + cursor.execute(""" + SELECT * FROM functions + WHERE module = ? + ORDER BY status, name + """, (module,)) + return [dict(row) for row in cursor.fetchall()] + + def get_statistics(self) -> Dict: + """Get overall statistics about decompilation progress.""" + cursor = self.conn.cursor() + + # Total counts by status + cursor.execute(""" + SELECT status, COUNT(*) as count + FROM functions + GROUP BY status + """) + status_counts = {row['status']: row['count'] for row in cursor.fetchall()} + + # Total count + cursor.execute("SELECT COUNT(*) as total FROM functions") + total = cursor.fetchone()['total'] + + # Counts by module + cursor.execute(""" + SELECT module, COUNT(*) as count + FROM functions + GROUP BY module + ORDER BY count DESC + """) + module_counts = {row['module']: row['count'] for row in cursor.fetchall()} + + return { + 'total': total, + 'total_functions': total, # Keep both for compatibility + 'by_status': status_counts, + 'by_module': module_counts + } + + def get_next_todo(self, limit: int = 10) -> List[Dict]: + """Get the next functions to work on (todo status, ordered by difficulty). + + Functions with a rank score (from ``mako.sh rank``) come first, sorted + easiest-to-hardest. Functions without a score fall back to line_count. + """ + cursor = self.conn.cursor() + cursor.execute(""" + SELECT * FROM functions + WHERE status = 'todo' + ORDER BY + CASE WHEN difficulty_score IS NULL THEN 1 ELSE 0 END ASC, + difficulty_score ASC, + line_count ASC, + name ASC + LIMIT ? + """, (limit,)) + return [dict(row) for row in cursor.fetchall()] + + def update_rank_scores(self, scores: Dict[str, float]) -> int: + """Bulk-update difficulty_score from mako.sh rank output. + + Args: + scores: Mapping of function_name → rank score (0.0 easiest, 1.0 hardest). + + Returns: + Number of rows updated. + """ + if not scores: + return 0 + cursor = self.conn.cursor() + updated = 0 + for name, score in scores.items(): + cursor.execute( + "UPDATE functions SET difficulty_score = ?, updated_at = CURRENT_TIMESTAMP " + "WHERE name = ?", + (score, name), + ) + updated += cursor.rowcount + self.conn.commit() + return updated + + def _migrate(self): + """Apply any schema migrations needed for existing databases.""" + cursor = self.conn.cursor() + # Ensure difficulty_score column exists (older DBs may pre-date it). + cursor.execute("PRAGMA table_info(functions)") + cols = {row['name'] for row in cursor.fetchall()} + if 'difficulty_score' not in cols: + cursor.execute("ALTER TABLE functions ADD COLUMN difficulty_score REAL") + self.conn.commit() + + def close(self): + """Close database connection.""" + self.conn.close() + + # ============================================================ + # Struct Learning Methods + # ============================================================ + + def record_struct_usage(self, function_name: str, symbol_name: str, + access_pattern: str = None): + """Record that a function uses a particular symbol/struct.""" + cursor = self.conn.cursor() + cursor.execute(""" + INSERT INTO symbol_usage (function_name, symbol_name, access_pattern) + VALUES (?, ?, ?) + """, (function_name, symbol_name, access_pattern)) + self.conn.commit() + + def learn_struct_pattern(self, symbol_name: str, likely_type: str = None, + field_map: Dict = None, confidence: float = 0.5): + """ + Learn or update a struct pattern from a successful decompilation. + + Args: + symbol_name: Symbol like 'D_800F83D0' + likely_type: Type name like 'Unk800F83D0' or 'BattleStruct' + field_map: Dict of {offset: (field_name, field_type)} + confidence: 0.0-1.0 confidence score + """ + import json + cursor = self.conn.cursor() + + field_map_json = json.dumps(field_map) if field_map else None + + # Check if we already have this symbol + cursor.execute(""" + SELECT seen_count, confidence FROM struct_patterns + WHERE symbol_name = ? + """, (symbol_name,)) + existing = cursor.fetchone() + + if existing: + # Update existing pattern (increase confidence with more sightings) + new_seen = existing['seen_count'] + 1 + # Weighted average of confidence + new_confidence = (existing['confidence'] * existing['seen_count'] + confidence) / new_seen + + cursor.execute(""" + UPDATE struct_patterns + SET likely_type = COALESCE(?, likely_type), + field_map = COALESCE(?, field_map), + confidence = ?, + seen_count = ?, + updated_at = CURRENT_TIMESTAMP + WHERE symbol_name = ? + """, (likely_type, field_map_json, new_confidence, new_seen, symbol_name)) + else: + # Insert new pattern + cursor.execute(""" + INSERT INTO struct_patterns + (symbol_name, likely_type, field_map, confidence) + VALUES (?, ?, ?, ?) + """, (symbol_name, likely_type, field_map_json, confidence)) + + self.conn.commit() + + def get_known_type(self, symbol_name: str, min_confidence: float = 0.3) -> Optional[Dict]: + """ + Get known type information for a symbol. + + Returns: + Dict with 'likely_type', 'field_map', 'confidence' if known, else None + """ + import json + cursor = self.conn.cursor() + cursor.execute(""" + SELECT likely_type, field_map, confidence, seen_count + FROM struct_patterns + WHERE symbol_name = ? AND confidence >= ? + """, (symbol_name, min_confidence)) + + row = cursor.fetchone() + if not row: + return None + + return { + 'likely_type': row['likely_type'], + 'field_map': json.loads(row['field_map']) if row['field_map'] else {}, + 'confidence': row['confidence'], + 'seen_count': row['seen_count'] + } + + def get_all_known_types(self, min_confidence: float = 0.3) -> Dict[str, Dict]: + """Get all known struct patterns above confidence threshold.""" + import json + cursor = self.conn.cursor() + cursor.execute(""" + SELECT symbol_name, likely_type, field_map, confidence, seen_count + FROM struct_patterns + WHERE confidence >= ? + ORDER BY confidence DESC, seen_count DESC + """, (min_confidence,)) + + return { + row['symbol_name']: { + 'likely_type': row['likely_type'], + 'field_map': json.loads(row['field_map']) if row['field_map'] else {}, + 'confidence': row['confidence'], + 'seen_count': row['seen_count'] + } + for row in cursor.fetchall() + } + + def get_functions_using_symbol(self, symbol_name: str) -> List[str]: + """Get list of functions that reference a symbol.""" + cursor = self.conn.cursor() + cursor.execute(""" + SELECT DISTINCT function_name + FROM symbol_usage + WHERE symbol_name = ? + """, (symbol_name,)) + return [row['function_name'] for row in cursor.fetchall()] + + def mark_struct_success(self, symbol_name: str): + """Increment successful use counter for a struct pattern.""" + cursor = self.conn.cursor() + cursor.execute(""" + UPDATE struct_patterns + SET successful_uses = successful_uses + 1, + confidence = MIN(1.0, confidence + 0.05) + WHERE symbol_name = ? + """, (symbol_name,)) + self.conn.commit() + + def get_struct_learning_stats(self) -> Dict: + """Get statistics on struct learning.""" + cursor = self.conn.cursor() + + cursor.execute("SELECT COUNT(*) as total FROM struct_patterns") + total = cursor.fetchone()['total'] + + cursor.execute(""" + SELECT COUNT(*) as high_conf + FROM struct_patterns + WHERE confidence >= 0.7 + """) + high_conf = cursor.fetchone()['high_conf'] + + cursor.execute(""" + SELECT COUNT(*) as medium_conf + FROM struct_patterns + WHERE confidence >= 0.3 AND confidence < 0.7 + """) + medium_conf = cursor.fetchone()['medium_conf'] + + return { + 'total_patterns': total, + 'high_confidence': high_conf, + 'medium_confidence': medium_conf, + 'low_confidence': total - high_conf - medium_conf + } diff --git a/automation/decomp.db b/automation/decomp.db new file mode 100644 index 0000000..0eaddbb Binary files /dev/null and b/automation/decomp.db differ diff --git a/automation/decompile.py b/automation/decompile.py new file mode 100755 index 0000000..48a4fa5 --- /dev/null +++ b/automation/decompile.py @@ -0,0 +1,1191 @@ +#!/usr/bin/env python3 +""" +Automated Decompilation Runner + +Orchestrates the decompilation process: +1. Picks functions from the database (easiest first) +2. Runs ./mako.sh dec +3. Updates database with results +4. Optionally verifies the decompilation +5. Handles errors gracefully + +Usage: + python decompile.py --auto # Process next function + python decompile.py --auto --batch 10 # Process 10 functions + python decompile.py --auto --verify # Auto-verify after decompilation + python decompile.py --function func_800A1158 # Specific function + python decompile.py --status # Show decompilation progress +""" + +import subprocess +import argparse +import sys +import re +import json +from pathlib import Path +from datetime import datetime +from typing import Optional, Tuple, Dict +from database import DecompDatabase + +# Project root is one level up from automation/ +PROJECT_ROOT = Path(__file__).parent.parent +MAKO_SCRIPT = PROJECT_ROOT / "mako.sh" + +# Validation errors that represent m2c artifacts that are syntactically valid C and +# can be fixed without reverting the decompiled code. Functions that fail only with +# one of these errors are kept in the source file and marked 'decompiled_needs_refine' +# instead of being reverted to INCLUDE_ASM and marked 'blocked'. +# +# Hard errors (still revert → blocked): +# M2C_ERROR(), Decompilation failure:, INCLUDE_ASM still present, void*/sp pointer, +# saved_reg_ra, missing jr $ra, internal error traceback, func_XXXX as integer, +# PSY-Q compilation failed, negative-offset unk-N field, C99 mid-block declaration. + +# Base set: always treated as soft (code compiles, just needs renaming/casting). +BASE_SOFT_VALIDATION_ERRORS = ( + # saved_reg_s0..s7, saved_reg_v0, etc. — valid C identifiers, code compiles, + # just needs the variables renamed to something meaningful. + "saved_reg_", + # (unaligned type) casts — compile fine, just need a cast substitution. + "unaligned type", +) + +# Extended set (used by default): additionally treats '?' type-unknown artifacts as +# soft errors so that functions are kept as decompiled_needs_refine rather than +# being immediately reverted to INCLUDE_ASM. Pass --strict-validation to agent.py +# to use only BASE_SOFT_VALIDATION_ERRORS and revert these functions instead. +SOFT_VALIDATION_ERRORS = BASE_SOFT_VALIDATION_ERRORS + ( + # Unknown '?' type markers — m2c could not infer a type; the surrounding code + # structure is intact and the issue is purely a missing type annotation. + "pointer to unknown type", + "unknown parameter type", + "unknown variable type", + "unknown type marker", + "unknown return type", + "'?' type in cast expression", +) + + +class DecompilationRunner: + """Automates running mako.sh dec and tracking results.""" + + def __init__(self, db: DecompDatabase, verbose: bool = False, enable_llm_fixes: bool = False, + build_verifier=None, fix_structs: bool = False, strict_validation: bool = False): + self.db = db + self.verbose = verbose + self.enable_llm_fixes = enable_llm_fixes + # Optional BuildVerifier for per-file PSY-Q compilation check + self.build_verifier = build_verifier + # Pass --fix-structs to mako.sh dec (replaces D_8009XXXX with Savemap fields) + self.fix_structs = fix_structs + # Strict mode: only BASE_SOFT_VALIDATION_ERRORS are treated as soft. + # Default (False) uses the extended SOFT_VALIDATION_ERRORS set which also + # keeps '?' type-unknown functions as decompiled_needs_refine. + self.soft_errors = BASE_SOFT_VALIDATION_ERRORS if strict_validation else SOFT_VALIDATION_ERRORS + + # Optional LLM support for auto-fixing + self.llm = None + if enable_llm_fixes: + try: + from llm_helper import LLMHelper + self.llm = LLMHelper(verbose=verbose) + if not self.llm.available: + if verbose: + print("⚠️ LLM requested but not available, continuing without auto-fix") + self.llm = None + except ImportError: + if verbose: + print("⚠️ LLMHelper not available, continuing without auto-fix") + self.llm = None + + def run_mako_dec(self, function_name: str) -> Tuple[bool, str, str]: + """ + Run ./mako.sh dec + + Returns: + (success, stdout, stderr) tuple + """ + if not MAKO_SCRIPT.exists(): + return False, "", f"mako.sh not found at {MAKO_SCRIPT}" + + cmd = [str(MAKO_SCRIPT), "dec", function_name] + if self.fix_structs: + cmd.append("--fix-structs") + + if self.verbose: + print(f"Running: {' '.join(cmd)}") + + try: + result = subprocess.run( + cmd, + cwd=PROJECT_ROOT, + capture_output=True, + text=True, + timeout=60 # 60 second timeout + ) + + success = result.returncode == 0 + return success, result.stdout, result.stderr + + except subprocess.TimeoutExpired: + return False, "", "Command timed out after 60 seconds" + except Exception as e: + return False, "", f"Exception running command: {str(e)}" + + def validate_c_file(self, c_file_path: Path, function_name: str, original_content: Optional[str] = None) -> Tuple[bool, Optional[str]]: + """ + Validate the C file after decompilation to catch m2c failures. + + Checks both function-specific issues and file-wide pollution from m2c errors. + + Returns: + (is_valid, error_message) tuple + """ + if not c_file_path.exists(): + return False, "C file not found" + + try: + content = c_file_path.read_text() + + # File-wide check: Did m2c add decompilation failure comments? + # These appear when m2c can't parse external declarations + if "Decompilation failure:" in content: + if original_content: + old_failure_count = original_content.count("Decompilation failure:") + new_failure_count = content.count("Decompilation failure:") + if new_failure_count > old_failure_count: + return False, f"m2c added {new_failure_count - old_failure_count} decompilation failure comment(s) (dependency issues)" + else: + return False, "Contains 'Decompilation failure' marker from m2c" + + # Primary check: Is INCLUDE_ASM still present for THIS specific function? + # If mako.sh dec succeeded, it should have replaced INCLUDE_ASM with actual C code + include_asm_pattern = rf'INCLUDE_ASM\s*\([^,]*,\s*"[^"]*",\s*{re.escape(function_name)}' + if re.search(include_asm_pattern, content): + return False, "INCLUDE_ASM still present (decompilation incomplete)" + + # Sanity check: the function name must appear as a definition in the file. + # Catches LLM hallucinations where the function was renamed or completely + # replaced with a fabricated stub under a different name. + func_def_pattern = rf'\b{re.escape(function_name)}\s*\(' + if not re.search(func_def_pattern, content): + return False, f"Function '{function_name}' not found as a definition after decompilation (LLM may have renamed it)" + + # ENHANCED: Hard structural checks run first (before any soft/? checks). + # These detect type-safety violations that produce incorrect runtime behaviour + # and must NOT be masked by a preceding soft-error short-circuit. + + # Helper: given a position in content, return the position of the closing '}' + # that ends the innermost enclosing function body. Returns len(content) if not + # found. Strips string literals and comments before counting braces so that + # '{'/'}' characters inside them don't skew the depth counter. + def _find_function_end(text, decl_pos): + # Replace string/char literals and comments with same-length whitespace + # so that character offsets stay valid after the substitution. + _clean = re.sub(r'"(?:[^"\\]|\\.)*"', + lambda m: ' ' * len(m.group()), text) + _clean = re.sub(r"'(?:[^'\\]|\\.)*'", + lambda m: ' ' * len(m.group()), _clean) + _clean = re.sub(r'//[^\n]*', + lambda m: ' ' * len(m.group()), _clean) + _clean = re.sub(r'/\*.*?\*/', + lambda m: ' ' * len(m.group()), _clean, + flags=re.DOTALL) + depth = 0 + for i in range(decl_pos): + if _clean[i] == '{': depth += 1 + elif _clean[i] == '}': depth -= 1 + target = max(1, depth) + for i in range(decl_pos, len(_clean)): + if _clean[i] == '{': + depth += 1 + elif _clean[i] == '}': + depth -= 1 + if depth < target: + return i + 1 + return len(text) + + # H1. void* LOCAL variables / parameters accessing struct fields via -> + # m2c sometimes fails to infer the actual struct type, leaving variables + # typed as void*. This produces type-unsafe code that compiles under old + # GCC but is semantically wrong — it must be a hard reject. + _VOID_PTR_RE = re.compile(r'\bvoid\s*\*\s*(\w+)\s*[;,=]') + for _vm in _VOID_PTR_RE.finditer(content): + _void_var = _vm.group(1) + _func_end = _find_function_end(content, _vm.start()) + _scope = content[_vm.start():_func_end] + if re.search(rf'\b{re.escape(_void_var)}\s*->', _scope): + return False, f"Local variable '{_void_var}' is void* but used with -> (m2c struct type inference failure)" + + # H2. Primitive pointer types used with ->unk* field access. + # Legitimate struct pointers use named fields; ->unkN means m2c couldn't + # determine the struct type and left the variable as s32*/u8* etc. + _PRIM_PTR_RE = re.compile( + r'\b(?:s8|s16|s32|s64|u8|u16|u32|u64|f32|f64)\s*\*\s*(\w+)\s*[;,=]' + ) + for _m in _PRIM_PTR_RE.finditer(content): + _prim_var = _m.group(1) + _func_end = _find_function_end(content, _m.start()) + _scope = content[_m.start():_func_end] + if re.search(rf'\b{re.escape(_prim_var)}\s*->unk\w*', _scope): + return False, f"Local variable '{_prim_var}' is a primitive pointer but used with ->unk (m2c struct type inference failure)" + + # ENHANCED: Check for m2c incomplete type artifacts in the entire file + # These indicate m2c lacked context to determine proper types + + # 1. Check for ? as return type: "? sprintf(s8*, s8*, s8*);" + if re.search(r'^\s*\?\s+\w+\s*\(', content, re.MULTILINE): + return False, "Contains function declaration with unknown return type '?'" + + # 2. Check for ?* pointer type: "?* var_a2_2;" + if re.search(r'\?\s*\*\s+\w+', content): + return False, "Contains pointer to unknown type '?*'" + + # 3. Check for /*?*/ unknown type comments + # m2c uses /*?*/primitive to annotate guessed primitive types on extern + # declarations (e.g. "extern /*?*/s32 D_800F9F3C;"). These are valid C + # because the comment is stripped by the preprocessor, so we allow them. + # Only flag /*?*/ that is NOT immediately followed by a known primitive. + _PRIMITIVE_PAT = (r'(?:s8|s16|s32|s64|u8|u16|u32|u64|f32|f64' + r'|char|short|int|long|float|double' + r'|unsigned|signed|void)') + _content_stripped = re.sub(r'/\*\?\*/\s*' + _PRIMITIVE_PAT, '', content) + if '/*?*/' in _content_stripped: + return False, "Contains unknown type marker /*?*/" + + # 4. Check for ? in parameter lists or declarations + # Matches: (? argname), (, ? argname), (?), (?,) etc. + # The (?:\w|\s*[,)]) ensures we catch both (? name) and (?) + if re.search(r'[,(]\s*\?\s*(?:[,)]|\w)', content): + return False, "Contains unknown parameter type '?'" + + # 5. Check for M2C_ERROR macro (unset registers, unknown instructions) + # Only match uncommented instances (not //...M2C_ERROR(...) or /* ... M2C_ERROR ... */) + if re.search(r'^(?!\s*//).*M2C_ERROR\(', content, re.MULTILINE): + return False, "Contains M2C_ERROR() macro (m2c could not determine register/instruction)" + + # 5a. Check for negative-offset field names: ->unk-N / .unk-N (m2c arithmetic error) + # These should have been fixed by intellisense_fixer.apply_all_fixes() before + # validation runs. If any remain it means the fixer was skipped or missed an + # occurrence — still reject so the file is reverted cleanly. + if re.search(r'(?:->|\.)unk-[0-9A-Fa-f]+\b', content): + return False, "Contains negative-offset field access unk-N (m2c struct offset error)" + + # 5b. Check for '?' used inside cast expressions: (?**), (?*), (? *) + # This occurs when m2c cannot determine the type in a cast context but the + # outer expression type is valid, so checks 1–4 above miss it. + if re.search(r'\(\s*\?[\s*]+\)', content): + return False, "Contains '?' type in cast expression (m2c type inference failure)" + + # 6. Check for saved_reg_ra (m2c artifact for $ra — never valid in C) + if 'saved_reg_ra' in content: + return False, "Contains saved_reg_ra (m2c return-address artifact)" + + # 7. Check for "Warning: missing \"jr $ra\"" comments injected by m2c + if re.search(r'//\s*Warning: missing "jr \$ra"', content): + return False, "Contains m2c 'missing jr $ra' warning comment" + + # 8. Check for Internal error tracebacks injected by m2c + if re.search(r'/\*\s*Internal error in function', content): + return False, "Contains m2c 'Internal error in function' traceback" + + # Extract the function body (approximately) to check for local issues + # Look for the function definition and the next few lines + func_pattern = rf'{re.escape(function_name)}\s*\([^)]*\)\s*{{[^}}]*}}' + func_match = re.search(func_pattern, content, re.DOTALL) + + if func_match: + func_body = func_match.group(0) + + # Hard checks first (must not be reordered after any soft check) + + # Check for m2c-specific error patterns in the function body + if "Decompilation failure:" in func_body: + return False, "Function contains 'Decompilation failure' marker from m2c" + + # Check for void* parameters being dereferenced — hard check, must precede + # the soft '? variable type' check below so that a function with BOTH a + # void*→struct access AND a '?' type annotation isn't mis-classified soft. + sig_match = re.search(rf'{re.escape(function_name)}\s*\(([^)]*)\)', func_body) + if sig_match: + params = sig_match.group(1) + void_ptr_params = re.findall(r'void\s*\*\s*(\w+)', params) + for param in void_ptr_params: + if re.search(rf'{re.escape(param)}\s*->', func_body): + return False, f"Parameter '{param}' is void* but accessed as struct (m2c couldn't determine type)" + + # Check for incomplete multiline comment that might indicate failure + if func_body.count("/*") != func_body.count("*/"): + return False, "Unclosed comment block (possible m2c error)" + + # Soft checks below (may produce decompiled_needs_refine state) + + # Check for (unaligned type) casts + if re.search(r'\(\s*unaligned\s+', func_body): + return False, "Contains '(unaligned type)' cast (m2c error)" + + # Check for unknown type markers in variable declarations + if re.search(r'\?\s+\w+\s*[;,=]', func_body): + return False, "Contains unknown variable type '?' (m2c cannot determine type)" + + # Check for C99-style mid-block variable declarations (PSY-Q cc1 is C89 only). + # In C89, all declarations must precede any statements in a block. + # Pattern: a type declaration appearing after any statement in the function body. + _c99_decl_re = re.compile( + r'^\s+(?:const\s+)?(?:unsigned\s+|signed\s+)?' + r'(?:u8|u16|u32|u64|s8|s16|s32|s64|f32|f64|char|short|int|long|float|double)\s*\*?\s*\w+\s*=' + ) + _found_stmt = False + for _line in func_body.split('\n'): + _stripped = _line.strip() + if not _stripped or _stripped.startswith('//') or _stripped.startswith('/*'): + continue + if _c99_decl_re.match(_line): + if _found_stmt: + return False, "Contains C99-style mid-block variable declaration (PSY-Q cc1 requires C89)" + elif _stripped.endswith(';') and not _c99_decl_re.match(_line): + _found_stmt = True + + # If we can't find the function body, that's suspicious but not necessarily invalid + # (could be a complex function or macro) + + # --- File-wide structural checks (not limited to function body) --- + + # 9 (now H1) and 10 (now H2) were moved above checks #1-8 — see the + # '_find_function_end / H1 / H2' block near the top of this function. + + # 11. Check for saved_reg_ artifacts (undeclared m2c callee-save register variables) + # saved_reg_ra is already caught above; this catches saved_reg_s0..s7, saved_reg_v0, etc. + if re.search(r'\bsaved_reg_[a-z]\d*\b', content): + return False, "Contains saved_reg_* artifact (m2c callee-save register not resolved)" + + # 12. Check for 'sp' used as dereference base (leaked stack pointer register). + # Valid uses include: &sp (taking address of local struct named 'sp'), + # sp.member (struct member access), sp10/sp14 etc. (suffixed local names). + # Bad use: sp -> field access or *(sp + offset) — sp treated as a pointer. + _content_no_comments = re.sub(r'//[^\n]*', '', content) + _content_no_comments = re.sub(r'/\*.*?\*/', '', _content_no_comments, flags=re.DOTALL) + if re.search(r'\bsp\s*->', _content_no_comments) or \ + re.search(r'\*\s*\(\s*(?:.*?[+\-]\s*)?sp\b(?!\d|\w)', _content_no_comments): + return False, "Contains 'sp' used as a pointer/dereference base (leaked PSX stack pointer register)" + + # 13. Check for func_XXXXXXXX used as an integer/data value (not a call) + # Valid: func_XXXXXXXX(args) — a call + # Bad: func_XXXXXXXX * 4, (func_XXXXXXXX + ...), &D_...[func_XXXXXXXX] + # Pattern: function name followed by arithmetic operator or used as array index, + # but NOT followed by '(' (which would be a call). + if re.search(r'\bfunc_[0-9A-Fa-f]+\s*(?:[+\-\*/%]|\[)', content): + return False, "Function name used as integer value in arithmetic (m2c function pointer / data confusion)" + + return True, None + + except Exception as e: + return False, f"Error reading C file: {e}" + + def extract_missing_types(self, c_file_path: Path, function_name: str, validation_error: str) -> Dict: + """ + Extract detailed information about missing types from the decompiled code. + This creates actionable reports for manual type definition. + + Note: Extracts ALL missing type issues from the file, not just the first validation error. + + Returns dict with: + - function_name: str + - file: str + - primary_error: str (the validation error that triggered the revert) + - missing_items: list of dicts describing what's missing + """ + report = { + 'function_name': function_name, + 'file': str(c_file_path.relative_to(PROJECT_ROOT)), + 'primary_error': validation_error, + 'missing_items': [] + } + + try: + content = c_file_path.read_text() + + # Check for ALL types of missing type issues in the file + # (not just the one that triggered validation failure) + + # 1. External functions with unknown return types (? or /*?*/) + extern_with_unknown = re.findall(r'(?:/\*\?\*/\s+)?(\w+)\s+(\w+)\s*\(([^)]*)\)\s*;?\s*//\s*extern', content) + for return_type, func_name, params in extern_with_unknown: + if '?' in return_type or '?' in params: + report['missing_items'].append({ + 'type': 'extern_function', + 'name': func_name, + 'return_type': return_type if '?' not in return_type else 'unknown', + 'parameters': params, + 'suggestion': f'Define proper signature for {func_name} in header' + }) + + # Also check for inline ? function declarations + inline_unknown = re.findall(r'^\s*\?\s+(\w+)\s*\(([^)]*)\)', content, re.MULTILINE) + for func_name, params in inline_unknown: + if func_name not in [item.get('name') for item in report['missing_items']]: + report['missing_items'].append({ + 'type': 'extern_function', + 'name': func_name, + 'return_type': 'unknown', + 'parameters': params, + 'suggestion': f'Define proper signature for {func_name} in header' + }) + + # 2. void* parameters used as structs + # Find function with void* parameters + void_ptr_params = re.findall(rf'({re.escape(function_name)})\s*\([^)]*\bvoid\s*\*\s*(\w+)[^)]*\)', content) + for func, param_name in void_ptr_params: + # Find all field accesses for this parameter + field_accesses = re.findall(rf'{re.escape(param_name)}\s*->\s*(\w+)', content) + if field_accesses: # Only report if there are actual field accesses + unique_fields = sorted(set(field_accesses)) + report['missing_items'].append({ + 'type': 'void_pointer_struct', + 'parameter_name': param_name, + 'accessed_fields': unique_fields, + 'suggestion': f'Define struct for {param_name} with fields: {", ".join(unique_fields[:10])}{"..." if len(unique_fields) > 10 else ""}' + }) + + # 3. /*?*/ markers (unknown types in comments) + comment_unknown = re.findall(r'/\*\?\*/\s*(\w+)\s+(\w+)', content) + for type_name, var_name in comment_unknown: + # Check if it's extern declaration + if re.search(rf'extern\s+/\*\?\*/\s*{re.escape(type_name)}\s+{re.escape(var_name)}', content): + report['missing_items'].append({ + 'type': 'extern_variable', + 'name': var_name, + 'declared_type': type_name, + 'suggestion': f'Unknown type for extern variable {var_name}' + }) + + # 4. ?* pointers + unknown_pointers = re.findall(r'\?\s*\*\s+(\w+)', content) + for var_name in unknown_pointers: + report['missing_items'].append({ + 'type': 'unknown_pointer', + 'name': var_name, + 'suggestion': f'm2c could not determine type of pointer {var_name}' + }) + + # 5. ? types in variable declarations + unknown_vars = re.findall(r'^\s*\?\s+(\w+)\s*[;,=]', content, re.MULTILINE) + for var_name in unknown_vars: + if var_name not in [item.get('name') for item in report['missing_items']]: + report['missing_items'].append({ + 'type': 'unknown_variable', + 'name': var_name, + 'suggestion': f'm2c could not determine type of variable {var_name}' + }) + + # 6. unaligned casts + unaligned_casts = re.findall(r'\(\s*unaligned\s+(\w+)\s*\)', content) + for type_name in set(unaligned_casts): + report['missing_items'].append({ + 'type': 'unaligned_cast', + 'cast_type': type_name, + 'suggestion': f'Unaligned access to {type_name} - may need struct packing or alignment fix' + }) + + except Exception as e: + if self.verbose: + print(f" Warning: Could not extract missing types: {e}") + + return report + + def parse_decompilation_output(self, stdout: str, stderr: str, returncode: int) -> Dict[str, any]: + """ + Parse mako.sh output to extract useful information. + + Returns dict with keys: + - success: bool + - already_decompiled: bool (if function already in C) + - error_message: str + - error_type: str (infra, compile, link, unknown) + - warnings: list of str + """ + result = { + 'success': False, + 'already_decompiled': False, + 'error_message': None, + 'error_type': 'unknown', + 'warnings': [] + } + + combined_output = stdout + "\n" + stderr + + # First check return code - if non-zero, it's a failure + if returncode != 0: + result['success'] = False + + # tools/decompile.py prints " found in " and exits 1 when the + # function already exists as C code (not as INCLUDE_ASM). This is the + # "already fully decompiled into C" case — treat it as success. + if re.search(r'\bfound in\b', combined_output): + result['already_decompiled'] = True + result['success'] = True + return result + + # Classify the error type + if "not found" in combined_output.lower(): + result['error_message'] = "Function not found" + result['error_type'] = 'infra' + elif "timeout" in combined_output.lower(): + result['error_message'] = "Command timed out" + result['error_type'] = 'infra' + elif "undefined reference" in combined_output.lower(): + # Extract undefined symbols + symbols = re.findall(r"undefined reference to `([^']+)'", combined_output) + result['error_message'] = f"Undefined references: {', '.join(symbols[:3])}" + result['error_type'] = 'link' + elif "error:" in combined_output.lower(): + # Compile error + error_lines = [line for line in combined_output.split('\n') + if 'error:' in line.lower()] + result['error_message'] = error_lines[0].strip() if error_lines else "Compile error" + result['error_type'] = 'compile' + else: + result['error_message'] = "Command failed with non-zero exit code" + result['error_type'] = 'unknown' + else: + # Return code 0 - check for success indicators + if "could not find function" in combined_output.lower(): + result['success'] = False + result['error_message'] = "Function not found in version" + result['error_type'] = 'infra' + elif re.search(r'already\s+(?:been\s+)?decompiled', combined_output, re.IGNORECASE): + result['already_decompiled'] = True + result['success'] = True + elif "decompiled in" in combined_output.lower(): + # mako.sh typically says "func_name decompiled in path/to/file.c" + result['success'] = True + elif stdout.strip() and "error" not in combined_output.lower(): + # Has output and no error mentions + result['success'] = True + else: + # Ambiguous case + result['error_message'] = "Unclear if decompilation succeeded" + result['error_type'] = 'unknown' + + return result + + def decompile_function(self, function_name: str) -> bool: + """ + Decompile a single function and update database. + + Returns: + True if decompilation succeeded, False otherwise + """ + print(f"\n{'='*60}") + print(f"Attempting to decompile: {function_name}") + print(f"{'='*60}") + + # Get function info from database + func = self.db.get_function(function_name) + if not func: + print(f"❌ Function {function_name} not found in database") + return False + + print(f"Module: {func['module']}") + # print(f"File: {func['c_file_path']}") + # print(f"ASM lines: {func['line_count']}") + print(f"Current status: {func['status']}") + + # Save original C file content before decompilation + c_file = PROJECT_ROOT / func['c_file_path'] + original_content = c_file.read_text() if c_file.exists() else None + + # PRE-DECOMPILATION TYPE INFERENCE + # If LLM is available, try to infer types for extern symbols before m2c runs + if self.llm: + try: + from dependency_analyzer import DependencyAnalyzer + analyzer = DependencyAnalyzer(PROJECT_ROOT, self.db.db_path) + + # Extract extern symbols from assembly + extern_symbols = analyzer.get_function_extern_symbols(function_name) + + if extern_symbols: + if self.verbose: + print(f"🔍 Found {len(extern_symbols)} extern symbols, inferring types...") + + # Check if we already have types for these symbols + known_types = self.db.get_all_known_types(min_confidence=0.3) + unknown_symbols = [s for s in extern_symbols if s not in known_types] + + if unknown_symbols: + if self.verbose: + print(f" 🤖 Inferring types for {len(unknown_symbols)} unknown symbols: {', '.join(list(unknown_symbols)[:3])}...") + + # Infer types from assembly + inferred = self.llm.infer_types_from_assembly(function_name, list(unknown_symbols)) + + if inferred: + # Generate header file with inferred types + temp_header = PROJECT_ROOT / "include" / "auto_types.h" + self.llm.generate_type_header(inferred, temp_header) + + # Store learned types in database + for symbol, type_info in inferred.items(): + field_map = { + offset: {'name': field[0], 'type': field[1]} + for offset, field in type_info.get('fields', {}).items() + } + self.db.learn_struct_pattern( + symbol, + likely_type=type_info.get('typedef', '').split('}')[-1].strip().rstrip(';'), + field_map=field_map, + confidence=type_info.get('confidence', 0.5) + ) + self.db.record_struct_usage(function_name, symbol) + + if self.verbose: + print(f" ✅ Generated type definitions in {temp_header}") + else: + if self.verbose: + print(f" ✅ All extern symbols have known types") + except Exception as e: + if self.verbose: + print(f" ⚠️ Type inference failed: {e}") + # Continue with decompilation anyway + + # Mark as in progress + self.db.update_function_status( + function_name, + 'in_progress', + notes="Attempting automatic decompilation" + ) + + # Run decompilation + success, stdout, stderr = self.run_mako_dec(function_name) + + if self.verbose: + print(f"\n--- STDOUT ---\n{stdout}") + print(f"\n--- STDERR ---\n{stderr}") + + # Parse output (pass returncode for better analysis) + returncode = 0 if success else 1 + parse_result = self.parse_decompilation_output(stdout, stderr, returncode) + + # Update database based on result + if parse_result['already_decompiled']: + print(f"✅ Function already decompiled!") + self.db.record_decompilation_attempt( + function_name, + 'decompiled', + notes="Already decompiled (found in C code)" + ) + return True + + elif parse_result['success']: + # Apply deterministic IntelliSense fixes (unk-N field names, typedef hoisting) + # before validation so these artifacts don't cause spurious failures. + try: + from intellisense_fixer import apply_all_fixes + except ImportError: + apply_all_fixes = None + if apply_all_fixes is not None: + raw = c_file.read_text() + fixed, changes = apply_all_fixes(raw) + if changes: + c_file.write_text(fixed) + if self.verbose: + print(f" 🔧 intellisense_fixer: {', '.join(changes)}") + + # Additional validation: check C file for m2c failures + is_valid, validation_error = self.validate_c_file(c_file, function_name, original_content) + + # If text validation passes, run the actual PSY-Q compiler on the changed file. + # This catches type errors, incompatible declarations, and other issues that + # heuristic text checks miss. Failures are treated the same as text-validation + # failures: LLM auto-fix is attempted if available, then the file is reverted. + if is_valid and self.build_verifier is not None: + compile_ok, compile_errors = self.build_verifier.check_file_compiles(c_file) + if not compile_ok: + errors_summary = "; ".join(e['message'] for e in compile_errors[:3]) + is_valid = False + validation_error = f"PSY-Q compilation failed: {errors_summary}" + if self.verbose: + print(f" Compile errors: {errors_summary}") + + if not is_valid: + print(f"⚠️ Decompilation produced invalid output: {validation_error}") + + # Attempt LLM auto-fix if enabled + llm_fixed = False + # Trigger auto-fix for multiple error types + should_try_llm_fix = self.llm and any([ + "unaligned" in validation_error.lower(), + "decompilation failure" in validation_error.lower(), + "syntax error" in validation_error.lower(), + "m2c_error" in validation_error.lower(), + "psy-q compilation failed" in validation_error.lower(), + "void*" in validation_error.lower(), + "unknown parameter type" in validation_error.lower(), + "unknown variable type" in validation_error.lower(), + "primitive pointer" in validation_error.lower(), + "function pointer" in validation_error.lower(), + "saved_reg" in validation_error.lower(), + "unaligned type" in validation_error.lower(), + "unknown type" in validation_error.lower(), + "cast expression" in validation_error.lower(), + ]) + + if should_try_llm_fix: + print(f"🤖 Attempting automatic fix with LLM...") + + # Retrieve pre-analysis from database if available + pre_analysis = None + try: + cursor = self.db.conn.cursor() + cursor.execute("SELECT notes FROM functions WHERE name = ?", (function_name,)) + row = cursor.fetchone() + if row and row['notes']: + # Try parsing as JSON first (new format) + try: + notes_data = json.loads(row['notes']) + if 'llm_analysis' in notes_data: + pre_analysis = notes_data['llm_analysis'] + print(f" 📋 Using pre-analysis: {pre_analysis['complexity']} - {pre_analysis['summary'][:50]}...") + except (json.JSONDecodeError, KeyError): + # Fall back to old string format + if 'LLM Analysis:' in row['notes']: + notes = row['notes'] + analysis_match = re.search(r'LLM Analysis: (\w+) - (.+)', notes) + if analysis_match: + pre_analysis = { + 'complexity': analysis_match.group(1), + 'summary': analysis_match.group(2), + 'c_suggestion': None + } + print(f" 📋 Using pre-analysis: {pre_analysis['complexity']} - {pre_analysis['summary'][:50]}...") + except Exception as e: + if self.verbose: + print(f" Could not retrieve pre-analysis: {e}") + + # Extract function body + try: + content = c_file.read_text() + # Find function start — handle both "type func_name(" and "func_name(" + # Use brace counting to handle nested braces correctly + func_header_pattern = rf'\b{re.escape(function_name)}\s*\(' + header_match = re.search(func_header_pattern, content) + broken_code = None + if header_match: + # Walk backwards to include return type (one line) + start = content.rfind('\n', 0, header_match.start()) + start = 0 if start == -1 else start + 1 + # Find the opening brace + brace_start = content.find('{', header_match.end()) + if brace_start != -1: + depth = 0 + i = brace_start + while i < len(content): + if content[i] == '{': + depth += 1 + elif content[i] == '}': + depth -= 1 + if depth == 0: + broken_code = content[start:i+1] + break + i += 1 + if broken_code is not None: + fix_result = self.llm.fix_m2c_error( + function_name, + broken_code, + validation_error, + pre_analysis=pre_analysis + ) + + if fix_result and fix_result['fixed_code'] and fix_result['confidence'] in ('high', 'medium'): + print(f" Confidence: {fix_result['confidence']}") + print(f" {fix_result['explanation']}") + + # Replace the function in the file + new_content = content.replace(broken_code, fix_result['fixed_code']) + c_file.write_text(new_content) + + # Re-validate + is_valid_again, validation_error_again = self.validate_c_file(c_file, function_name, original_content) + + if is_valid_again: + print(f"\u2705 LLM fix successful!") + if fix_result['confidence'] == 'high': + status = 'decompiled' + print(f" ✅ High confidence - marked as decompiled") + else: + status = 'decompiled_needs_refine' + print(f" ⚠️ Medium confidence - flagged for manual review") + + self.db.record_decompilation_attempt( + function_name, + status, + notes=f"LLM auto-fix ({fix_result['confidence']} confidence): {fix_result['explanation']}" + ) + llm_fixed = True + + # Log to audit file for manual review tracking + try: + audit_log = PROJECT_ROOT / "automation" / "llm_fixes_audit.log" + with open(audit_log, 'a') as f: + timestamp = datetime.now().isoformat() + f.write(f"{timestamp}\t{function_name}\t{c_file}\t{fix_result['confidence']}\t{validation_error}\t{fix_result['explanation']}\n") + except Exception as e: + if self.verbose: + print(f" Warning: Could not write to audit log: {e}") + + return True + else: + print(f" \u274c LLM fix didn't resolve the issue: {validation_error_again}") + else: + confidence = fix_result['confidence'] if fix_result else 'unknown' + print(f" \u274c LLM fix confidence too low ({confidence}), skipping") + except Exception as e: + print(f" \u274c LLM fix failed: {e}") + + # Extract missing types information before reverting + missing_types_report = None + try: + missing_types_report = self.extract_missing_types(c_file, function_name, validation_error) + + # Store report to JSON file + reports_file = PROJECT_ROOT / "automation" / "missing_types_reports.json" + reports = [] + + if reports_file.exists(): + try: + with open(reports_file, 'r') as f: + reports = json.load(f) + except (json.JSONDecodeError, FileNotFoundError): + reports = [] + + # Add timestamp and append + missing_types_report['timestamp'] = datetime.now().isoformat() + reports.append(missing_types_report) + + with open(reports_file, 'w') as f: + json.dump(reports, f, indent=2) + + if self.verbose and missing_types_report['missing_items']: + print(f"📊 Extracted {len(missing_types_report['missing_items'])} missing type requirements") + except Exception as e: + if self.verbose: + print(f" Warning: Could not extract missing types: {e}") + + # Determine if this is a "soft" error: the decompiled code is valid C + # but has m2c artifacts that a human (or future pass) can clean up. + # For soft errors we keep the code in the file instead of reverting. + is_soft_error = not llm_fixed and any( + pattern in validation_error for pattern in self.soft_errors + ) + + if is_soft_error: + # Keep the decompiled code — it compiles and just needs tidying. + # But first strip any extern declarations that contain '?' types: + # those are syntactically invalid and cause IntelliSense errors in + # other editors even though PSY-Q cc1 can compile past them. + _content = c_file.read_text() + _cleaned = re.sub( + r'^[^\n]*//\s*extern[^\n]*\?[^\n]*\n', + '', + _content, + flags=re.MULTILINE, + ) + # Also remove bare extern declarations with ? type markers + _cleaned = re.sub( + r'^\s*/\*\?\*/\s*\w[\w\s\*,]*\([^)]*\?[^)]*\)[^;]*;\s*//\s*extern\n', + '', + _cleaned, + flags=re.MULTILINE, + ) + if _cleaned != _content: + c_file.write_text(_cleaned) + if self.verbose: + print(f" 🧹 Stripped invalid extern declarations with '?' types from soft-error file") + print(f"📋 Soft error — keeping decompiled code, marking as needs_refine") + notes_text = f"m2c soft error (kept for manual fix): {validation_error}" + if missing_types_report and missing_types_report['missing_items']: + notes_text += f"\nMissing types tracked: {len(missing_types_report['missing_items'])} items" + self.db.record_decompilation_attempt( + function_name, + 'decompiled_needs_refine', + notes=notes_text + ) + else: + # Hard error — revert to INCLUDE_ASM and mark blocked. + if original_content and not llm_fixed: + print(f"🔄 Reverting {c_file.name} to INCLUDE_ASM (keeping file clean)") + c_file.write_text(original_content) + + notes_text = f"m2c decompilation error (reverted): {validation_error}" + if missing_types_report and missing_types_report['missing_items']: + notes_text += f"\nMissing types tracked: {len(missing_types_report['missing_items'])} items" + self.db.record_decompilation_attempt( + function_name, + 'blocked', + notes=notes_text + ) + return False + + print(f"\u2705 Decompilation successful!") + self.db.record_decompilation_attempt( + function_name, + 'decompiled', + notes="Successfully decompiled by automation" + ) + + # Mark successful use of struct patterns in learning database + try: + from dependency_analyzer import DependencyAnalyzer + analyzer = DependencyAnalyzer(PROJECT_ROOT, self.db.db_path) + extern_symbols = analyzer.get_function_extern_symbols(function_name) + + for symbol in extern_symbols: + known_type = self.db.get_known_type(symbol) + if known_type: + # This symbol's type helped with successful decompilation + self.db.mark_struct_success(symbol) + if self.verbose: + print(f" 📈 Increased confidence for {symbol} pattern") + except Exception as e: + if self.verbose: + print(f" ⚠️ Could not update struct learning: {e}") + + return True + + else: + error_msg = parse_result['error_message'] or "Unknown error" + error_type = parse_result.get('error_type', 'unknown') + print(f"❌ Decompilation failed: {error_msg}") + + # Revert to original INCLUDE_ASM to keep file clean + if original_content: + print(f"🔄 Reverting {c_file.name} to INCLUDE_ASM (keeping file clean)") + c_file.write_text(original_content) + + # Classify based on error type + if error_type in ('compile', 'link'): + # Blocking errors - likely needs manual intervention + status = 'blocked' + notes = f"Blocked by {error_type} error (reverted): {error_msg}" + else: + # Other failures - can retry + status = 'failed' + notes = f"Decompilation failed ({error_type}, reverted): {error_msg}" + + self.db.record_decompilation_attempt( + function_name, + status, + notes=notes + ) + return False + + def decompile_next_batch(self, batch_size: int = 1, module: Optional[str] = None): + """ + Decompile the next N easiest functions. + + Args: + batch_size: Number of functions to attempt + module: Optional module filter (e.g., 'battle', 'field') + """ + print(f"\n{'='*60}") + print(f"BATCH DECOMPILATION: Processing {batch_size} function(s)") + if module: + print(f"Filtering by module: {module}") + print(f"{'='*60}\n") + + # Get functions to process + functions = self.db.get_functions_by_status( + 'todo', + limit=batch_size, + module=module, + order_by='difficulty_score' # Easiest first (from mako.sh rank scores) + ) + + if not functions: + print("✅ No more functions to decompile!") + return + + print(f"Found {len(functions)} function(s) to process\n") + + success_count = 0 + failed_count = 0 + + for i, func in enumerate(functions, 1): + print(f"\n[{i}/{len(functions)}] Processing: {func['name']}") + + if self.decompile_function(func['name']): + success_count += 1 + else: + failed_count += 1 + + # Summary + print(f"\n{'='*60}") + print(f"BATCH COMPLETE") + print(f"{'='*60}") + print(f"✅ Successful: {success_count}") + print(f"❌ Failed: {failed_count}") + print(f"{'='*60}\n") + + +def show_status(db: DecompDatabase): + """Show overall decompilation progress.""" + stats = db.get_statistics() + + print("\n" + "="*60) + print("DECOMPILATION PROGRESS") + print("="*60) + + total = stats['total'] + by_status = stats['by_status'] + + # Calculate progress + verified = by_status.get('verified', 0) + decompiled = by_status.get('decompiled', 0) + needs_refine = by_status.get('decompiled_needs_refine', 0) + in_progress = by_status.get('in_progress', 0) + failed = by_status.get('failed', 0) + blocked = by_status.get('blocked', 0) + todo = by_status.get('todo', 0) + + if total > 0: + # Progress includes verified + decompiled + needs_refine + completed = verified + decompiled + needs_refine + progress_pct = (completed / total) * 100 + print(f"\nTotal Functions: {total}") + print(f"Progress: {completed}/{total} ({progress_pct:.1f}%)") + print(f"\nStatus Breakdown:") + print(f" ✅ Verified: {verified:>6}") + print(f" 🔄 Decompiled: {decompiled:>6}") + print(f" 🔧 Needs Refine: {needs_refine:>6}") + print(f" ⚙️ In Progress: {in_progress:>6}") + print(f" ⚠️ Blocked: {blocked:>6}") + print(f" ❌ Failed: {failed:>6}") + print(f" ⏳ Todo: {todo:>6}") + + # Show by module + print(f"\nBy Module:") + for module, count in stats['by_module'].items(): + print(f" {module:15s}: {count:>4}") + + print("="*60 + "\n") + + +def main(): + parser = argparse.ArgumentParser(description="Automated decompilation runner") + parser.add_argument('--auto', action='store_true', + help='Process next function(s) automatically') + parser.add_argument('--batch', type=int, default=1, + help='Number of functions to process (default: 1)') + parser.add_argument('--function', type=str, + help='Decompile a specific function by name') + parser.add_argument('--module', type=str, + help='Filter by module (e.g., battle, field)') + parser.add_argument('--status', action='store_true', + help='Show decompilation progress') + parser.add_argument('--verify', action='store_true', + help='Verify decompiled functions after completion') + parser.add_argument('--audit', action='store_true', + help='Audit existing decompiled/verified functions for m2c errors') + parser.add_argument('--llm-auto-fix', action='store_true', + help='Enable automatic LLM fixing of m2c errors (requires Ollama)') + parser.add_argument('--verbose', '-v', action='store_true', + help='Verbose output') + + args = parser.parse_args() + + # Initialize database + db_path = PROJECT_ROOT / "automation" / "functions.db" + db = DecompDatabase(str(db_path)) + runner = DecompilationRunner(db, verbose=args.verbose, enable_llm_fixes=args.llm_auto_fix) + + if args.status: + show_status(db) + + elif args.audit: + # Audit existing decompilations for m2c errors + print("\n" + "="*60) + print("AUDITING DECOMPILED FUNCTIONS") + print("="*60 + "\n") + + # Check both decompiled and verified functions + to_check = [] + to_check.extend(db.get_functions_by_status('decompiled')) + to_check.extend(db.get_functions_by_status('verified')) + + if not to_check: + print("No decompiled/verified functions to audit.") + else: + print(f"Auditing {len(to_check)} function(s)...\n") + + invalid_count = 0 + for i, func in enumerate(to_check, 1): + c_file = PROJECT_ROOT / func['c_file_path'] + is_valid, error = runner.validate_c_file(c_file, func['name'], None) + if not is_valid: + invalid_count += 1 + print(f"[{i}/{len(to_check)}] ❌ {func['name']}: {error}") + # Mark as blocked + db.update_function_status( + func['name'], + 'blocked', + notes=f"Audit found m2c error: {error}" + ) + elif args.verbose: + print(f"[{i}/{len(to_check)}] ✅ {func['name']}") + + print(f"\n{'='*60}") + print(f"Audit complete: {invalid_count} invalid decompilations found") + if invalid_count > 0: + print(f"Marked {invalid_count} function(s) as 'blocked' for manual review") + print(f"{'='*60}\n") + + elif args.function: + # Decompile specific function + success = runner.decompile_function(args.function) + + # Optionally verify + if success and args.verify: + print("\n" + "="*60) + print("Running verification...") + print("="*60) + try: + from build import BuildVerifier + verifier = BuildVerifier(db, verbose=args.verbose) + verifier.verify_decompiled_functions() + except ImportError: + print("⚠️ build.py not found, skipping verification") + + sys.exit(0 if success else 1) + + elif args.auto: + # Batch decompilation + runner.decompile_next_batch( + batch_size=args.batch, + module=args.module + ) + + # Optionally verify + if args.verify: + print("\n" + "="*60) + print("Running verification...") + print("="*60) + try: + from build import BuildVerifier + verifier = BuildVerifier(db, verbose=args.verbose) + verifier.verify_decompiled_functions() + except ImportError: + print("⚠️ build.py not found, skipping verification") + + else: + parser.print_help() + print("\nQuick examples:") + print(" python decompile.py --status") + print(" python decompile.py --auto") + print(" python decompile.py --auto --batch 10") + print(" python decompile.py --auto --verify") + print(" python decompile.py --function AverageSZ4") + + +if __name__ == '__main__': + main() diff --git a/automation/dependency_analyzer.py b/automation/dependency_analyzer.py new file mode 100644 index 0000000..7419615 --- /dev/null +++ b/automation/dependency_analyzer.py @@ -0,0 +1,1073 @@ +""" +Dependency analyzer for function call graphs. + +Analyzes assembly files to determine which functions call which other functions, +enabling dependency-aware scheduling for decompilation. +""" + +import re +import sqlite3 +from pathlib import Path +from typing import Dict, Set, List, Optional +from collections import defaultdict + + +class DependencyAnalyzer: + """Analyzes function dependencies from assembly files.""" + + def __init__(self, project_root: Path, db_path: Optional[Path] = None, + blocker_multiplier: int = 10): + self.project_root = project_root + self.asm_dir = project_root / "asm" + + # Multiplier for the "number of dependents" bonus in scoring. + # Higher values surface high-blocker functions more aggressively. + self._blocker_multiplier = blocker_multiplier + + # Database connection (optional, for sibling completion scoring) + self.db_path = db_path or (project_root / "automation" / "functions.db") + self.db_conn = None + + # Dependency graph: function_name -> set of functions it calls + self.calls: Dict[str, Set[str]] = defaultdict(set) + + # Reverse graph: function_name -> set of functions that call it + self.called_by: Dict[str, Set[str]] = defaultdict(set) + + # All known function names + self.all_functions: Set[str] = set() + + # Cache for C file completion rates + self.c_file_completion: Dict[str, float] = {} + + def analyze_asm_file(self, asm_file: Path) -> Dict[str, Set[str]]: + """ + Analyze a single assembly file to extract function calls. + + Each .s file typically contains one function. We extract: + - Function name from glabel + - All functions it calls via 'jal' instructions + + Returns: + Dict mapping function names to the set of functions they call + """ + if not asm_file.exists() or asm_file.suffix != '.s': + return {} + + try: + content = asm_file.read_text() + except: + return {} + + result = {} + + # Split into function blocks using glabel markers + # Format: glabel func_name + function_pattern = r'^\s*glabel\s+(\w+)\s*$' + + current_function = None + current_calls = set() + + for line in content.split('\n'): + # Check for function label + func_match = re.match(function_pattern, line) + if func_match: + # Save previous function + if current_function: + result[current_function] = current_calls + + # Start new function + current_function = func_match.group(1) + current_calls = set() + continue + + # Look for function calls (jal instruction) + # Format: jal func_name or /* ... */ jal func_name + if current_function: + # Match jal with optional comment before it + call_match = re.search(r'jal\s+(\w+)', line) + if call_match: + called_func = call_match.group(1) + # Filter out register names and common false positives + if not called_func.startswith('$') and not called_func in ('delay', 'nop'): + current_calls.add(called_func) + + # Save last function + if current_function: + result[current_function] = current_calls + + return result + + def build_call_graph(self, module: Optional[str] = None) -> None: + """ + Build the complete call graph from assembly files. + + Args: + module: Optional module filter (e.g., 'battle', 'world') + """ + self.calls.clear() + self.called_by.clear() + self.all_functions.clear() + + # Find all assembly files + # Structure: asm/us/MODULE/nonmatchings/**/*.s + if module: + # Look in specific module directory + search_dirs = [ + self.asm_dir / "us" / module / "nonmatchings", + ] + else: + # Look in all module directories + search_dirs = [ + self.asm_dir / "us", + ] + + asm_files = [] + for search_dir in search_dirs: + if search_dir.exists(): + asm_files.extend(search_dir.rglob("*.s")) + + # Analyze each file + for asm_file in asm_files: + # Skip data and bss files + if '.data.s' in asm_file.name or '.bss.s' in asm_file.name: + continue + + file_calls = self.analyze_asm_file(asm_file) + + for func_name, called_funcs in file_calls.items(): + self.all_functions.add(func_name) + self.calls[func_name].update(called_funcs) + + # Build reverse graph + for called_func in called_funcs: + self.all_functions.add(called_func) + self.called_by[called_func].add(func_name) + + def get_dependencies(self, func_name: str) -> Set[str]: + """Get the set of functions that this function calls.""" + return self.calls.get(func_name, set()) + + def get_dependents(self, func_name: str) -> Set[str]: + """Get the set of functions that call this function.""" + return self.called_by.get(func_name, set()) + + def get_unresolved_dependencies(self, func_name: str, decompiled_funcs: Set[str]) -> Set[str]: + """ + Get dependencies that haven't been decompiled yet. + + Args: + func_name: Function to check + decompiled_funcs: Set of functions already decompiled + + Returns: + Set of function names that are dependencies but not yet decompiled + """ + deps = self.get_dependencies(func_name) + return deps - decompiled_funcs + + def get_c_file_completion_rate(self, c_file_path: str) -> float: + """ + Get the completion rate (% of verified functions) for a C file. + + Args: + c_file_path: Path to C file (e.g., 'src/battle/battle.c') + + Returns: + Completion rate as percentage (0-100) + """ + if c_file_path in self.c_file_completion: + return self.c_file_completion[c_file_path] + + if not self.db_conn: + try: + self.db_conn = sqlite3.connect(self.db_path) + self.db_conn.row_factory = sqlite3.Row + except: + return 0.0 + + try: + cursor = self.db_conn.cursor() + cursor.execute(""" + SELECT + COUNT(*) as total, + SUM(CASE WHEN status = 'verified' THEN 1 ELSE 0 END) as verified + FROM functions + WHERE c_file_path = ? + """, (c_file_path,)) + row = cursor.fetchone() + + if row and row['total'] > 0: + completion = (row['verified'] / row['total']) * 100.0 + else: + completion = 0.0 + + self.c_file_completion[c_file_path] = completion + return completion + except: + return 0.0 + + def compute_dependency_score(self, func_name: str, decompiled_funcs: Set[str], + c_file_path: Optional[str] = None) -> float: + """ + Compute a score for prioritizing decompilation. + + Higher score = better candidate for decompilation. + + Score factors: + - Functions with all dependencies resolved: +100 + - Functions with some dependencies resolved: proportional bonus + - Leaf functions (no dependencies): +50 + - Functions that many others depend on: bonus based on dependents + - Sibling completion: Up to +50 based on how many functions in same C file are done + + Returns: + Score (0-250+) + """ + deps = self.get_dependencies(func_name) + + # Leaf function (calls nothing or only decompiled functions) + if not deps: + score = 150.0 # Very high priority + else: + # Count resolved vs unresolved dependencies + unresolved = deps - decompiled_funcs + resolved_ratio = (len(deps) - len(unresolved)) / len(deps) + + # Base score from dependency resolution + score = resolved_ratio * 100.0 + + # All dependencies resolved - major bonus + if not unresolved: + score += 100.0 + + # Bonus for being a dependency of many functions (unlock more work). + # Uses a higher multiplier and cap so high-blocker functions meaningfully + # outrank leaf functions — blocking 9 callers gives +90, blocking 20 gives +200. + dependents = len(self.get_dependents(func_name)) + blocker_multiplier = getattr(self, '_blocker_multiplier', 10) + score += min(dependents * blocker_multiplier, 200) + + # Sibling completion bonus + if c_file_path: + completion_rate = self.get_c_file_completion_rate(c_file_path) + # Higher completion = fewer sibling placeholder issues + # At 50%+ completion, give full bonus. Below that, scale proportionally. + sibling_bonus = min(completion_rate / 50.0, 1.0) * 50.0 + score += sibling_bonus + + return score + + def get_recommended_functions(self, + candidate_funcs: List[str], + decompiled_funcs: Set[str], + limit: int = 20) -> List[tuple]: + """ + Get recommended functions to decompile based on dependencies. + + Args: + candidate_funcs: List of function names to consider + decompiled_funcs: Set of already decompiled function names + limit: Maximum number of recommendations + + Returns: + List of (func_name, score, unresolved_count) tuples, sorted by score + """ + recommendations = [] + + for func_name in candidate_funcs: + score = self.compute_dependency_score(func_name, decompiled_funcs) + unresolved = len(self.get_unresolved_dependencies(func_name, decompiled_funcs)) + + recommendations.append((func_name, score, unresolved)) + + # Sort by score (descending), then by unresolved count (ascending) + recommendations.sort(key=lambda x: (-x[1], x[2])) + + return recommendations[:limit] + + # ============================================================ + # Type-Aware Decompilation Scoring + # ============================================================ + + def extract_extern_symbols(self, asm_file: Path) -> Set[str]: + """ + Extract extern symbol references from an assembly file. + + Looks for patterns like: + - lui/addiu pairs: lui $v0, %hi(D_800XXXXX) + - lw/sw with symbol: lw $v0, D_800XXXXX + + Returns: + Set of extern symbol names referenced + """ + if not asm_file.exists(): + return set() + + try: + content = asm_file.read_text() + except: + return set() + + symbols = set() + + # Pattern for %hi/%lo symbol references + hi_lo_pattern = r'%(?:hi|lo)\(([A-Za-z_][A-Za-z0-9_]*)\)' + + # Pattern for direct symbol references (not registers) + # Like: lw $v0, D_800F83D0 + direct_pattern = r'\s+(?:lw|lh|lb|sw|sh|sb|lui|addiu|la)\s+\$\w+,\s*(-?\d+\()?\s*([A-Za-z_][A-Za-z0-9_]*)' + + for line in content.split('\n'): + # Check for %hi/%lo references + for match in re.finditer(hi_lo_pattern, line): + symbol = match.group(1) + # Filter out obvious non-data symbols + if symbol.startswith('D_') or symbol.startswith('g_') or symbol.isupper(): + symbols.add(symbol) + + # Check for direct references + match = re.search(direct_pattern, line) + if match: + symbol = match.group(2) + # Filter: must start with D_, g_, or be all caps data symbols + if symbol.startswith('D_') or symbol.startswith('g_') or (symbol.isupper() and '_' in symbol): + symbols.add(symbol) + + return symbols + + def get_function_extern_symbols(self, func_name: str) -> Set[str]: + """ + Get extern symbols referenced by a specific function. + + Args: + func_name: Function name + + Returns: + Set of extern symbol names + """ + # Find the assembly file for this function + # Typical path: asm/us/MODULE/nonmatchings/SUBDIR/func_name.s + asm_files = list(self.asm_dir.rglob(f"**/{func_name}.s")) + + symbols = set() + for asm_file in asm_files: + symbols.update(self.extract_extern_symbols(asm_file)) + + return symbols + + def check_type_availability(self, func_name: str, known_types: Dict[str, Dict]) -> tuple: + """ + Check if types are available for all extern symbols used by a function. + + Args: + func_name: Function to check + known_types: Dict from DB.get_all_known_types() + + Returns: + (known_count, unknown_count, unknown_symbols) + """ + extern_symbols = self.get_function_extern_symbols(func_name) + + if not extern_symbols: + # No extern symbols = no type issues + return (0, 0, set()) + + known = 0 + unknown_symbols = set() + + for symbol in extern_symbols: + if symbol in known_types and known_types[symbol]['confidence'] >= 0.3: + known += 1 + else: + unknown_symbols.add(symbol) + + return (known, len(unknown_symbols), unknown_symbols) + + def compute_type_aware_score(self, func_name: str, decompiled_funcs: Set[str], + known_types: Dict[str, Dict], + c_file_path: Optional[str] = None) -> float: + """ + Enhanced dependency score that considers type availability. + + Score factors: + - All base dependency factors from compute_dependency_score + - Type availability bonus: Functions with all types known get +50 + - Type availability penalty: Functions with many unknown types penalized + + Returns: + Score (0-300+) + """ + # Start with base dependency score + score = self.compute_dependency_score(func_name, decompiled_funcs, c_file_path) + + # Add type awareness + known_count, unknown_count, unknown_symbols = self.check_type_availability( + func_name, known_types + ) + + total_symbols = known_count + unknown_count + + if total_symbols == 0: + # No extern symbols = no type issues = small bonus + score += 25.0 + elif unknown_count == 0: + # All types known = big bonus + score += 50.0 + else: + # Some types unknown = penalty proportional to unknowns + type_ratio = known_count / total_symbols + # Scale penalty: 0% known = -50, 100% known = +50 + type_adjustment = (type_ratio * 100) - 50 + score += type_adjustment + + return score + + def get_type_aware_recommendations(self, + candidate_funcs: List[str], + decompiled_funcs: Set[str], + known_types: Dict[str, Dict], + limit: int = 20) -> List[tuple]: + """ + Get recommendations that consider both dependencies and type availability. + + Args: + candidate_funcs: Functions to consider + decompiled_funcs: Already decompiled functions + known_types: Dict from DB.get_all_known_types() + limit: Max recommendations + + Returns: + List of (func_name, score, unresolved_deps, unknown_types) tuples + """ + recommendations = [] + + for func_name in candidate_funcs: + score = self.compute_type_aware_score( + func_name, decompiled_funcs, known_types + ) + unresolved = len(self.get_unresolved_dependencies(func_name, decompiled_funcs)) + known, unknown, _ = self.check_type_availability(func_name, known_types) + + recommendations.append((func_name, score, unresolved, unknown)) + + # Sort by score (descending) + recommendations.sort(key=lambda x: -x[1]) + + return recommendations[:limit] + + def get_function_status_map(self) -> Dict[str, str]: + """ + Query the DB for the status of every known function. + + Returns: + Dict mapping function_name -> status string (e.g. 'verified', 'todo', …) + Functions not in the DB are mapped to 'unknown'. + """ + if not self.db_conn: + try: + self.db_conn = sqlite3.connect(self.db_path) + self.db_conn.row_factory = sqlite3.Row + except Exception: + return {} + + try: + cursor = self.db_conn.cursor() + cursor.execute("SELECT name, status FROM functions") + return {row['name']: row['status'] for row in cursor.fetchall()} + except Exception: + return {} + + def generate_dependency_report(self, output_path: Optional[Path] = None) -> str: + """ + Generate a report listing all known functions separated into two categories: + + 1. Decompiled – functions whose status is 'verified', 'decompiled', or + 'decompiled_needs_refine', sorted descending by number of dependents. + 2. Not yet decompiled – all remaining functions (todo, blocked, failed, …), + sorted descending by number of dependents. + + Within each category functions are additionally grouped by their exact DB + status so the file is easy to scan. + + Args: + output_path: If supplied, the report is written to this file in addition + to being returned as a string. + + Returns: + The full report as a string. + """ + DECOMPILED_STATUSES = {'verified', 'decompiled', 'decompiled_needs_refine', 'sdk_excluded'} + + status_map = self.get_function_status_map() + + # Functions with no ASM split file are either already matched or are SDK + # stubs in the main binary — exclude them from the "not yet decompiled" list. + funcs_with_asm = {asm_file.stem for asm_file in self.asm_dir.rglob('*.s') if 'nonmatchings' in asm_file.parts} + + decompiled: List[tuple] = [] # (func_name, dependents, status) + not_decompiled: List[tuple] = [] # (func_name, dependents, status) + + for func in self.all_functions: + dep_count = len(self.called_by.get(func, set())) + status = status_map.get(func, 'unknown') + if status in DECOMPILED_STATUSES: + decompiled.append((func, dep_count, status)) + elif func in funcs_with_asm: + not_decompiled.append((func, dep_count, status)) + + # Sort each list by descending dependent count, then name for stable ordering + decompiled.sort(key=lambda x: (-x[1], x[0])) + not_decompiled.sort(key=lambda x: (-x[1], x[0])) + + lines: List[str] = [] + + def _write_section(title: str, entries: List[tuple]) -> None: + lines.append('=' * 72) + lines.append(title) + lines.append(f' Total: {len(entries)} functions') + lines.append('=' * 72) + if not entries: + lines.append(' (none)') + lines.append('') + return + # Sub-group by status + by_status: Dict[str, List[tuple]] = {} + for entry in entries: + by_status.setdefault(entry[2], []).append(entry) + for status_key in sorted(by_status.keys()): + group = by_status[status_key] + lines.append(f' [{status_key}] ({len(group)} functions)') + lines.append(f' {"Function":<40} {"Dependents":>10} {"Calls":>8}') + lines.append(f' {"-" * 40} {"-" * 10} {"-" * 8}') + for fname, dep_count, _ in group: + call_count = len(self.calls.get(fname, set())) + lines.append(f' {fname:<40} {dep_count:>10} {call_count:>8}') + lines.append('') + + lines.append('FF7 Decompilation Dependency Report') + lines.append(f'Generated: {__import__("datetime").datetime.now().strftime("%Y-%m-%d %H:%M:%S")}') + lines.append(f'Total functions in call graph: {len(self.all_functions)}') + lines.append('') + + _write_section( + f'SECTION 1 – DECOMPILED ({len(decompiled)} functions)', + decompiled, + ) + _write_section( + f'SECTION 2 – NOT YET DECOMPILED ({len(not_decompiled)} functions)', + not_decompiled, + ) + + report = '\n'.join(lines) + + if output_path is not None: + output_path = Path(output_path) + output_path.write_text(report) + + return report + + def get_function_status_map(self) -> Dict[str, str]: + """ + Query the DB for the status of every known function. + + Returns: + Dict mapping function_name -> status string (e.g. 'verified', 'todo', …) + Functions not in the DB are mapped to 'unknown'. + """ + if not self.db_conn: + try: + self.db_conn = sqlite3.connect(self.db_path) + self.db_conn.row_factory = sqlite3.Row + except Exception: + return {} + + try: + cursor = self.db_conn.cursor() + cursor.execute("SELECT name, status FROM functions") + return {row['name']: row['status'] for row in cursor.fetchall()} + except Exception: + return {} + + def generate_dependency_report(self, output_path: Optional[Path] = None) -> str: + """ + Generate a report listing all known functions separated into two categories: + + 1. Decompiled – functions whose status is 'verified', 'decompiled', or + 'decompiled_needs_refine', sorted descending by number of dependents. + 2. Not yet decompiled – all remaining functions (todo, blocked, failed, …), + sorted descending by number of dependents. + + Within each category functions are additionally grouped by their exact DB + status so the file is easy to scan. + + Args: + output_path: If supplied, the report is written to this file in addition + to being returned as a string. + + Returns: + The full report as a string. + """ + DECOMPILED_STATUSES = {'verified', 'decompiled', 'decompiled_needs_refine', 'sdk_excluded'} + + status_map = self.get_function_status_map() + + # Functions with no ASM split file are either already matched or are SDK + # stubs in the main binary — exclude them from the "not yet decompiled" list. + funcs_with_asm = {asm_file.stem for asm_file in self.asm_dir.rglob('*.s') if 'nonmatchings' in asm_file.parts} + + decompiled: List[tuple] = [] # (func_name, dependents, status) + not_decompiled: List[tuple] = [] # (func_name, dependents, status) + + for func in self.all_functions: + dep_count = len(self.called_by.get(func, set())) + status = status_map.get(func, 'unknown') + if status in DECOMPILED_STATUSES: + decompiled.append((func, dep_count, status)) + elif func in funcs_with_asm: + not_decompiled.append((func, dep_count, status)) + + # Sort each list by descending dependent count, then name for stable ordering + decompiled.sort(key=lambda x: (-x[1], x[0])) + not_decompiled.sort(key=lambda x: (-x[1], x[0])) + + lines: List[str] = [] + + def _write_section(title: str, entries: List[tuple]) -> None: + lines.append('=' * 72) + lines.append(title) + lines.append(f' Total: {len(entries)} functions') + lines.append('=' * 72) + if not entries: + lines.append(' (none)') + lines.append('') + return + # Sub-group by status + by_status: Dict[str, List[tuple]] = {} + for entry in entries: + by_status.setdefault(entry[2], []).append(entry) + for status_key in sorted(by_status.keys()): + group = by_status[status_key] + lines.append(f' [{status_key}] ({len(group)} functions)') + lines.append(f' {"Function":<40} {"Dependents":>10} {"Calls":>8}') + lines.append(f' {"-" * 40} {"-" * 10} {"-" * 8}') + for fname, dep_count, _ in group: + call_count = len(self.calls.get(fname, set())) + lines.append(f' {fname:<40} {dep_count:>10} {call_count:>8}') + lines.append('') + + lines.append('FF7 Decompilation Dependency Report') + lines.append(f'Generated: {__import__("datetime").datetime.now().strftime("%Y-%m-%d %H:%M:%S")}') + lines.append(f'Total functions in call graph: {len(self.all_functions)}') + lines.append('') + + _write_section( + f'SECTION 1 – DECOMPILED ({len(decompiled)} functions)', + decompiled, + ) + _write_section( + f'SECTION 2 – NOT YET DECOMPILED ({len(not_decompiled)} functions)', + not_decompiled, + ) + + report = '\n'.join(lines) + + if output_path is not None: + output_path = Path(output_path) + output_path.write_text(report) + + return report + + def get_function_status_map(self) -> Dict[str, str]: + """ + Query the DB for the status of every known function. + + Returns: + Dict mapping function_name -> status string (e.g. 'verified', 'todo', …) + Functions not in the DB are mapped to 'unknown'. + """ + if not self.db_conn: + try: + self.db_conn = sqlite3.connect(self.db_path) + self.db_conn.row_factory = sqlite3.Row + except Exception: + return {} + + try: + cursor = self.db_conn.cursor() + cursor.execute("SELECT name, status FROM functions") + return {row['name']: row['status'] for row in cursor.fetchall()} + except Exception: + return {} + + def generate_dependency_report(self, output_path: Optional[Path] = None) -> str: + """ + Generate a report listing all known functions separated into two categories: + + 1. Decompiled – functions whose status is 'verified', 'decompiled', or + 'decompiled_needs_refine', sorted descending by number of dependents. + 2. Not yet decompiled – all remaining functions (todo, blocked, failed, …), + sorted descending by number of dependents. + + Within each category functions are additionally grouped by their exact DB + status so the file is easy to scan. + + Args: + output_path: If supplied, the report is written to this file in addition + to being returned as a string. + + Returns: + The full report as a string. + """ + DECOMPILED_STATUSES = {'verified', 'decompiled', 'decompiled_needs_refine', 'sdk_excluded'} + + status_map = self.get_function_status_map() + + # Functions with no ASM split file are either already matched or are SDK + # stubs in the main binary — exclude them from the "not yet decompiled" list. + funcs_with_asm = {asm_file.stem for asm_file in self.asm_dir.rglob('*.s') if 'nonmatchings' in asm_file.parts} + + decompiled: List[tuple] = [] # (func_name, dependents, status) + not_decompiled: List[tuple] = [] # (func_name, dependents, status) + + for func in self.all_functions: + dep_count = len(self.called_by.get(func, set())) + status = status_map.get(func, 'unknown') + if status in DECOMPILED_STATUSES: + decompiled.append((func, dep_count, status)) + elif func in funcs_with_asm: + not_decompiled.append((func, dep_count, status)) + + # Sort each list by descending dependent count, then name for stable ordering + decompiled.sort(key=lambda x: (-x[1], x[0])) + not_decompiled.sort(key=lambda x: (-x[1], x[0])) + + lines: List[str] = [] + + def _write_section(title: str, entries: List[tuple]) -> None: + lines.append('=' * 72) + lines.append(title) + lines.append(f' Total: {len(entries)} functions') + lines.append('=' * 72) + if not entries: + lines.append(' (none)') + lines.append('') + return + # Sub-group by status + by_status: Dict[str, List[tuple]] = {} + for entry in entries: + by_status.setdefault(entry[2], []).append(entry) + for status_key in sorted(by_status.keys()): + group = by_status[status_key] + lines.append(f' [{status_key}] ({len(group)} functions)') + lines.append(f' {"Function":<40} {"Dependents":>10} {"Calls":>8}') + lines.append(f' {"-" * 40} {"-" * 10} {"-" * 8}') + for fname, dep_count, _ in group: + call_count = len(self.calls.get(fname, set())) + lines.append(f' {fname:<40} {dep_count:>10} {call_count:>8}') + lines.append('') + + lines.append('FF7 Decompilation Dependency Report') + lines.append(f'Generated: {__import__("datetime").datetime.now().strftime("%Y-%m-%d %H:%M:%S")}') + lines.append(f'Total functions in call graph: {len(self.all_functions)}') + lines.append('') + + _write_section( + f'SECTION 1 – DECOMPILED ({len(decompiled)} functions)', + decompiled, + ) + _write_section( + f'SECTION 2 – NOT YET DECOMPILED ({len(not_decompiled)} functions)', + not_decompiled, + ) + + report = '\n'.join(lines) + + if output_path is not None: + output_path = Path(output_path) + output_path.write_text(report) + + return report + + def get_function_status_map(self) -> Dict[str, str]: + """ + Query the DB for the status of every known function. + + Returns: + Dict mapping function_name -> status string (e.g. 'verified', 'todo', …) + Functions not in the DB are mapped to 'unknown'. + """ + if not self.db_conn: + try: + self.db_conn = sqlite3.connect(self.db_path) + self.db_conn.row_factory = sqlite3.Row + except Exception: + return {} + + try: + cursor = self.db_conn.cursor() + cursor.execute("SELECT name, status FROM functions") + return {row['name']: row['status'] for row in cursor.fetchall()} + except Exception: + return {} + + def generate_dependency_report(self, output_path: Optional[Path] = None) -> str: + """ + Generate a report listing all known functions separated into two categories: + + 1. Decompiled – functions whose status is 'verified', 'decompiled', or + 'decompiled_needs_refine', sorted descending by number of dependents. + 2. Not yet decompiled – all remaining functions (todo, blocked, failed, …), + sorted descending by number of dependents. + + Within each category functions are additionally grouped by their exact DB + status so the file is easy to scan. + + Args: + output_path: If supplied, the report is written to this file in addition + to being returned as a string. + + Returns: + The full report as a string. + """ + DECOMPILED_STATUSES = {'verified', 'decompiled', 'decompiled_needs_refine', 'sdk_excluded'} + + status_map = self.get_function_status_map() + + # Functions with no ASM split file are either already matched or are SDK + # stubs in the main binary — exclude them from the "not yet decompiled" list. + funcs_with_asm = {asm_file.stem for asm_file in self.asm_dir.rglob('*.s') if 'nonmatchings' in asm_file.parts} + + decompiled: List[tuple] = [] # (func_name, dependents, status) + not_decompiled: List[tuple] = [] # (func_name, dependents, status) + + for func in self.all_functions: + dep_count = len(self.called_by.get(func, set())) + status = status_map.get(func, 'unknown') + if status in DECOMPILED_STATUSES: + decompiled.append((func, dep_count, status)) + elif func in funcs_with_asm: + not_decompiled.append((func, dep_count, status)) + + # Sort each list by descending dependent count, then name for stable ordering + decompiled.sort(key=lambda x: (-x[1], x[0])) + not_decompiled.sort(key=lambda x: (-x[1], x[0])) + + lines: List[str] = [] + + def _write_section(title: str, entries: List[tuple]) -> None: + lines.append('=' * 72) + lines.append(title) + lines.append(f' Total: {len(entries)} functions') + lines.append('=' * 72) + if not entries: + lines.append(' (none)') + lines.append('') + return + # Sub-group by status + by_status: Dict[str, List[tuple]] = {} + for entry in entries: + by_status.setdefault(entry[2], []).append(entry) + for status_key in sorted(by_status.keys()): + group = by_status[status_key] + lines.append(f' [{status_key}] ({len(group)} functions)') + lines.append(f' {"Function":<40} {"Dependents":>10} {"Calls":>8}') + lines.append(f' {"-" * 40} {"-" * 10} {"-" * 8}') + for fname, dep_count, _ in group: + call_count = len(self.calls.get(fname, set())) + lines.append(f' {fname:<40} {dep_count:>10} {call_count:>8}') + lines.append('') + + lines.append('FF7 Decompilation Dependency Report') + lines.append(f'Generated: {__import__("datetime").datetime.now().strftime("%Y-%m-%d %H:%M:%S")}') + lines.append(f'Total functions in call graph: {len(self.all_functions)}') + lines.append('') + + _write_section( + f'SECTION 1 – DECOMPILED ({len(decompiled)} functions)', + decompiled, + ) + _write_section( + f'SECTION 2 – NOT YET DECOMPILED ({len(not_decompiled)} functions)', + not_decompiled, + ) + + report = '\n'.join(lines) + + if output_path is not None: + output_path = Path(output_path) + output_path.write_text(report) + + return report + + def get_ready_functions( + self, + candidate_names: List[str], + resolved_funcs: Set[str], + db_funcs: Set[str], + func_to_c_file: Optional[Dict[str, str]] = None, + check_cross_file: bool = False, + ) -> List[str]: + """ + Return the subset of *candidate_names* that are "ready" for strict + bottom-up decompilation ordering. + + By default (check_cross_file=False): + A function is ready when every callee that lives in the **same C file** + is already resolved (verified / decompiled / sdk_excluded). + Cross-file callees are excluded — decomp_decls.h provides their + signatures to m2c regardless of decompilation status. + + When check_cross_file=True: + A function is ready only when ALL db-tracked callees (same-file AND + cross-file) are resolved. This ensures m2c never encounters a callee + whose declaration is missing from decomp_decls.h, eliminating the + "/*?*/" unknown-type markers that cause validation failures. + + Callees not tracked in *db_funcs* (SDK / extern symbols) are always + treated as satisfied. + """ + if func_to_c_file is None: + func_to_c_file = {} + + ready = [] + for func_name in candidate_names: + callees = self.get_dependencies(func_name) + + if check_cross_file: + # All db-tracked callees must be resolved + relevant_callees = callees & db_funcs + else: + my_c_file = func_to_c_file.get(func_name) + if my_c_file: + relevant_callees = { + c for c in callees + if c in db_funcs and func_to_c_file.get(c) == my_c_file + } + else: + relevant_callees = callees & db_funcs + + if relevant_callees <= resolved_funcs: + ready.append(func_name) + + return ready + + def get_statistics(self) -> Dict: + """Get statistics about the dependency graph.""" + if not self.all_functions: + return { + 'total_functions': 0, + 'leaf_functions': 0, + 'avg_dependencies': 0.0, + 'max_dependencies': 0, + 'most_depended_on': None + } + + leaf_count = sum(1 for f in self.all_functions if not self.calls.get(f)) + avg_deps = sum(len(deps) for deps in self.calls.values()) / len(self.all_functions) + max_deps = max((len(deps) for deps in self.calls.values()), default=0) + + # Find most depended on function + most_depended = max( + ((f, len(self.called_by[f])) for f in self.all_functions), + key=lambda x: x[1], + default=(None, 0) + ) + + return { + 'total_functions': len(self.all_functions), + 'leaf_functions': leaf_count, + 'avg_dependencies': avg_deps, + 'max_dependencies': max_deps, + 'most_depended_on': most_depended[0], + 'most_depended_count': most_depended[1] + } + + +def main(): + """CLI for dependency analysis.""" + import argparse + from pathlib import Path + + parser = argparse.ArgumentParser(description='FF7 decomp dependency analyzer') + parser.add_argument('--module', '-m', type=str, default=None, + help='Limit analysis to a specific module (e.g. battle, world)') + parser.add_argument('--function', '-f', type=str, default=None, + help='Show detailed info for a specific function') + parser.add_argument('--report', '-r', type=str, default=None, metavar='OUTPUT_FILE', + help='Generate a full dependency report and write it to OUTPUT_FILE') + parser.add_argument('--top', type=int, default=30, + help='Number of top blocking functions to display (default: 30)') + args = parser.parse_args() + + project_root = Path(__file__).parent.parent + analyzer = DependencyAnalyzer(project_root) + + if args.module: + print(f'Analyzing dependencies for module: {args.module}') + analyzer.build_call_graph(args.module) + else: + print('Analyzing dependencies for all modules...') + analyzer.build_call_graph() + + stats = analyzer.get_statistics() + print(f'\nDependency Statistics:') + print(f' Total functions: {stats["total_functions"]}') + if stats['total_functions']: + print(f' Leaf functions: {stats["leaf_functions"]} ({stats["leaf_functions"]/stats["total_functions"]*100:.1f}%)') + print(f' Avg dependencies per function: {stats["avg_dependencies"]:.1f}') + print(f' Max dependencies: {stats["max_dependencies"]}') + print(f' Most depended on: {stats["most_depended_on"]} ({stats.get("most_depended_count", 0)} dependents)') + + # Top blocking (not yet decompiled) functions + try: + status_map = analyzer.get_function_status_map() + DECOMPILED = {'verified', 'decompiled', 'decompiled_needs_refine', 'sdk_excluded'} + decompiled_funcs = {f for f, s in status_map.items() if s in DECOMPILED} + + # Only consider functions that have an actual ASM split file — functions + # with no .s file are either already matched (removed from ASM) or are + # PSX SDK stubs that live in the main binary and can never be decompiled. + funcs_with_asm = { + asm_file.stem + for asm_file in analyzer.asm_dir.rglob('*.s') + if 'nonmatchings' in asm_file.parts + } + + undecompiled_with_dependents = [ + (func, len(analyzer.called_by[func])) + for func in analyzer.all_functions + if func not in decompiled_funcs + and func in funcs_with_asm + and len(analyzer.called_by[func]) > 0 + ] + + if undecompiled_with_dependents: + top_blocking = sorted(undecompiled_with_dependents, key=lambda x: x[1], reverse=True)[:args.top] + print(f' Top {args.top} blocking functions (not decompiled):') + for i, (func, dep_count) in enumerate(top_blocking, 1): + print(f' {i:2}. {func:<40} ({dep_count:3} dependents)') + else: + print(' Top blocking functions (not decompiled): None (all high-value targets done!)') + + except Exception as e: + print(f' Top blocking functions (not decompiled): Unable to determine (DB error: {e})') + + # Optional full report + if args.report: + output_path = Path(args.report) + report = analyzer.generate_dependency_report(output_path) + print(f'\nReport written to: {output_path} ({len(report.splitlines())} lines)') + + # Per-function detail + if args.function: + func_name = args.function + deps = analyzer.get_dependencies(func_name) + dependents = analyzer.get_dependents(func_name) + print(f'\nFunction: {func_name}') + print(f' Calls {len(deps)} functions: {chr(44)+" ".join(sorted(deps)[:5])}{"..." if len(deps) > 5 else ""}') + print(f' Called by {len(dependents)} functions: {", ".join(sorted(dependents)[:5])}{"..." if len(dependents) > 5 else ""}') + + +if __name__ == '__main__': + main() diff --git a/automation/dependency_report.txt b/automation/dependency_report.txt new file mode 100644 index 0000000..4c66d37 --- /dev/null +++ b/automation/dependency_report.txt @@ -0,0 +1,2193 @@ +FF7 Decompilation Dependency Report +Generated: 2026-04-11 14:18:34 +Total functions in call graph: 3382 + +======================================================================== +SECTION 1 – DECOMPILED (1421 functions) + Total: 1421 functions +======================================================================== + [sdk_excluded] (333 functions) + Function Dependents Calls + ---------------------------------------- ---------- -------- + EnterCriticalSection 9 0 + SpuSetIRQ 9 1 + SpuSetIRQCallback 9 1 + puts 9 0 + ExitCriticalSection 8 0 + SpuSetTransferCallback 8 0 + SpuSetTransferStartAddr 8 1 + func_8003DE84 8 0 + DMACallback 7 0 + func_800484A8 7 0 + func_80048540 7 0 + SpuSetIRQAddr 6 1 + SpuSetKey 6 0 + func_80038F04 6 1 + func_8003DE6C 6 0 + func_80041D28 6 6 + func_80041E30 6 3 + CD_flush 5 0 + GetGraphType 5 0 + InterruptCallback 5 0 + SetDefDrawEnv 5 2 + get_alarm 5 3 + set_alarm 5 1 + CD_sync 4 6 + SetIntrMask 4 0 + SetSZfifo3 4 0 + _spu_FsetRXXa 4 0 + _spu_FwaitFs 4 0 + checkRECT 4 0 + func_8003DE2C 4 1 + func_8003EF30 4 7 + getintr 4 2 + DecDCToutCallback 3 1 + DecDCTvlc 3 0 + SetDefDispEnv 3 0 + SpuSetVoiceLoopStartAddr 3 1 + _SpuIsInAllocateArea_ 3 0 + _SpuSetAnyVoice 3 0 + _spu_t 3 2 + func_8003A0E8 3 0 + func_8003DE4C 3 1 + func_80041AFC 3 11 + get_tw 3 0 + CD_memcpy 2 0 + CdReset 2 3 + ColorDpq 2 0 + MDEC_in 2 1 + MDEC_in_sync 2 1 + MDEC_out_sync 2 1 + SpuGetKeyStatus 2 0 + SpuSetCommonAttr 2 0 + SpuSetTransferMode 2 0 + StFreeRing 2 0 + StSetMask 2 0 + StUnSetRing 2 4 + _exeque 2 2 + _patch_card2 2 2 + _spu_FsetDelayR 2 0 + _spu_FsetRXX 2 0 + _spu_gcSPU 2 0 + _spu_writeByIO 2 2 + cd_read 2 4 + func_8003DCD8 2 0 + func_8003DD84 2 1 + func_8003E28C 2 1 + func_80040CA8 2 5 + get_ce 2 0 + get_cs 2 0 + get_mode 2 0 + get_ofs 2 0 + init_ring_status 2 0 + timeout 2 1 + CD_cachefile 1 4 + CD_datasync 1 4 + CD_getsector 1 0 + CD_init 1 6 + CD_initintr 1 2 + CD_initvol 1 0 + CD_newmedia 1 4 + CD_ready 1 6 + CD_searchdir 1 1 + CD_vol 1 0 + DMA_memclr 1 0 + GetRCnt 1 0 + InitGeom 1 1 + Lzc 1 0 + MDEC_out 1 1 + MDEC_reset 1 3 + RotMatrix 1 0 + RotTransPers 1 0 + ScaleMatrix 1 0 + SetGeomOffset 1 0 + SetGeomScreen 1 0 + SetRotMatrix 1 0 + SetTransMatrix 1 0 + SpuClearReverbWorkArea 1 3 + SpuGetReverbModeParam 1 0 + SpuInitMalloc 1 0 + SpuMallocWithStartAddr 1 2 + SpuRead 1 1 + SpuSetNoiseClock 1 0 + SpuSetNoiseVoice 1 1 + SpuSetPitchLFOVoice 1 1 + SpuSetReverb 1 1 + SpuSetReverbDepth 1 0 + SpuSetReverbModeParam 1 4 + SpuSetReverbVoice 1 1 + SpuSetVoiceARAttr 1 0 + SpuSetVoiceDR 1 0 + SpuSetVoicePitch 1 0 + SpuSetVoiceRRAttr 1 0 + SpuSetVoiceSL 1 0 + SpuSetVoiceSRAttr 1 0 + SpuSetVoiceStartAddr 1 1 + SpuSetVoiceVolume 1 0 + SpuSetVoiceVolumeAttr 1 0 + SpuStart 1 5 + StClearRing 1 1 + StGetBackloc 1 2 + StGetNext 1 0 + StRingStatus 1 0 + StSetRing 1 1 + StSetStream 1 1 + StartRCnt 1 0 + StopRCnt 1 0 + VSyncCallback 1 0 + VSync_memclr 1 0 + _ExitCard 1 3 + _SpuCallback 1 1 + _SpuDataCallback 1 1 + _SpuInit 1 4 + _SpuMallocSeparateTo3 1 1 + _addque2 1 5 + _card_write 1 0 + _cmp 1 1 + _cwc 1 0 + _new_card 1 0 + _param 1 0 + _patch_card 1 2 + _patch_gte 1 3 + _reset 1 3 + _spu_FsetDelayW 1 0 + _spu_init 1 3 + _spu_read 1 1 + _spu_setReverbAttr 1 0 + _spu_write 1 2 + _version 1 0 + csqrt_1 1 0 + data_ready_callback 1 0 + exit 1 0 + func_8003DCE8 1 0 + func_8003DDA4 1 0 + func_80041620 1 0 + func_80041654 1 1 + func_80041EFC 1 0 + func_800485A0 1 0 + get_dx 1 0 + get_tim_addr 1 2 + get_tmd_addr 1 2 + memclr 1 0 + setjmp 1 0 + sin_1 1 0 + startIntrDMA 1 2 + startIntrVSync 1 2 + trapIntr 1 2 + unpack_packet 1 3 + v_wait 1 3 + ApplyMatrix 0 0 + ApplyMatrixLV 0 0 + ApplyMatrixSV 0 0 + ApplyRotMatrix 0 0 + AverageSZ3 0 0 + AverageSZ4 0 0 + AverageZ3 0 0 + AverageZ4 0 0 + ColorCol 0 0 + CompMatrix 0 0 + DecDCTGetEnv 0 0 + DecDCTPutEnv 0 0 + DecDCTinCallback 0 1 + DecDCTvlcSize 0 0 + DpqColor 0 0 + DpqColor3 0 0 + DpqColorLight 0 0 + DrawSyncCallback 0 0 + DumpClut 0 0 + DumpDispEnv 0 0 + DumpDrawEnv 0 1 + DumpTPage 0 1 + GetIntrMask 0 0 + GetODE 0 0 + Intpl 0 0 + InvSquareRoot 0 0 + LightColor 0 0 + LoadAverage0 0 0 + LoadAverage12 0 0 + LoadAverageByte 0 0 + LoadAverageCol 0 0 + LoadAverageShort0 0 0 + LoadAverageShort12 0 0 + LocalLight 0 0 + MargePrim 0 0 + MatrixNormal 0 1 + MulMatrix 0 0 + MulMatrix0 0 0 + MulMatrix2 0 0 + MulRotMatrix 0 0 + MulRotMatrix0 0 0 + NormalColor 0 0 + NormalColor3 0 0 + NormalColorCol 0 0 + NormalColorCol3 0 0 + NormalColorDpq 0 0 + NormalColorDpq3 0 0 + OuterProduct0 0 0 + OuterProduct12 0 0 + PadInit 0 3 + PadRead 0 1 + PadStop 0 1 + PopMatrix 0 1 + PushMatrix 0 1 + ReadColorMatrix 0 0 + ReadGeomOffset 0 0 + ReadGeomScreen 0 0 + ReadLZC 0 0 + ReadLightMatrix 0 0 + ReadOTZ 0 0 + ReadRotMatrix 0 0 + ResetRCnt 0 0 + RotAverage3 0 0 + RotAverage4 0 0 + RotAverageNclip3 0 0 + RotAverageNclip4 0 0 + RotMatrixX 0 0 + RotMatrixY 0 0 + RotMatrixYXZ 0 0 + RotMatrixZ 0 0 + RotMatrixZYX 0 0 + RotTrans 0 0 + RotTransPers3 0 0 + RotTransPers4 0 0 + RotTransSV 0 0 + ScaleMatrixL 0 0 + SetBackColor 0 0 + SetBlockFill 0 0 + SetColorMatrix 0 0 + SetDrawMove 0 0 + SetFarColor 0 0 + SetFogNearFar 0 2 + SetGraphQueue 0 1 + SetGraphReverse 0 0 + SetIR123 0 0 + SetLightMatrix 0 0 + SetMAC123 0 0 + SetMulMatrix 0 0 + SetPriority 0 0 + SetRGBfifo 0 0 + SetRii 0 0 + SetSXSYfifo 0 0 + SetSZfifo4 0 0 + SetTexWindow 0 1 + SetVertexTri 0 0 + Square0 0 0 + Square12 0 0 + SquareRoot0 0 0 + SquareRoot12 0 0 + SquareSL0 0 0 + SquareSL12 0 0 + SquareSS0 0 0 + SquareSS12 0 0 + SsInitHot 0 3 + StCdInterrupt2 0 1 + TransMatrix 0 0 + TransposeMatrix 0 0 + VSyncCallbacks 0 0 + VectorNormal 0 1 + VectorNormalS 0 0 + VectorNormalSS 0 1 + _SpuIsInAllocateArea 0 0 + _addque 0 1 + _card_auto 0 0 + _card_clear 0 2 + _card_info 0 0 + _card_load 0 0 + _clr 0 2 + _ctl 0 0 + _cwb 0 0 + _drs 0 2 + _dws 0 2 + _getctl 0 0 + _otc 0 2 + _spu_FgetRXXa 0 0 + _spu_FiDMA 0 2 + _spu_FsetPCR 0 0 + _spu_r_ 0 2 + _status 0 0 + _sync 0 3 + callback 0 1 + close 0 0 + csqrt 0 2 + def_cbread 0 1 + def_cbready 0 1 + def_cbsync 0 1 + delete 0 0 + firstfile 0 0 + format 0 0 + func_8003CE0C 0 0 + func_8003DCF8 0 0 + func_8003DDBC 0 0 + func_8003DDF4 0 0 + func_8003E2B0 0 1 + func_8003FA9C 0 0 + func_800418D8 0 8 + func_80041CD4 0 3 + func_800487F0 0 0 + func_80048BBC 0 0 + func_80048C58 0 0 + gteMIMefunc 0 0 + nextfile 0 0 + open 0 0 + ratan2 0 0 + rcos 0 0 + read 0 0 + restartIntr 0 2 + rsin 0 1 + setIntr 0 2 + setIntrDMA 0 0 + setIntrVSync 0 0 + startIntr 0 8 + stopIntr 0 2 + trapIntrDMA 0 1 + trapIntrVSync 0 0 + write 0 0 + + [verified] (1088 functions) + Function Dependents Calls + ---------------------------------------- ---------- -------- + func_800BEAD4 237 6 + func_800BF908 64 2 + func_800BEE10 63 2 + func_80034B44 47 0 + func_800BECA4 46 7 + func_8003B48C 40 0 + func_8003B51C 38 0 + func_800BF3AC 33 2 + AddPrim 31 0 + VSync 30 1 + func_80026A34 29 2 + func_800C0248 28 2 + func_8001AC9C 26 0 + func_80026F44 26 3 + printf 25 0 + func_80046794 23 0 + func_8002DA7C 22 2 + func_80044A68 21 0 + func_800A0B40 19 0 + func_800AA0E0 19 0 + func_80015248 18 8 + SetShadeTex 16 0 + func_800211C4 16 2 + func_800BC04C 16 4 + GetClut 14 0 + SetSemiTrans 14 0 + func_8001E040 14 6 + func_80028CA0 14 4 + func_8002FF4C 14 2 + func_80030038 14 2 + func_80030148 14 2 + func_800A2108 14 2 + func_800A7254 14 0 + DrawSync 13 0 + CdControl 12 1 + GetTPage 12 1 + func_800A993C 12 0 + func_80028E00 11 3 + func_800A9A44 11 0 + LoadImage 10 1 + func_8002A510 10 0 + func_800A6884 10 0 + func_8001B834 9 0 + func_800264A8 9 1 + func_800AE0BC 9 4 + PutDispEnv 8 3 + PutDrawEnv 8 2 + func_8001C808 8 1 + func_8002A094 8 4 + func_8002A6C4 8 0 + func_80034CAC 8 2 + func_80034D18 8 0 + func_800A91A4 8 0 + func_800ADFC0 8 1 + func_800BB9B8 8 0 + func_800C46A4 8 0 + func_800D9BF4 8 0 + func_800DA334 8 0 + func_800DA368 8 0 + CdControlB 7 2 + CdIntToPos 7 0 + ResetCallback 7 0 + func_8001964C 7 0 + func_8002A748 7 0 + func_800A8640 7 0 + func_800D4848 7 0 + StoreImage 6 1 + func_80025788 6 0 + func_80026A00 6 0 + func_800A90EC 6 0 + func_800A9240 6 0 + func_800AA098 6 0 + func_800ABA18 6 1 + func_800B63F0 6 0 + func_800D29D4 6 5 + func_800E6B94 6 0 + CdControlF 5 1 + ChangeClearPAD 5 0 + MoveImage 5 1 + func_80014A84 5 2 + func_80014B70 5 0 + func_8001C8D4 5 1 + func_800257CC 5 0 + func_80026090 5 3 + func_80026B70 5 0 + func_8002BCCC 5 0 + func_8002BD04 5 0 + func_8002BFCC 5 0 + func_8002C004 5 0 + func_800A1FAC 5 4 + func_800A2088 5 0 + func_800AB988 5 2 + func_800ADC80 5 0 + func_800AE47C 5 1 + func_800B0098 5 2 + func_800B7714 5 0 + func_800B79B8 5 0 + func_800D33FC 5 0 + func_800DA124 5 1 + DeliverEvent 4 0 + DrawOTag 4 0 + FlushCache 4 0 + SetDrawMode 4 2 + SetPolyFT4 4 0 + SetTile 4 0 + func_800155A4 4 0 + func_80017678 4 1 + func_80019608 4 0 + func_8001BD50 4 0 + func_8001C3CC 4 0 + func_8001CB48 4 1 + func_8001FA28 4 1 + func_80023050 4 0 + func_8002603C 4 0 + func_8002708C 4 3 + func_8002FDA0 4 0 + func_80033CB8 4 4 + func_800A1498 4 0 + func_800A19FC 4 2 + func_800A273C 4 0 + func_800A6B8C 4 0 + func_800A8A1C 4 2 + func_800A92F8 4 0 + func_800A98E4 4 0 + func_800A9D5C 4 1 + func_800AA238 4 0 + func_800AA7DC 4 0 + func_800AB6E4 4 1 + func_800B6EFC 4 5 + func_800BB9FC 4 0 + func_800C4C9C 4 0 + memcpy 4 0 + CdPosToInt 3 0 + CheckCallback 3 0 + ClearImage 3 1 + ClearOTag 3 0 + ClearOTagR 3 0 + DecDCTout 3 1 + GPU_memset 3 0 + GetGraphDebug 3 0 + SetDispMask 3 1 + SetDrawEnv 3 5 + SetPolyG4 3 0 + func_80012A8C 3 1 + func_800148A0 3 0 + func_80015AFC 3 0 + func_80015B44 3 0 + func_80015B50 3 0 + func_80015BC0 3 1 + func_800185A8 3 0 + func_8001C980 3 0 + func_800258BC 3 0 + func_80026C5C 3 4 + func_80027354 3 1 + func_800285AC 3 3 + func_80028930 3 3 + func_800294A4 3 0 + func_80029B78 3 0 + func_8002A798 3 0 + func_8002A7E8 3 1 + func_8002B1A8 3 0 + func_8003408C 3 4 + func_800A1D38 3 0 + func_800A1D54 3 0 + func_800A21A4 3 0 + func_800A2504 3 12 + func_800A32F4 3 0 + func_800A3354 3 0 + func_800A358C 3 4 + func_800A4134 3 0 + func_800A5EB0 3 0 + func_800A8DCC 3 0 + func_800A921C 3 0 + func_800A9C64 3 2 + func_800AA170 3 0 + func_800AA1B8 3 0 + func_800AA8F8 3 2 + func_800ABA68 3 1 + func_800ABB24 3 11 + func_800ADD4C 3 0 + func_800AE024 3 0 + func_800AE180 3 0 + func_800AFFBC 3 2 + func_800B11B4 3 0 + func_800B1218 3 0 + func_800B39B4 3 4 + func_800B5AAC 3 0 + func_800B624C 3 2 + func_800BC9E8 3 1 + func_800BCA38 3 0 + func_800C2000 3 3 + func_800CF60C 3 0 + func_800D4B28 3 0 + func_800D4EB4 3 0 + strncmp 3 0 + CdGetSector 2 1 + CdRead2 2 3 + CdSearchFile 2 5 + ChangeClearRCnt 2 0 + DecDCTReset 2 2 + EnableEvent 2 0 + GetVideoMode 2 0 + HookEntryInt 2 0 + OpenEvent 2 0 + ResetGraph 2 5 + SetLineF2 2 0 + func_8001117C 2 1 + func_80012840 2 2 + func_800131B8 2 1 + func_80014980 2 1 + func_800150E4 2 0 + func_80015668 2 0 + func_80015D14 2 1 + func_80015D64 2 2 + func_80016340 2 0 + func_80018834 2 1 + func_8001BB30 2 0 + func_8001BCE8 2 0 + func_8001DE70 2 0 + func_8001DEB0 2 0 + func_8001DEF0 2 0 + func_8001FA68 2 1 + func_8002120C 2 1 + func_8002305C 2 0 + func_800230C4 2 9 + func_80023788 2 0 + func_8002382C 2 0 + func_80024A3C 2 25 + func_80025288 2 0 + func_80025380 2 0 + func_80025A44 2 0 + func_800262D8 2 1 + func_80029114 2 3 + func_8002E428 2 1 + func_80033A90 2 0 + func_800343F0 2 1 + func_80034BB0 2 0 + func_80034D5C 2 0 + func_800A12AC 2 2 + func_800A1370 2 5 + func_800A2894 2 0 + func_800A31C0 2 0 + func_800A31F8 2 0 + func_800A38C8 2 2 + func_800A3908 2 3 + func_800A3DFC 2 3 + func_800A4094 2 0 + func_800A4480 2 0 + func_800A45D4 2 0 + func_800A5208 2 1 + func_800A56B0 2 0 + func_800A5AD8 2 1 + func_800A5C08 2 0 + func_800A5FB0 2 0 + func_800A5FB4 2 2 + func_800A63FC 2 0 + func_800A692C 2 0 + func_800A71E8 2 29 + func_800A7F38 2 2 + func_800A82F0 2 0 + func_800A8ABC 2 0 + func_800A8AF4 2 1 + func_800A8E84 2 0 + func_800A8FA0 2 1 + func_800A9480 2 0 + func_800A94D0 2 0 + func_800A9520 2 0 + func_800A97A8 2 0 + func_800A9910 2 0 + func_800A9A70 2 0 + func_800A9AD0 2 0 + func_800A9B04 2 0 + func_800A9DB4 2 0 + func_800AA32C 2 0 + func_800AA8D8 2 0 + func_800AB8EC 2 0 + func_800ACE14 2 0 + func_800AD0FC 2 3 + func_800ADE30 2 0 + func_800AE42C 2 1 + func_800AE4B8 2 1 + func_800AE954 2 1 + func_800AEB20 2 0 + func_800AF1A8 2 0 + func_800AF874 2 0 + func_800AF96C 2 1 + func_800AF9A0 2 1 + func_800B0240 2 0 + func_800B0794 2 1 + func_800B0E5C 2 0 + func_800B10AC 2 1 + func_800B1304 2 0 + func_800B18A8 2 1 + func_800B2638 2 0 + func_800B2A2C 2 0 + func_800B2FD0 2 0 + func_800B338C 2 0 + func_800B3FFC 2 1 + func_800B4E30 2 3 + func_800B5314 2 4 + func_800B59F4 2 4 + func_800B5DD8 2 0 + func_800B5FE8 2 0 + func_800B6570 2 0 + func_800B6724 2 4 + func_800B7480 2 14 + func_800B86C4 2 0 + func_800B888C 2 0 + func_800B8D4C 2 7 + func_800B90C0 2 8 + func_800B962C 2 2 + func_800B98F0 2 1 + func_800BA938 2 1 + func_800BAA00 2 1 + func_800BAB60 2 0 + func_800BAC70 2 0 + func_800BBA0C 2 0 + func_800BBA84 2 0 + func_800BBC4C 2 8 + func_800BBD20 2 44 + func_800BFA98 2 0 + func_800BFB10 2 0 + func_800C03B8 2 0 + func_800C1304 2 0 + func_800C1490 2 0 + func_800C2FD4 2 0 + func_800C7924 2 1 + func_800C826C 2 0 + func_800CEB20 2 0 + func_800CF368 2 0 + func_800CF5A0 2 0 + func_800D4BFC 2 0 + func_800D4FA8 2 0 + func_800D9F00 2 0 + func_800DA214 2 0 + func_800DA480 2 0 + CdDiskReady 1 2 + CdGetDiskType 1 5 + CdInit 1 5 + CdLastPos 1 0 + CdMix 1 1 + CloseEvent 1 0 + DecDCTin 1 1 + DisableEvent 1 0 + GPU_cw 1 0 + GetDispEnv 1 1 + InitCARD2 1 0 + InitPAD 1 0 + OpenTIM 1 0 + PAD_dr 1 0 + PAD_init 1 0 + ReadTIM 1 1 + ResetEntryInt 1 0 + ReturnFromException 1 0 + SetDQA 1 0 + SetDQB 1 0 + SetGraphDebug 1 0 + SetMem 1 0 + SetRCnt 1 0 + SetTile1 1 0 + StartCARD2 1 0 + StartPAD 1 0 + StopCARD2 1 0 + StopCallback 1 0 + StopPAD 1 0 + UnDeliverEvent 1 0 + WaitEvent 1 0 + _96_remove 1 0 + func_8001146C 1 4 + func_80011784 1 4 + func_80011860 1 5 + func_800119E4 1 0 + func_80011AEC 1 0 + func_80011BB4 1 0 + func_800128B8 1 3 + func_80012DB0 1 1 + func_800134F4 1 0 + func_80013564 1 0 + func_800135C0 1 0 + func_80013624 1 2 + func_80013800 1 2 + func_800138EC 1 7 + func_800146A4 1 3 + func_800148B4 1 5 + func_80014B08 1 0 + func_80014BE4 1 2 + func_80014C44 1 0 + func_80014C80 1 0 + func_80014E0C 1 1 + func_80014E74 1 4 + func_800159B0 1 0 + func_80015B88 1 0 + func_80015C3C 1 1 + func_800166C0 1 0 + func_80016808 1 3 + func_800169B8 1 3 + func_80016F90 1 3 + func_8001708C 1 1 + func_80017E68 1 1 + func_80017F38 1 1 + func_80018028 1 10 + func_80018220 1 0 + func_800182FC 1 0 + func_800184C0 1 4 + func_80018AB0 1 0 + func_80018B14 1 1 + func_80018C94 1 4 + func_80018D4C 1 6 + func_80018E18 1 1 + func_80018E90 1 0 + func_80018ECC 1 1 + func_80018FC0 1 1 + func_80019064 1 1 + func_800190E8 1 2 + func_800191A0 1 4 + func_80019254 1 2 + func_80019338 1 0 + func_8001937C 1 0 + func_800193F4 1 0 + func_80019440 1 2 + func_800194BC 1 1 + func_80019544 1 2 + func_80019690 1 2 + func_800197B8 1 14 + func_80019978 1 0 + func_80019DA0 1 0 + func_80019E4C 1 0 + func_80019E84 1 0 + func_8001A1C8 1 1 + func_8001A280 1 1 + func_8001A384 1 1 + func_8001A3B8 1 2 + func_8001A440 1 1 + func_8001A4A8 1 2 + func_8001A518 1 2 + func_8001A684 1 1 + func_8001A780 1 2 + func_8001A980 1 2 + func_8001A9CC 1 1 + func_8001AB1C 1 1 + func_8001AE08 1 0 + func_8001AEE4 1 0 + func_8001B4A0 1 3 + func_8001B5E4 1 3 + func_8001B704 1 2 + func_8001B8A8 1 0 + func_8001B944 1 3 + func_8001BA54 1 0 + func_8001BC18 1 1 + func_8001C0EC 1 0 + func_8001C484 1 0 + func_8001C498 1 0 + func_8001C4E8 1 2 + func_8001C5BC 1 3 + func_8001C788 1 3 + func_8001D6A8 1 6 + func_8001EC70 1 5 + func_8001FAAC 1 1 + func_8001FBAC 1 0 + func_8001FCDC 1 0 + func_8001FE6C 1 0 + func_8001FF50 1 0 + func_8001FF8C 1 0 + func_8001FFD4 1 0 + func_8002001C 1 0 + func_80020B68 1 6 + func_80021BAC 1 4 + func_80022B5C 1 17 + func_80022FE0 1 3 + func_8002368C 1 1 + func_80023940 1 0 + func_80024A04 1 2 + func_80025040 1 0 + func_80025174 1 7 + func_80025310 1 0 + func_800254E4 1 0 + func_80025514 1 2 + func_80025668 1 0 + func_80025800 1 0 + func_80025988 1 0 + func_80025B10 1 0 + func_80025B48 1 0 + func_80026258 1 4 + func_80026408 1 1 + func_8002988C 1 12 + func_80029998 1 0 + func_8002A958 1 2 + func_8002BDCC 1 1 + func_8002C3A8 1 1 + func_8002C8DC 1 1 + func_8002D1E4 1 1 + func_8002D2D4 1 1 + func_8002DA30 1 0 + func_8002E1A8 1 0 + func_8002FE48 1 2 + func_800318BC 1 0 + func_80031A70 1 0 + func_80032B30 1 1 + func_80032C20 1 1 + func_80032CE8 1 1 + func_80033BE0 1 4 + func_80033C20 1 1 + func_80034444 1 0 + func_80034DB0 1 0 + func_800A0000 1 29 + func_800A04C4 1 20 + func_800A0514 1 0 + func_800A0B48 1 0 + func_800A0C54 1 3 + func_800A0D2C 1 13 + func_800A141C 1 10 + func_800A16E0 1 0 + func_800A1710 1 0 + func_800A1DF0 1 7 + func_800A1ED4 1 0 + func_800A2040 1 2 + func_800A21B4 1 32 + func_800A22C0 1 0 + func_800A283C 1 0 + func_800A2974 1 4 + func_800A2BF4 1 0 + func_800A2DB0 1 0 + func_800A2F78 1 0 + func_800A304C 1 0 + func_800A310C 1 0 + func_800A31E8 1 0 + func_800A3210 1 0 + func_800A3240 1 0 + func_800A32C0 1 0 + func_800A3304 1 8 + func_800A3964 1 17 + func_800A3C74 1 0 + func_800A3E4C 1 3 + func_800A3E9C 1 1 + func_800A3EC8 1 2 + func_800A4008 1 2 + func_800A4080 1 1 + func_800A40B8 1 2 + func_800A4138 1 2 + func_800A41E8 1 3 + func_800A4268 1 3 + func_800A4350 1 3 + func_800A4430 1 0 + func_800A4494 1 0 + func_800A44A4 1 0 + func_800A44B4 1 0 + func_800A44C4 1 0 + func_800A44D8 1 0 + func_800A45C4 1 0 + func_800A45E4 1 0 + func_800A460C 1 82 + func_800A47F8 1 0 + func_800A4860 1 4 + func_800A4954 1 3 + func_800A496C 1 0 + func_800A4DDC 1 0 + func_800A4F08 1 0 + func_800A4F78 1 3 + func_800A52A4 1 0 + func_800A5348 1 1 + func_800A53A8 1 3 + func_800A54F0 1 3 + func_800A5660 1 0 + func_800A5750 1 0 + func_800A57C8 1 3 + func_800A5970 1 0 + func_800A59A0 1 0 + func_800A5A20 1 0 + func_800A5A94 1 0 + func_800A5B88 1 1 + func_800A5D00 1 1 + func_800A5E0C 1 0 + func_800A5E28 1 2 + func_800A60D8 1 0 + func_800A635C 1 0 + func_800A64AC 1 10 + func_800A65A4 1 11 + func_800A65B0 1 0 + func_800A67A8 1 1 + func_800A6C3C 1 6 + func_800A71F4 1 0 + func_800A7EA4 1 3 + func_800A7F18 1 1 + func_800A806C 1 18 + func_800A8300 1 0 + func_800A835C 1 0 + func_800A8600 1 0 + func_800A8620 1 0 + func_800A86C4 1 1 + func_800A886C 1 0 + func_800A8888 1 0 + func_800A8898 1 0 + func_800A891C 1 2 + func_800A8A88 1 0 + func_800A8C70 1 0 + func_800A8CA4 1 0 + func_800A8CE4 1 0 + func_800A8D58 1 1 + func_800A8E50 1 0 + func_800A8F48 1 0 + func_800A9018 1 1 + func_800A9064 1 0 + func_800A9134 1 0 + func_800A9194 1 0 + func_800A929C 1 0 + func_800A94F4 1 0 + func_800A9678 1 1 + func_800A96D0 1 0 + func_800A97E4 1 0 + func_800A9820 1 0 + func_800A984C 1 0 + func_800A9878 1 0 + func_800A9AA4 1 0 + func_800A9D88 1 1 + func_800A9E14 1 2 + func_800AA04C 1 0 + func_800AA128 1 0 + func_800AA2B8 1 0 + func_800AA580 1 2 + func_800AA640 1 2 + func_800AA6A4 1 0 + func_800AA738 1 0 + func_800AAA00 1 1 + func_800AAB18 1 12 + func_800AB2B4 1 0 + func_800AB308 1 0 + func_800AB310 1 0 + func_800AB36C 1 0 + func_800AB398 1 3 + func_800AB480 1 1 + func_800AB48C 1 0 + func_800AB4F4 1 1 + func_800AB570 1 2 + func_800AB5E4 1 0 + func_800AB674 1 0 + func_800AB788 1 2 + func_800AB92C 1 1 + func_800AB9C8 1 0 + func_800ABA34 1 0 + func_800ABA78 1 2 + func_800ABE58 1 1 + func_800ABF0C 1 6 + func_800ABFC0 1 8 + func_800AC3C0 1 1 + func_800AC484 1 4 + func_800AC6B4 1 1 + func_800AC700 1 72 + func_800ACA4C 1 0 + func_800ACB98 1 0 + func_800ACD88 1 0 + func_800ACE88 1 0 + func_800AD088 1 1 + func_800AD420 1 0 + func_800AD480 1 0 + func_800AD5E8 1 0 + func_800AD63C 1 8 + func_800AD788 1 1 + func_800AD804 1 4 + func_800AD928 1 0 + func_800ADA08 1 1 + func_800ADA64 1 0 + func_800ADB30 1 0 + func_800ADC3C 1 0 + func_800ADC70 1 0 + func_800AE5B8 1 1 + func_800AE5F0 1 1 + func_800AE628 1 0 + func_800AE638 1 8 + func_800AE82C 1 1 + func_800AE8AC 1 1 + func_800AEA48 1 8 + func_800AEB80 1 2 + func_800AF0A0 1 0 + func_800AF0B0 1 1 + func_800AF0C4 1 0 + func_800AF1E8 1 0 + func_800AF24C 1 0 + func_800AF2A4 1 0 + func_800AF324 1 0 + func_800AF364 1 0 + func_800AF3A4 1 5 + func_800AF65C 1 0 + func_800AF834 1 0 + func_800AF9C8 1 3 + func_800AFCC8 1 5 + func_800AFDE4 1 0 + func_800AFECC 1 0 + func_800B0170 1 0 + func_800B017C 1 0 + func_800B01C4 1 0 + func_800B0200 1 1 + func_800B0234 1 0 + func_800B0250 1 3 + func_800B0334 1 4 + func_800B04AC 1 1 + func_800B0670 1 1 + func_800B075C 1 1 + func_800B0810 1 6 + func_800B0B94 1 0 + func_800B0BF4 1 5 + func_800B0C14 1 0 + func_800B0D98 1 3 + func_800B0E84 1 9 + func_800B0F04 1 1 + func_800B104C 1 0 + func_800B10B4 1 0 + func_800B10F0 1 3 + func_800B1368 1 0 + func_800B13B0 1 0 + func_800B141C 1 0 + func_800B1624 1 0 + func_800B16D0 1 1 + func_800B17F0 1 0 + func_800B1A5C 1 1 + func_800B1AA0 1 0 + func_800B1B64 1 0 + func_800B1C1C 1 0 + func_800B1C80 1 3 + func_800B1C94 1 0 + func_800B21E4 1 2 + func_800B28CC 1 8 + func_800B29CC 1 11 + func_800B2CFC 1 2 + func_800B2E90 1 8 + func_800B2F70 1 0 + func_800B2FA4 1 0 + func_800B3030 1 0 + func_800B3044 1 0 + func_800B307C 1 13 + func_800B3300 1 0 + func_800B3350 1 0 + func_800B3418 1 12 + func_800B37E0 1 0 + func_800B3828 1 6 + func_800B392C 1 0 + func_800B3C40 1 4 + func_800B3FAC 1 0 + func_800B40B4 1 9 + func_800B4244 1 1 + func_800B45DC 1 14 + func_800B579C 1 0 + func_800B57C0 1 0 + func_800B57DC 1 5 + func_800B58F8 1 1 + func_800B5E28 1 9 + func_800B60E0 1 0 + func_800B6348 1 0 + func_800B64A0 1 1 + func_800B64D8 1 1 + func_800B650C 1 0 + func_800B65A4 1 1 + func_800B667C 1 0 + func_800B69A4 1 3 + func_800B69C0 1 1 + func_800B6B28 1 2 + func_800B6D10 1 1 + func_800B6E08 1 0 + func_800B6E78 1 4 + func_800B7104 1 1 + func_800B717C 1 0 + func_800B7228 1 14 + func_800B7620 1 1 + func_800B76A8 1 4 + func_800B77A8 1 1 + func_800B77F4 1 0 + func_800B7820 1 0 + func_800B7838 1 0 + func_800B785C 1 0 + func_800B786C 1 0 + func_800B7A40 1 4 + func_800B7AC0 1 0 + func_800B7B1C 1 0 + func_800B7B3C 1 0 + func_800B7B54 1 0 + func_800B7B78 1 0 + func_800B7BA0 1 0 + func_800B7BC0 1 0 + func_800B7BD8 1 0 + func_800B7C1C 1 1 + func_800B7C7C 1 17 + func_800B832C 1 11 + func_800B8488 1 1 + func_800B84D8 1 1 + func_800B851C 1 1 + func_800B858C 1 1 + func_800B86E8 1 1 + func_800B8720 1 1 + func_800B8760 1 1 + func_800B87D8 1 1 + func_800B8944 1 2 + func_800B89C4 1 0 + func_800B8A34 1 0 + func_800B8A5C 1 0 + func_800B8B00 1 0 + func_800B95E8 1 0 + func_800BA11C 1 0 + func_800BA24C 1 0 + func_800BA2BC 1 0 + func_800BA360 1 0 + func_800BAE60 1 0 + func_800BB1B4 1 0 + func_800BB350 1 0 + func_800BB430 1 0 + func_800BB450 1 0 + func_800BB4F8 1 0 + func_800BB568 1 0 + func_800BB8B0 1 0 + func_800BB8E8 1 7 + func_800BB9D0 1 0 + func_800BBA44 1 0 + func_800BBBB0 1 3 + func_800BC1CC 1 2 + func_800BC338 1 1 + func_800BC420 1 13 + func_800BC438 1 0 + func_800BC630 1 0 + func_800BCA48 1 0 + func_800BCA78 1 0 + func_800BCB2C 1 0 + func_800BCBE8 1 0 + func_800BCECC 1 0 + func_800BFCAC 1 1 + func_800C0254 1 3 + func_800C0314 1 0 + func_800C1394 1 3 + func_800C1D58 1 2 + func_800C1FD8 1 0 + func_800C2130 1 0 + func_800C2150 1 0 + func_800C2864 1 0 + func_800C2C1C 1 0 + func_800C31F0 1 1 + func_800C3948 1 0 + func_800C3AA0 1 0 + func_800C45EC 1 0 + func_800C5864 1 0 + func_800C6104 1 0 + func_800C76C8 1 1 + func_800CD860 1 3 + func_800D0958 1 0 + func_800D32B4 1 0 + func_800D3354 1 0 + func_800D3418 1 0 + func_800D3474 1 0 + func_800D348C 1 0 + func_800D3548 1 2 + func_800D3A6C 1 2 + func_800D415C 1 1 + func_800D41FC 1 3 + func_800D4284 1 4 + func_800D48C0 1 0 + func_800D4BC0 1 0 + func_800D4E24 1 0 + func_800D4E88 1 0 + func_800D4FF0 1 0 + func_800D5228 1 0 + func_800D61AC 1 2 + func_800D6260 1 0 + func_800D6394 1 4 + func_800D726C 1 0 + func_800D7A58 1 0 + func_800D7B1C 1 0 + func_800D7BA4 1 0 + func_800D7C98 1 0 + func_800D828C 1 0 + func_800D8304 1 0 + func_800D83A4 1 0 + func_800D85C0 1 0 + func_800D8B60 1 0 + func_800DA194 1 0 + func_800DA1D4 1 0 + func_800DA2CC 1 0 + func_800DBF8C 1 0 + func_800DC0CC 1 12 + func_800DDFEC 1 0 + func_800E08C4 1 0 + func_800E0BE0 1 0 + func_800E0E34 1 9 + func_800E1A2C 1 0 + func_800E1AC0 1 0 + func_800E60F8 1 0 + func_800E68B4 1 0 + func_800E7170 1 4 + func_801D027C 1 0 + memchr 1 0 + memmove 1 0 + memset 1 0 + strcmp 1 0 + strlen 1 0 + AddPrims 0 0 + CatPrim 0 0 + ChangeClearSIO 0 0 + DecDCTBufSize 0 0 + DecDCTinSync 0 1 + DecDCToutSync 0 1 + DrawPrim 0 0 + GetDrawEnv 0 1 + InitCARD 0 6 + InitHeap 0 0 + IsEndPrim 0 0 + LoadClut 0 2 + LoadTPage 0 2 + NextPrim 0 0 + OpenTMD 0 1 + ReadTMD 0 1 + RestartCallback 0 0 + SetData32 0 0 + SetDrawArea 0 2 + SetDrawOffset 0 1 + SetIR0 0 0 + SetLineF3 0 0 + SetLineF4 0 0 + SetLineG2 0 0 + SetLineG3 0 0 + SetLineG4 0 0 + SetPolyF3 0 0 + SetPolyF4 0 0 + SetPolyFT3 0 0 + SetPolyG3 0 0 + SetPolyGT3 0 0 + SetPolyGT4 0 0 + SetSp 0 0 + SetSprt 0 0 + SetSprt16 0 0 + SetSprt8 0 0 + SetTile16 0 0 + SetTile8 0 0 + SetVertex0 0 0 + SetVertex1 0 0 + SetVertex2 0 0 + SetVideoMode 0 0 + StartCARD 0 4 + SystemError 0 0 + TermPrim 0 0 + TestEvent 0 0 + __SN_ENTRY_POINT 0 0 + _bu_init 0 0 + bcopy 0 0 + func_8001155C 0 4 + func_800129D0 0 2 + func_80014804 0 5 + func_800155B0 0 2 + func_8001FAF8 0 0 + func_800211B8 0 0 + func_80023AC4 0 0 + func_800256DC 0 0 + func_80025ED4 0 3 + func_800269D0 0 0 + func_800269E8 0 0 + func_80026A0C 0 0 + func_80026A20 0 0 + func_80026B64 0 0 + func_80027990 0 1 + func_800293D0 0 1 + func_8002BB20 0 1 + func_8002BE2C 0 1 + func_8002C0CC 0 1 + func_8002C12C 0 1 + func_8002C408 0 1 + func_8002C7E8 0 2 + func_8002C81C 0 2 + func_8002C850 0 2 + func_8002CA84 0 1 + func_8002CEC0 0 2 + func_8002CF1C 0 2 + func_8002CF78 0 1 + func_8002DF88 0 0 + func_80031BE4 0 0 + func_80032718 0 0 + func_8003345C 0 0 + func_80034410 0 0 + func_80034430 0 0 + func_8003447C 0 1 + func_800345BC 0 1 + func_800347B4 0 1 + func_800347F8 0 5 + func_80035D64 0 2 + func_80036038 0 3 + func_80036190 0 2 + func_800425F8 0 0 + func_800A0E68 0 4 + func_800A0F90 0 2 + func_800A1F48 0 1 + func_800A22E4 0 0 + func_800A2420 0 0 + func_800A2E80 0 6 + func_800A40F0 0 0 + func_800A5924 0 1 + func_800A6C00 0 2 + func_800A6C04 0 2 + func_800A76CC 0 1 + func_800A8424 0 3 + func_800A8A6C 0 4 + func_800A91E0 0 0 + func_800A96A4 0 1 + func_800A9988 0 0 + func_800AA468 0 2 + func_800AA684 0 0 + func_800AA688 0 0 + func_800ADD2C 0 0 + func_800ADF38 0 1 + func_800AE080 0 2 + func_800AEF68 0 3 + func_800AF3AC 0 2 + func_800B062C 0 2 + func_800B089C 0 0 + func_800B0910 0 2 + func_800B11C4 0 0 + func_800B1650 0 1 + func_800B2304 0 2 + func_800B2EBC 0 0 + func_800B4794 0 5 + func_800B6A4C 0 3 + func_800B6C84 0 5 + func_800B6DCC 0 2 + func_800B7134 0 1 + func_800B7DB4 0 0 + func_800B8A98 0 0 + func_800B8CBC 0 0 + func_800B8D20 0 0 + func_800B8E48 0 0 + func_800BB650 0 2 + func_800BB7DC 0 2 + func_800BFB88 0 2 + func_800C02F4 0 1 + func_800C0DE0 0 3 + func_800C3068 0 1 + func_800C32CC 0 2 + func_800C36B4 0 1 + func_800C3CA8 0 3 + func_800C3DE4 0 1 + func_800C43C4 0 1 + func_800C4814 0 3 + func_800C4AE8 0 4 + func_800C4CE8 0 3 + func_800C5740 0 1 + func_800C64D4 0 0 + func_800C6628 0 0 + func_800C7340 0 4 + func_800C7C4C 0 49 + func_800CB450 0 2 + func_800CB660 0 2 + func_800CC284 0 3 + func_800CC404 0 3 + func_800CC70C 0 3 + func_800CC944 0 2 + func_800CCA68 0 2 + func_800CD0C4 0 1 + func_800CD16C 0 2 + func_800CD214 0 2 + func_800CD6B0 0 2 + func_800CEB94 0 1 + func_800CF874 0 2 + func_800CFC1C 0 1 + func_800D09D0 0 0 + func_800D298C 0 3 + func_800D3BF0 0 4 + func_800D3E64 0 2 + func_800D4160 0 1 + func_800D4378 0 1 + func_800D4420 0 1 + func_800D44E8 0 3 + func_800D491C 0 1 + func_800D51D4 0 0 + func_800D5230 0 0 + func_800D5774 0 1 + func_800D5B6C 0 4 + func_800D6998 0 3 + func_800D6ACC 0 2 + func_800D6D8C 0 6 + func_800D70C0 0 1 + func_800D7368 0 7 + func_800D7724 0 7 + func_800D7888 0 6 + func_800D8468 0 0 + func_800D84F8 0 1 + func_800D87EC 0 1 + func_800DCFD4 0 3 + func_800DDCE8 0 8 + func_800DEC10 0 6 + func_800E1C40 0 0 + func_800E2098 0 11 + func_800E5530 0 5 + func_801D1F40 0 4 + main 0 59 + rand 0 0 + sprintf 0 3 + srand 0 0 + +======================================================================== +SECTION 2 – NOT YET DECOMPILED (737 functions) + Total: 737 functions +======================================================================== + [blocked] (640 functions) + Function Dependents Calls + ---------------------------------------- ---------- -------- + func_800A4F60 9 2 + func_800BBEAC 7 4 + func_8002E23C 6 9 + func_800C33B4 6 3 + func_800D3994 6 2 + func_80029A50 5 7 + func_8002C2CC 5 0 + func_8002C300 5 0 + func_80034104 5 2 + func_800D9E0C 5 0 + func_80017108 4 1 + func_80020058 4 8 + func_80028484 4 3 + func_80031820 4 0 + func_800A2FD0 4 1 + func_800A8E34 4 0 + func_800A9334 4 4 + func_800A9CE8 4 0 + func_800BC11C 4 4 + func_800C4BCC 4 3 + func_800CDC14 4 0 + func_800DA444 4 0 + func_80027408 3 2 + func_80029424 3 2 + func_80029C48 3 4 + func_80029E98 3 0 + func_80034350 3 5 + func_80035658 3 5 + func_800A3178 3 0 + func_800A343C 3 0 + func_800A34C4 3 1 + func_800A6994 3 2 + func_800A72C8 3 1 + func_800A8DF4 3 0 + func_800AE4DC 3 0 + func_800AF110 3 5 + func_800B1C7C 3 1 + func_800B5C1C 3 2 + func_800BB538 3 2 + func_800BFBF0 3 2 + func_800C2E00 3 1 + func_800D0B4C 3 2 + func_800DA424 3 0 + func_800E368C 3 5 + func_80013C9C 2 9 + func_80018630 2 2 + func_80018934 2 1 + func_8001F1BC 2 11 + func_80026A94 2 3 + func_80027B84 2 2 + func_80028030 2 1 + func_800293F4 2 1 + func_80029BAC 2 1 + func_80029F44 2 0 + func_8002A43C 2 0 + func_8002AABC 2 3 + func_8002AFB8 2 0 + func_8002CFC0 2 11 + func_80033894 2 3 + func_80034D2C 2 0 + func_80034F5C 2 4 + func_80035DC8 2 1 + func_80036244 2 0 + func_80036298 2 1 + func_800A2888 2 5 + func_800A3D4C 2 0 + func_800A3F4C 2 3 + func_800A41CC 2 6 + func_800A4BA4 2 0 + func_800A6168 2 6 + func_800A61D4 2 3 + func_800A8B30 2 2 + func_800AA514 2 0 + func_800AE6C0 2 1 + func_800AEE24 2 0 + func_800B0EDC 2 1 + func_800B271C 2 4 + func_800B2B5C 2 2 + func_800B2DD4 2 1 + func_800B5CD4 2 1 + func_800B5D38 2 2 + func_800B787C 2 1 + func_800B9B2C 2 6 + func_800BBF7C 2 4 + func_800C0808 2 1 + func_800C2450 2 1 + func_800C24A8 2 2 + func_800C2970 2 2 + func_800C5B38 2 0 + func_800C614C 2 2 + func_800C7D5C 2 0 + func_800C8634 2 1 + func_800D1200 2 1 + func_800D1350 2 1 + func_800D152C 2 1 + func_800D3F0C 2 1 + func_800D4D90 2 0 + func_800D6840 2 4 + func_800112E8 1 4 + func_80018390 1 2 + func_8001840C 1 3 + func_80018A04 1 1 + func_80018BB8 1 2 + func_80019D1C 1 2 + func_80019F90 1 3 + func_8001A174 1 2 + func_8001A5B4 1 5 + func_8001A874 1 1 + func_8001B570 1 0 + func_8001BDB0 1 2 + func_8001F710 1 9 + func_800212A8 1 13 + func_80021C4C 1 7 + func_80021D5C 1 8 + func_80021E70 1 5 + func_800294BC 1 2 + func_800297A4 1 3 + func_80029818 1 3 + func_800299C8 1 8 + func_8002A28C 1 4 + func_8002B2F8 1 5 + func_8002E478 1 2 + func_8002E954 1 2 + func_8002ED34 1 0 + func_8002F24C 1 0 + func_8002F738 1 1 + func_80030E7C 1 1 + func_80032ABC 1 1 + func_80032BB4 1 1 + func_80032E6C 1 0 + func_80032ED0 1 0 + func_80034F3C 1 1 + func_80034FC8 1 8 + func_800354CC 1 4 + func_80035CF0 1 3 + func_80035F14 1 3 + func_80036100 1 0 + func_800A0030 1 19 + func_800A0534 1 1 + func_800A05D4 1 1 + func_800A0C58 1 25 + func_800A1368 1 3 + func_800A14D8 1 2 + func_800A2934 1 0 + func_800A2A2C 1 1 + func_800A2D5C 1 3 + func_800A2F1C 1 6 + func_800A3020 1 5 + func_800A311C 1 0 + func_800A3208 1 0 + func_800A3368 1 1 + func_800A3488 1 0 + func_800A34CC 1 0 + func_800A35F8 1 9 + func_800A364C 1 0 + func_800A36AC 1 8 + func_800A379C 1 1 + func_800A424C 1 1 + func_800A50E0 1 0 + func_800A5250 1 1 + func_800A5AC8 1 0 + func_800A6418 1 0 + func_800A6FC0 1 3 + func_800A82A0 1 0 + func_800A8304 1 1 + func_800A8858 1 1 + func_800A9B64 1 0 + func_800A9EEC 1 2 + func_800AA180 1 1 + func_800AA304 1 0 + func_800AA6D0 1 5 + func_800AA870 1 1 + func_800AA950 1 3 + func_800AB4AC 1 4 + func_800AB5E8 1 6 + func_800AB728 1 0 + func_800AB830 1 4 + func_800ABA70 1 4 + func_800ABFE8 1 6 + func_800AC73C 1 4 + func_800ACBA0 1 2 + func_800ACC5C 1 1 + func_800AD7B8 1 1 + func_800AD858 1 2 + func_800AD970 1 0 + func_800ADAA4 1 0 + func_800ADC90 1 3 + func_800ADD70 1 2 + func_800ADEA8 1 1 + func_800AE23C 1 1 + func_800AE764 1 1 + func_800AF6EC 1 2 + func_800AF9DC 1 2 + func_800AFAC4 1 0 + func_800AFE1C 1 1 + func_800B0618 1 1 + func_800B0A48 1 0 + func_800B0FB0 1 0 + func_800B153C 1 1 + func_800B1E40 1 1 + func_800B2598 1 0 + func_800B2F40 1 0 + func_800B38E0 1 2 + func_800B5138 1 1 + func_800B5260 1 1 + func_800B5504 1 2 + func_800B5C7C 1 3 + func_800B85D4 1 5 + func_800B8CF0 1 0 + func_800BA7C4 1 0 + func_800BACEC 1 0 + func_800BAF54 1 4 + func_800BBBCC 1 0 + func_800BBF74 1 3 + func_800BE69C 1 3 + func_800BE86C 1 3 + func_800C08A8 1 1 + func_800C0B48 1 0 + func_800C14C0 1 4 + func_800C1D8C 1 6 + func_800C2524 1 0 + func_800C3DB0 1 0 + func_800C4FB4 1 0 + func_800C5CD4 1 1 + func_800C6598 1 0 + func_800CB354 1 2 + func_800D34C8 1 0 + func_800D4368 1 4 + func_800D493C 1 1 + func_800D4C08 1 1 + func_800D4C68 1 1 + func_800D775C 1 0 + func_800D785C 1 0 + func_800D7970 1 0 + func_800D7D6C 1 2 + func_800D7F9C 1 7 + func_800D8710 1 1 + func_800D91DC 1 9 + func_800D9C04 1 0 + func_800E6DCC 1 0 + func_8001726C 0 4 + func_800206E4 0 6 + func_80022DE4 0 4 + func_80029464 0 2 + func_8002B5A8 0 2 + func_8002B608 0 2 + func_8002B668 0 2 + func_8002B6AC 0 3 + func_8002B730 0 4 + func_8002B7E0 0 4 + func_8002B8B4 0 3 + func_8002B904 0 3 + func_8002B958 0 3 + func_8002B9AC 0 4 + func_8002BA08 0 3 + func_8002BA5C 0 1 + func_8002BA98 0 1 + func_8002BBB4 0 1 + func_8002BBEC 0 0 + func_8002BC58 0 0 + func_8002C5C8 0 0 + func_8002C634 0 0 + func_8002C6C8 0 0 + func_8002C734 0 0 + func_8002C884 0 0 + func_8002C8C4 0 0 + func_8002C9E4 0 3 + func_8002CB78 0 3 + func_8002CC18 0 0 + func_8002CC44 0 1 + func_8002CCDC 0 4 + func_8002CDD0 0 3 + func_8002D410 0 5 + func_8002D4A0 0 5 + func_8002D530 0 5 + func_8002D668 0 5 + func_8002D7A0 0 6 + func_8002D8E8 0 6 + func_80030234 0 3 + func_80031AB0 0 0 + func_80031AFC 0 0 + func_80031BA0 0 0 + func_80031CB0 0 0 + func_80031CE0 0 0 + func_80031D6C 0 1 + func_80031E98 0 0 + func_80031EEC 0 0 + func_80031F30 0 0 + func_80031FF0 0 0 + func_800320C4 0 1 + func_80032274 0 0 + func_800323CC 0 0 + func_8003252C 0 0 + func_8003257C 0 0 + func_80032614 0 0 + func_80032770 0 0 + func_80032804 0 0 + func_800328F8 0 0 + func_8003298C 0 0 + func_80032A28 0 0 + func_80032C8C 0 1 + func_80032D6C 0 0 + func_80032E08 0 0 + func_80032F34 0 0 + func_80032F98 0 0 + func_80032FFC 0 0 + func_80033060 0 0 + func_800330C4 0 0 + func_80033128 0 0 + func_800331CC 0 0 + func_80033224 0 0 + func_80033264 0 0 + func_800332EC 0 0 + func_8003337C 0 0 + func_80033420 0 0 + func_800344C0 0 5 + func_80034600 0 5 + func_800346F8 0 2 + func_80034754 0 2 + func_800348F4 0 2 + func_80034974 0 4 + func_80034E00 0 1 + func_80035430 0 1 + func_800A09DC 0 3 + func_800A0AB8 0 1 + func_800A0BA8 0 1 + func_800A0CAC 0 0 + func_800A11B4 0 1 + func_800A139C 0 1 + func_800A14BC 0 1 + func_800A16E4 0 0 + func_800A1FC8 0 2 + func_800A2014 0 4 + func_800A208C 0 1 + func_800A20F8 0 2 + func_800A2328 0 2 + func_800A2458 0 7 + func_800A24A8 0 3 + func_800A2C68 0 1 + func_800A2FB8 0 1 + func_800A32D8 0 0 + func_800A555C 0 0 + func_800A66A4 0 3 + func_800A6BCC 0 1 + func_800A784C 0 0 + func_800A79CC 0 8 + func_800A80DC 0 3 + func_800A81B8 0 2 + func_800A853C 0 1 + func_800AEC10 0 7 + func_800AF1D4 0 2 + func_800B0378 0 7 + func_800B2A00 0 0 + func_800B37A0 0 1 + func_800B383C 0 5 + func_800B480C 0 1 + func_800B4B04 0 1 + func_800B4EAC 0 1 + func_800B5274 0 2 + func_800B62C4 0 2 + func_800B6AE4 0 0 + func_800B6B4C 0 4 + func_800B6B98 0 0 + func_800B8360 0 2 + func_800B86D8 0 1 + func_800B91CC 0 5 + func_800B9568 0 8 + func_800BB2A8 0 2 + func_800BC81C 0 3 + func_800C0480 0 2 + func_800C0630 0 1 + func_800C0970 0 2 + func_800C0B20 0 1 + func_800C0B54 0 5 + func_800C0C18 0 2 + func_800C0E5C 0 3 + func_800C0EDC 0 3 + func_800C0F58 0 3 + func_800C0FD8 0 3 + func_800C107C 0 3 + func_800C1214 0 3 + func_800C13B0 0 4 + func_800C1674 0 3 + func_800C1714 0 3 + func_800C17B8 0 3 + func_800C1858 0 2 + func_800C1AB4 0 2 + func_800C1BF4 0 1 + func_800C1D24 0 1 + func_800C1DE4 0 3 + func_800C1EEC 0 3 + func_800C223C 0 6 + func_800C228C 0 3 + func_800C2394 0 3 + func_800C2704 0 3 + func_800C2754 0 3 + func_800C285C 0 3 + func_800C2928 0 5 + func_800C2BFC 0 2 + func_800C2CA8 0 2 + func_800C2D54 0 2 + func_800C2F7C 0 2 + func_800C2FFC 0 2 + func_800C307C 0 2 + func_800C30FC 0 2 + func_800C31E4 0 2 + func_800C3A20 0 2 + func_800C3C34 0 2 + func_800C3EA0 0 1 + func_800C3F1C 0 1 + func_800C3FA0 0 1 + func_800C401C 0 1 + func_800C40A4 0 2 + func_800C42B0 0 1 + func_800C4350 0 1 + func_800C45AC 0 3 + func_800C46D0 0 5 + func_800C4804 0 4 + func_800C493C 0 5 + func_800C494C 0 2 + func_800C49EC 0 3 + func_800C4A40 0 3 + func_800C4A94 0 3 + func_800C4DC8 0 3 + func_800C4DE8 0 3 + func_800C4EE8 0 3 + func_800C506C 0 1 + func_800C50EC 0 1 + func_800C5194 0 1 + func_800C523C 0 1 + func_800C532C 0 1 + func_800C5414 0 1 + func_800C54BC 0 1 + func_800C5564 0 1 + func_800C560C 0 1 + func_800C5668 0 1 + func_800C57B0 0 1 + func_800C5898 0 1 + func_800C59B8 0 3 + func_800C5A2C 0 1 + func_800C5ADC 0 2 + func_800C5CE8 0 2 + func_800C5E80 0 2 + func_800C5FF4 0 1 + func_800C62F4 0 1 + func_800C63CC 0 1 + func_800C6748 0 1 + func_800C684C 0 1 + func_800C6924 0 2 + func_800C6D64 0 2 + func_800C6FD8 0 2 + func_800C728C 0 1 + func_800C7354 0 2 + func_800C75F0 0 2 + func_800C7C3C 0 2 + func_800C7CE8 0 2 + func_800C814C 0 2 + func_800C81C0 0 2 + func_800C8514 0 2 + func_800C8588 0 2 + func_800C8B98 0 2 + func_800C8F64 0 1 + func_800C9080 0 1 + func_800C91D8 0 2 + func_800C955C 0 2 + func_800C9A20 0 2 + func_800C9B88 0 2 + func_800C9C84 0 2 + func_800C9D80 0 2 + func_800C9E7C 0 2 + func_800C9F78 0 2 + func_800CA074 0 2 + func_800CA158 0 2 + func_800CA254 0 2 + func_800CA394 0 2 + func_800CA490 0 2 + func_800CA5D4 0 2 + func_800CA77C 0 2 + func_800CA95C 0 1 + func_800CAA24 0 1 + func_800CAAEC 0 2 + func_800CAC98 0 2 + func_800CADFC 0 2 + func_800CAF60 0 2 + func_800CB01C 0 2 + func_800CB0B8 0 4 + func_800CB1CC 0 3 + func_800CB28C 0 4 + func_800CB4F8 0 2 + func_800CB5C0 0 2 + func_800CB718 0 2 + func_800CB7C0 0 3 + func_800CB858 0 3 + func_800CB8F4 0 3 + func_800CB98C 0 3 + func_800CBA28 0 3 + func_800CBAC0 0 3 + func_800CBB5C 0 3 + func_800CBBF4 0 3 + func_800CBCA4 0 3 + func_800CBD40 0 3 + func_800CBDFC 0 3 + func_800CBE94 0 3 + func_800CBF40 0 3 + func_800CBFDC 0 3 + func_800CC098 0 3 + func_800CC134 0 3 + func_800CC1D4 0 3 + func_800CC358 0 3 + func_800CC4D8 0 3 + func_800CC558 0 3 + func_800CC5EC 0 3 + func_800CC670 0 3 + func_800CC78C 0 3 + func_800CC824 0 3 + func_800CC8A8 0 3 + func_800CC9EC 0 2 + func_800CCB10 0 2 + func_800CCBBC 0 2 + func_800CCC3C 0 2 + func_800CCCC8 0 2 + func_800CCD54 0 1 + func_800CCE94 0 1 + func_800CCFE8 0 2 + func_800CD2E8 0 2 + func_800CD3F0 0 2 + func_800CD554 0 1 + func_800CD5F0 0 2 + func_800CD770 0 1 + func_800CD834 0 4 + func_800CD91C 0 3 + func_800CDA24 0 4 + func_800CDB0C 0 3 + func_800CDC28 0 2 + func_800CDD40 0 2 + func_800CDE8C 0 2 + func_800CE054 0 2 + func_800CE214 0 2 + func_800CE480 0 2 + func_800CE6F4 0 2 + func_800CE904 0 2 + func_800CEE44 0 4 + func_800CF028 0 3 + func_800CF140 0 2 + func_800CF200 0 3 + func_800CF2BC 0 2 + func_800CF718 0 2 + func_800CF9B8 0 1 + func_800CFAF0 0 1 + func_800CFB84 0 1 + func_800CFCE4 0 2 + func_800CFE78 0 2 + func_800D0180 0 4 + func_800D08B8 0 0 + func_800D1654 0 2 + func_800D184C 0 3 + func_800D195C 0 1 + func_800D1A80 0 1 + func_800D1B94 0 3 + func_800D1C68 0 2 + func_800D1D3C 0 2 + func_800D1DB8 0 2 + func_800D1F20 0 5 + func_800D1FDC 0 5 + func_800D2098 0 5 + func_800D2164 0 9 + func_800D2794 0 2 + func_800D28A8 0 2 + func_800D2A70 0 3 + func_800D2B60 0 4 + func_800D2C60 0 4 + func_800D2E94 0 1 + func_800D2F3C 0 2 + func_800D3004 0 2 + func_800D3124 0 2 + func_800D3264 0 4 + func_800D3330 0 4 + func_800D368C 0 4 + func_800D3728 0 4 + func_800D3840 0 4 + func_800D3958 0 4 + func_800D3A70 0 4 + func_800D3B88 0 3 + func_800D3C18 0 3 + func_800D3CA8 0 3 + func_800D3D40 0 3 + func_800D3DCC 0 2 + func_800D3F30 0 1 + func_800D4038 0 2 + func_800D4214 0 1 + func_800D4300 0 2 + func_800D461C 0 2 + func_800D4780 0 1 + func_800D4CBC 0 2 + func_800D56A8 0 3 + func_800D579C 0 2 + func_800D5938 0 1 + func_800D5A60 0 1 + func_800D5D28 0 5 + func_800D6D44 0 1 + func_800D6E0C 0 1 + func_800D6F6C 0 1 + func_800D6F78 0 4 + func_800D707C 0 1 + func_800D7178 0 2 + func_800D751C 0 7 + func_800D76B8 0 1 + func_800D7D3C 0 2 + func_800D85B0 0 1 + func_800D85FC 0 3 + func_800D93E4 0 7 + func_800D9FA4 0 3 + func_800DA380 0 5 + func_800DA4FC 0 0 + func_800DB818 0 5 + func_800DD85C 0 3 + func_800DDAD8 0 5 + func_800DE46C 0 3 + func_800DEB18 0 1 + func_800DF24C 0 0 + func_800DF530 0 1 + func_800DF9F8 0 1 + func_800DFA94 0 5 + func_800DFC40 0 1 + func_800DFE34 0 5 + func_800DFFE4 0 0 + func_800E2C6C 0 7 + func_800E3088 0 9 + func_800E33A0 0 8 + func_800E3FB4 0 6 + func_800E4180 0 7 + func_800E4394 0 5 + func_800E4A64 0 5 + func_800E4C08 0 8 + func_800E53C8 0 0 + func_800E5978 0 12 + func_801D080C 0 25 + func_801D1C2C 0 3 + func_801D1D40 0 4 + func_801D2DA8 0 1 + + [failed] (26 functions) + Function Dependents Calls + ---------------------------------------- ---------- -------- + func_801B11BC 2 0 + func_801B1598 2 0 + func_800D3658 1 1 + func_800D58D0 1 1 + func_800D7A88 1 1 + func_801B0668 1 1 + func_801B08C0 1 9 + func_801B1120 1 1 + func_801B1734 1 1 + func_801B19AC 1 1 + func_801B1CB0 1 0 + func_801B1E0C 1 0 + func_800A015C 0 3 + func_800A01A0 0 17 + func_800A32F0 0 0 + func_800A32FC 0 0 + func_800A3308 0 0 + func_800D376C 0 3 + func_800D508C 0 1 + func_800D5138 0 1 + func_800D52A0 0 1 + func_800D5350 0 0 + func_800D5444 0 1 + func_800D6734 0 1 + func_801B0050 0 28 + func_801B0F08 0 6 + + [todo] (66 functions) + Function Dependents Calls + ---------------------------------------- ---------- -------- + func_800A6000 5 5 + func_8001786C 4 12 + func_80034150 4 8 + func_800260DC 3 13 + func_800A5BC8 3 3 + func_800B5E64 3 3 + func_800B1D48 2 21 + func_800B54B8 2 3 + func_800140F4 1 17 + func_80021F58 1 18 + func_8002B1F8 1 6 + func_8002F848 1 7 + func_80030380 1 4 + func_800308D4 1 8 + func_800A16CC 1 21 + func_800A2314 1 33 + func_800A23E0 1 10 + func_800A38FC 1 10 + func_800A4BEC 1 7 + func_800A6278 1 4 + func_800A8968 1 2 + func_800A8F88 1 10 + func_800AA348 1 2 + func_800AA5E4 1 4 + func_800AA930 1 7 + func_800AAB24 1 5 + func_800AB9C4 1 3 + func_800ABB0C 1 23 + func_800AC35C 1 11 + func_800BA534 1 6 + func_800BA598 1 8 + func_800BA65C 1 8 + func_800BB3A8 1 4 + func_800BC9FC 1 9 + func_800BCB1C 1 9 + func_800BEA38 1 4 + func_800C4148 1 4 + func_800D0518 1 6 + func_800D0938 1 5 + func_800D8D78 1 21 + func_80023AD4 0 27 + func_8002B3B4 0 6 + func_80035744 0 15 + func_800A1158 0 17 + func_800A12F0 0 4 + func_800A17C0 0 6 + func_800A19A4 0 8 + func_800A3ED0 0 7 + func_800A866C 0 4 + func_800AABBC 0 16 + func_800B33A4 0 8 + func_800B3968 0 4 + func_800B3A04 0 4 + func_800B3AB8 0 4 + func_800B3B84 0 4 + func_800B8B48 0 8 + func_800B9B0C 0 2 + func_800C74E4 0 2 + func_800D4710 0 5 + func_800D5C9C 0 6 + func_800D650C 0 9 + func_800DF2CC 0 6 + func_800DF5C8 0 7 + func_800E3B64 0 7 + func_800E3E10 0 7 + func_801D2408 0 9 + + [unknown] (5 functions) + Function Dependents Calls + ---------------------------------------- ---------- -------- + func_800D4840 4 0 + func_800A1798 1 14 + func_800A3828 1 1 + func_80034A90 0 4 + func_800D4838 0 0 diff --git a/automation/discover.py b/automation/discover.py new file mode 100644 index 0000000..125001a --- /dev/null +++ b/automation/discover.py @@ -0,0 +1,358 @@ +#!/usr/bin/env python3 +""" +Function Discovery Scanner + +Scans the FF7 decompilation codebase to find all INCLUDE_ASM macros +and populates the tracking database. + +Usage: + python discover.py --scan # Scan codebase and update database + python discover.py --stats # Show statistics + python discover.py --list battle # List functions in battle module + python discover.py --list-todo # Show next functions to decompile +""" + +import re +import os +import argparse +import subprocess +from pathlib import Path +from typing import List, Tuple, Optional, Dict +from database import DecompDatabase + + +# Project root is one level up from automation/ +PROJECT_ROOT = Path(__file__).parent.parent +SRC_DIR = PROJECT_ROOT / "src" +ASM_DIR = PROJECT_ROOT / "asm" / "us" + + +def find_include_asm_functions(c_file_path: Path) -> List[Tuple[str, str]]: + """ + Parse a C file and find all INCLUDE_ASM macros. + + Returns: + List of (function_name, asm_path_hint) tuples + """ + functions = [] + + try: + content = c_file_path.read_text(encoding='utf-8', errors='ignore') + except Exception as e: + print(f"Warning: Could not read {c_file_path}: {e}") + return functions + + # Honour the "do not decompile" sentinel comment: stop scanning at that point. + # This is checked by content rather than line number so it survives edits above it. + SENTINEL = "// NOTE: please do not decompile any of these functions." + sentinel_pos = content.find(SENTINEL) + if sentinel_pos != -1: + content = content[:sentinel_pos] + + # Match patterns like: + # INCLUDE_ASM("asm/us/battle/nonmatchings/battle", func_800A1158); + # INCLUDE_ASM(const s32, "asm/us/main/nonmatchings/1050", D_8002AA14); + pattern = r'INCLUDE_ASM\s*\([^,]*,\s*"([^"]+)"\s*,\s*([^);\s]+)' + matches = re.finditer(pattern, content) + + for match in matches: + asm_path_hint = match.group(1) + func_name = match.group(2) + functions.append((func_name, asm_path_hint)) + + # Also match simpler pattern without type: + # INCLUDE_ASM("asm/us/battle/nonmatchings/battle", func_800A1158); + pattern2 = r'INCLUDE_ASM\s*\(\s*"([^"]+)"\s*,\s*([^);\s]+)' + matches2 = re.finditer(pattern2, content) + + for match in matches2: + asm_path_hint = match.group(1) + func_name = match.group(2) + # Avoid duplicates + if (func_name, asm_path_hint) not in functions: + functions.append((func_name, asm_path_hint)) + + return functions + + +def infer_module_from_path(c_file_path: Path) -> str: + """Infer the module name from the source file path.""" + rel_path = c_file_path.relative_to(SRC_DIR) + parts = rel_path.parts + if len(parts) > 0: + return parts[0] # First directory is usually the module + return "unknown" + + +def count_asm_lines(asm_path: Path) -> int: + """Count the number of assembly instruction lines (rough difficulty metric).""" + if not asm_path.exists(): + return 0 + + try: + content = asm_path.read_text(encoding='utf-8', errors='ignore') + # Count lines that look like instructions (start with whitespace + instruction) + lines = [l for l in content.split('\n') if l.strip() and not l.strip().startswith('#')] + return len(lines) + except Exception: + return 0 + + +def resolve_asm_path(asm_path_hint: str) -> Optional[Path]: + """ + Try to find the actual .s file from the hint in INCLUDE_ASM. + + The hint is usually like "asm/us/battle/nonmatchings/battle" + and we need to find the .s file in that directory. + """ + # Remove "asm/us/" prefix if present + hint = asm_path_hint.replace("asm/us/", "").replace("asm/", "") + + # This is typically a directory; function .s files are inside + asm_dir_path = ASM_DIR / hint + + return asm_dir_path if asm_dir_path.exists() else None + + +def scan_codebase(db: DecompDatabase): + """Scan the entire src/ directory for INCLUDE_ASM functions.""" + print(f"Scanning {SRC_DIR} for INCLUDE_ASM functions...") + + total_found = 0 + + # Find all .c files + c_files = list(SRC_DIR.rglob("*.c")) + print(f"Found {len(c_files)} C files to scan") + + for c_file in c_files: + functions = find_include_asm_functions(c_file) + + if not functions: + continue + + module = infer_module_from_path(c_file) + rel_c_path = str(c_file.relative_to(PROJECT_ROOT)) + + for func_name, asm_hint in functions: + # Try to resolve the actual asm path + asm_dir = resolve_asm_path(asm_hint) + asm_path_str = str(Path(asm_hint) / f"{func_name}.s") if asm_dir else asm_hint + + # Try to count lines for difficulty estimate + if asm_dir: + asm_file = asm_dir / f"{func_name}.s" + line_count = count_asm_lines(asm_file) + else: + line_count = 0 + + # Add to database + db.add_function( + name=func_name, + c_file_path=rel_c_path, + asm_file_path=asm_path_str, + module=module, + line_count=line_count + ) + + total_found += 1 + print(f" Found: {func_name} in {module} ({line_count} asm lines)") + + # Remove any previously-scanned entries from this file that are now beyond + # the sentinel comment (i.e. not in the set we just collected). + valid_names = {fn for fn, _ in functions} + removed = db.remove_functions_not_in_set(rel_c_path, valid_names) + for name in removed: + print(f" Removed (below sentinel): {name}") + + print(f"\n✓ Scan complete! Found {total_found} functions") + + +def show_statistics(db: DecompDatabase): + """Display statistics about the decompilation progress.""" + stats = db.get_statistics() + + print("\n" + "="*60) + print("DECOMPILATION STATISTICS") + print("="*60) + + print(f"\nTotal functions: {stats['total_functions']}") + + print("\nBy Status:") + for status, count in sorted(stats['by_status'].items()): + percentage = (count / stats['total_functions'] * 100) if stats['total_functions'] > 0 else 0 + print(f" {status:15s}: {count:4d} ({percentage:5.1f}%)") + + print("\nBy Module:") + for module, count in sorted(stats['by_module'].items()): + print(f" {module:15s}: {count:4d}") + + print("\n" + "="*60 + "\n") + + +def list_functions_by_module(db: DecompDatabase, module: str): + """List all functions in a specific module.""" + functions = db.get_functions_by_module(module) + + if not functions: + print(f"No functions found in module '{module}'") + return + + print(f"\nFunctions in {module} module ({len(functions)} total):") + print("-" * 80) + + for func in functions: + status_emoji = { + 'todo': '⏳', + 'in_progress': '🔄', + 'decompiled': '✓', + 'verified': '✓✓', + 'failed': '✗' + }.get(func['status'], '?') + + print(f"{status_emoji} {func['name']:30s} | {func['status']:12s} | " + f"{func['line_count']:3d} lines | {func['c_file_path']}") + + +def populate_rank_scores(db: DecompDatabase) -> int: + """Run `mako.sh rank` for every module and store scores in the database. + + The rank score (0.0 easiest → 1.0 hardest) comes from the asm-differ + similarity metric embedded in mako.sh rank. Lower scores mean the + function is structurally closer to its original assembly, making it a + better candidate for automated decompilation. + + Returns: + Total number of database rows updated. + """ + mako = PROJECT_ROOT / "mako.sh" + asm_base = PROJECT_ROOT / "asm" / "us" + + modules = sorted(p.name for p in asm_base.iterdir() if p.is_dir()) + scores: Dict[str, float] = {} + + for module in modules: + try: + result = subprocess.run( + [str(mako), "rank", module], + capture_output=True, + text=True, + cwd=PROJECT_ROOT, + ) + if result.returncode != 0: + print(f" rank: skipping {module} ({result.stderr.strip()[:80]})") + continue + for line in result.stdout.splitlines(): + line = line.strip() + if not line: + continue + parts = line.split(": ", 1) + if len(parts) != 2: + continue + try: + score = float(parts[0]) + except ValueError: + continue + func_name = parts[1].removesuffix(".s") + scores[func_name] = score + except Exception as e: + print(f" rank: error for {module}: {e}") + + updated = db.update_rank_scores(scores) + print(f"✓ Rank scores updated for {updated} functions ({len(scores)} from mako.sh rank)") + return updated + + +def list_todo_functions(db: DecompDatabase, limit: int = 20): + """List the next functions to work on.""" + functions = db.get_next_todo(limit) + + if not functions: + print("No TODO functions found! 🎉") + return + + print(f"\nNext {limit} functions to decompile (sorted by difficulty):") + print("-" * 80) + + for i, func in enumerate(functions, 1): + print(f"{i:2d}. {func['name']:30s} | {func['module']:10s} | " + f"{func['line_count']:3d} asm lines | {func['c_file_path']}") + + print("\nTo decompile a function manually:") + print(f" ./mako.sh dec {functions[0]['name']}") + + +def list_by_status(db: DecompDatabase, status: str, limit: int = 50): + """List functions with a specific status.""" + functions = db.get_functions_by_status(status, limit=limit) + + if not functions: + print(f"No functions with status '{status}' found.") + return + + print(f"\nFunctions with status '{status}' ({len(functions)} shown):") + print("-" * 80) + + for i, func in enumerate(functions, 1): + attempts = func.get('attempt_count', 0) + notes = func.get('notes', '') + note_preview = (notes[:50] + '...') if notes and len(notes) > 50 else (notes or '') + + print(f"{i:3d}. {func['name']:30s} | {func['module']:10s} | " + f"{func['line_count']:3d} lines | attempts: {attempts}") + if note_preview: + print(f" Note: {note_preview}") + + print(f"\nTotal {status}: {len(functions)}") + if len(functions) >= limit: + print(f"(Limited to {limit}, use --limit to see more)") + + +def main(): + parser = argparse.ArgumentParser( + description="Discover and track INCLUDE_ASM functions in FF7 decompilation" + ) + parser.add_argument('--scan', action='store_true', + help='Scan the codebase and update database') + parser.add_argument('--stats', action='store_true', + help='Show decompilation statistics') + parser.add_argument('--list', type=str, metavar='MODULE', + help='List functions in a specific module') + parser.add_argument('--list-todo', action='store_true', + help='List next functions to decompile') + parser.add_argument('--list-status', type=str, metavar='STATUS', + help='List functions with specific status (blocked, failed, decompiled_needs_refine, etc.)') + parser.add_argument('--update-ranks', action='store_true', + help='Run mako.sh rank for all modules and update difficulty scores in DB') + parser.add_argument('--limit', type=int, default=50, + help='Limit number of results (default: 50)') + parser.add_argument('--db', type=str, default='functions.db', + help='Database file path (default: functions.db)') + + args = parser.parse_args() + + # Initialize database + db = DecompDatabase(args.db) + + try: + if args.scan: + scan_codebase(db) + populate_rank_scores(db) + show_statistics(db) + elif args.update_ranks: + populate_rank_scores(db) + elif args.stats: + show_statistics(db) + elif args.list: + list_functions_by_module(db, args.list) + elif args.list_todo: + list_todo_functions(db, args.limit if args.limit != 50 else 20) + elif args.list_status: + list_by_status(db, args.list_status, args.limit) + else: + parser.print_help() + finally: + db.close() + + +if __name__ == "__main__": + main() diff --git a/automation/expand_strings.py b/automation/expand_strings.py new file mode 100644 index 0000000..9118ff6 --- /dev/null +++ b/automation/expand_strings.py @@ -0,0 +1,147 @@ +#!/usr/bin/env python3 +"""expand_strings.py + +Finds FF7-encoded byte arrays in .c source files and converts them back to +human-readable _S() / _SL() string macros. + +A byte array is treated as an FF7 string when: + - It contains a 0xFF terminator byte + - Every byte before 0xFF is in the range 0x00-0x5E (maps to ASCII 0x20-0x7E) + - Every byte after 0xFF is 0x00 (padding) + +Encoding: byte + 0x20 = ASCII character (e.g. 0x28 -> 'H', 0x00 -> ' ') + +Usage: + python3 expand_strings.py # all src/**/*.c files + python3 expand_strings.py src/menu # specific directory or file + python3 expand_strings.py --in-place # overwrite files instead of printing +""" + +import argparse +import re +import sys +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parent.parent + +# Matches a braced list of hex bytes (0xNN) and/or bare zeros, possibly multiline. +# Captures the interior so we can extract individual values. +_ARRAY_RE = re.compile( + r'\{((?:\s*(?:0x[0-9A-Fa-f]{1,2}|0)\s*,?\s*)+)\}', + re.DOTALL, +) + +# Pulls every numeric token out of the interior matched above. +_TOKEN_RE = re.compile(r'0x([0-9A-Fa-f]{1,2})|(? list[int] | None: + """Return list of byte values from the array interior, or None on parse error.""" + values = [] + for m in _TOKEN_RE.finditer(interior): + if m.group(1) is not None: + values.append(int(m.group(1), 16)) + else: + values.append(0) + return values if values else None + + +def _decode_ff7(byte_list: list[int]) -> tuple[str, int] | None: + """ + Try to decode a byte list as an FF7 ASCII string. + + Returns (decoded_text, num_padding_zeros) if valid, else None. + Valid means: + - contains 0xFF + - all bytes before 0xFF are in 0x00-0x5E (printable ASCII when + 0x20) + - all bytes after 0xFF are 0x00 (padding) + """ + try: + ff_idx = byte_list.index(0xFF) + except ValueError: + return None + + content = byte_list[:ff_idx] + padding = byte_list[ff_idx + 1:] + + if any(b > 0x5E for b in content): + return None # contains non-ASCII FF7 special bytes + if any(b != 0x00 for b in padding): + return None # non-zero bytes after terminator + + text = ''.join(chr(b + 0x20) for b in content) + return (text, len(padding)) + + +def _encode_c_string(text: str) -> str: + """Escape a string for inclusion inside a C double-quoted literal.""" + return text.replace('\\', '\\\\').replace('"', '\\"') + + +def collect_file(content: str) -> str: + """ + Scan *content* for byte-array initializers that look like FF7 strings and + replace them with _S() / _SL() macros. Returns the rewritten content. + """ + def replace(m: re.Match) -> str: + interior = m.group(1) + byte_list = _parse_bytes(interior) + if byte_list is None: + return m.group(0) + + result = _decode_ff7(byte_list) + if result is None: + return m.group(0) + + text, num_padding = result + escaped = _encode_c_string(text) + + if num_padding == 0: + return f'_S("{escaped}")' + else: + # _SL(N, "text") produces N-1 bytes total, so N = len(byte_list) + 1 + return f'_SL({len(byte_list) + 1}, "{escaped}")' + + return _ARRAY_RE.sub(replace, content) + + +def main() -> None: + parser = argparse.ArgumentParser( + description="Convert FF7-encoded hex byte arrays in C source files back to _S()/_SL() macros" + ) + parser.add_argument( + "target", + nargs="?", + default=str(REPO_ROOT / "src"), + help="path to a .c file or directory to search recursively (default: src/)", + ) + parser.add_argument( + "--in-place", + action="store_true", + help="overwrite source files with converted output instead of printing to stdout", + ) + args = parser.parse_args() + + target = Path(args.target) + if target.is_file(): + files = [target] + elif target.is_dir(): + files = sorted(target.rglob("*.c")) + else: + print(f"error: not a file or directory: {target}", file=sys.stderr) + sys.exit(1) + + for path in files: + original = path.read_text(errors="replace") + converted = collect_file(original) + if args.in_place: + if converted != original: + path.write_text(converted) + print(f"converted: {path}") + else: + print(f"/* === {path} === */") + print(converted) + + +if __name__ == "__main__": + main() diff --git a/automation/fix_existing_errors.py b/automation/fix_existing_errors.py new file mode 100755 index 0000000..021a28b --- /dev/null +++ b/automation/fix_existing_errors.py @@ -0,0 +1,1477 @@ +#!/usr/bin/env python3 +""" +Standalone script to fix type errors in existing decompiled functions. + +This scans files with compilation errors and uses LLM to fix void* type issues. +""" + +import os +import sys +import re +import subprocess +from pathlib import Path +from datetime import datetime +from typing import List, Tuple, Dict, Optional +from database import DecompDatabase + +# Add parent directory to path for imports +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) + +try: + from llm_helper import LLMHelper + HAS_LLM = True +except ImportError: + HAS_LLM = False + LLMHelper = None + + +class TypeErrorFixer: + """Fix type errors in decompiled functions using LLM.""" + + def __init__(self, model: str = "qwen2.5-coder:7b", verbose: bool = False): + """Initialize the fixer with Ollama.""" + if not HAS_LLM: + print("[ERROR] llm_helper not available") + sys.exit(1) + + self.llm = LLMHelper(model=model, verbose=verbose) + if not self.llm.available: + print("[ERROR] Ollama not available. Please install and start Ollama:") + print(" https://ollama.ai/") + sys.exit(1) + + self.db = DecompDatabase() + self.workspace_root = Path(__file__).parent.parent.absolute() + self.file_context = {} # Cache for file-level context + # Track functions that already caused validation failures so we skip them + # in subsequent passes. Key: func_name, Value: number of validation failures. + self._validation_failures: Dict[str, int] = {} + + def extract_file_context(self, file_path: str) -> Dict: + """ + Extract file-level context (typedefs, externs, includes). + Returns dict with 'typedefs', 'externs', 'includes'. + """ + if file_path in self.file_context: + return self.file_context[file_path] + + with open(file_path, 'r') as f: + content = f.read() + + context = { + 'typedefs': [], + 'externs': [], + 'includes': [], + 'header_typedef_names': [] + } + + # Extract typedef declarations + typedef_pattern = re.compile(r'typedef\s+(?:struct|enum|union)?\s*\w*\s*\{[^}]+\}\s*\w+;', re.MULTILINE | re.DOTALL) + for match in typedef_pattern.finditer(content): + typedef_text = match.group(0) + # Extract the name + name_match = re.search(r'\}\s*(\w+);', typedef_text) + if name_match: + context['typedefs'].append({ + 'name': name_match.group(1), + 'text': typedef_text + }) + + # Extract extern declarations + extern_pattern = re.compile(r'extern\s+[^;]+;') + for match in extern_pattern.finditer(content): + context['externs'].append(match.group(0)) + + # Extract includes and follow them (up to 3 levels deep) to collect all visible typedef names + include_pattern = re.compile(r'#include\s+[<"]([^>"]+)[>"]') + header_typedef_names = set() + + def _collect_from_header(hpath: Path, depth: int): + if depth <= 0 or not hpath.exists(): + return + names = self._extract_typedef_names_from_header(hpath) + header_typedef_names.update(names) + try: + hcontent = hpath.read_text(errors='replace') + except Exception: + return + for m in include_pattern.finditer(hcontent): + sub_name = m.group(1) + sub_path = self._resolve_include(sub_name, str(hpath)) + if sub_path: + _collect_from_header(sub_path, depth - 1) + + for match in include_pattern.finditer(content): + include_name = match.group(1) + context['includes'].append(f'#include "{include_name}"') + header_path = self._resolve_include(include_name, file_path) + if header_path: + _collect_from_header(header_path, depth=5) + context['header_typedef_names'] = sorted(header_typedef_names) + + self.file_context[file_path] = context + return context + + def _resolve_include(self, include_name: str, source_file: str) -> Optional[Path]: + """Resolve an #include filename to an actual path, searching standard dirs.""" + candidates = [ + Path(source_file).parent / include_name, + self.workspace_root / 'include' / include_name, + self.workspace_root / 'include' / 'psxsdk' / include_name, + self.workspace_root / include_name, + ] + for candidate in candidates: + if candidate.exists(): + return candidate + return None + + def _extract_typedef_names_from_header(self, header_path: Path) -> List[str]: + """ + Extract all typedef names from a header file. + Returns a flat list of type name strings. + """ + try: + content = header_path.read_text(errors='replace') + except Exception: + return [] + names = [] + # Struct/union/enum typedef: '} TypeName;' + names += re.findall(r'\}\s*(\w+)\s*;', content) + # Simple typedef: 'typedef TypeName;' + for m in re.finditer(r'^typedef\s+\S.*?\s+(\w+)\s*;', content, re.MULTILINE): + names.append(m.group(1)) + return [n for n in names if n and not n[0].isdigit()] + + def _extract_struct_field_maps(self, header_path: Path) -> Dict[str, Dict[int, tuple]]: + """ + Parse struct definitions from a header file. + Returns {struct_name: {byte_offset: (field_name, c_type)}} using the + '/* 0xNN */' offset comments common in this codebase. If a field has + no offset comment the offset is derived from sequential layout. + """ + TYPE_SIZES = { + 'u8': 1, 's8': 1, 'char': 1, + 'u16': 2, 's16': 2, + 'u32': 4, 's32': 4, 'int': 4, 'float': 4, + 'u64': 8, 's64': 8, 'double': 8, + } + try: + content = header_path.read_text(errors='replace') + except Exception: + return {} + + result: Dict[str, Dict[int, tuple]] = {} + # Match: typedef struct [OptName] { body } TypeName; + struct_re = re.compile( + r'typedef\s+struct\s*\w*\s*\{([^}]+)\}\s*(\w+)\s*;', re.DOTALL + ) + field_re = re.compile( + r'(?:/\*\s*(0x[0-9a-fA-F]+|\d+)\s*\*/\s*)?' # optional /* 0xNN */ + r'([\w\s\*]+?)\s+(\w+)\s*(?:\[[\w\s\+\-\*]*\])?\s*;' # type name[array]; + ) + for sm in struct_re.finditer(content): + body = sm.group(1) + struct_name = sm.group(2) + fields: Dict[int, tuple] = {} + current_offset = 0 + for fm in field_re.finditer(body): + offset_str, ftype, fname = fm.group(1), fm.group(2).strip(), fm.group(3) + if offset_str: + try: + current_offset = int(offset_str, 16) if '0x' in offset_str else int(offset_str) + except ValueError: + pass + fields[current_offset] = (fname, ftype) + # Advance for next field + base = ftype.rstrip('* ').split()[-1] if ftype.split() else ftype + size = 4 if '*' in ftype else TYPE_SIZES.get(base, 4) + current_offset += size + if fields: + result[struct_name] = fields + return result + + def _collect_struct_field_maps(self, file_path: str) -> Dict[str, Dict[int, tuple]]: + """ + Walk the transitive include chain for file_path and return the merged + struct field map (see _extract_struct_field_maps). + """ + include_pattern = re.compile(r'#include\s+[<"]([^>"]+)[>"]') + all_maps: Dict[str, Dict[int, tuple]] = {} + visited: set = set() + + def _walk(path: Path, depth: int): + key = str(path) + if key in visited or depth <= 0 or not path.exists(): + return + visited.add(key) + maps = self._extract_struct_field_maps(path) + for k, v in maps.items(): + if k not in all_maps: + all_maps[k] = v + try: + content = path.read_text(errors='replace') + except Exception: + return + for m in include_pattern.finditer(content): + sub = self._resolve_include(m.group(1), str(path)) + if sub: + _walk(sub, depth - 1) + + try: + with open(file_path) as f: + src = f.read() + except Exception: + return all_maps + for m in include_pattern.finditer(src): + hp = self._resolve_include(m.group(1), file_path) + if hp: + _walk(hp, depth=5) + return all_maps + + def _get_psyq_params(self, rel_path: str): + """ + Parse build.ninja to find PSY-Q compiler parameters for a source file. + Returns (cc1_binary, cc_flags) or None if the file has no psx-cc rule. + """ + ninja_file = self.workspace_root / 'build.ninja' + if not ninja_file.exists(): + return None + + lines = ninja_file.read_text().splitlines() + + # Find: "build .o: psx-cc " (possibly with a trailing " | $") + build_line_idx = None + for i, line in enumerate(lines): + if re.match(r'build\s+\S+\.o\s*:\s*psx-cc\s+' + re.escape(rel_path) + r'\b', line): + build_line_idx = i + break + + if build_line_idx is None: + return None + + # Skip the build rule and any continuation lines (ending with "$") + idx = build_line_idx + 1 + while idx < len(lines) and lines[idx - 1].endswith('$'): + idx += 1 + + # Read the indented variable block that follows + cc1 = 'cc1-psx-26' + cc_flags = '-O2 -G0' + while idx < len(lines) and lines[idx].startswith(' '): + m = re.match(r'\s+cc1\s*=\s*(\S+)', lines[idx]) + if m: + cc1 = m.group(1) + m = re.match(r'\s+cc_flags\s*=\s*(.+)', lines[idx]) + if m: + cc_flags = m.group(1).strip() + idx += 1 + + return cc1, cc_flags + + def get_compilation_errors(self, file_path: str) -> List[Dict]: + """ + Get compilation errors for a file by running the PSY-Q compiler directly. + Parses build.ninja to find the correct cc1 binary and flags for this file, + then invokes the cpp | str | iconv | cc1 pipeline directly — bypassing the + full `make` chain that fails at the linker step before overlay files compile. + Falls back to `make` if no PSY-Q rule is found in build.ninja. + """ + try: + rel_path = str(Path(file_path).relative_to(self.workspace_root)) + file_name = Path(file_path).name + + params = self._get_psyq_params(rel_path) + + if params: + cc1, cc_flags = params + # Run the PSY-Q pipeline up to cc1; redirect cc1 stdout (assembly) + # to /dev/null — errors go to stderr which we capture. + cmd = ( + f'mipsel-linux-gnu-cpp -Iinclude -Iinclude/psxsdk -DUSE_INCLUDE_ASM -DFF7_STR' + f' -lang-c -Iinclude -Iinclude/psxsdk -undef -Wall -fno-builtin {rel_path}' + f' | bin/str' + f' | iconv --from-code=UTF-8 --to-code=Shift-JIS' + f' | bin/{cc1} -quiet -mcpu=3000 -g -mgas -gcoff {cc_flags} > /dev/null' + ) + result = subprocess.run( + cmd, shell=True, + cwd=str(self.workspace_root), + stderr=subprocess.PIPE, + text=True, + timeout=60 + ) + output = result.stderr + else: + # Fallback for files that go through make directly (e.g. main overlay) + Path(file_path).touch() + result = subprocess.run( + ['make'], + cwd=str(self.workspace_root), + capture_output=True, + text=True, + timeout=60 + ) + output = result.stdout + '\n' + result.stderr + + errors = [] + error_pattern = re.compile( + rf'{re.escape(file_name)}:(\d+):\s*(?:warning:\s*)?(.+)' + ) + + for line in output.split('\n'): + match = error_pattern.search(line) + if match: + line_num = int(match.group(1)) + message = match.group(2).strip() + + # Skip pure warnings unless they're relevant + if 'warning:' in line.lower() and not any(x in message.lower() + for x in ['incompatible', 'pointer', 'cast', 'type']): + continue + + category = self._categorize_error(message) + errors.append({ + 'line': line_num, + 'type': category, + 'message': message, + 'raw_type': 'error' if 'error' in line.lower() else 'warning' + }) + + return errors + + except subprocess.TimeoutExpired: + print(f"[WARN] Compilation timed out for {file_path}") + return [] + except Exception as e: + print(f"[WARN] Could not compile {file_path}: {e}") + return [] + + def _categorize_error(self, message: str) -> str: + """Categorize error message into error type.""" + msg_lower = message.lower() + + # PSY-Q compiler specific error messages + if 'undeclared' in msg_lower or 'not declared' in msg_lower: + return 'undefined_identifier' + elif 'parse error' in msg_lower: + return 'syntax_error' + elif 'incompatible types' in msg_lower or 'incompatible pointer' in msg_lower: + return 'type_mismatch' + elif 'invalid type argument' in msg_lower: + return 'invalid_operation' + elif 'redefinition' in msg_lower or 'previously declared' in msg_lower: + return 'redefinition' + elif 'duplicate label' in msg_lower: + return 'duplicate_label' + elif 'struct' in msg_lower and ('member' in msg_lower or 'field' in msg_lower): + return 'missing_struct_field' + elif 'void' in msg_lower and ('dereference' in msg_lower or 'incomplete type' in msg_lower): + return 'void_pointer_dereference' + elif 'pointer' in msg_lower and ('integer' in msg_lower or 'cast' in msg_lower): + return 'pointer_cast' + elif 'assignment' in msg_lower and 'incompatible' in msg_lower: + return 'type_mismatch' + else: + return 'unknown' + + def detect_type_errors_in_function(self, code: str, start_line: int, + compiler_errors: List[Dict]) -> List[Dict]: + """ + Detect type errors in function code using compiler errors. + Returns list of error dictionaries filtered to this function's line range. + """ + code_lines = code.count('\n') + 1 + end_line = start_line + code_lines - 1 + + # Filter compiler errors to this function + func_errors = [] + for err in compiler_errors: + err_line = err['line'] + if start_line <= err_line <= end_line: + # Add relative line number within function + err_copy = err.copy() + err_copy['func_line'] = err_line - start_line + 1 + func_errors.append(err_copy) + + # Also detect potential issues from code patterns + # Pattern 1: void* pointer dereference with -> + if 'void*' in code or 'void *' in code: + code_lower = code.lower() + if '->' in code and ('void*' in code_lower or 'void *' in code_lower): + # Check if not already in compiler errors + has_void_error = any(e['type'] == 'void_pointer_dereference' for e in func_errors) + if not has_void_error: + func_errors.append({ + 'line': start_line, + 'func_line': 1, + 'type': 'void_pointer_dereference', + 'message': 'void* pointer used with -> operator', + 'raw_type': 'potential' + }) + + # Pattern 2: Struct field access on void* variables + void_ptr_pattern = re.compile(r'\b(\w+)\s*\*\s*(\w+)\s*=.*?void\s*\*', re.DOTALL) + struct_access_pattern = re.compile(r'\b(\w+)->unk\w*') + + void_pointers = set() + for match in void_ptr_pattern.finditer(code): + var_name = match.group(2) + void_pointers.add(var_name) + + for match in struct_access_pattern.finditer(code): + var_name = match.group(1) + if var_name in void_pointers: + has_struct_error = any( + var_name in e.get('message', '') for e in func_errors + ) + if not has_struct_error: + func_errors.append({ + 'line': start_line, + 'func_line': 1, + 'type': 'void_pointer_dereference', + 'message': f'Struct field access on void* variable: {var_name}', + 'raw_type': 'potential' + }) + + return func_errors + + def infer_struct_type_from_fields(self, code: str) -> Optional[str]: + """ + Infer struct type from field access patterns. + Returns struct typedef or None. + """ + # Find all field accesses (->unk0, ->unk4, etc.) + field_accesses = re.findall(r'->unk([0-9A-Fa-fxX]+)', code) + if not field_accesses: + return None + + # Convert hex to decimal and get unique fields + fields = set() + for f in field_accesses: + try: + # Remove 0x prefix if present and convert + f_clean = f.replace('0x', '').replace('0X', '') + fields.add(int(f_clean, 16) if any(c in f_clean.upper() for c in 'ABCDEF') else int(f_clean)) + except ValueError: + continue + + if not fields: + return None + + fields = sorted(fields) + max_field = max(fields) + + # Build struct based on fields (4-byte aligned for PS1) + struct_def = "typedef struct SpuMallocBlock {\n" + for offset in range(0, max_field + 4, 4): + hex_offset = f"{offset:X}" + if offset in fields: + struct_def += f" s32 unk{hex_offset}; /* offset 0x{hex_offset} */\n" + struct_def += "} SpuMallocBlock;" + + return struct_def + + def discover_functions_in_file(self, file_path: str) -> List[Tuple[str, int, int]]: + """ + Discover all actual decompiled functions in a file by parsing the code. + Returns list of (func_name, start_line, end_line). + """ + with open(file_path, 'r') as f: + lines = f.readlines() + + functions = [] + i = 0 + while i < len(lines): + line = lines[i] + + # Skip INCLUDE_ASM lines + if 'INCLUDE_ASM' in line: + i += 1 + continue + + # Strip inline // comments before checking whether the line is a + # declaration (ends with ';') vs. a definition (has a body). + # Lines like "void func_800D5350(); // extern" must be skipped; + # rstrip() alone keeps the comment, so the ';' check fails. + stripped_no_comment = re.sub(r'//.*$', '', line).rstrip() + if '(' not in line or stripped_no_comment.endswith(';'): + i += 1 + continue + + # Check if this looks like a function definition + match = re.search(r'\b([a-zA-Z_][a-zA-Z0-9_]*)\s*\(', line) + if match and not line.strip().startswith('//') and not line.strip().startswith('/*'): + func_name = match.group(1) + + # Skip common non-function keywords + if func_name in ['if', 'while', 'for', 'switch', 'return', 'sizeof', + 'typedef', 'struct', 'union', 'enum', 'INCLUDE_ASM']: + i += 1 + continue + + # Find opening brace + brace_line = None + for j in range(i, min(i + 15, len(lines))): + if '{' in lines[j]: + brace_line = j + break + + if brace_line is not None: + # Find closing brace + brace_count = 0 + end_line = None + for j in range(brace_line, len(lines)): + brace_count += lines[j].count('{') + brace_count -= lines[j].count('}') + if brace_count == 0: + end_line = j + break + + if end_line is not None and end_line > brace_line: + functions.append((func_name, i, end_line)) + i = end_line + 1 + continue + + i += 1 + + return functions + + # ------------------------------------------------------------------ + # Deterministic pre-pass fixes (no LLM required) + # ------------------------------------------------------------------ + + def _offset_from_unk_name(self, field_name: str) -> Optional[int]: + """ + Convert a decompiler unk-field name to a byte offset integer. + e.g. 'unk4' -> 4, 'unk1C' -> 28, 'unk16' -> 22. + Returns None if the name doesn't look like an unk-offset field. + """ + m = re.match(r'^unk([0-9A-Fa-f]+)$', field_name) + if not m: + return None + hex_part = m.group(1) + # Treat as hex if it contains A-F or starts with 0, else try decimal first + if any(c in hex_part.upper() for c in 'ABCDEF') or (len(hex_part) > 1 and hex_part[0] == '0'): + return int(hex_part, 16) + # Ambiguous (e.g. "unk8", "unk4") — in this codebase these are hex offsets + return int(hex_part, 16) + + def apply_deterministic_fixes(self, file_path: str, compiler_errors: List[Dict], + struct_maps: Dict[str, Dict[int, tuple]]) -> int: + """ + Apply mechanical fixes for errors that don't need LLM reasoning: + - missing_struct_field: look up the correct field name by byte offset + - pointer_cast (integer↔pointer): insert explicit u32/intptr cast + Modifies file_path in-place. Returns number of lines changed. + """ + # Process errors from last line to first so edits don't invalidate indices + fixable = sorted( + [e for e in compiler_errors if e['type'] in ('missing_struct_field', 'pointer_cast')], + key=lambda e: e['line'], reverse=True + ) + if not fixable: + return 0 + + with open(file_path, 'r') as fh: + lines = fh.readlines() + + changed = 0 + for err in fixable: + idx = err['line'] - 1 + if idx < 0 or idx >= len(lines): + continue + original = lines[idx] + fixed = self._fix_one_line(original, err, struct_maps) + if fixed is not None and fixed != original: + lines[idx] = fixed + changed += 1 + + if changed: + with open(file_path, 'w') as fh: + fh.writelines(lines) + return changed + + def _fix_one_line(self, line: str, err: Dict, + struct_maps: Dict[str, Dict[int, tuple]]) -> Optional[str]: + """Attempt a deterministic single-line fix for one compiler error.""" + msg = err['message'] + err_type = err['type'] + + if err_type == 'missing_struct_field': + return self._fix_missing_field(line, msg, struct_maps) + if err_type == 'pointer_cast': + return self._fix_pointer_cast(line, msg) + return None + + def _fix_missing_field(self, line: str, msg: str, + struct_maps: Dict[str, Dict[int, tuple]]) -> Optional[str]: + """ + Fix 'structure has no member named unkXX' by replacing the access with a + byte-offset cast. This is always type-safe without needing to infer + the pointer's declared struct type. + + Handles both LHS (assignment target) and RHS (value read) positions. + The cast type defaults to s16 for small offsets (< 0x10) and s32 otherwise, + which is a reasonable guess for PS1 struct fields. + """ + bad_field_m = re.search(r"no member named [`'\"]?(\w+)[`'\"]?", msg) + if not bad_field_m: + return None + bad_field = bad_field_m.group(1) # e.g. 'unk4' + offset = self._offset_from_unk_name(bad_field) + if offset is None: + return None # Not an unkXX name — can't determine offset safely + + # Access pattern: ptr->unkX or ptr.unkX + access_re = re.compile(r'(\w+)(->|\.)(' + re.escape(bad_field) + r')\b') + if not access_re.search(line): + return None # Pattern not found on this line — nothing to do + + # Choose a sensible cast type based on field size hint from any known struct + cast_type = 's16' if offset < 0x10 else 's32' + for _sname, field_map in struct_maps.items(): + if offset in field_map: + _, ftype = field_map[offset] + # Clean up noise from multi-line comments in the header + base = ftype.strip().split('\n')[0].strip() + if base in ('u8', 's8', 'u16', 's16', 'u32', 's32', 'u64', 's64'): + cast_type = base + break + + def byte_cast_sub(m: re.Match) -> str: + ptr = m.group(1) + op = m.group(2) + ref = ptr if op == '->' else f'&{ptr}' + return f'(*({cast_type}*)((u8*){ref} + {offset}))' + + result = access_re.sub(byte_cast_sub, line) + if result == line: + return None + return result + + def _fix_pointer_cast(self, line: str, msg: str) -> Optional[str]: + """ + Add explicit casts to silence integer↔pointer warnings on a single line. + Only applies safe, well-understood transformations. + """ + if 'makes integer from pointer without a cast' in msg: + # lhs = ptr_expr; → lhs = (u32)ptr_expr; + # Only handle simple `var = rhs;` assignments — avoid touching calls with + # multiple = in the same statement. + m = re.match(r'^(\s*[\w.\[\]\->]+\s*=\s*)([^=;][^;]*)(;.*)$', line) + if m and not re.search(r'\(u(32|64)\s*\)', m.group(2)): + return f'{m.group(1)}(u32){m.group(2)}{m.group(3)}\n' + + elif 'makes pointer from integer without a cast' in msg: + # lhs = int_expr; → lhs = (void*)int_expr; + # (The correct pointer type would need type inference; void* is safe.) + m = re.match(r'^(\s*[\w.\[\]\->]+\s*=\s*)([^=;][^;]*)(;.*)$', line) + if m and not re.search(r'^\s*\(', m.group(2)): + return f'{m.group(1)}(void*){m.group(2)}{m.group(3)}\n' + + elif 'cast to pointer from integer of different size' in msg: + # (SomeType*)intval → (SomeType*)(u32)intval + result = re.sub( + r'\((\w[\w\s]*\s*\*+)\)\s*(\w[\w.\[\]\->]*)', + r'(\1)(u32)\2', line + ) + if result != line: + return result + + return None + + def fix_function_with_llm(self, func_name: str, file_path: str, code: str, + start_line: int, compiler_errors: List[Dict]) -> Optional[str]: + """ + Use LLM to fix type errors in a function. + Returns fixed code or None if fixing failed. + """ + errors = self.detect_type_errors_in_function(code, start_line, compiler_errors) + if not errors: + return None # No errors detected + + code_size = len(code) + error_count = len(errors) + + # Adjust timeout based on size and error count + if code_size > 5000 or error_count > 20: + timeout = 360 # 6 minutes for very large/complex functions + elif code_size > 3000 or error_count > 10: + timeout = 240 # 4 minutes for large functions + else: + timeout = 120 # 2 minutes for normal functions + + print(f"[INFO] 🔍 {func_name}: Found {error_count} error(s) ({code_size} chars, {timeout}s timeout)") + + # Get file-level context + file_ctx = self.extract_file_context(file_path) + + # Build struct field maps (byte_offset → field_name) for all known structs + struct_maps = self._collect_struct_field_maps(file_path) + + # Build context string + context_str = "" + + # Collect ALL known type names from both the .c file and its included headers + all_known_types = set(t['name'] for t in file_ctx['typedefs']) + all_known_types.update(file_ctx.get('header_typedef_names', [])) + if all_known_types: + context_str += f"\n**ALL Defined Types (from file and headers) — DO NOT redefine any of these:**\n" + context_str += ', '.join(sorted(all_known_types)) + '\n' + context_str += ("CRITICAL: These types are already defined in included headers. " + "Adding a new typedef or struct definition for any of these names " + "will cause cascading redefinition errors across the entire file. " + "If a struct is missing a field, you CANNOT add that field here — " + "only fix the code within the function body using casts or type changes.\n") + + # Inject struct field maps so the LLM knows the EXACT correct field names + if struct_maps and 'missing_struct_field' in {e['type'] for e in errors}: + context_str += "\n**Struct Field Reference (byte offset → field name, type):**\n" + context_str += "Use these to replace accesses to non-existent unkXX fields.\n" + for sname, field_map in sorted(struct_maps.items()): + if not field_map: + continue + # Only include structs that appear in the function's code or its errors + if sname not in code and not any(sname in e['message'] for e in errors): + continue + fields_repr = ', '.join( + f'0x{off:02X}: {fname} ({ftype})' + for off, (fname, ftype) in sorted(field_map.items()) + ) + context_str += f" {sname}: {{ {fields_repr} }}\n" + + if file_ctx['externs']: + extern_samples = file_ctx['externs'][:10] + context_str += f"\n**Existing Extern Declarations:** (showing first 10)\n" + for ext in extern_samples: + context_str += f" {ext}\n" + + # Group errors by type + error_types = {} + for err in errors: + err_type = err['type'] + if err_type not in error_types: + error_types[err_type] = [] + error_types[err_type].append(err) + + # Build error summary for prompt + error_summary = [] + for err_type, err_list in error_types.items(): + error_summary.append(f"**{err_type.replace('_', ' ').title()}** ({len(err_list)} occurrences):") + for err in err_list[:5]: # Limit to first 5 of each type + line_info = f"Line {err.get('func_line', '?')}" if 'func_line' in err else f"Line {err['line']}" + error_summary.append(f" - {line_info}: {err['message']}") + if len(err_list) > 5: + error_summary.append(f" ... and {len(err_list) - 5} more") + + error_list = '\n'.join(error_summary) + + # Generate specialized instructions based on dominant error type + dominant_type = max(error_types.keys(), key=lambda k: len(error_types[k])) + instructions = self._generate_fix_instructions(dominant_type, error_types, struct_maps) + + # For large functions, infer struct type first to help LLM - but only + # suggest new types that are NOT already defined anywhere + struct_hint = "" + if code_size > 2000 or 'void_pointer_dereference' in error_types: + inferred_struct = self.infer_struct_type_from_fields(code) + if inferred_struct: + # Check if this struct already exists in file or headers + struct_name_match = re.search(r'typedef struct \w+ \{', inferred_struct) + if struct_name_match: + struct_name = struct_name_match.group(0).split()[-2] + if struct_name not in all_known_types: + struct_hint = f"\n**Suggested New Struct Type (safe to add — not already defined):**\n```c\n{inferred_struct}\n```\n" + + # Build prompt for LLM + prompt = f"""## Project: Final Fantasy VII (PS1 USA) Decompilation +Goal: byte-accurate recompilation — the output C must compile to IDENTICAL machine code as the original PSX binary. + +### PSX SDK Types — use ONLY these, never int/short/char/long +s8/u8 (signed/unsigned char, lb/lbu) | s16/u16 (signed/unsigned short, lh/lhu) | s32/u32 (signed/unsigned int, lw/sw) + +### Decompilation Rules (MUST follow) +- No `/*?*/` unknown types — infer from register/context +- No `void*` for struct pointer params — use concrete struct types +- Struct fields via `->` / `.` only — no manual pointer arithmetic `*(ptr + offset)` +- Arrays via `arr[i]` — not `*(arr + i * n)` +- `goto loop_XX` → rewrite as `while` / `do-while` +- `goto block_XX` in switch → inline the branch target body +- Type must match load instruction: s8→`lb`, u8→`lbu`, s16→`lh`, u16→`lhu` + +### Common Matching Pitfalls +- Merged calls: duplicate common calls inside each if/else branch (don't hoist them out) +- Struct vs isolated locals: use `RECT`/struct for groups of related stack vars +- Unknown struct fields: use `unkXX` (offset hex) or cast `*(s16*)((u8*)ptr + 0x10)` + +**Function:** {func_name} +**File:** {file_path} +{context_str} +**Compilation Errors:** +{error_list} +{struct_hint} +**Current Code:** +```c +{code} +``` + +**Fix Instructions:** +{instructions} + +**Output Format:** +Return ONLY the fixed C function code (no markdown, no explanation, no comments about what you changed). + +CRITICAL RULES: +1. NEVER add or redefine any typedef, struct, union, or enum that appears in the "ALL Defined Types" list above +2. NEVER add a new struct/typedef definition to fix "structure has no member" errors — those require header changes and cannot be fixed here +3. For "structure has no member named X" errors: fix by casting the pointer to a compatible type (e.g., change the variable's declared type or add an explicit cast like `(StructType*)ptr`) +4. Do NOT include code fences (```) or explanatory text +5. Only add NEW extern declarations if the variable is truly undeclared and not in the headers +6. Start directly with the function's return type (no preamble) +7. Add `/* LLM: Fixed [error_type] */` comment only on lines you modify within the function body + +Start your response with the function's return type (e.g., 'void', 's32', etc.).""" + + try: + # Call Ollama via LLMHelper with extended timeout + response = self.llm._call_ollama(prompt, temperature=0.1, max_tokens=8192, timeout=timeout) + + if not response: + print(f"[WARN] ❌ {func_name}: No response from LLM (timed out after {timeout}s or error)") + return None + + fixed_code = response.strip() + + # Remove markdown code fences more aggressively + lines = fixed_code.split('\n') + cleaned_lines = [] + in_code_block = False + skip_explanation = False + + for line in lines: + # Detect code fence markers + if line.strip().startswith('```'): + in_code_block = not in_code_block + continue + + # Skip explanation text (starts with -, *, or numbered lists outside code) + if not in_code_block and (line.strip().startswith('-') or + line.strip().startswith('*') or + re.match(r'^\d+\.', line.strip())): + skip_explanation = True + continue + + # Skip common explanation phrases + if any(phrase in line.lower() for phrase in [ + 'explanation:', 'note:', 'changes made:', 'output:', + 'i have', 'i\'ve', 'the fix', 'this fix' + ]): + skip_explanation = True + continue + + # Reset skip if we see code-like content + if line.strip() and ('{' in line or '}' in line or ';' in line or '#include' in line): + skip_explanation = False + + # Only add actual code lines + if not skip_explanation or in_code_block: + cleaned_lines.append(line) + + fixed_code = '\n'.join(cleaned_lines).strip() + + # Reject fixes that add new struct/typedef definitions for types that + # already exist — that's the main cause of error count exploding. + for known_type in all_known_types: + if re.search(r'\btypedef\b.*\b' + re.escape(known_type) + r'\b', fixed_code): + print(f"[WARN] ❌ {func_name}: LLM tried to redefine '{known_type}' which already exists, skipping") + return None + + # Final validation - ensure it starts with a function signature + if not (fixed_code.startswith('/*') or + fixed_code.startswith('//') or + func_name in fixed_code[:200]): + print(f"[WARN] ❌ {func_name}: Fixed code doesn't look valid (missing function)") + return None + + # Validate the fix + if len(fixed_code) < len(code) * 0.5: + print(f"[WARN] ❌ {func_name}: Fixed code too short, skipping") + return None + + # Brace balance check — unbalanced braces mean the LLM truncated or + # duplicated part of the function, which causes cascading errors. + open_braces = fixed_code.count('{') + close_braces = fixed_code.count('}') + if open_braces != close_braces: + print(f"[WARN] ❌ {func_name}: LLM output has unbalanced braces " + f"({open_braces} open vs {close_braces} close), skipping") + return None + + # Also reject if line count changed dramatically (truncated/appended output) + orig_lines = code.count('\n') + fixed_lines = fixed_code.count('\n') + if fixed_lines < orig_lines * 0.7 or fixed_lines > orig_lines * 1.5: + print(f"[WARN] ❌ {func_name}: LLM output line count changed drastically " + f"({orig_lines} → {fixed_lines}), skipping") + return None + + # Check if meaningful changes were made + if fixed_code.strip() == code.strip(): + print(f"[WARN] ❌ {func_name}: No changes made, skipping") + return None + + has_llm_comment = '/* LLM:' in fixed_code + if not has_llm_comment: + print(f"[WARN] ⚠️ {func_name}: No LLM markers found, but applying anyway") + + print(f"[INFO] ✅ {func_name}: Successfully fixed") + return fixed_code + + except Exception as e: + print(f"[ERROR] ❌ {func_name}: LLM fix failed: {e}") + return None + + def _generate_fix_instructions(self, dominant_type: str, all_error_types: Dict, + struct_maps: Optional[Dict] = None) -> str: + """Generate specialized fixing instructions based on error types.""" + + instructions = [] + + if dominant_type == 'void_pointer_dereference' or 'void_pointer_dereference' in all_error_types: + instructions.append(""" +1. **Void Pointer Fixes:** + - Find all variables declared as `void*` that are used with struct field access (`->`) + - Replace `void*` with the appropriate struct pointer type (use inferred type if provided) + - For `extern void*` declarations, replace with `extern StructType*` +""") + + if 'missing_struct_field' in all_error_types: + # Build a lookup hint from the struct maps if available + field_hint = "" + if struct_maps: + lines = [] + for sname, field_map in sorted(struct_maps.items()): + if field_map: + entries = ', '.join( + f'0x{off:02X}→{fname}({ftype})' + for off, (fname, ftype) in sorted(field_map.items()) + ) + lines.append(f" {sname}: {entries}") + if lines: + field_hint = ( + "\n Use these offset maps to find the CORRECT field name:\n" + + '\n'.join(lines) + '\n' + ) + instructions.append(f""" +2. **Missing Struct Field Fixes:** + The struct is defined in an included header — you CANNOT add new fields to it. + Fix only the code INSIDE this function using one of these strategies: + + **Strategy A (preferred) — rename to the correct field:**{field_hint} + - Look up which field is at that byte offset in the struct reference above. + - Replace `ptr->unkX` with `ptr->correct_field_name` from the table. + - Example: if unk4 is at offset 0x04 and the table shows `0x04→D_8016297C(s16)`, + change `ptr->unk4` to `ptr->D_8016297C`. + + **Strategy B — byte-offset cast (when no field exists at that offset):** + - For a READ: `var = *(s16*)((u8*)ptr + offset);` + - For a WRITE: `*(s16*)((u8*)ptr + offset) = value;` + - CRITICAL: replace the ENTIRE `ptr->unkX` — do NOT leave `ptr->unkX` on the LHS + of an assignment. Wrong: `ptr->unk4 = ...`. Right: `*(s16*)((u8*)ptr+4) = ...`. + - Pick the cast type (s16/u16/s32/u32/u8) by the field's size in the struct. +""") + + if 'undefined_identifier' in all_error_types: + instructions.append(""" +3. **Undefined Identifier Fixes:** + - Find undefined variables (often global vars like `D_8004A698`, or locals like `sp1C`) + - For D_XXXXXXXX globals: add extern declaration at top of file + - For spXX stack variables: declare them properly at function start + - Infer the type from usage context (how it's assigned/used) +""") + + if 'type_mismatch' in all_error_types: + instructions.append(""" +4. **Type Mismatch Fixes:** + - Fix incompatible type assignments (e.g., assigning struct to u8) + - Use proper pointer dereferencing: if assigning struct to scalar, use `&variable` or cast + - Ensure pointer arithmetic uses correct types + - Add necessary type casts where appropriate (e.g., `(u8*)` for byte access) +""") + + if 'pointer_cast' in all_error_types: + instructions.append(""" +5. **Pointer Cast Fixes:** + - "assignment makes integer from pointer without cast": + Change `var = ptr;` to `var = (u32)ptr;` + - "assignment makes pointer from integer without cast": + Change `ptr = int_val;` to `ptr = (TYPE*)(u32)int_val;` (use the correct pointer type) + - "cast to pointer from integer of different size": + Change `(TYPE*)val` to `(TYPE*)(u32)val` to avoid size mismatch + - "passing arg N ... makes pointer from integer": + Wrap the argument: `(TYPE*)(u32)arg` +""") + + if 'invalid_operation' in all_error_types: + instructions.append(""" +6. **Invalid Operation Fixes:** + - Fix "invalid type argument of unary *" - trying to dereference non-pointer + - Change variable to pointer type, or remove dereference operator + - Check if variable should be a pointer based on context +""") + + if 'syntax_error' in all_error_types or 'parse_error' in all_error_types: + instructions.append(""" +7. **Parse/Syntax Error Fixes:** + - Fix "parse error before *" - usually missing semicolon or typedef + - Check for missing struct/typedef declarations + - Ensure proper syntax for pointer declarations +""") + + if 'redefinition' in all_error_types: + instructions.append(""" +8. **Redefinition Fixes:** + - Remove duplicate struct/typedef declarations + - If same struct defined twice, keep only one definition + - Ensure typedefs are not redeclared +""") + + if 'duplicate_label' in all_error_types: + instructions.append(""" +9. **Duplicate Label Fixes:** + - Rename duplicate labels to unique names (e.g., block_25 -> block_25_alt) + - Ensure goto targets use the correct renamed label +""") + + instructions.append(""" +**General Rules (PSX / FF7 decompilation standards):** +- Preserve all existing logic, calculations, and control flow exactly +- Keep all variable names unchanged (except renaming duplicate labels) +- Only fix type declarations and type-related errors +- Do NOT refactor or optimize code +- Ensure PS1/PSX SDK compatibility (32-bit, 4-byte aligned structs) +- Use only PSX SDK types: s8/u8/s16/u16/s32/u32 — never int/short/char/long +- Type determines the load instruction: s8→lb, u8→lbu, s16→lh, u16→lhu — change the type if the wrong instruction is generated +- `goto loop_XX` patterns MUST be rewritten as `while` or `do-while` loops +- `goto block_XX` inside switch statements: inline the branch target, do not leave dangling gotos +- Array access must use `arr[i]`, never `*(arr + i * sizeof(...))` +- Struct field access must use `->` or `.`, never pointer arithmetic offsets +- Add `/* LLM: Fixed [issue] */` comment on lines you modify within the function body +""") + + return '\n'.join(instructions) + + def extract_function_code(self, file_path: str, func_name: str) -> Optional[Tuple[str, int, int]]: + """ + Extract function code from file. + Returns (code, start_line, end_line) or None if not found. + """ + try: + with open(file_path, 'r') as f: + lines = f.readlines() + + # Find function start - look for function name followed by ( on same or next line + start_line = None + for i, line in enumerate(lines): + # Match function definition: func_name followed by ( + # Handle cases where function spans multiple lines + if func_name + '(' in line.replace(' ', ''): + start_line = i + break + # Also try with space + if func_name + ' (' in line or func_name + ' (' in line: + start_line = i + break + + if start_line is None: + return None + + # Find the opening brace + brace_line = None + for i in range(start_line, min(start_line + 10, len(lines))): # Look within 10 lines + if '{' in lines[i]: + brace_line = i + break + + if brace_line is None: + return None + + # Find function end (matching braces) + brace_count = 0 + end_line = None + for i in range(brace_line, len(lines)): + line = lines[i] + brace_count += line.count('{') + brace_count -= line.count('}') + if brace_count == 0: + end_line = i + break + + if end_line is None: + return None + + code = ''.join(lines[start_line:end_line+1]) + return (code, start_line, end_line) + + except Exception as e: + print(f"[ERROR] Could not extract {func_name} from {file_path}: {e}") + return None + + def apply_fix_to_file(self, file_path: str, func_name: str, fixed_code: str, + start_line: int, end_line: int) -> bool: + """ + Apply fixed code to file, replacing the original function. + Returns True if successful. + """ + try: + with open(file_path, 'r') as f: + lines = f.readlines() + + # Don't add header comment - it was already added by LLM or not needed + # Just ensure the code ends with newline + if not fixed_code.endswith('\n'): + fixed_code = fixed_code + '\n' + + # Replace function - build as a single string to avoid mixing + # \n-terminated strings (from readlines) with non-terminated strings + # (from split('\n')), which would cause writelines to merge lines. + new_content = ''.join(lines[:start_line]) + fixed_code + ''.join(lines[end_line+1:]) + + # Write to temp file first + temp_path = file_path + '.tmp' + with open(temp_path, 'w') as f: + f.write(new_content) + + # Move temp to actual file + import shutil + shutil.move(temp_path, file_path) + + return True + + except Exception as e: + print(f"[ERROR] Could not apply fix to {file_path}: {e}") + return False + + def validate_fix(self, file_path: str, func_name: str, + original_error_count: int, + func_error_count_before: int = 0, + func_start_line: int = 0, + func_end_line: int = 0) -> bool: + """ + Validate a fix by recompiling and checking if errors decreased. + When function line bounds are provided, uses function-level error + counting as the primary signal — this avoids false-positive "inconclusive" + results where the LLM moves an error without actually fixing it. + Returns True if fix is valid. + """ + print(f"[INFO] Validating fix for {func_name}...") + + # Force recompile + Path(file_path).touch() + + # Get new error count + new_errors = self.get_compilation_errors(file_path) + new_error_count = len(new_errors) + + # --- Function-level check (preferred when bounds are known) --- + if func_start_line > 0 and func_end_line > 0 and func_error_count_before > 0: + # Re-discover the function's new position (line numbers may have shifted) + discovered = self.discover_functions_in_file(file_path) + new_start, new_end = func_start_line, func_end_line # fallback + for fname, s, e in discovered: + if fname == func_name: + new_start, new_end = s, e + break + + func_errors_after = sum( + 1 for e in new_errors if new_start <= e['line'] <= new_end + 5 + ) + + if func_errors_after > func_error_count_before: + print(f"[WARN] ❌ Validation failed: function errors increased " + f"{func_error_count_before} → {func_errors_after}") + return False + elif func_errors_after == func_error_count_before: + # No change in the function itself — only allow if global count decreased + if new_error_count < original_error_count: + print(f"[INFO] ✅ Validation passed: global errors decreased " + f"{original_error_count} → {new_error_count}") + return True + print(f"[WARN] ⚠️ Validation inconclusive: function errors unchanged " + f"({func_errors_after}), global {original_error_count} → {new_error_count}") + # Allow only if at least the file didn't get worse + return new_error_count <= original_error_count + else: + print(f"[INFO] ✅ Validation passed: function errors decreased " + f"{func_error_count_before} → {func_errors_after}") + return True + + # --- Fallback: file-level check only --- + if new_error_count > original_error_count: + print(f"[WARN] ❌ Validation failed: errors increased from {original_error_count} to {new_error_count}") + return False + elif new_error_count == original_error_count: + print(f"[WARN] ⚠️ Validation inconclusive: error count unchanged ({new_error_count})") + return True + else: + print(f"[INFO] ✅ Validation passed: errors decreased from {original_error_count} to {new_error_count}") + return True + + def backup_file(self, file_path: str) -> str: + """Create a backup of the file. Returns backup path.""" + import shutil + backup_path = file_path + '.backup' + shutil.copy2(file_path, backup_path) + return backup_path + + def restore_backup(self, file_path: str, backup_path: str): + """Restore file from backup.""" + import shutil + shutil.move(backup_path, file_path) + print(f"[INFO] Restored from backup") + + def fix_file(self, file_path: str, max_functions: int = 20, max_passes: int = 3, + target_function: str = None) -> int: + """ + Fix type errors in a file, looping until no more progress can be made + or max_passes is reached. + If target_function is given, only that function is fixed (all others are skipped). + Returns total number of functions fixed across all passes. + """ + print(f"[INFO] Processing {file_path}...") + + # Create a single backup before any passes + backup_path = self.backup_file(file_path) + print(f"[INFO] Created backup at {backup_path}") + + # Reset per-file failure tracker + self._validation_failures = {} + + total_fixed = 0 + total_failed = 0 + + for pass_num in range(1, max_passes + 1): + if pass_num > 1: + print(f"[INFO] --- Pass {pass_num}/{max_passes} ---") + + # Get compilation errors for this pass + print(f"[INFO] Compiling to detect errors...") + compiler_errors = self.get_compilation_errors(file_path) + print(f"[INFO] Found {len(compiler_errors)} compilation error(s)") + + if not compiler_errors: + print(f"[INFO] No compilation errors found, done!") + break + + # Group errors by type + error_types = {} + for err in compiler_errors: + err_type = err['type'] + error_types[err_type] = error_types.get(err_type, 0) + 1 + + print(f"[INFO] Error breakdown: {', '.join(f'{k}: {v}' for k, v in error_types.items())}") + + # Discover all actual decompiled functions in the file + print(f"[INFO] Discovering decompiled functions...") + discovered_functions = self.discover_functions_in_file(file_path) + print(f"[INFO] Found {len(discovered_functions)} decompiled function(s) in file") + + if not discovered_functions: + print(f"[INFO] No decompiled functions found") + break + + # Debug: show some discovered functions and error lines + print(f"[DEBUG] Sample functions: {discovered_functions[:3]}") + print(f"[DEBUG] Sample error lines: {[e['line'] for e in compiler_errors[:5]]}") + + # ── Deterministic pre-pass ────────────────────────────────────── + # Handle pointer_cast and missing_struct_field errors mechanically + # before spending LLM time on them. + struct_maps = self._collect_struct_field_maps(file_path) + det_changed = self.apply_deterministic_fixes(file_path, compiler_errors, struct_maps) + if det_changed: + print(f"[INFO] 🔧 Deterministic pre-pass: fixed {det_changed} line(s)") + # Re-read errors after deterministic edits + compiler_errors = self.get_compilation_errors(file_path) + print(f"[INFO] Errors after deterministic pass: {len(compiler_errors)}") + if not compiler_errors: + print(f"[INFO] All errors resolved by deterministic pass!") + total_fixed += det_changed + break + # ──────────────────────────────────────────────────────────────── + + # Map functions to their errors + functions_with_errors = [] + for func_name, start_line, end_line in discovered_functions: + func_errors = [e for e in compiler_errors + if start_line <= e['line'] <= end_line] + + if func_errors: + # Skip functions that have already had N validation failures + prior_failures = self._validation_failures.get(func_name, 0) + if prior_failures >= 2: + print(f"[DEBUG] {func_name}: skipping (failed validation {prior_failures} times already)") + continue + + result = self.extract_function_code(file_path, func_name) + if not result: + print(f"[WARN] ⚠️ {func_name}: Could not extract function code") + continue + + code, extracted_start, extracted_end = result + + functions_with_errors.append({ + 'func_name': func_name, + 'code': code, + 'start_line': extracted_start, + 'end_line': extracted_end, + 'errors': func_errors, + 'func_error_count': len(func_errors), + }) + print(f"[DEBUG] {func_name}: {len(func_errors)} error(s), lines {extracted_start}-{extracted_end}") + + # Limit to max_functions *with errors*, not overall discovered + if len(functions_with_errors) >= max_functions: + break + + # If a specific function was requested, restrict to it + if target_function: + functions_with_errors = [f for f in functions_with_errors + if f['func_name'] == target_function] + + if not functions_with_errors: + print(f"[INFO] No decompiled functions have errors") + break + + print(f"[INFO] {len(functions_with_errors)} function(s) with errors to fix") + + original_error_count = len(compiler_errors) + pass_fixed = 0 + pass_failed = 0 + + for func_info in functions_with_errors: + func_name = func_info['func_name'] + code = func_info['code'] + start_line = func_info['start_line'] + end_line = func_info['end_line'] + func_error_count_before = func_info['func_error_count'] + + # Create a function-specific backup + func_backup = None + try: + import shutil + func_backup = file_path + f'.func_{func_name}.bak' + shutil.copy2(file_path, func_backup) + except: + pass + + # Fix with LLM (pass compiler errors) + fixed_code = self.fix_function_with_llm( + func_name, file_path, code, start_line, compiler_errors + ) + if not fixed_code: + print(f"[INFO] ℹ️ {func_name}: No fixes applied or fixing skipped") + if func_backup: + Path(func_backup).unlink(missing_ok=True) + continue + + # Apply fix + if not self.apply_fix_to_file(file_path, func_name, fixed_code, start_line, end_line): + print(f"[ERROR] ❌ {func_name}: Failed to apply fix to file") + if func_backup: + Path(func_backup).unlink(missing_ok=True) + pass_failed += 1 + continue + + # Validate using function-level error counts where possible + if not self.validate_fix(file_path, func_name, original_error_count, + func_error_count_before, start_line, end_line): + print(f"[ERROR] ❌ {func_name}: Fix validation failed, rolling back") + self._validation_failures[func_name] = self._validation_failures.get(func_name, 0) + 1 + if func_backup: + import shutil + shutil.move(func_backup, file_path) + print(f"[INFO] Rolled back changes for {func_name}") + pass_failed += 1 + continue + + # Success — reset failure counter for this function + self._validation_failures.pop(func_name, None) + # Success - clean up function backup + if func_backup: + Path(func_backup).unlink(missing_ok=True) + + # Try to update database if function exists + try: + self.db.update_status(func_name, 'decompiled_needs_refine', + notes='LLM fixed type errors, needs re-verification') + except: + pass # Function might not be in database + + pass_fixed += 1 + # Update original error count for next validation + original_error_count = len(self.get_compilation_errors(file_path)) + + total_fixed += pass_fixed + total_failed += pass_failed + + if pass_fixed == 0: + print(f"[INFO] No progress in pass {pass_num}, stopping") + break + + print(f"[INFO] Pass {pass_num} fixed {pass_fixed} function(s), {pass_failed} failed") + + # Clean up master backup + if total_failed == 0: + Path(backup_path).unlink(missing_ok=True) + print(f"[INFO] All fixes successful, removed backup") + else: + print(f"[INFO] Backup kept at {backup_path} due to {total_failed} failed fix(es)") + + return total_fixed + + +def main(): + """Main entry point.""" + import argparse + + parser = argparse.ArgumentParser(description='Fix type errors in existing decompiled functions') + parser.add_argument('--file', type=str, help='Specific file to fix (relative to workspace)') + parser.add_argument('--all', action='store_true', help='Fix all files with errors') + parser.add_argument('--max-functions', type=int, default=20, + help='Maximum functions to fix per file (default: 20)') + parser.add_argument('--max-passes', type=int, default=3, + help='Maximum LLM fix passes per file (default: 3)') + parser.add_argument('--model', type=str, default='qwen2.5-coder:7b', + help='Ollama model to use (default: qwen2.5-coder:7b)') + parser.add_argument('--verbose', action='store_true', help='Verbose output') + + args = parser.parse_args() + + fixer = TypeErrorFixer(model=args.model, verbose=args.verbose) + + if args.file: + # Fix specific file + file_path = fixer.workspace_root / args.file + if not file_path.exists(): + print(f"[ERROR] File not found: {file_path}") + sys.exit(1) + + fixed = fixer.fix_file(str(file_path), max_functions=args.max_functions, max_passes=args.max_passes) + print(f"\n✅ Fixed {fixed} function(s) in {args.file}") + + elif args.all: + print("[ERROR] --all mode not yet implemented") + print("[INFO] Use --file to fix a specific file, e.g.:") + print(" python3 fix_existing_errors.py --file src/main/psxsdk.c") + sys.exit(1) + + else: + # Default: show help + parser.print_help() + print("\nExample usage:") + print(" python3 fix_existing_errors.py --file src/main/psxsdk.c") + + +if __name__ == '__main__': + main() diff --git a/automation/functions.db b/automation/functions.db new file mode 100644 index 0000000..dbc4216 Binary files /dev/null and b/automation/functions.db differ diff --git a/automation/generate_decls.py b/automation/generate_decls.py new file mode 100644 index 0000000..b5d54ad --- /dev/null +++ b/automation/generate_decls.py @@ -0,0 +1,366 @@ +#!/usr/bin/env python3 +""" +Generate supplementary forward-declaration headers for m2c context. + +When m2c decompiles a function it only sees the context of that function's +own C source file. Functions defined in OTHER C files are invisible, so m2c +emits /*?*/ unknown-type markers for every cross-file call. + +This script scans every C source file, extracts the return type and parameter +list of each function that already has a concrete C body (not INCLUDE_ASM), +and writes all those signatures to: + + include/decomp_decls.h + +tools/decompile.py appends that file to the m2c temp-context file, so m2c +can resolve cross-file call signatures automatically. + +Run this manually or let the automation agent call generate() during startup. +""" + +import re +import subprocess +import sys +from pathlib import Path +from typing import Dict, Optional, Set + +# Regex to match C function definitions (non-static, public ABI) +# Matches: return_type func_name(params) { +# - Handles multi-word return types (s32, void, u8*, etc.) +# - Anchored so it won't match calls or prototypes +_FUNC_DEF_RE = re.compile( + r'^' + r'((?:const\s+)?(?:unsigned\s+|signed\s+)?' + r'(?:void|u8|s8|u16|s16|u32|s32|int|char|short|long|unk_data|unk_ptr|ff7s|Yamada|Unk\w+)' + r'(?:\s*\*+)?)' # optional pointer stars + r'\s+' + r'(func_[0-9A-Fa-f]+|[A-Za-z_][A-Za-z0-9_]*)' # function name + r'\s*\(' + r'([^)]*)' # parameter list (no nesting needed) + r'\)' + r'\s*\{', + re.MULTILINE, +) + +# Skip patterns that indicate INCLUDE_ASM or a call (not a definition) +_INCLUDE_ASM_RE = re.compile(r'INCLUDE_ASM\s*\(') +# Skip static functions (file-internal; m2c context already has them) +_STATIC_RE = re.compile(r'^\s*static\s+', re.MULTILINE) + +# Broader regex that captures ALL function signatures, including struct-typed ones. +# Used for per-module declaration files (where the module's own struct types are +# always available because the module's C file is already in the m2c context). +_FUNC_DEF_RE_ALL = re.compile( + r'^' + r'((?:const\s+)?(?:unsigned\s+|signed\s+)?' + r'\w[\w\s]*?' # return type — any identifier sequence (non-greedy) + r'(?:\s*\*+)?)' # optional pointer stars + r'\s+' + r'(func_[0-9A-Fa-f]+|[A-Za-z_][A-Za-z0-9_]*)' # function name + r'\s*\(' + r'([^)]*)' # parameter list + r'\)' + r'\s*\{', + re.MULTILINE, +) + + +def _extract_signatures(c_file: Path) -> Dict[str, str]: + """ + Parse a C source file and return {func_name: declaration_line} for every + non-static function that has a concrete C body (not INCLUDE_ASM). + + Returns a dict like: + {"func_800BEAD4": "void func_800BEAD4(u8* arg0, s32 arg1);"} + """ + try: + text = c_file.read_text(errors='replace') + except OSError: + return {} + + result: Dict[str, str] = {} + + for m in _FUNC_DEF_RE.finditer(text): + ret_type = m.group(1).strip() + func_name = m.group(2).strip() + params = m.group(3).strip() + + # Skip if the match is preceded by 'static' on the same "line" + line_start = text.rfind('\n', 0, m.start()) + 1 + prefix = text[line_start:m.start()] + if 'static' in prefix: + continue + + # Skip declarations that reference struct/typedef names (identifiers starting + # with an uppercase letter, e.g. RECT, GzHeader, AKAO_TRACK) or PSX SDK + # platform types like u_long that are not defined in common.h. + # Including these would cause parse errors in modules that don't have + # their headers. + if re.search(r'\b[A-Z][A-Za-z0-9_]*\b|\bu_long\b', ret_type + ' ' + params): + continue + + # Normalise param list (collapse whitespace, remove comments) + params_clean = re.sub(r'\s+', ' ', params).strip() + if not params_clean: + params_clean = 'void' + + decl = f"{ret_type} {func_name}({params_clean});" + result[func_name] = decl + + return result + + +def _get_module_types(module_dir: Path, project_root: Path) -> Set[str]: + """ + Run cpp on the module's C files to collect all typedef names that are + defined after preprocessing. These are the types it's safe to reference + in a per-module declaration file. + + Returns an empty set on failure (caller should then skip struct-typed + declarations for that module). + """ + # Try the canonical private header first, fall back to any .h in the module dir + candidates = [ + module_dir / f"{module_dir.name}_private.h", + module_dir / f"{module_dir.name}.h", + ] + header = next((h for h in candidates if h.exists()), None) + if header is None: + return set() + + cpp_flags = [ + "-Iinclude", "-Isrc", "-Iinclude/psxsdk", + "-D_LANGUAGE_C", "-DM2CTX", "-D_MIPS_SZLONG=32", + "-DSCRIPT(...)={}", "-D__attribute__(...)=", "-D__asm__(...)=", + "-ffreestanding", + ] + try: + result = subprocess.check_output( + ["gcc", "-E", "-P"] + cpp_flags + [str(header.relative_to(project_root))], + cwd=str(project_root), + encoding="utf-8", + stderr=subprocess.DEVNULL, + ) + except (subprocess.CalledProcessError, FileNotFoundError): + return set() + + types: Set[str] = set() + # typedef { ... } TypeName; or typedef ExistingType TypeName; + for m in re.finditer(r'}\s*(\w+)\s*;', result): + types.add(m.group(1)) + for m in re.finditer(r'^typedef\s+\S+\s+(\w+)\s*;', result, re.MULTILINE): + types.add(m.group(1)) + return types + + +# Primitive types that are always safe regardless of module +_PRIMITIVE_TYPES = frozenset({ + 'void', 'char', 'short', 'int', 'long', 'float', 'double', + 'u8', 's8', 'u16', 's16', 'u32', 's32', 'u64', 's64', + 'f32', 'f64', 'unk_data', 'unk_ptr', 'ff7s', +}) + + +def _extract_signatures_all(c_file: Path, allowed_types: Set[str]) -> Dict[str, str]: + """ + Like _extract_signatures but includes struct-typed signatures whose types are + all in `allowed_types` (the set of types defined by the module's own headers). + """ + try: + text = c_file.read_text(errors='replace') + except OSError: + return {} + + result: Dict[str, str] = {} + + for m in _FUNC_DEF_RE_ALL.finditer(text): + ret_type = m.group(1).strip() + func_name = m.group(2).strip() + params = m.group(3).strip() + + # Skip static functions — check both the prefix text before the regex + # match start AND the ret_type itself (since \w[\w\s]*? can consume 'static') + line_start = text.rfind('\n', 0, m.start()) + 1 + prefix = text[line_start:m.start()] + if 'static' in prefix or 'static' in ret_type.split(): + continue + + # Strip any leading qualifiers that slipped into ret_type (e.g. 'static') + ret_type = ret_type.lstrip() + + # Skip multi-word return types spanning lines (bogus match) + if '\n' in ret_type: + continue + + # Skip control-flow keywords + if func_name in ('if', 'else', 'while', 'for', 'do', 'switch', 'return', 'goto'): + continue + + # Collect all identifier tokens in return type and params + combined = ret_type + ' ' + params + identifiers = set(re.findall(r'\b([A-Z]\w*)\b', combined)) # uppercase-start = type names + + # All non-primitive uppercase type names must be in allowed_types. + # Also reject u_long (lowercase but not a primitive — requires psxsdk/types.h). + unknown = identifiers - allowed_types + if unknown or re.search(r'\bu_long\b', combined): + continue + + params_clean = re.sub(r'\s+', ' ', params).strip() + if not params_clean: + params_clean = 'void' + + decl = f"{ret_type} {func_name}({params_clean});" + # Keep the FIRST definition found — #ifndef NON_MATCHINGS blocks come before + # the #else alternatives, and the #ifndef version is what actually compiles. + result.setdefault(func_name, decl) + + return result + + +def generate_module_decls(project_root: Optional[Path] = None, verbose: bool = False) -> int: + """ + For each module under src/, scan all *.c files and write + include/decomp_decls_{module}.h with ALL decompiled function signatures + (including struct-typed ones). + + These per-module files are appended to the m2c context only when decompiling + a function from that same module, ensuring the struct types referenced in the + declarations are already defined (via the module's own preprocessed headers). + + Returns the total number of declarations written across all modules. + """ + if project_root is None: + here = Path(__file__).resolve().parent + project_root = here.parent if here.name == 'automation' else here + + src_dir = project_root / 'src' + include_dir = project_root / 'include' + + if not src_dir.is_dir(): + return 0 + + total = 0 + + # Each subdirectory of src/ is a module + for module_dir in sorted(src_dir.iterdir()): + if not module_dir.is_dir(): + continue + module_name = module_dir.name + + # Collect the types defined by this module's headers so we only emit + # declarations whose parameter types are actually available. + allowed_types = _get_module_types(module_dir, project_root) + + all_decls: Dict[str, str] = {} + for c_file in sorted(module_dir.rglob('*.c')): + sigs = _extract_signatures_all(c_file, allowed_types) + all_decls.update(sigs) + + if not all_decls: + continue + + out_path = include_dir / f"decomp_decls_{module_name}.h" + lines = [ + f"/* AUTO-GENERATED by automation/generate_decls.py — do not edit manually */", + f"/* Per-module declarations for '{module_name}' — only valid in {module_name} m2c context */", + f"/* struct types referenced here are defined by the module's own preprocessed headers */", + "", + f'#include "common.h"', + "" + ] + # Always emit #include "_private.h" if the file exists — it defines + # the struct types referenced by the declarations below, and must not be + # removed even though tools/decompile.py strips '#'-prefixed lines before + # feeding this file to m2c (the include is kept for editor tooling / clangd). + private_header = module_dir / f"{module_name}_private.h" + if private_header.exists(): + lines.append(f'#include "../src/{module_name}/{module_name}_private.h"') + lines.append("") + for func_name in sorted(all_decls): + lines.append(all_decls[func_name]) + lines.append("") + + out_path.write_text('\n'.join(lines)) + total += len(all_decls) + + if verbose: + print( + f"[generate_decls] {module_name}: {len(all_decls)} declarations → " + f"{out_path.relative_to(project_root)}" + ) + + return total + + +def generate(project_root: Optional[Path] = None, verbose: bool = False) -> int: + """ + Scan all src/**/*.c files and write include/decomp_decls.h. + + Returns the number of declarations written. + """ + if project_root is None: + # Running from automation/ or from project root + here = Path(__file__).resolve().parent + project_root = here.parent if here.name == 'automation' else here + + src_dir = project_root / 'src' + out_path = project_root / 'include' / 'decomp_decls.h' + + if not src_dir.is_dir(): + if verbose: + print(f"[generate_decls] src dir not found: {src_dir}", file=sys.stderr) + return 0 + + all_decls: Dict[str, str] = {} + files_scanned = 0 + + for c_file in sorted(src_dir.rglob('*.c')): + sigs = _extract_signatures(c_file) + all_decls.update(sigs) + files_scanned += 1 + + if not all_decls: + # Nothing to write — don't create an empty file that would clobber a good one + if verbose: + print("[generate_decls] No signatures extracted", file=sys.stderr) + return 0 + + lines = [ + "/* AUTO-GENERATED by automation/generate_decls.py — do not edit manually */", + "/* Forward declarations for all decompiled functions, used as m2c context. */", + "#ifndef DECOMP_DECLS_H", + "#define DECOMP_DECLS_H", + "", + '#include "common.h"', + "", + ] + for func_name in sorted(all_decls): + lines.append(all_decls[func_name]) + lines += ["", "#endif /* DECOMP_DECLS_H */", ""] + + out_path.write_text('\n'.join(lines)) + + if verbose: + print( + f"[generate_decls] Wrote {len(all_decls)} declarations from " + f"{files_scanned} files → {out_path.relative_to(project_root)}" + ) + + # Also regenerate per-module declaration files + generate_module_decls(project_root=project_root, verbose=verbose) + + return len(all_decls) + + +if __name__ == '__main__': + import argparse + + parser = argparse.ArgumentParser(description="Generate m2c supplementary context declarations") + parser.add_argument('--root', type=Path, default=None, + help='Project root (default: auto-detect)') + parser.add_argument('--verbose', '-v', action='store_true') + args = parser.parse_args() + + count = generate(project_root=args.root, verbose=True) + print(f"Generated {count} declarations.") diff --git a/automation/initial run log.txt b/automation/initial run log.txt new file mode 100644 index 0000000..3dd515f --- /dev/null +++ b/automation/initial run log.txt @@ -0,0 +1,1646 @@ +calvin@Begemot:~/GitHub/ff7-decomp-armstrca/automation$ python3 agent.py --run --target 100 --batch 10 --module battle --llm --llm-threshold 25 +[2026-03-01 22:20:24] [INFO] ============================================================ +[2026-03-01 22:20:24] [INFO] STARTING DECOMPILATION AGENT +[2026-03-01 22:20:24] [INFO] ============================================================ +[2026-03-01 22:20:24] [INFO] Batch size: 10 +[2026-03-01 22:20:24] [INFO] Verify interval: 20 +[2026-03-01 22:20:24] [INFO] Module filter: battle +[2026-03-01 22:20:24] [INFO] Target count: 100 +[2026-03-01 22:20:24] [INFO] Initial state: 59/2362 verified +[2026-03-01 22:20:24] [INFO] Processing batch of 10 functions +[2026-03-01 22:20:24] [INFO] [1/10] Decompiling func_800A3208 (19 lines) + +============================================================ +Attempting to decompile: func_800A3208 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 19 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:20:26] [INFO] [2/10] Decompiling func_800A3240 (19 lines) + +============================================================ +Attempting to decompile: func_800A3240 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 19 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:20:26] [INFO] [3/10] Decompiling func_800A55BC (19 lines) + +============================================================ +Attempting to decompile: func_800A55BC +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 19 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:20:27] [INFO] [4/10] Decompiling func_800A8CC8 (19 lines) + +============================================================ +Attempting to decompile: func_800A8CC8 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 19 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:20:28] [INFO] [5/10] Decompiling func_800B10B4 (19 lines) + +============================================================ +Attempting to decompile: func_800B10B4 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 19 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:20:29] [INFO] [6/10] Decompiling func_800BB4F8 (20 lines) + +============================================================ +Attempting to decompile: func_800BB4F8 +============================================================ +Module: battle +File: src/battle/battle1.c +ASM lines: 20 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:20:29] [INFO] [7/10] Decompiling func_800BB978 (20 lines) + +============================================================ +Attempting to decompile: func_800BB978 +============================================================ +Module: battle +File: src/battle/battle1.c +ASM lines: 20 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:20:30] [INFO] [8/10] Decompiling func_800A4E00 (21 lines) + +============================================================ +Attempting to decompile: func_800A4E00 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 21 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:20:30] [INFO] [9/10] Decompiling func_800AE25C (21 lines) + +============================================================ +Attempting to decompile: func_800AE25C +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 21 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:20:31] [INFO] [10/10] Decompiling func_800B1A5C (21 lines) + +============================================================ +Attempting to decompile: func_800B1A5C +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 21 +Current status: todo +✅ Decompilation successful! + +============================================================ +AGENT PROGRESS - 22:20:32 +============================================================ +Processed: 10 functions +Verified: 59/2362 (2.9%) +Failed: 1 +Todo: 2292 +Batches: 1 +Builds: 0 +LLM analyzed: 0 +Rate: 1.41 functions/second +Elapsed: 0:00:07 +============================================================ + +[2026-03-01 22:20:34] [INFO] Processing batch of 10 functions +[2026-03-01 22:20:34] [INFO] [1/10] Decompiling func_800BB9B8 (21 lines) + +============================================================ +Attempting to decompile: func_800BB9B8 +============================================================ +Module: battle +File: src/battle/battle1.c +ASM lines: 21 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:20:34] [INFO] [2/10] Decompiling func_800BB9FC (21 lines) + +============================================================ +Attempting to decompile: func_800BB9FC +============================================================ +Module: battle +File: src/battle/battle1.c +ASM lines: 21 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:20:35] [INFO] [3/10] Decompiling func_800BBA40 (21 lines) + +============================================================ +Attempting to decompile: func_800BBA40 +============================================================ +Module: battle +File: src/battle/battle1.c +ASM lines: 21 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:20:36] [INFO] [4/10] Decompiling func_800C03B8 (21 lines) + +============================================================ +Attempting to decompile: func_800C03B8 +============================================================ +Module: battle +File: src/battle/battle1.c +ASM lines: 21 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:20:36] [INFO] [5/10] Decompiling func_800A8D18 (22 lines) + +============================================================ +Attempting to decompile: func_800A8D18 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 22 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:20:37] [INFO] [6/10] Decompiling func_800AF834 (22 lines) + +============================================================ +Attempting to decompile: func_800AF834 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 22 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:20:37] [INFO] [7/10] Decompiling func_800B1368 (22 lines) + +============================================================ +Attempting to decompile: func_800B1368 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 22 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:20:38] [INFO] [8/10] Decompiling func_800D4FA8 (22 lines) + +============================================================ +Attempting to decompile: func_800D4FA8 +============================================================ +Module: battle +File: src/battle/battle2.c +ASM lines: 22 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:20:39] [INFO] [9/10] Decompiling func_800A3488 (23 lines) + +============================================================ +Attempting to decompile: func_800A3488 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 23 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:20:39] [INFO] [10/10] Decompiling func_800A4F14 (23 lines) + +============================================================ +Attempting to decompile: func_800A4F14 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 23 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:20:40] [INFO] Running verification... + +============================================================ +VERIFYING DECOMPILED FUNCTIONS +============================================================ + +Found 20 decompiled function(s) to verify + +[1/20] Checking func_800A3208... + ✅ Matches +[2/20] Checking func_800A3240... + ✅ Matches +[3/20] Checking func_800A3488... + ✅ Matches +[4/20] Checking func_800A4E00... + ✅ Matches +[5/20] Checking func_800A4F14... + ✅ Matches +[6/20] Checking func_800A55BC... + ✅ Matches +[7/20] Checking func_800A8CC8... + ✅ Matches +[8/20] Checking func_800A8D18... + ✅ Matches +[9/20] Checking func_800AE25C... + ✅ Matches +[10/20] Checking func_800AF834... + ✅ Matches +[11/20] Checking func_800B10B4... + ✅ Matches +[12/20] Checking func_800B1368... + ✅ Matches +[13/20] Checking func_800B1A5C... + ✅ Matches +[14/20] Checking func_800BB4F8... + ✅ Matches +[15/20] Checking func_800BB978... + ✅ Matches +[16/20] Checking func_800BB9B8... + ✅ Matches +[17/20] Checking func_800BB9FC... + ✅ Matches +[18/20] Checking func_800BBA40... + ✅ Matches +[19/20] Checking func_800C03B8... + ✅ Matches +[20/20] Checking func_800D4FA8... + ✅ Matches + +============================================================ +VERIFICATION COMPLETE +============================================================ +✅ Verified: 20 +❌ Not matching: 0 +============================================================ + +[2026-03-01 22:20:40] [INFO] Verified 20 functions + +============================================================ +AGENT PROGRESS - 22:20:40 +============================================================ +Processed: 20 functions +Verified: 79/2362 (3.3%) +Failed: 1 +Todo: 2282 +Batches: 2 +Builds: 0 +LLM analyzed: 0 +Rate: 1.29 functions/second +Elapsed: 0:00:15 +============================================================ + +[2026-03-01 22:20:42] [INFO] Processing batch of 10 functions +[2026-03-01 22:20:42] [INFO] [1/10] Decompiling func_800AD8DC (23 lines) + +============================================================ +Attempting to decompile: func_800AD8DC +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 23 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:20:43] [INFO] [2/10] Decompiling func_800B37A0 (23 lines) + +============================================================ +Attempting to decompile: func_800B37A0 +============================================================ +Module: battle +File: src/battle/battle1.c +ASM lines: 23 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:20:43] [INFO] [3/10] Decompiling func_800B888C (23 lines) + +============================================================ +Attempting to decompile: func_800B888C +============================================================ +Module: battle +File: src/battle/battle1.c +ASM lines: 23 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:20:44] [INFO] [4/10] Decompiling func_800A6CC0 (24 lines) + +============================================================ +Attempting to decompile: func_800A6CC0 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 24 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:20:44] [INFO] [5/10] Decompiling func_800A6D3C (24 lines) + +============================================================ +Attempting to decompile: func_800A6D3C +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 24 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:20:45] [INFO] [6/10] Decompiling func_800AD890 (24 lines) + +============================================================ +Attempting to decompile: func_800AD890 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 24 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:20:45] [INFO] [7/10] Decompiling func_800B1218 (24 lines) + +============================================================ +Attempting to decompile: func_800B1218 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 24 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:20:46] [INFO] [8/10] Decompiling func_800D55A4 (24 lines) + +============================================================ +Attempting to decompile: func_800D55A4 +============================================================ +Module: battle +File: src/battle/battle2.c +ASM lines: 24 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:20:47] [INFO] [9/10] Decompiling func_800D5774 (24 lines) + +============================================================ +Attempting to decompile: func_800D5774 +============================================================ +Module: battle +File: src/battle/battle2.c +ASM lines: 24 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:20:47] [INFO] [10/10] Decompiling func_800A5FB0 (25 lines) +[2026-03-01 22:20:47] [INFO] ⚙️ Analyzing with LLM (25 lines)... +[2026-03-01 22:21:02] [INFO] 📊 Complexity: medium, Summary: ** The function appears to check if certain conditions are met related to memory... + +============================================================ +Attempting to decompile: func_800A5FB0 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 25 +Current status: todo +✅ Decompilation successful! + +============================================================ +AGENT PROGRESS - 22:21:03 +============================================================ +Processed: 30 functions +Verified: 79/2362 (3.8%) +Failed: 1 +Todo: 2272 +Batches: 3 +Builds: 0 +LLM analyzed: 1 +Rate: 0.79 functions/second +Elapsed: 0:00:38 +============================================================ + +[2026-03-01 22:21:05] [INFO] Processing batch of 10 functions +[2026-03-01 22:21:05] [INFO] [1/10] Decompiling func_800A6A70 (25 lines) +[2026-03-01 22:21:05] [INFO] ⚙️ Analyzing with LLM (25 lines)... +[2026-03-01 22:21:12] [INFO] 📊 Complexity: easy, Summary: ** The function `func_800A6A70` appears to be modifying a byte at a specific mem... + +============================================================ +Attempting to decompile: func_800A6A70 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 25 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:21:12] [INFO] [2/10] Decompiling func_800B2F70 (25 lines) +[2026-03-01 22:21:12] [INFO] ⚙️ Analyzing with LLM (25 lines)... +[2026-03-01 22:21:19] [WARN] ⚠️ LLM analysis failed: 'NoneType' object is not subscriptable + +============================================================ +Attempting to decompile: func_800B2F70 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 25 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:21:19] [INFO] [3/10] Decompiling func_800B38E0 (25 lines) +[2026-03-01 22:21:19] [INFO] ⚙️ Analyzing with LLM (25 lines)... +[2026-03-01 22:21:28] [INFO] 📊 Complexity: medium, Summary: This function appears to be a subroutine that reads data from a memory location ... + +============================================================ +Attempting to decompile: func_800B38E0 +============================================================ +Module: battle +File: src/battle/battle1.c +ASM lines: 25 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:21:28] [INFO] [4/10] Decompiling func_800A6AC4 (26 lines) +[2026-03-01 22:21:28] [INFO] ⚙️ Analyzing with LLM (26 lines)... +[2026-03-01 22:21:39] [INFO] 📊 Complexity: medium, Summary: ** This function appears to be manipulating specific data stored in memory locat... + +============================================================ +Attempting to decompile: func_800A6AC4 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 26 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:21:40] [INFO] [5/10] Decompiling func_800A6C04 (26 lines) +[2026-03-01 22:21:40] [INFO] ⚙️ Analyzing with LLM (26 lines)... +[2026-03-01 22:21:49] [INFO] 📊 Complexity: medium, Summary: This function appears to perform some data manipulation, likely related to loadi... + +============================================================ +Attempting to decompile: func_800A6C04 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 26 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:21:50] [INFO] [6/10] Decompiling func_800ADE84 (26 lines) +[2026-03-01 22:21:50] [INFO] ⚙️ Analyzing with LLM (26 lines)... +[2026-03-01 22:21:56] [INFO] 📊 Complexity: medium, Summary: ** This function performs a calculation involving subtraction, multiplication, a... + +============================================================ +Attempting to decompile: func_800ADE84 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 26 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:21:57] [INFO] [7/10] Decompiling func_800B0EB4 (26 lines) +[2026-03-01 22:21:57] [INFO] ⚙️ Analyzing with LLM (26 lines)... +[2026-03-01 22:22:04] [INFO] 📊 Complexity: medium, Summary: ** This function appears to calculate an index based on the input parameter, fet... + +============================================================ +Attempting to decompile: func_800B0EB4 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 26 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:22:05] [INFO] [8/10] Decompiling func_800A4480 (27 lines) +[2026-03-01 22:22:05] [INFO] ⚙️ Analyzing with LLM (27 lines)... +[2026-03-01 22:22:17] [INFO] 📊 Complexity: medium, Summary: ** The function `func_800A4480` appears to be iterating over a range of values, ... + +============================================================ +Attempting to decompile: func_800A4480 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 27 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:22:18] [INFO] [9/10] Decompiling func_800A5660 (27 lines) +[2026-03-01 22:22:18] [INFO] ⚙️ Analyzing with LLM (27 lines)... +[2026-03-01 22:22:26] [INFO] 📊 Complexity: medium, Summary: ** The function `func_800A5660` iterates through a memory range, checking for sp... + +============================================================ +Attempting to decompile: func_800A5660 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 27 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:22:27] [INFO] [10/10] Decompiling func_800ADFF4 (27 lines) +[2026-03-01 22:22:27] [INFO] ⚙️ Analyzing with LLM (27 lines)... +[2026-03-01 22:22:38] [INFO] 📊 Complexity: medium, Summary: ** This function appears to calculate some values based on the contents of memor... + +============================================================ +Attempting to decompile: func_800ADFF4 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 27 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:22:39] [INFO] Running verification... + +============================================================ +VERIFYING DECOMPILED FUNCTIONS +============================================================ + +Found 20 decompiled function(s) to verify + +[1/20] Checking func_800A4480... + ✅ Matches +[2/20] Checking func_800A5660... + ✅ Matches +[3/20] Checking func_800A5FB0... + ✅ Matches +[4/20] Checking func_800A6A70... + ✅ Matches +[5/20] Checking func_800A6AC4... + ✅ Matches +[6/20] Checking func_800A6C04... + ✅ Matches +[7/20] Checking func_800A6CC0... + ✅ Matches +[8/20] Checking func_800A6D3C... + ✅ Matches +[9/20] Checking func_800AD890... + ✅ Matches +[10/20] Checking func_800AD8DC... + ✅ Matches +[11/20] Checking func_800ADE84... + ✅ Matches +[12/20] Checking func_800ADFF4... + ✅ Matches +[13/20] Checking func_800B0EB4... + ✅ Matches +[14/20] Checking func_800B1218... + ✅ Matches +[15/20] Checking func_800B2F70... + ✅ Matches +[16/20] Checking func_800B37A0... + ✅ Matches +[17/20] Checking func_800B38E0... + ✅ Matches +[18/20] Checking func_800B888C... + ✅ Matches +[19/20] Checking func_800D55A4... + ✅ Matches +[20/20] Checking func_800D5774... + ✅ Matches + +============================================================ +VERIFICATION COMPLETE +============================================================ +✅ Verified: 20 +❌ Not matching: 0 +============================================================ + +[2026-03-01 22:22:39] [INFO] Verified 20 functions + +============================================================ +AGENT PROGRESS - 22:22:39 +============================================================ +Processed: 40 functions +Verified: 99/2362 (4.2%) +Failed: 1 +Todo: 2262 +Batches: 4 +Builds: 0 +LLM analyzed: 11 +Rate: 0.30 functions/second +Elapsed: 0:02:14 +============================================================ + +[2026-03-01 22:22:41] [INFO] Processing batch of 10 functions +[2026-03-01 22:22:41] [INFO] [1/10] Decompiling func_800B0E5C (27 lines) +[2026-03-01 22:22:41] [INFO] ⚙️ Analyzing with LLM (27 lines)... +[2026-03-01 22:22:49] [INFO] 📊 Complexity: medium, Summary: ** The function checks if the input value is negative. If it is, it calculates a... + +============================================================ +Attempting to decompile: func_800B0E5C +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 27 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:22:49] [INFO] [2/10] Decompiling func_800B3FAC (27 lines) +[2026-03-01 22:22:49] [INFO] ⚙️ Analyzing with LLM (27 lines)... +[2026-03-01 22:22:58] [INFO] 📊 Complexity: medium, Summary: ** The function appears to be searching for a specific value in a memory buffer,... + +============================================================ +Attempting to decompile: func_800B3FAC +============================================================ +Module: battle +File: src/battle/battle1.c +ASM lines: 27 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:22:59] [INFO] [3/10] Decompiling func_800BC2F0 (27 lines) +[2026-03-01 22:22:59] [INFO] ⚙️ Analyzing with LLM (27 lines)... +[2026-03-01 22:23:08] [INFO] 📊 Complexity: medium, Summary: ** The function `func_800BC2F0` appears to be initializing memory blocks at spec... + +============================================================ +Attempting to decompile: func_800BC2F0 +============================================================ +Module: battle +File: src/battle/battle1.c +ASM lines: 27 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:23:09] [INFO] [4/10] Decompiling func_800D3474 (27 lines) +[2026-03-01 22:23:09] [INFO] ⚙️ Analyzing with LLM (27 lines)... +[2026-03-01 22:23:22] [INFO] 📊 Complexity: medium, Summary: ** This function appears to be manipulating registers related to coprocessor 2 (... + +============================================================ +Attempting to decompile: func_800D3474 +============================================================ +Module: battle +File: src/battle/battle2.c +ASM lines: 27 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:23:23] [INFO] [5/10] Decompiling func_800A311C (28 lines) +[2026-03-01 22:23:23] [INFO] ⚙️ Analyzing with LLM (28 lines)... +[2026-03-01 22:23:34] [WARN] ⚠️ LLM analysis failed: 'NoneType' object is not subscriptable + +============================================================ +Attempting to decompile: func_800A311C +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 28 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:23:35] [INFO] [6/10] Decompiling func_800A555C (28 lines) +[2026-03-01 22:23:35] [INFO] ⚙️ Analyzing with LLM (28 lines)... +[2026-03-01 22:23:54] [INFO] 📊 Complexity: medium, Summary: ** This function appears to modify a memory block by performing several operatio... + +============================================================ +Attempting to decompile: func_800A555C +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 28 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:23:54] [INFO] [7/10] Decompiling func_800B950C (28 lines) +[2026-03-01 22:23:54] [INFO] ⚙️ Analyzing with LLM (28 lines)... +[2026-03-01 22:24:07] [INFO] 📊 Complexity: medium, Summary: ** The function appears to be a loop that reads two 16-bit unsigned integers fro... + +============================================================ +Attempting to decompile: func_800B950C +============================================================ +Module: battle +File: src/battle/battle1.c +ASM lines: 28 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:24:08] [INFO] [8/10] Decompiling func_800E68B4 (28 lines) +[2026-03-01 22:24:08] [INFO] ⚙️ Analyzing with LLM (28 lines)... +[2026-03-01 22:24:21] [WARN] ⚠️ LLM analysis failed: 'NoneType' object is not subscriptable + +============================================================ +Attempting to decompile: func_800E68B4 +============================================================ +Module: battle +File: src/battle/battle3.c +ASM lines: 28 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:24:22] [INFO] [9/10] Decompiling func_800A283C (29 lines) +[2026-03-01 22:24:22] [INFO] ⚙️ Analyzing with LLM (29 lines)... +[2026-03-01 22:24:33] [INFO] 📊 Complexity: medium, Summary: ** The function `func_800A283C` appears to increment a counter stored in memory ... + +============================================================ +Attempting to decompile: func_800A283C +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 29 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:24:34] [INFO] [10/10] Decompiling func_800A6C5C (29 lines) +[2026-03-01 22:24:34] [INFO] ⚙️ Analyzing with LLM (29 lines)... +[2026-03-01 22:24:41] [INFO] 📊 Complexity: medium, Summary: The function appears to be processing some data by calling another function and ... + +============================================================ +Attempting to decompile: func_800A6C5C +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 29 +Current status: todo +✅ Decompilation successful! + +============================================================ +AGENT PROGRESS - 22:24:42 +============================================================ +Processed: 50 functions +Verified: 99/2362 (4.6%) +Failed: 1 +Todo: 2252 +Batches: 5 +Builds: 0 +LLM analyzed: 21 +Rate: 0.19 functions/second +Elapsed: 0:04:17 +============================================================ + +[2026-03-01 22:24:44] [INFO] Processing batch of 10 functions +[2026-03-01 22:24:44] [INFO] [1/10] Decompiling func_800A6E0C (29 lines) +[2026-03-01 22:24:44] [INFO] ⚙️ Analyzing with LLM (29 lines)... +[2026-03-01 22:24:52] [INFO] 📊 Complexity: medium, Summary: This function appears to set up memory addresses based on the input parameter, p... + +============================================================ +Attempting to decompile: func_800A6E0C +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 29 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:24:53] [INFO] [2/10] Decompiling func_800A73F8 (29 lines) +[2026-03-01 22:24:53] [INFO] ⚙️ Analyzing with LLM (29 lines)... +[2026-03-01 22:25:07] [INFO] 📊 Complexity: medium, Summary: ** This function appears to be handling a data structure, possibly for managing ... + +============================================================ +Attempting to decompile: func_800A73F8 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 29 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:25:08] [INFO] [3/10] Decompiling func_800AD420 (29 lines) +[2026-03-01 22:25:08] [INFO] ⚙️ Analyzing with LLM (29 lines)... +[2026-03-01 22:25:23] [WARN] ⚠️ LLM analysis failed: 'NoneType' object is not subscriptable + +============================================================ +Attempting to decompile: func_800AD420 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 29 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:25:24] [INFO] [4/10] Decompiling func_800AE318 (29 lines) +[2026-03-01 22:25:24] [INFO] ⚙️ Analyzing with LLM (29 lines)... +[2026-03-01 22:25:35] [INFO] 📊 Complexity: medium, Summary: ** The function `func_800AE318` appears to be part of a larger system that proce... + +============================================================ +Attempting to decompile: func_800AE318 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 29 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:25:35] [INFO] [5/10] Decompiling func_800AEB20 (29 lines) +[2026-03-01 22:25:35] [INFO] ⚙️ Analyzing with LLM (29 lines)... +[2026-03-01 22:25:46] [INFO] 📊 Complexity: medium, Summary: ** This function appears to be handling memory access and manipulation based on ... + +============================================================ +Attempting to decompile: func_800AEB20 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 29 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:25:47] [INFO] [6/10] Decompiling func_800B5CD4 (29 lines) +[2026-03-01 22:25:47] [INFO] ⚙️ Analyzing with LLM (29 lines)... +[2026-03-01 22:25:56] [INFO] 📊 Complexity: medium, Summary: This function appears to be performing a series of calculations and memory acces... + +============================================================ +Attempting to decompile: func_800B5CD4 +============================================================ +Module: battle +File: src/battle/battle1.c +ASM lines: 29 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:25:57] [INFO] [7/10] Decompiling func_800B8360 (29 lines) +[2026-03-01 22:25:57] [INFO] ⚙️ Analyzing with LLM (29 lines)... +[2026-03-01 22:26:10] [INFO] 📊 Complexity: medium, Summary: ** The function `func_800B8360` appears to initialize graphics drawing parameter... + +============================================================ +Attempting to decompile: func_800B8360 +============================================================ +Module: battle +File: src/battle/battle1.c +ASM lines: 29 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:26:11] [INFO] [8/10] Decompiling func_800D34C8 (29 lines) +[2026-03-01 22:26:11] [INFO] ⚙️ Analyzing with LLM (29 lines)... +[2026-03-01 22:26:27] [WARN] ⚠️ LLM analysis failed: 'NoneType' object is not subscriptable + +============================================================ +Attempting to decompile: func_800D34C8 +============================================================ +Module: battle +File: src/battle/battle2.c +ASM lines: 29 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:26:28] [INFO] [9/10] Decompiling func_800A4CC8 (30 lines) +[2026-03-01 22:26:28] [INFO] ⚙️ Analyzing with LLM (30 lines)... +[2026-03-01 22:26:39] [WARN] ⚠️ LLM analysis failed: 'NoneType' object is not subscriptable + +============================================================ +Attempting to decompile: func_800A4CC8 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 30 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:26:40] [INFO] [10/10] Decompiling func_800A71F4 (30 lines) +[2026-03-01 22:26:40] [INFO] ⚙️ Analyzing with LLM (30 lines)... +[2026-03-01 22:26:54] [INFO] 📊 Complexity: medium, Summary: ** The function appears to perform a specific operation involving memory manipul... + +============================================================ +Attempting to decompile: func_800A71F4 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 30 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:26:55] [INFO] Running verification... + +============================================================ +VERIFYING DECOMPILED FUNCTIONS +============================================================ + +Found 20 decompiled function(s) to verify + +[1/20] Checking func_800A283C... + ✅ Matches +[2/20] Checking func_800A311C... + ✅ Matches +[3/20] Checking func_800A4CC8... + ✅ Matches +[4/20] Checking func_800A555C... + ✅ Matches +[5/20] Checking func_800A6C5C... + ✅ Matches +[6/20] Checking func_800A6E0C... + ✅ Matches +[7/20] Checking func_800A71F4... + ✅ Matches +[8/20] Checking func_800A73F8... + ✅ Matches +[9/20] Checking func_800AD420... + ✅ Matches +[10/20] Checking func_800AE318... + ✅ Matches +[11/20] Checking func_800AEB20... + ✅ Matches +[12/20] Checking func_800B0E5C... + ✅ Matches +[13/20] Checking func_800B3FAC... + ✅ Matches +[14/20] Checking func_800B5CD4... + ✅ Matches +[15/20] Checking func_800B8360... + ✅ Matches +[16/20] Checking func_800B950C... + ✅ Matches +[17/20] Checking func_800BC2F0... + ✅ Matches +[18/20] Checking func_800D3474... + ✅ Matches +[19/20] Checking func_800D34C8... + ✅ Matches +[20/20] Checking func_800E68B4... + ✅ Matches + +============================================================ +VERIFICATION COMPLETE +============================================================ +✅ Verified: 20 +❌ Not matching: 0 +============================================================ + +[2026-03-01 22:26:55] [INFO] Verified 20 functions + +============================================================ +AGENT PROGRESS - 22:26:55 +============================================================ +Processed: 60 functions +Verified: 119/2362 (5.0%) +Failed: 1 +Todo: 2242 +Batches: 6 +Builds: 0 +LLM analyzed: 31 +Rate: 0.15 functions/second +Elapsed: 0:06:30 +============================================================ + +[2026-03-01 22:26:57] [INFO] Processing batch of 10 functions +[2026-03-01 22:26:57] [INFO] [1/10] Decompiling func_800AA688 (30 lines) +[2026-03-01 22:26:57] [INFO] ⚙️ Analyzing with LLM (30 lines)... +[2026-03-01 22:27:08] [INFO] 📊 Complexity: medium, Summary: ** The function `func_800AA688` iterates over a series of values, checking each ... + +============================================================ +Attempting to decompile: func_800AA688 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 30 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:27:09] [INFO] [2/10] Decompiling func_800B798C (30 lines) +[2026-03-01 22:27:09] [INFO] ⚙️ Analyzing with LLM (30 lines)... +[2026-03-01 22:27:17] [INFO] 📊 Complexity: easy, Summary: The function iterates up to 74 times, writing values to specific memory addresse... + +============================================================ +Attempting to decompile: func_800B798C +============================================================ +Module: battle +File: src/battle/battle1.c +ASM lines: 30 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:27:18] [INFO] [3/10] Decompiling func_800D3418 (30 lines) +[2026-03-01 22:27:18] [INFO] ⚙️ Analyzing with LLM (30 lines)... +[2026-03-01 22:27:33] [INFO] 📊 Complexity: easy, Summary: ** This function appears to manipulate certain control registers in the MIPS R30... + +============================================================ +Attempting to decompile: func_800D3418 +============================================================ +Module: battle +File: src/battle/battle2.c +ASM lines: 30 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:27:34] [INFO] [4/10] Decompiling func_800D51D4 (30 lines) +[2026-03-01 22:27:34] [INFO] ⚙️ Analyzing with LLM (30 lines)... +[2026-03-01 22:27:46] [INFO] 📊 Complexity: medium, Summary: ** This function reads an integer from a memory address stored in `$a1`, negates... + +============================================================ +Attempting to decompile: func_800D51D4 +============================================================ +Module: battle +File: src/battle/battle2.c +ASM lines: 30 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:27:47] [INFO] [5/10] Decompiling func_800D58D0 (30 lines) +[2026-03-01 22:27:47] [INFO] ⚙️ Analyzing with LLM (30 lines)... +[2026-03-01 22:28:03] [INFO] 📊 Complexity: medium, Summary: ** This function appears to call another function (`func_800BBEAC`), performs so... + +============================================================ +Attempting to decompile: func_800D58D0 +============================================================ +Module: battle +File: src/battle/battle2.c +ASM lines: 30 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:28:03] [INFO] [6/10] Decompiling func_800A70C4 (31 lines) +[2026-03-01 22:28:03] [INFO] ⚙️ Analyzing with LLM (31 lines)... +[2026-03-01 22:28:13] [INFO] 📊 Complexity: medium, Summary: ** The function appears to be loading a configuration value from memory, perform... + +============================================================ +Attempting to decompile: func_800A70C4 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 31 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:28:13] [INFO] [7/10] Decompiling func_800A853C (31 lines) +[2026-03-01 22:28:13] [INFO] ⚙️ Analyzing with LLM (31 lines)... +[2026-03-01 22:28:23] [INFO] 📊 Complexity: medium, Summary: ** The function appears to be a loop that iterates 10 times, performs some bitwi... + +============================================================ +Attempting to decompile: func_800A853C +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 31 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:28:24] [INFO] [8/10] Decompiling func_800B1304 (31 lines) +[2026-03-01 22:28:24] [INFO] ⚙️ Analyzing with LLM (31 lines)... +[2026-03-01 22:28:36] [INFO] 📊 Complexity: medium, Summary: ** The function appears to be searching for a specific value in a memory region,... + +============================================================ +Attempting to decompile: func_800B1304 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 31 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:28:36] [INFO] [9/10] Decompiling func_800C20E8 (31 lines) +[2026-03-01 22:28:36] [INFO] ⚙️ Analyzing with LLM (31 lines)... +[2026-03-01 22:28:44] [INFO] 📊 Complexity: medium, Summary: ** The function appears to perform some kind of computation involving multiplica... + +============================================================ +Attempting to decompile: func_800C20E8 +============================================================ +Module: battle +File: src/battle/battle1.c +ASM lines: 31 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:28:45] [INFO] [10/10] Decompiling func_800D76B8 (31 lines) +[2026-03-01 22:28:45] [INFO] ⚙️ Analyzing with LLM (31 lines)... +[2026-03-01 22:28:59] [INFO] 📊 Complexity: medium, Summary: ** The function appears to perform some operations on a data structure located a... + +============================================================ +Attempting to decompile: func_800D76B8 +============================================================ +Module: battle +File: src/battle/battle2.c +ASM lines: 31 +Current status: todo +✅ Decompilation successful! + +============================================================ +AGENT PROGRESS - 22:29:00 +============================================================ +Processed: 70 functions +Verified: 119/2362 (5.5%) +Failed: 1 +Todo: 2232 +Batches: 7 +Builds: 0 +LLM analyzed: 41 +Rate: 0.14 functions/second +Elapsed: 0:08:35 +============================================================ + +[2026-03-01 22:29:02] [INFO] Processing batch of 10 functions +[2026-03-01 22:29:02] [INFO] [1/10] Decompiling func_800D8A88 (31 lines) +[2026-03-01 22:29:02] [INFO] ⚙️ Analyzing with LLM (31 lines)... +[2026-03-01 22:29:15] [INFO] 📊 Complexity: medium, Summary: ** This function appears to synchronize a drawing process with vertical synchron... + +============================================================ +Attempting to decompile: func_800D8A88 +============================================================ +Module: battle +File: src/battle/battle3.c +ASM lines: 31 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:29:16] [INFO] [2/10] Decompiling func_800A65B0 (32 lines) +[2026-03-01 22:29:16] [INFO] ⚙️ Analyzing with LLM (32 lines)... +[2026-03-01 22:29:25] [WARN] ⚠️ LLM analysis failed: 'NoneType' object is not subscriptable + +============================================================ +Attempting to decompile: func_800A65B0 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 32 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:29:26] [INFO] [3/10] Decompiling func_800A8DCC (32 lines) +[2026-03-01 22:29:26] [INFO] ⚙️ Analyzing with LLM (32 lines)... +[2026-03-01 22:29:39] [INFO] 📊 Complexity: medium, Summary: ** This function appears to update memory addresses based on the input parameter... + +============================================================ +Attempting to decompile: func_800A8DCC +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 32 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:29:39] [INFO] [4/10] Decompiling func_800B11B4 (32 lines) +[2026-03-01 22:29:39] [INFO] ⚙️ Analyzing with LLM (32 lines)... +[2026-03-01 22:29:51] [INFO] 📊 Complexity: medium, Summary: ** This function appears to be searching for a specific value in an array, possi... + +============================================================ +Attempting to decompile: func_800B11B4 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 32 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:29:52] [INFO] [5/10] Decompiling func_800A34CC (33 lines) +[2026-03-01 22:29:52] [INFO] ⚙️ Analyzing with LLM (33 lines)... +[2026-03-01 22:30:01] [INFO] 📊 Complexity: medium, Summary: ** The function appears to be a loop that processes data at memory locations poi... + +============================================================ +Attempting to decompile: func_800A34CC +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 33 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:30:02] [INFO] [6/10] Decompiling func_800A44D8 (33 lines) +[2026-03-01 22:30:02] [INFO] ⚙️ Analyzing with LLM (33 lines)... +[2026-03-01 22:30:13] [INFO] 📊 Complexity: medium, Summary: ** The function appears to check if a given input is within a specific range and... + +============================================================ +Attempting to decompile: func_800A44D8 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 33 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:30:14] [INFO] [7/10] Decompiling func_800A6B1C (33 lines) +[2026-03-01 22:30:14] [INFO] ⚙️ Analyzing with LLM (33 lines)... +[2026-03-01 22:30:29] [INFO] 📊 Complexity: easy, Summary: ** The function `func_800A6B1C` appears to be a bit manipulation routine that pr... + +============================================================ +Attempting to decompile: func_800A6B1C +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 33 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:30:30] [INFO] [8/10] Decompiling func_800A85FC (33 lines) +[2026-03-01 22:30:30] [INFO] ⚙️ Analyzing with LLM (33 lines)... +[2026-03-01 22:30:40] [INFO] 📊 Complexity: medium, Summary: ** This function appears to check a condition, perform some calculations, and ca... + +============================================================ +Attempting to decompile: func_800A85FC +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 33 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:30:41] [INFO] [9/10] Decompiling func_800ADDE8 (33 lines) +[2026-03-01 22:30:41] [INFO] ⚙️ Analyzing with LLM (33 lines)... +[2026-03-01 22:30:58] [INFO] 📊 Complexity: medium, Summary: ** The function appears to perform calculations and manipulate data structures, ... + +============================================================ +Attempting to decompile: func_800ADDE8 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 33 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:30:58] [INFO] [10/10] Decompiling func_800AEB80 (33 lines) +[2026-03-01 22:30:58] [INFO] ⚙️ Analyzing with LLM (33 lines)... +[2026-03-01 22:31:19] [INFO] 📊 Complexity: medium, Summary: ** The function appears to be managing memory allocation and performing some bit... + +============================================================ +Attempting to decompile: func_800AEB80 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 33 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:31:19] [INFO] Running verification... + +============================================================ +VERIFYING DECOMPILED FUNCTIONS +============================================================ + +Found 20 decompiled function(s) to verify + +[1/20] Checking func_800A34CC... + ✅ Matches +[2/20] Checking func_800A44D8... + ✅ Matches +[3/20] Checking func_800A65B0... + ✅ Matches +[4/20] Checking func_800A6B1C... + ✅ Matches +[5/20] Checking func_800A70C4... + ✅ Matches +[6/20] Checking func_800A853C... + ✅ Matches +[7/20] Checking func_800A85FC... + ✅ Matches +[8/20] Checking func_800A8DCC... + ✅ Matches +[9/20] Checking func_800AA688... + ✅ Matches +[10/20] Checking func_800ADDE8... + ✅ Matches +[11/20] Checking func_800AEB80... + ✅ Matches +[12/20] Checking func_800B11B4... + ✅ Matches +[13/20] Checking func_800B1304... + ✅ Matches +[14/20] Checking func_800B798C... + ✅ Matches +[15/20] Checking func_800C20E8... + ✅ Matches +[16/20] Checking func_800D3418... + ✅ Matches +[17/20] Checking func_800D51D4... + ✅ Matches +[18/20] Checking func_800D58D0... + ✅ Matches +[19/20] Checking func_800D76B8... + ✅ Matches +[20/20] Checking func_800D8A88... + ✅ Matches + +============================================================ +VERIFICATION COMPLETE +============================================================ +✅ Verified: 20 +❌ Not matching: 0 +============================================================ + +[2026-03-01 22:31:20] [INFO] Verified 20 functions + +============================================================ +AGENT PROGRESS - 22:31:20 +============================================================ +Processed: 80 functions +Verified: 139/2362 (5.9%) +Failed: 1 +Todo: 2222 +Batches: 8 +Builds: 0 +LLM analyzed: 51 +Rate: 0.12 functions/second +Elapsed: 0:10:55 +============================================================ + +[2026-03-01 22:31:22] [INFO] Processing batch of 10 functions +[2026-03-01 22:31:22] [INFO] [1/10] Decompiling func_800D5230 (33 lines) +[2026-03-01 22:31:22] [INFO] ⚙️ Analyzing with LLM (33 lines)... +[2026-03-01 22:31:41] [INFO] 📊 Complexity: medium, Summary: ** This function appears to perform a series of calculations and memory operatio... + +============================================================ +Attempting to decompile: func_800D5230 +============================================================ +Module: battle +File: src/battle/battle2.c +ASM lines: 33 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:31:41] [INFO] [2/10] Decompiling func_800E58CC (33 lines) +[2026-03-01 22:31:41] [INFO] ⚙️ Analyzing with LLM (33 lines)... +[2026-03-01 22:31:56] [INFO] 📊 Complexity: medium, Summary: ** The function appears to be a loop that iterates up to 3 times, performing cal... + +============================================================ +Attempting to decompile: func_800E58CC +============================================================ +Module: battle +File: src/battle/battle3.c +ASM lines: 33 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:31:57] [INFO] [3/10] Decompiling func_800A55F4 (34 lines) +[2026-03-01 22:31:57] [INFO] ⚙️ Analyzing with LLM (34 lines)... +[2026-03-01 22:32:06] [INFO] 📊 Complexity: medium, Summary: ** This function appears to search through a table of 16-bit values, looking for... + +============================================================ +Attempting to decompile: func_800A55F4 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 34 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:32:07] [INFO] [4/10] Decompiling func_800A6D88 (34 lines) +[2026-03-01 22:32:07] [INFO] ⚙️ Analyzing with LLM (34 lines)... +[2026-03-01 22:32:20] [INFO] 📊 Complexity: medium, Summary: ** This function calculates an offset based on the input argument, reads a value... + +============================================================ +Attempting to decompile: func_800A6D88 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 34 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:32:21] [INFO] [5/10] Decompiling func_800A7254 (34 lines) +[2026-03-01 22:32:21] [INFO] ⚙️ Analyzing with LLM (34 lines)... +[2026-03-01 22:32:34] [INFO] 📊 Complexity: medium, Summary: ** This function appears to be involved in modifying a data structure based on s... + +============================================================ +Attempting to decompile: func_800A7254 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 34 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:32:35] [INFO] [6/10] Decompiling func_800AD088 (34 lines) +[2026-03-01 22:32:35] [INFO] ⚙️ Analyzing with LLM (34 lines)... +[2026-03-01 22:32:46] [INFO] 📊 Complexity: medium, Summary: ** This function appears to check a condition based on memory values and calls a... + +============================================================ +Attempting to decompile: func_800AD088 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 34 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:32:46] [INFO] [7/10] Decompiling func_800AD480 (34 lines) +[2026-03-01 22:32:46] [INFO] ⚙️ Analyzing with LLM (34 lines)... +[2026-03-01 22:32:58] [INFO] 📊 Complexity: medium, Summary: ** This function appears to be a loop that processes data based on certain condi... + +============================================================ +Attempting to decompile: func_800AD480 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 34 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:32:59] [INFO] [8/10] Decompiling func_800AE2A0 (34 lines) +[2026-03-01 22:32:59] [INFO] ⚙️ Analyzing with LLM (34 lines)... +[2026-03-01 22:33:13] [INFO] 📊 Complexity: medium, Summary: ** This function performs a series of arithmetic and logical operations on its i... + +============================================================ +Attempting to decompile: func_800AE2A0 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 34 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:33:13] [INFO] [9/10] Decompiling func_800B13B0 (34 lines) +[2026-03-01 22:33:13] [INFO] ⚙️ Analyzing with LLM (34 lines)... +[2026-03-01 22:33:27] [INFO] 📊 Complexity: medium, Summary: ** The function `func_800B13B0` appears to be a conditional write function that ... + +============================================================ +Attempting to decompile: func_800B13B0 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 34 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:33:28] [INFO] [10/10] Decompiling func_800B88CC (34 lines) +[2026-03-01 22:33:28] [INFO] ⚙️ Analyzing with LLM (34 lines)... +[2026-03-01 22:33:44] [INFO] 📊 Complexity: medium, Summary: ** This function appears to be performing a series of operations on the input pa... + +============================================================ +Attempting to decompile: func_800B88CC +============================================================ +Module: battle +File: src/battle/battle1.c +ASM lines: 34 +Current status: todo +✅ Decompilation successful! + +============================================================ +AGENT PROGRESS - 22:33:45 +============================================================ +Processed: 90 functions +Verified: 139/2362 (6.3%) +Failed: 1 +Todo: 2212 +Batches: 9 +Builds: 0 +LLM analyzed: 61 +Rate: 0.11 functions/second +Elapsed: 0:13:20 +============================================================ + +[2026-03-01 22:33:47] [INFO] Processing batch of 10 functions +[2026-03-01 22:33:47] [INFO] [1/10] Decompiling func_800BA24C (34 lines) +[2026-03-01 22:33:47] [INFO] ⚙️ Analyzing with LLM (34 lines)... +[2026-03-01 22:34:02] [INFO] 📊 Complexity: easy, Summary: ** This function appears to be managing some form of status flags and updating m... + +============================================================ +Attempting to decompile: func_800BA24C +============================================================ +Module: battle +File: src/battle/battle1.c +ASM lines: 34 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:34:03] [INFO] [2/10] Decompiling func_800BFA98 (34 lines) +[2026-03-01 22:34:03] [INFO] ⚙️ Analyzing with LLM (34 lines)... +[2026-03-01 22:34:19] [INFO] 📊 Complexity: medium, Summary: ** This function appears to be processing input values stored in specific memory... + +============================================================ +Attempting to decompile: func_800BFA98 +============================================================ +Module: battle +File: src/battle/battle1.c +ASM lines: 34 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:34:20] [INFO] [3/10] Decompiling func_800BFB10 (34 lines) +[2026-03-01 22:34:20] [INFO] ⚙️ Analyzing with LLM (34 lines)... +[2026-03-01 22:34:37] [INFO] 📊 Complexity: medium, Summary: ** This function appears to be manipulating memory addresses and performing bitw... + +============================================================ +Attempting to decompile: func_800BFB10 +============================================================ +Module: battle +File: src/battle/battle1.c +ASM lines: 34 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:34:38] [INFO] [4/10] Decompiling func_800C614C (34 lines) +[2026-03-01 22:34:38] [INFO] ⚙️ Analyzing with LLM (34 lines)... +[2026-03-01 22:34:54] [INFO] 📊 Complexity: medium, Summary: ** This function appears to process a TIM file, which is typically used for stor... + +============================================================ +Attempting to decompile: func_800C614C +============================================================ +Module: battle +File: src/battle/battle1.c +ASM lines: 34 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:34:54] [INFO] [5/10] Decompiling func_800D09D0 (34 lines) +[2026-03-01 22:34:54] [INFO] ⚙️ Analyzing with LLM (34 lines)... +[2026-03-01 22:35:11] [INFO] 📊 Complexity: medium, Summary: ** The function appears to perform a series of memory operations based on an inp... + +============================================================ +Attempting to decompile: func_800D09D0 +============================================================ +Module: battle +File: src/battle/battle2.c +ASM lines: 34 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:35:12] [INFO] [6/10] Decompiling func_800D5444 (34 lines) +[2026-03-01 22:35:12] [INFO] ⚙️ Analyzing with LLM (34 lines)... +[2026-03-01 22:35:29] [WARN] ⚠️ LLM analysis failed: 'NoneType' object is not subscriptable + +============================================================ +Attempting to decompile: func_800D5444 +============================================================ +Module: battle +File: src/battle/battle2.c +ASM lines: 34 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:35:30] [INFO] [7/10] Decompiling func_800A66A4 (35 lines) +[2026-03-01 22:35:30] [INFO] ⚙️ Analyzing with LLM (35 lines)... +[2026-03-01 22:35:52] [INFO] 📊 Complexity: medium, Summary: ** This function appears to perform some form of data manipulation or processing... + +============================================================ +Attempting to decompile: func_800A66A4 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 35 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:35:53] [INFO] [8/10] Decompiling func_800ACE14 (35 lines) +[2026-03-01 22:35:53] [INFO] ⚙️ Analyzing with LLM (35 lines)... +[2026-03-01 22:36:03] [INFO] 📊 Complexity: medium, Summary: ** This function appears to be responsible for checking a condition based on the... + +============================================================ +Attempting to decompile: func_800ACE14 +============================================================ +Module: battle +File: src/battle/battle.c +ASM lines: 35 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:36:04] [INFO] [9/10] Decompiling func_800C0410 (35 lines) +[2026-03-01 22:36:04] [INFO] ⚙️ Analyzing with LLM (35 lines)... +[2026-03-01 22:36:18] [INFO] 📊 Complexity: medium, Summary: ** This function performs a series of calculations and conditional checks using ... + +============================================================ +Attempting to decompile: func_800C0410 +============================================================ +Module: battle +File: src/battle/battle1.c +ASM lines: 35 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:36:19] [INFO] [10/10] Decompiling func_800C0900 (35 lines) +[2026-03-01 22:36:19] [INFO] ⚙️ Analyzing with LLM (35 lines)... +[2026-03-01 22:36:33] [INFO] 📊 Complexity: medium, Summary: ** The function `func_800C0900` appears to perform a series of operations involv... + +============================================================ +Attempting to decompile: func_800C0900 +============================================================ +Module: battle +File: src/battle/battle1.c +ASM lines: 35 +Current status: todo +✅ Decompilation successful! +[2026-03-01 22:36:33] [INFO] Running verification... + +============================================================ +VERIFYING DECOMPILED FUNCTIONS +============================================================ + +Found 20 decompiled function(s) to verify + +[1/20] Checking func_800A55F4... + ✅ Matches +[2/20] Checking func_800A66A4... + ✅ Matches +[3/20] Checking func_800A6D88... + ✅ Matches +[4/20] Checking func_800A7254... + ✅ Matches +[5/20] Checking func_800ACE14... + ✅ Matches +[6/20] Checking func_800AD088... + ✅ Matches +[7/20] Checking func_800AD480... + ✅ Matches +[8/20] Checking func_800AE2A0... + ✅ Matches +[9/20] Checking func_800B13B0... + ✅ Matches +[10/20] Checking func_800B88CC... + ✅ Matches +[11/20] Checking func_800BA24C... + ✅ Matches +[12/20] Checking func_800BFA98... + ✅ Matches +[13/20] Checking func_800BFB10... + ✅ Matches +[14/20] Checking func_800C0410... + ✅ Matches +[15/20] Checking func_800C0900... + ✅ Matches +[16/20] Checking func_800C614C... + ✅ Matches +[17/20] Checking func_800D09D0... + ✅ Matches +[18/20] Checking func_800D5230... + ✅ Matches +[19/20] Checking func_800D5444... + ✅ Matches +[20/20] Checking func_800E58CC... + ✅ Matches + +============================================================ +VERIFICATION COMPLETE +============================================================ +✅ Verified: 20 +❌ Not matching: 0 +============================================================ + +[2026-03-01 22:36:34] [INFO] Verified 20 functions +[2026-03-01 22:36:34] [INFO] Running full build check... + +============================================================ +RUNNING BUILD +============================================================ + +❌ Build failed! + +Errors: 72 + +Compile Errors: + src/main/psxsdk.c +src/main/psxsdk.c: + Line 555: parse error before `:' + +Undefined References (71): + - SetMem + - StartPAD + - InitPAD + - GetGraphType + - GetGraphType + - OpenTIM + - OpenEvent + - EnableEvent + - UnDeliverEvent + - DisableEvent + ... and 61 more + +============================================================ + +[2026-03-01 22:36:35] [WARN] Build failed, check output for errors + +============================================================ +AGENT PROGRESS - 22:36:35 +============================================================ +Processed: 100 functions +Verified: 159/2362 (6.7%) +Failed: 1 +Todo: 2202 +Batches: 10 +Builds: 1 +LLM analyzed: 71 +Rate: 0.10 functions/second +Elapsed: 0:16:10 +============================================================ + +[2026-03-01 22:36:35] [INFO] Target count reached (100) +[2026-03-01 22:36:35] [INFO] Target count reached (100) + +============================================================ +AGENT EXECUTION COMPLETE +============================================================ +Total time: 0:16:10 +Functions processed: 100 +Functions verified: 100 +Functions failed: 0 +Batches completed: 10 +Builds run: 1 +LLM analyzed: 71 +Average rate: 0.10 functions/second + +Final Progress: 159/2362 (6.7%) +============================================================ + +Summary saved to agent_summary.json \ No newline at end of file diff --git a/automation/intellisense_errors.json b/automation/intellisense_errors.json new file mode 100644 index 0000000..e69de29 diff --git a/automation/intellisense_fixer.py b/automation/intellisense_fixer.py new file mode 100644 index 0000000..bae94cb --- /dev/null +++ b/automation/intellisense_fixer.py @@ -0,0 +1,456 @@ +#!/usr/bin/env python3 +""" +Deterministic IntelliSense / clangd error fixer for m2c-generated C code. + +These passes run after m2c writes a decompiled function and BEFORE validation, +so they reduce spurious validation failures caused by known m2c artifacts rather +than genuine type-inference problems. + +Passes (all text-based, no LLM required): + 1. fix_unk_negative_fields — ->unk-C → ->unkC (m2c hex-suffix bug) + 2. hoist_early_typedefs — move typedefs that appear after their first use + 3. remove_duplicate_typedefs — deduplicate identical typedef blocks + 4. hoist_extern_declarations — collect all top-level extern / forward-decl lines + and place them in a single block before the first + INCLUDE_ASM / function definition +""" + +import re +from typing import List, Tuple, Optional + + +# --------------------------------------------------------------------------- +# Pass 1: fix ->unk-N / .unk-N → ->unkN / .unkN +# --------------------------------------------------------------------------- + +def fix_unk_negative_fields(content: str) -> Tuple[str, int]: + """ + Fix m2c artifact where struct field names get a spurious '-' before their + hex offset suffix. + + Before: D_800AF3D4.unk-C = 0; + After: D_800AF3D4.unkC = 0; + + Before: temp->unk-4 + After: temp->unk4 + + Returns (fixed_content, num_fixes). + """ + # Match ->unk-HEX or .unk-HEX (hex digits follow the minus) + pattern = re.compile(r'(->|\.)unk-([0-9A-Fa-f]+)\b') + count = [0] + + def _replace(m: re.Match) -> str: + count[0] += 1 + sep = m.group(1) + hex_part = m.group(2) + return f'{sep}unk{hex_part}' + + fixed = pattern.sub(_replace, content) + return fixed, count[0] + + +# --------------------------------------------------------------------------- +# Pass 2 & 3: typedef hoisting and deduplication +# --------------------------------------------------------------------------- + +def _find_typedef_blocks(lines: List[str]) -> List[Tuple[int, int, str, str]]: + """ + Scan lines for typedef blocks, including multi-line struct typedefs. + + Returns list of (start_idx, end_idx, typedef_name, full_text). + Indices are 0-based into `lines`. + """ + blocks: List[Tuple[int, int, str, str]] = [] + i = 0 + while i < len(lines): + line = lines[i] + stripped = line.strip() + if not re.match(r'typedef\b', stripped): + i += 1 + continue + + start = i + + if '{' in line: + # Multi-line struct/union typedef — scan until braces balance + depth = line.count('{') - line.count('}') + j = i + 1 + while j < len(lines) and depth > 0: + depth += lines[j].count('{') - lines[j].count('}') + j += 1 + end = j - 1 + # typedef name is on the closing line: } TypeName; + m = re.search(r'\}\s*(\w+)\s*;', lines[end]) + if m: + name = m.group(1) + text = '\n'.join(lines[start:end + 1]) + blocks.append((start, end, name, text)) + i = end + 1 + else: + # Single-line typedef. Try several name-extraction patterns: + # 1. Standard: typedef Name; + # 2. Function pointer: typedef RetType (*Name)(Params); + # 3. Array: typedef Type Name[N]; + name = None + + # Pattern 1: function pointer — typedef ... (*Name)(...) + m = re.search(r'typedef\s+.+?\(\s*\*\s*(\w+)\s*\)\s*\(', line) + if m: + name = m.group(1) + + # Pattern 2: standard — last \w+ before the final ; + if name is None: + m = re.search(r'typedef\s+.+?\s+(\w+)\s*(?:\[\w*\])?\s*;', line) + if m: + name = m.group(1) + + if name: + blocks.append((i, i, name, line)) + i += 1 + + return blocks + + +def _first_use_line(lines: List[str], typedef_name: str, + exclude_start: int, exclude_end: int) -> Optional[int]: + """ + Return the index of the first line that uses `typedef_name` as a type name, + excluding the definition lines [exclude_start, exclude_end]. + + We look for the name at a word boundary that looks like a type position: + - extern TypeName ... + - TypeName* var + - TypeName var + - function parameter of that type + We also explicitly ignore lines that are only inside the typedef definition + itself and comment lines. + """ + # Build a pattern that matches the name used as a type (not as part of a larger word) + pat = re.compile(rf'\b{re.escape(typedef_name)}\b') + for idx, line in enumerate(lines): + if exclude_start <= idx <= exclude_end: + continue + stripped = line.strip() + if stripped.startswith('//') or stripped.startswith('*'): + continue + if pat.search(line): + return idx + return None + + +def hoist_early_typedefs(content: str) -> Tuple[str, int]: + """ + For any typedef whose first use appears *before* its definition, move the + typedef to just before that first use. + + Also removes exact duplicate typedef blocks (same name, keeps first). + + Returns (fixed_content, num_typedefs_moved). + """ + lines = content.split('\n') + blocks = _find_typedef_blocks(lines) + + if not blocks: + return content, 0 + + # --- Deduplicate: keep first occurrence of each name --- + seen_names: set = set() + unique_blocks: List[Tuple[int, int, str, str]] = [] + dup_ranges: set = set() # line ranges to delete (duplicates) + + for start, end, name, text in blocks: + if name in seen_names: + for ln in range(start, end + 1): + dup_ranges.add(ln) + else: + seen_names.add(name) + unique_blocks.append((start, end, name, text)) + + # Remove duplicate lines first (in a copy we'll work with) + if dup_ranges: + lines = [line for i, line in enumerate(lines) if i not in dup_ranges] + # Re-scan after removal + blocks = _find_typedef_blocks(lines) + unique_blocks_new = [] + seen2: set = set() + for start, end, name, text in blocks: + if name not in seen2: + seen2.add(name) + unique_blocks_new.append((start, end, name, text)) + unique_blocks = unique_blocks_new + + moved = 0 + # Process typedefs in reverse order so that removing/inserting lines doesn't + # invalidate earlier indices. + for start, end, name, text in reversed(unique_blocks): + first_use = _first_use_line(lines, name, start, end) + if first_use is None or first_use >= start: + # No earlier use — leave in place + continue + + # Extract the typedef block + typedef_lines = lines[start:end + 1] + + # Remove it from current position (may leave a blank line) + del lines[start:end + 1] + + # Recalculate insertion point (indices shifted after delete) + insert_at = first_use # first_use < start, so not affected by the delete + + # Insert before first use, preceded by a blank line if not already present + insertion = typedef_lines + [''] + lines[insert_at:insert_at] = insertion + moved += 1 + + return '\n'.join(lines), moved + len(dup_ranges) + + +# --------------------------------------------------------------------------- +# Pass 4: hoist extern declarations to the file header +# --------------------------------------------------------------------------- + +# Patterns for extern declarations (both forms produced by m2c / mako.sh dec) +_EXTERN_KW_PAT = re.compile(r'^\s*extern\b') # extern TYPE NAME; +_EXTERN_FWD_PAT = re.compile(r'//\s*extern\s*$') # TYPE FUNC(...); // extern + + +def _is_extern_decl(line: str) -> bool: + """Return True if the line is a top-level extern declaration (either style).""" + stripped = line.strip() + # Skip declarations with m2c '?' unknown types — PSY-Q can't compile them + if '?' in stripped: + return False + # Skip extern declarations with initializers (e.g. m2c %gp annotations like + # `extern s32 D_80062F10 = 0; // %gp`). These define symbols, which will + # conflict with ASM BSS/sdata objects that already own those symbols. + if _EXTERN_KW_PAT.match(stripped) and '=' in stripped: + return False + if _EXTERN_KW_PAT.match(stripped): + return True + # Forward-decl comment style: must also look like a prototype (has parens) + if _EXTERN_FWD_PAT.search(stripped) and '(' in stripped and ')' in stripped: + return True + return False + + +def _extern_type_name(line: str) -> Optional[str]: + """ + Extract the primary type name used in an extern declaration, so we can + check whether that type is defined later in the file. + + Returns the first identifier after 'extern' (or at the start of a + forward-decl line), stripping qualifiers like 'const', '/*?*/', etc. + Returns None if extraction fails. + """ + stripped = line.strip() + # Remove leading /*?*/ comment if present + stripped = re.sub(r'^/\*\??\*/\s*', '', stripped) + # Remove 'extern' keyword + stripped = re.sub(r'^extern\s+', '', stripped) + # Remove const / volatile / static + stripped = re.sub(r'^(const|volatile|static)\s+', '', stripped) + # First word is the type name (may have trailing * or [) + m = re.match(r'^([A-Za-z_]\w*)', stripped) + if m: + return m.group(1) + return None + + +def _typedef_name_to_last_line(lines: List[str]) -> dict: + """ + Return a dict mapping typedef name -> last line index of its definition. + Only covers typedefs that are locally defined in the file (not in headers). + """ + result: dict = {} + blocks = _find_typedef_blocks(lines) + for start, end, name, _ in blocks: + result[name] = end + return result + + +def _is_function_boundary(line: str) -> bool: + """Return True if the line starts a function definition or INCLUDE_ASM stub.""" + stripped = line.strip() + if stripped.startswith('INCLUDE_ASM('): + return True + # Function definition: contains ( and ends with { (no = before the brace, + # so we don't accidentally match const array initialisers) + if '{' not in stripped or ';' in stripped: + return False + if stripped.startswith(('//', '/*', 'typedef', 'extern', '#', 'const ')): + return False + brace_pos = stripped.rfind('{') + before_brace = stripped[:brace_pos] + if '(' not in before_brace or '=' in before_brace: + return False + return True + + +def hoist_extern_declarations(content: str) -> Tuple[str, int]: + """ + Collect every top-level extern declaration that appears *after* the first + INCLUDE_ASM / function definition and move them to a single block just + before that first function boundary. + + Handles both declaration styles: + - ``extern TYPE NAME;`` (standard extern variable/function) + - ``/*?*/ TYPE FUNCNAME(PARAMS); // extern`` (m2c forward declaration) + - ``TYPE FUNCNAME(PARAMS); // extern`` (forward declaration) + + Deduplicates against externs already present in the header section so + the pass is idempotent. + + Returns (fixed_content, num_externs_moved). + """ + lines = content.split('\n') + + # ---------------------------------------------------------------- + # 1. Find the first function boundary at brace-depth 0 + # ---------------------------------------------------------------- + depth = 0 + func_boundary: Optional[int] = None + for i, line in enumerate(lines): + stripped = line.strip() + if depth == 0 and _is_function_boundary(line): + func_boundary = i + break + depth += stripped.count('{') - stripped.count('}') + if depth < 0: + depth = 0 + + if func_boundary is None: + return content, 0 # No functions/INCLUDE_ASM found — nothing to do + + # ---------------------------------------------------------------- + # 2. Build set of externs already in the header section (before boundary) + # ---------------------------------------------------------------- + existing: set = set() + depth = 0 + for i in range(func_boundary): + stripped = lines[i].strip() + if depth == 0 and _is_extern_decl(lines[i]): + existing.add(stripped) + depth += stripped.count('{') - stripped.count('}') + if depth < 0: + depth = 0 + + # ---------------------------------------------------------------- + # 3. Collect top-level externs that appear AT or AFTER the boundary + # ---------------------------------------------------------------- + lines_to_remove: set = set() + new_externs: List[str] = [] + seen: set = set(existing) + + # Build a map of typedef name -> last line of its definition so we can + # skip hoisting any extern whose type is defined *after* the function + # boundary (i.e., in the body section of the file, not the header). + # Using `> func_boundary` instead of `> i` because hoisting moves the + # extern to *before* func_boundary — so any typedef that lives anywhere + # after func_boundary would end up after the extern post-hoist. + typedef_last_line = _typedef_name_to_last_line(lines) + + depth = 0 # depth AT func_boundary (reset; recompute from scratch) + for i in range(func_boundary): + stripped = lines[i].strip() + depth += stripped.count('{') - stripped.count('}') + if depth < 0: + depth = 0 + + for i in range(func_boundary, len(lines)): + stripped = lines[i].strip() + if depth == 0 and _is_extern_decl(lines[i]): + # Don't hoist if the extern's type is defined in the body section + # (i.e., after the function boundary) — hoisting would place the + # extern before its typedef. + type_name = _extern_type_name(lines[i]) + if type_name and type_name in typedef_last_line and typedef_last_line[type_name] > func_boundary: + pass # skip — type defined after this extern, leave in place + else: + if stripped not in seen: + new_externs.append(lines[i].rstrip()) + seen.add(stripped) + lines_to_remove.add(i) + depth += stripped.count('{') - stripped.count('}') + if depth < 0: + depth = 0 + + if not new_externs: + return content, 0 + + # ---------------------------------------------------------------- + # 4. Rebuild lines without removed externs; collapse extra blank lines + # ---------------------------------------------------------------- + result: List[str] = [] + prev_blank = False + for i, line in enumerate(lines): + if i in lines_to_remove: + continue + blank = line.strip() == '' + if blank and prev_blank: + continue # collapse consecutive blanks + prev_blank = blank + result.append(line) + + # ---------------------------------------------------------------- + # 5. Find new function boundary in the rebuilt list and insert block + # ---------------------------------------------------------------- + new_boundary: Optional[int] = None + depth = 0 + for i, line in enumerate(result): + if depth == 0 and _is_function_boundary(line): + new_boundary = i + break + stripped = line.strip() + depth += stripped.count('{') - stripped.count('}') + if depth < 0: + depth = 0 + + if new_boundary is None: + # Shouldn't happen; fall back to appending + result += [''] + new_externs + return '\n'.join(result), len(new_externs) + + # Build insertion block: blank separator + externs + blank separator + insert: List[str] = [] + if new_boundary > 0 and result[new_boundary - 1].strip() != '': + insert.append('') + insert.extend(new_externs) + insert.append('') + + result[new_boundary:new_boundary] = insert + return '\n'.join(result), len(new_externs) + + +# --------------------------------------------------------------------------- +# Combined entry point +# --------------------------------------------------------------------------- + +def apply_all_fixes(content: str, verbose: bool = False) -> Tuple[str, List[str]]: + """ + Apply all deterministic IntelliSense fixes to `content`. + + Returns (fixed_content, list_of_change_descriptions). + + Order matters: + 1. fix_unk_negative_fields — clean up field-name artifacts first + 2. hoist_extern_declarations — move all externs to the header section so + their type references become the "first use" of those types + 3. hoist_early_typedefs — now move typedefs to before those first uses + (which are the extern declarations in the header) + """ + changes: List[str] = [] + + content, n = fix_unk_negative_fields(content) + if n: + changes.append(f"fixed {n} unk-N field name(s)") + + content, n = hoist_extern_declarations(content) + if n: + changes.append(f"hoisted {n} extern declaration(s) to file header") + + content, n = hoist_early_typedefs(content) + if n: + changes.append(f"hoisted/deduped {n} typedef(s)") + + return content, changes diff --git a/automation/llm_fixes_audit.log b/automation/llm_fixes_audit.log new file mode 100644 index 0000000..5c69adf --- /dev/null +++ b/automation/llm_fixes_audit.log @@ -0,0 +1,137 @@ +2026-03-28T18:38:18.346553 func_800A9910 /home/calvin/GitHub/ff7-decomp-armstrca/src/world/world.c medium PSY-Q compilation failed: `D_8010AD40' undeclared (first use this function); (Each undeclared identifier is reported only once; for each function it appears in.) The error indicates that the decompiler is unable to recognize the symbol `D_8010AD40`. This could be due to the variable not being declared in the current scope or being part of a different compilation unit. Since m2c cannot handle this, we need to manually add the declaration for `D_8010AD40` assuming it is a pointer type. +2026-03-28T18:39:54.627875 func_800C4C9C /home/calvin/GitHub/ff7-decomp-armstrca/src/field/field.c high PSY-Q compilation failed: warning: dereferencing `void *' pointer; request for member `unk2' in something not a structure or union; warning: dereferencing `void *' pointer The decompilation error is due to dereferencing a `void *` pointer and attempting to access structure members without proper casting. The original assembly code accesses specific bytes in memory, which need to be correctly mapped back into the structure. +2026-03-28T18:41:27.484682 func_800B10B4 /home/calvin/GitHub/ff7-decomp-armstrca/src/battle/battle.c high PSY-Q compilation failed: warning: assignment from incompatible pointer type; warning: large integer implicitly truncated to unsigned type; warning: assignment from incompatible pointer type The decompilation error is due to incompatible pointer types and implicit type conversions. The MIPS assembly code accesses memory at specific offsets and performs bitwise operations, but the m2c output is not correctly handling these pointers and types. +2026-03-28T18:41:58.797545 func_800D55A4 /home/calvin/GitHub/ff7-decomp-armstrca/src/battle/battle2.c medium PSY-Q compilation failed: warning: passing arg 3 of `func_800C7B60' makes pointer from integer without a cast; warning: passing arg 3 of `func_800C7BE8' makes pointer from integer without a cast; warning: assignment makes pointer from integer without a cast The decompilation error indicates that the integer values are being cast to pointers without proper casting. This typically happens when dereferencing a pointer that is not properly aligned or initialized. +2026-03-28T18:42:31.617697 func_800DA310 /home/calvin/GitHub/ff7-decomp-armstrca/src/field/field.c high PSY-Q compilation failed: warning: dereferencing `void *' pointer; request for member `unk2' in something not a structure or union; parse error before `result' The error is caused by an attempt to dereference a `void*` pointer and access a member `unk2`, which is not valid in C. Since the type of `D_800E4210` is unknown, we need to infer it from the assembly code. The assembly code suggests that `D_800E4210` is a pointer to some structure or union. We will assume it points to a struct with at least three members (since we are adding 1 and masking with 3). For simplicity, we will use a dummy struct type. +2026-03-28T18:52:23.725391 func_800B8E48 /home/calvin/GitHub/ff7-decomp-armstrca/src/battle/battle1.c high PSY-Q compilation failed: warning: passing arg 2 of `func_800D29D4' from incompatible pointer type The error in the decompiled code is due to the fact that m2c was unable to infer the correct type for the second argument of `func_800D29D4`. The assembly shows that this parameter is accessed using a base pointer and an offset, indicating it should be a struct pointer. + +### FIXED_CODE: +```c +struct SomeStruct { + u8 unk10; + u8 unk11; + u8 unk12; + u8 unk13; +}; + +void func_800B8E48(s32 arg0) { + s32 temp_a0; + s32 temp_v0; + struct SomeStruct* ptr1; + struct SomeStruct* ptr2; + + temp_a0 = arg0 & 0xFF; + temp_v0 = temp_a0 * 0xB9C; + ptr1 = (struct SomeStruct*)((u8*)D_801518E4 + temp_v0); + ptr1->unk10 = 1; + ptr1->unk11 &= 0x7F; + + temp_v0 = temp_a0 * 0x74; + ptr2 = (struct SomeStruct*)((u8*)D_80151200 + temp_v0); + ptr2->unk12 &= 0xFFDF; +} +``` + +### Explanation: +- The unknown struct type is assumed to be `SomeStruct` based on the field offsets. +- The second parameter of `func_800D29D4` is correctly typed as a pointer to this struct. +- The assembly instructions are translated into access to the struct fields using the correct PSX SDK types (`u8`). +2026-03-28T18:53:27.399060 func_801D01C4 /home/calvin/GitHub/ff7-decomp-armstrca/src/menu/bginmenu.c high PSY-Q compilation failed: warning: assignment from incompatible pointer type; warning: assignment from incompatible pointer type The error in the decompiled code is due to incorrect pointer arithmetic and type casting. Specifically, the `var_v1` variable is being used incorrectly in the loop. The original assembly code uses `lw` instructions to load 32-bit values from memory, but the decompiled code attempts to access the elements of an array using pointer arithmetic without proper type casting. + +### FIXED_CODE: +```c +func_801D01C4(s32 arg0) +{ + s32 var_a1; + s32 var_a2; + u8* var_v1; + + var_a1 = 0; + var_a2 = 0; + var_v1 = ((u8*)Savemap.party[0].unk40) + (arg0 * 0x84); + do { + if (*(s32*)var_v1 != -1) { + var_a2 += 1; + } + var_a1 += 1; + if (var_a1 >= 8) { + break; + } + var_v1 += 4; + } while (true); + + var_a1 = 0; + var_a2 = 0; + var_v1 = ((u8*)Savemap.party[0].unk64) + (arg0 * 0x84); + do { + if (*(s32*)var_v1 != -1) { + var_a2 += 1; + } + var_a1 += 1; + if (var_a1 >= 8) { + break; + } + var_v1 += 4; + } while (true); +} +``` + +### Explanation of Fixes: +1. **Pointer Arithmetic**: The original assembly code uses `lw` instructions to load 32-bit values from memory, so we need to use pointer arithmetic correctly by casting the pointer to a type that points to a 32-bit value (`s32*`). +2. **Base Pointer Calculation**: The base pointers for the two loops are correctly calculated using the `Savemap.party[0].unk40` and `Savemap.party[0].unk64` fields, which are likely arrays or structs. +3. **Loop Conditions**: The loop conditions are fixed to ensure that the loops run exactly 8 times (as indicated by the `slti $v0, $a1, 0x8` instructions in the assembly). +2026-03-28T19:02:39.261970 func_800D491C /home/calvin/GitHub/ff7-decomp-armstrca/src/battle/battle2.c high Contains '(unaligned type)' cast (m2c error) ** The code had a syntax error due to the incorrect use of pointer arithmetic and type casting. The assembly code was trying to access unaligned memory, which is not allowed in many systems, especially for 32-bit integers on a 64-bit architecture. + +**FIXED_CODE:** +```c +void func(void* ptr1, void* ptr2) { + u32* src = (u32*)ptr1; + u16* dst = (u16*)ptr2; + + memcpy(dst, src, sizeof(u32)); +} +``` + +This fix ensures that the code correctly casts the pointers to the appropriate types and uses `memcpy` to copy the unaligned data safely. +2026-03-28T19:03:47.051806 func_800C1FD8 /home/calvin/GitHub/ff7-decomp-armstrca/src/world/world2.c high Contains M2C_ERROR() macro (m2c could not determine register/instruction) ** The assembly code provided appears to be a decompiled function that handles some kind of data structure manipulation. The code includes several issues such as unaligned memory access, unknown type markers, missing struct members, and syntax errors in parsing the C context. These issues were addressed by inferring types from register usage, correcting offsets, using proper PSX SDK types, and rewriting certain parts of the code to be more readable. + +**FIXED_CODE:** +```c +void func_800C1FD8(u32 *ptr) { + u32 var_a1; + u32 var_v0; + u32 var_v1; + + memcpy(&var_a1, ptr, sizeof(u32)); + + if (*(u16*)((u8*)ptr + 0x10)) { + var_v0 = *(u32*)((u8*)ptr + 0x14); + while (var_a1 < var_v0) { + *(u32*)((u8*)ptr + 0x1C) = var_v0; + *(u32*)((u8*)ptr + 0x20) = var_v0; + *(u32*)((u8*)ptr + 0x24) = var_v0; + *(u32*)((u8*)ptr + 0x28) = var_v0; + *(u32*)((u8*)ptr + 0x2C) = var_v0; + *(u32*)((u8*)ptr + 0x30) = var_v0; + *(u32*)((u8*)ptr + 0x34) = var_v0; + *(u32*)((u8*)ptr + 0x38) = var_v0; + var_a1 += 1; + } + } else { + *(u32*)((u8*)ptr + 0x10) = 1; + } + + return; +} +``` + +This corrected version of the function should now be more readable and correctly handles the operations based on the assembly code. +2026-04-07T23:27:55.497887 func_800D8B60 /home/calvin/GitHub/ff7-decomp-armstrca/src/battle/battle3.c high Contains pointer to unknown type '?*' The original code uses unaligned memory access which can lead to undefined behavior on many systems. This is fixed by using memcpy to copy the aligned data into a properly aligned buffer. +// FIXED_CODE: +void func_800D8B60(void* arg) { + s32 dst; + memcpy(&dst, arg, sizeof(s32)); + // Rest of the function logic remains unchanged +} +``` +2026-04-11T15:59:22.273846 func_800B153C /home/calvin/GitHub/ff7-decomp-armstrca/src/battle/battle.c high Contains saved_reg_* artifact (m2c callee-save register not resolved) The original code had several issues related to pointer handling and type inference. Specifically, the `void*` parameter was not correctly identified as a pointer to a specific structure, leading to incorrect field access. Additionally, there were syntax errors and missing struct members that needed to be addressed. diff --git a/automation/llm_helper.py b/automation/llm_helper.py new file mode 100755 index 0000000..7c734e2 --- /dev/null +++ b/automation/llm_helper.py @@ -0,0 +1,827 @@ +#!/usr/bin/env python3 +""" +LLM Integration for Decompilation Assistance + +Interfaces with Ollama/Qwen to provide AI-assisted decompilation: +1. Analyze MIPS assembly before decompilation +2. Suggest C code improvements +3. Help refine non-matching functions +4. Provide context and explanations + +Usage: + python llm_helper.py --analyze-asm function_name + python llm_helper.py --suggest-c function_name + python llm_helper.py --explain asm/us/battle/file.s +""" + +import subprocess +import argparse +import json +import re +from pathlib import Path +from typing import Optional, Dict, List, Tuple +from database import DecompDatabase + +# Project root +PROJECT_ROOT = Path(__file__).parent.parent +ASM_DIR = PROJECT_ROOT / "asm" / "us" + +# Ollama configuration +OLLAMA_MODEL = "qwen2.5-coder:7b" +OLLAMA_ENDPOINT = "http://localhost:11434" + +# Shared FF7 project context injected into all LLM prompts +FF7_CONTEXT = """ +## Project: Final Fantasy VII (PS1 USA) Decompilation +Goal: byte-accurate recompilation — the output C must compile to identical machine code as the original binary. + +### PSX SDK Types (always use these — never int/short/char/long) +```c +typedef signed char s8; typedef unsigned char u8; +typedef signed short s16; typedef unsigned short u16; +typedef signed int s32; typedef unsigned int u32; +typedef u8 unk_data; typedef unsigned int* unk_ptr; +``` + +### Naming Conventions +- Unknown functions: `func_800XXXXX` (address-based, do not rename) +- Decompiled functions: verb-first (e.g., `InitBattle`, `LoadScene`, `DrawSprite`), prefer PSX SDK names +- Unknown globals: `D_800XXXXX` +- Known game state globals: `g_` prefix (e.g., `g_BattleState`) +- Unknown struct fields: `unkXX` (offset in hex, e.g., `unk10` for offset 0x10) + +### String Encoding +FF7 uses custom encoding — strings must use the `_S()` macro: `const char* msg = _S("Save game?");` + +### Decompilation Checklist — output MUST satisfy ALL of these +- No `/*?*/` unknown types — infer from register usage and context +- No `void*` parameters that should be typed struct pointers +- No pointer arithmetic for struct field access — use `->` or `.` operators +- Array elements accessed with `arr[i]`, not `*(arr + i * sizeof(...))` +- `goto loop_XX` patterns converted to `while` / `do-while` loops +- `goto block_XX` inside switch statements inlined (reverse compiler optimization) +- Struct sizes and field alignments match assembly access patterns (4-byte aligned) + +### Compiler Notes (PSYQ 3.3 / cc1-psx) +- GP (global pointer) = `0x80062D44` in main overlay — variables near this use gp-relative addressing +- Two compilers: `cc1-psx-26` (PSYQ 2.6) and `cc1-psx-272` (PSYQ 2.72); check `config/us.yaml` +- Calling convention: `$a0`–`$a3` args, `$v0`–`$v1` return values +- Type affects load instruction: `s8` → `lb`, `u8` → `lbu`, `s16` → `lh`, `u16` → `lhu` + +### Common Matching Pitfalls +- Merged calls: compiler merges common code after if/else branches; duplicate the call inside each branch to match +- Struct vs variables: use proper structs for stack-allocated data — compiler may optimize away isolated local vars +- Sign extension: `sll`/`sra` pairs appear in both branches of original — do not merge them +""" + + +class LLMHelper: + """Helper for LLM-assisted decompilation.""" + + def __init__(self, model: str = OLLAMA_MODEL, verbose: bool = False): + self.model = model + self.verbose = verbose + self.available = self._check_ollama() + + def _check_ollama(self) -> bool: + """Check if Ollama is available.""" + try: + result = subprocess.run( + ["ollama", "list"], + capture_output=True, + text=True, + timeout=5 + ) + return result.returncode == 0 and self.model.split(':')[0] in result.stdout + except Exception as e: + if self.verbose: + print(f"Warning: Ollama not available: {e}") + return False + + def _call_ollama(self, prompt: str, temperature: float = 0.2, max_tokens: int = 2048, timeout: int = 60) -> Optional[str]: + """Call Ollama with a prompt.""" + if not self.available: + return None + + try: + # Use ollama run command + result = subprocess.run( + ["ollama", "run", self.model, prompt], + capture_output=True, + text=True, + timeout=timeout + ) + + if result.returncode == 0: + return result.stdout.strip() + else: + if self.verbose: + print(f"Ollama error: {result.stderr}") + return None + + except subprocess.TimeoutExpired: + if self.verbose: + print(f"Ollama request timed out after {timeout}s") + return None + except Exception as e: + if self.verbose: + print(f"Error calling Ollama: {e}") + return None + + def get_assembly_code(self, function_name: str) -> Optional[str]: + """Get assembly code for a function from the ASM directory.""" + db = DecompDatabase() + func = db.get_function(function_name) + + if not func or not func['asm_file_path']: + return None + + asm_path = PROJECT_ROOT / func['asm_file_path'] + + if not asm_path.exists(): + return None + + try: + content = asm_path.read_text() + + # Extract just this function's assembly + # Look for function label and get code until next label or end + pattern = rf'^glabel\s+{re.escape(function_name)}\s*$(.+?)(?=^glabel|\Z)' + match = re.search(pattern, content, re.MULTILINE | re.DOTALL) + + if match: + return match.group(1).strip() + else: + # Fallback: just return a reasonable chunk + lines = content.split('\n') + for i, line in enumerate(lines): + if function_name in line: + # Get next 50 lines as approximation + return '\n'.join(lines[i:i+50]) + return None + + except Exception as e: + if self.verbose: + print(f"Error reading assembly: {e}") + return None + + def analyze_assembly(self, function_name: str) -> Optional[Dict]: + """ + Analyze MIPS assembly and provide insights. + + Returns dict with: + - summary: Brief description of what function does + - complexity: Estimated difficulty (easy/medium/hard) + - patterns: Detected patterns (loops, conditionals, etc.) + - suggestions: C code suggestions + """ + if not self.available: + return None + + asm_code = self.get_assembly_code(function_name) + if not asm_code: + return None + + prompt = f"""{FF7_CONTEXT} +Analyze this MIPS R3000 assembly function. + +Function: {function_name} + +Assembly: +{asm_code} + +Provide a concise analysis: +1. What does this function do? (1-2 sentences) +2. Complexity: easy/medium/hard +3. Key patterns: (loops, conditionals, function calls, memory access, struct usage) +4. Suggested C equivalent — use PSX SDK types (s32/u32/s16/u16/s8/u8), apply decompilation checklist rules (goto→while, array indices, struct `->` access) + +Format your response as: +SUMMARY: +COMPLEXITY: +PATTERNS: +C_SUGGESTION: + +""" + + if self.verbose: + print(f"Analyzing {function_name} with LLM...") + + response = self._call_ollama(prompt, temperature=0.2) + + if not response: + return None + + # Parse response + result = { + 'function': function_name, + 'raw_response': response, + 'summary': None, + 'complexity': 'medium', + 'patterns': [], + 'c_suggestion': None + } + + # Extract structured data + if 'SUMMARY:' in response: + summary_match = re.search(r'SUMMARY:\s*(.+?)(?=\n[A-Z]+:|$)', response, re.DOTALL) + if summary_match: + result['summary'] = summary_match.group(1).strip() + + if 'COMPLEXITY:' in response: + complexity_match = re.search(r'COMPLEXITY:\s*(\w+)', response, re.IGNORECASE) + if complexity_match: + result['complexity'] = complexity_match.group(1).lower() + + if 'PATTERNS:' in response: + patterns_match = re.search(r'PATTERNS:\s*(.+?)(?=\n[A-Z]+:|$)', response, re.DOTALL) + if patterns_match: + result['patterns'] = [p.strip() for p in patterns_match.group(1).strip().split(',')] + + if 'C_SUGGESTION:' in response: + c_match = re.search(r'C_SUGGESTION:\s*(.+?)$', response, re.DOTALL) + if c_match: + result['c_suggestion'] = c_match.group(1).strip() + + return result + + def suggest_c_code(self, function_name: str, context: Optional[str] = None) -> Optional[str]: + """ + Suggest C code for a function based on its assembly. + + Args: + function_name: Name of function + context: Optional additional context (nearby functions, structs, etc.) + """ + if not self.available: + return None + + asm_code = self.get_assembly_code(function_name) + if not asm_code: + return None + + prompt = f"""{FF7_CONTEXT} +Decompile this MIPS R3000 function to C code that will compile to identical assembly. + +Function: {function_name} + +Assembly: +{asm_code} +""" + + if context: + prompt += f"\nAdditional Context:\n{context}\n" + + prompt += """ +Generate C code following these rules: +- Use PSX SDK types exclusively: s8/u8/s16/u16/s32/u32 +- Apply decompilation checklist: no /*?*/, no void* for struct args, use ->/. for struct fields, array[i] not pointer arithmetic, goto loop_XX → while loops, goto block_XX in switch → inline the branch +- $a0–$a3 = arguments, $v0–$v1 = return values +- Type determines load instruction: s8→lb, u8→lbu, s16→lh, u16→lhu — pick types to match +- Duplicate common calls inside each branch of if/else to avoid compiler merging +- Use proper struct types for stack vars — not isolated s16 locals + +Provide ONLY the C function code, no explanation: +""" + + if self.verbose: + print(f"Generating C suggestion for {function_name}...") + + response = self._call_ollama(prompt, temperature=0.3, max_tokens=1024) + + if response: + # Clean up response - extract just code if wrapped in markdown + code_match = re.search(r'```c?\n(.*?)\n```', response, re.DOTALL) + if code_match: + return code_match.group(1).strip() + return response.strip() + + return None + + def infer_types_from_assembly(self, function_name: str, extern_symbols: List[str]) -> Optional[Dict]: + """ + Infer struct types for extern symbols before decompilation. + + Analyzes assembly to determine: + - Field offsets accessed for each symbol + - Field sizes (byte/half/word) + - Likely struct definitions + + Args: + function_name: Function to analyze + extern_symbols: List of extern symbols (D_800XXXXX, etc.) used + + Returns: + Dict mapping symbol_name -> { + 'typedef': suggested typedef string, + 'fields': {offset: (name, type)}, + 'confidence': 0.0-1.0 + } + """ + if not self.available or not extern_symbols: + return None + + asm_code = self.get_assembly_code(function_name) + if not asm_code: + return None + + symbols_str = ', '.join(extern_symbols) + + prompt = f"""{FF7_CONTEXT} +Analyze this MIPS R3000 assembly to infer struct types for extern symbols. + +Function: {function_name} +Extern Symbols to Analyze: {symbols_str} + +Assembly: +{asm_code} + +For each symbol, identify: +1. All memory offset accesses (from lw/lh/lb/sw/sh/sb instructions) +2. Access size determines field type: + - lb/sb (signed byte) → s8 + - lbu (unsigned byte) → u8 + - lh/sh (signed half) → s16 + - lhu (unsigned half) → u16 + - lw/sw (word) → s32/u32/pointer + +3. Generate typedef with fields at detected offsets + +Example: If you see: + lui $v0, %hi(D_800F83D0) + lhu $v1, %lo(D_800F83D0)($v0) # offset 0x0, unsigned half + lhu $a0, 0x2($v0) # offset 0x2, unsigned half + +Generate: + typedef struct {{ + u16 unk0; // offset 0x0 + u16 unk2; // offset 0x2 + }} Unk800F83D0; + +Format response as JSON: +{{ + "symbol_name": {{ + "typedef": "typedef struct {{ ... }} TypeName;", + "fields": {{ + "0x0": ["unk0", "u16"], + "0x2": ["unk2", "u16"] + }}, + "confidence": 0.8, + "notes": "brief reason for confidence level" + }} +}} + +Provide ONLY valid JSON, no markdown or explanation. +""" + + if self.verbose: + print(f"Inferring types for {function_name} ({len(extern_symbols)} symbols)...") + + response = self._call_ollama(prompt, temperature=0.1, max_tokens=2048, timeout=90) + + if not response: + return None + + try: + # Try to extract JSON from response (may have markdown wrapping) + json_match = re.search(r'```json\s*(\{.+?\})\s*```', response, re.DOTALL) + if json_match: + response = json_match.group(1) + elif '```' in response: + # Try without json tag + json_match = re.search(r'```\s*(\{.+?\})\s*```', response, re.DOTALL) + if json_match: + response = json_match.group(1) + + # Parse JSON + inferred = json.loads(response) + + if self.verbose: + for symbol, info in inferred.items(): + print(f" {symbol}: confidence={info.get('confidence', 0.0):.2f}, fields={len(info.get('fields', {}))}") + + return inferred + + except json.JSONDecodeError as e: + if self.verbose: + print(f"Failed to parse LLM response as JSON: {e}") + print(f"Response was: {response[:200]}...") + return None + + def generate_type_header(self, inferred_types: Dict, output_path: Optional[Path] = None) -> str: + """ + Generate a C header file from inferred types. + + Args: + inferred_types: Dict from infer_types_from_assembly + output_path: Optional path to write header file + + Returns: + Header file content as string + """ + header = """/* Auto-generated type definitions */ +#ifndef AUTO_TYPES_H +#define AUTO_TYPES_H + +#include "common.h" + +""" + + for symbol, type_info in inferred_types.items(): + typedef = type_info.get('typedef', '') + confidence = type_info.get('confidence', 0.0) + notes = type_info.get('notes', '') + + header += f"/* {symbol} - confidence: {confidence:.2f} */\n" + if notes: + header += f"/* {notes} */\n" + header += f"{typedef}\n\n" + + # Also add extern declaration + # Extract type name from typedef + type_match = re.search(r'\}\s*(\w+);', typedef) + if type_match: + type_name = type_match.group(1) + header += f"extern {type_name} {symbol};\n\n" + + header += "#endif /* AUTO_TYPES_H */\n" + + if output_path: + output_path.write_text(header) + if self.verbose: + print(f"Wrote type header to {output_path}") + + return header + + def explain_assembly_section(self, asm_code: str) -> Optional[str]: + """Explain what a section of assembly does.""" + if not self.available: + return None + + prompt = f"""Explain this MIPS R3000 assembly code in plain English: + +{asm_code} + +Provide a clear, concise explanation of what this code does. +""" + + return self._call_ollama(prompt, temperature=0.2) + + def suggest_refinement(self, function_name: str, current_c_code: str, error_message: Optional[str] = None) -> Optional[Dict]: + """ + Suggest refinements for C code that doesn't match. + + Args: + function_name: Function name + current_c_code: Current C implementation + error_message: Optional error/mismatch message + + Returns dict with: + - suggestions: List of suggested changes + - revised_code: Optional revised C code + """ + if not self.available: + return None + + asm_code = self.get_assembly_code(function_name) + if not asm_code: + return None + + prompt = f"""{FF7_CONTEXT} +Fix this decompiled function to match the original binary exactly. + +Function: {function_name} + +Original Assembly: +{asm_code} + +Current C Code (does not match): +{current_c_code} +""" + + if error_message: + prompt += f"\nError/Mismatch info:\n{error_message}\n" + + prompt += """ +Matching workflow — work through these in order: +1. **Size**: Count instructions in assembly vs compiled output. If size is wrong, fix structure first. +2. **Types**: `s8`→`lb`, `u8`→`lbu`, `s16`→`lh`, `u16`→`lhu` — change types to match load/store instructions. +3. **Merged calls**: If a call appears once after if/else in the C but twice in asm, duplicate it inside each branch. +4. **Struct vs locals**: Replace isolated `s16 a, b;` stack vars with a proper `RECT` or similar struct so the compiler stores all fields. +5. **goto patterns**: `goto loop_XX` → `while` loop; `goto block_XX` in switch → inline branch. +6. **Redundant instructions**: Original may have duplicate `sll`/`sra` pairs in both branches — reproduce the duplication. + +Provide: +SUGGESTIONS: +- + +REVISED_CODE: + +""" + + if self.verbose: + print(f"Getting refinement suggestions for {function_name}...") + + response = self._call_ollama(prompt, temperature=0.3) + + if not response: + return None + + result = { + 'function': function_name, + 'raw_response': response, + 'suggestions': [], + 'revised_code': None + } + + # Extract suggestions + if 'SUGGESTIONS:' in response: + sugg_match = re.search(r'SUGGESTIONS:\s*(.+?)(?=\nREVISED_CODE:|$)', response, re.DOTALL) + if sugg_match: + suggestions_text = sugg_match.group(1).strip() + result['suggestions'] = [s.strip('- ').strip() for s in suggestions_text.split('\n') if s.strip().startswith('-')] + + # Extract revised code + if 'REVISED_CODE:' in response: + code_match = re.search(r'REVISED_CODE:\s*(.+?)$', response, re.DOTALL) + if code_match: + code = code_match.group(1).strip() + # Clean markdown if present + code_clean = re.search(r'```c?\n(.*?)\n```', code, re.DOTALL) + if code_clean: + result['revised_code'] = code_clean.group(1).strip() + else: + result['revised_code'] = code + + return result + + def fix_m2c_error(self, function_name: str, broken_c_code: str, error_type: str, + pre_analysis: Optional[Dict] = None) -> Optional[Dict]: + """ + Attempt to automatically fix common m2c decompilation errors. + + Args: + function_name: Function name + broken_c_code: The function body with m2c errors + error_type: Type of error detected (e.g., "unaligned cast", "incomplete type") + pre_analysis: Optional pre-decompilation analysis with c_suggestion + + Returns dict with: + - fixed_code: Corrected C code + - explanation: What was fixed + - confidence: "high", "medium", or "low" + """ + if not self.available: + return None + + # Get assembly for reference + asm_code = self.get_assembly_code(function_name) + + prompt = f"""{FF7_CONTEXT} +Fix a decompilation error from m2c (MIPS → C decompiler) in a Final Fantasy VII function. + +Function: {function_name} +Error Type: {error_type} + +Broken C Code (from m2c): +{broken_c_code} +""" + + if asm_code: + prompt += f""" +Original Assembly (authoritative — your fix must match this): +{asm_code} +""" + + if pre_analysis and pre_analysis.get('c_suggestion'): + prompt += f""" +Pre-analysis C suggestion (use as structural guide): +{pre_analysis['c_suggestion']} +""" + + prompt += """ +Common m2c errors and how to fix them: + +1. `(unaligned s32)` / `(unaligned TYPE)` casts — unaligned memory access: + Fix: `memcpy(&dst, &src, sizeof(s32));` + +2. `/*?*/` unknown type markers — m2c couldn't infer the type: + Fix: Infer from register use ($a0=first arg→likely pointer), struct offset, or context. + Apply decompilation checklist: no `void*` for struct args, use proper PSX SDK types. + +3. `void*` variable or parameter used with `->` (struct type inference failure): + This is the most common battle-module error. m2c left a variable as `void*` because it + couldn't determine which struct it points to. + Fix: Look at which fields are accessed via `->` (e.g., `->unk4`, `->unk10`, `->unkC`) and + define a local anonymous struct or use explicit byte-offset casts: + Option A (struct): `typedef struct { s32 unk0; s32 unk4; s16 unkC; } SomeStruct;` + then change `void* var` → `SomeStruct* var` + Option B (cast): Replace `var->unk4` with `*(s32*)((u8*)var + 4)` + Replace `var->unkC` with `*(s16*)((u8*)var + 0xC)` + Check the assembly: the register holding the pointer is usually $a0/$a1 for args, + or $s0/$v0 for locals. The `lw/lh/lb` offset in the LW instruction = the field offset. + +4. `Contains unknown parameter type '?'` — function call with `?` in signature: + The extern declaration uses `?` as a placeholder because m2c saw an opaque argument. + Fix: Look at the call in the assembly. The register(s) passed to the call determine + the type. `$a0`=s32/ptr, `$a1`=s32, `$a2`=s32, `$a3`=s32. Change `/*?*/ void func(?)` + to `void func(s32 arg0)` (or appropriate type). If truly unknown, use `s32`. + +5. `primitive pointer used with ->unk` — e.g. `s32*` accessed as struct: + Same as case 3 — m2c guessed `s32*` instead of `void*`. Use explicit offset casts. + +6. Missing struct member / bad offset access: + Fix: Derive field name from byte offset (e.g., offset 0x10 → `unk10`), or cast: `*(s16*)((u8*)ptr + 0x10)` + +7. `Syntax error when parsing C context` / bad extern declarations: + Fix: Use `void*` for truly unknown pointer params, or add proper forward declarations with known types. + +8. `M2C_ERROR(...)` or decompilation failure comments — m2c gave up: + Fix: Hand-write C from the assembly. For stale/unset registers (`$a1` never set before call), use `0`. + E.g.: `func(ptr, 0 /* $a1 stale */);` + +9. `goto loop_XX` patterns: + Fix: Convert to `while` loop — `goto loop_4:` with label at top → `while (cond) { ... }` + +10. `goto block_XX` in switch statements: + Fix: Inline the branch body — reverse the compiler's jump-table optimization. + +Output format: +CONFIDENCE: high/medium/low +EXPLANATION: +FIXED_CODE: + +""" + + if self.verbose: + print(f"Attempting to fix m2c error in {function_name}...") + + response = self._call_ollama(prompt, temperature=0.2, max_tokens=1024) + + if not response: + return None + + result = { + 'function': function_name, + 'error_type': error_type, + 'raw_response': response, + 'fixed_code': None, + 'explanation': None, + 'confidence': 'low' + } + + # Extract confidence + conf_match = re.search(r'CONFIDENCE:\s*(high|medium|low)', response, re.IGNORECASE) + if conf_match: + result['confidence'] = conf_match.group(1).lower() + + # Extract explanation + exp_match = re.search(r'EXPLANATION:\s*(.+?)(?=\nFIXED_CODE:|$)', response, re.DOTALL) + if exp_match: + result['explanation'] = exp_match.group(1).strip() + + # Extract fixed code + if 'FIXED_CODE:' in response: + code_match = re.search(r'FIXED_CODE:\s*(.+?)$', response, re.DOTALL) + if code_match: + code = code_match.group(1).strip() + # Clean markdown if present + code_clean = re.search(r'```c?\n(.*?)\n```', code, re.DOTALL) + if code_clean: + result['fixed_code'] = code_clean.group(1).strip() + else: + result['fixed_code'] = code.strip() + + return result + + def batch_analyze(self, function_names: List[str]) -> Dict[str, Dict]: + """Analyze multiple functions in batch.""" + results = {} + + for func_name in function_names: + if self.verbose: + print(f"Analyzing {func_name}...") + + analysis = self.analyze_assembly(func_name) + if analysis: + results[func_name] = analysis + + return results + + +def main(): + parser = argparse.ArgumentParser(description="LLM-assisted decompilation helper") + + parser.add_argument('--analyze-asm', type=str, metavar='FUNCTION', + help='Analyze assembly for a function') + parser.add_argument('--suggest-c', type=str, metavar='FUNCTION', + help='Suggest C code for a function') + parser.add_argument('--explain', type=str, metavar='ASM_FILE', + help='Explain assembly in a file') + parser.add_argument('--refine', type=str, metavar='FUNCTION', + help='Suggest refinements for a function') + parser.add_argument('--batch', nargs='+', metavar='FUNCTION', + help='Analyze multiple functions') + parser.add_argument('--model', type=str, default=OLLAMA_MODEL, + help=f'Ollama model to use (default: {OLLAMA_MODEL})') + parser.add_argument('--check', action='store_true', + help='Check if LLM is available') + parser.add_argument('--verbose', '-v', action='store_true', + help='Verbose output') + + args = parser.parse_args() + + helper = LLMHelper(model=args.model, verbose=args.verbose) + + if args.check: + if helper.available: + print(f"✅ LLM available: {args.model}") + print(f"Endpoint: {OLLAMA_ENDPOINT}") + else: + print(f"❌ LLM not available") + print("Make sure Ollama is running: ollama serve") + print(f"And model is installed: ollama pull {args.model}") + return + + if not helper.available: + print("❌ LLM not available. Run with --check for details.") + return + + if args.analyze_asm: + print(f"\n{'='*60}") + print(f"ANALYZING: {args.analyze_asm}") + print(f"{'='*60}\n") + + result = helper.analyze_assembly(args.analyze_asm) + + if result: + print(f"Summary: {result['summary']}") + print(f"Complexity: {result['complexity']}") + if result['patterns']: + print(f"Patterns: {', '.join(result['patterns'])}") + if result['c_suggestion']: + print(f"\nSuggested C Structure:\n{result['c_suggestion']}") + else: + print("Could not analyze function") + + elif args.suggest_c: + print(f"\n{'='*60}") + print(f"C CODE SUGGESTION: {args.suggest_c}") + print(f"{'='*60}\n") + + suggestion = helper.suggest_c_code(args.suggest_c) + + if suggestion: + print(suggestion) + else: + print("Could not generate suggestion") + + elif args.explain: + asm_path = Path(args.explain) + if asm_path.exists(): + asm_code = asm_path.read_text()[:2000] # Limit size + + print(f"\n{'='*60}") + print(f"EXPLAINING: {args.explain}") + print(f"{'='*60}\n") + + explanation = helper.explain_assembly_section(asm_code) + if explanation: + print(explanation) + else: + print("Could not explain assembly") + else: + print(f"File not found: {args.explain}") + + elif args.refine: + print(f"\n{'='*60}") + print(f"REFINEMENT SUGGESTIONS: {args.refine}") + print(f"{'='*60}\n") + + # Would need to get current C code from the source file + print("Note: Refinement mode requires current C code as input") + print("This feature is best used programmatically from other scripts") + + elif args.batch: + print(f"\n{'='*60}") + print(f"BATCH ANALYSIS: {len(args.batch)} functions") + print(f"{'='*60}\n") + + results = helper.batch_analyze(args.batch) + + for func_name, result in results.items(): + print(f"\n{func_name}:") + print(f" Complexity: {result['complexity']}") + print(f" Summary: {result['summary']}") + + else: + parser.print_help() + print("\nQuick examples:") + print(" python llm_helper.py --check") + print(" python llm_helper.py --analyze-asm func_800A1234") + print(" python llm_helper.py --suggest-c AverageSZ4") + print(" python llm_helper.py --batch func_800A1234 func_800A5678") + + +if __name__ == '__main__': + main() diff --git a/automation/make build log.txt b/automation/make build log.txt new file mode 100644 index 0000000..e015799 --- /dev/null +++ b/automation/make build log.txt @@ -0,0 +1,363 @@ +calvin@Begemot:~/GitHub/ff7-decomp-armstrca$ make rebuild +[10/85] psx cc src/main/1255C.c +src/main/1255C.c:66: parse error before `?' +src/main/1255C.c:71: parse error before `?' +src/main/1255C.c: In function `func_80022FE0': +src/main/1255C.c:86: warning: passing arg 1 of `PutDispEnv' from incompatible pointer type +src/main/1255C.c: In function `func_80025040': +src/main/1255C.c:269: incompatible types in assignment +src/main/1255C.c: In function `func_80025514': +src/main/1255C.c:457: request for member `unk473' in something not a structure or union +src/main/1255C.c:457: request for member `unk473' in something not a structure or union +src/main/1255C.c:460: request for member `unk473' in something not a structure or union +src/main/1255C.c:460: request for member `unk473' in something not a structure or union +src/main/1255C.c: In function `func_80025668': +src/main/1255C.c:510: subscripted value is neither array nor pointer +src/main/1255C.c:513: invalid operands to binary * +src/main/1255C.c: In function `func_800256DC': +src/main/1255C.c:523: subscripted value is neither array nor pointer +src/main/1255C.c:526: invalid operands to binary * +src/main/1255C.c: In function `func_80025800': +src/main/1255C.c:557: subscripted value is neither array nor pointer +src/main/1255C.c:569: incompatible types in assignment +src/main/1255C.c: In function `func_800258BC': +src/main/1255C.c:580: subscripted value is neither array nor pointer +src/main/1255C.c:589: incompatible types in assignment +src/main/1255C.c: In function `func_80025988': +src/main/1255C.c:601: subscripted value is neither array nor pointer +src/main/1255C.c:613: incompatible types in assignment +src/main/1255C.c: In function `func_80025A44': +src/main/1255C.c:624: subscripted value is neither array nor pointer +src/main/1255C.c:633: incompatible types in assignment +src/main/1255C.c: At top level: +src/main/1255C.c:764: warning: type mismatch with previous external decl +src/main/1255C.c:415: warning: previous external decl of `func_8002603C' +src/main/1255C.c:764: warning: type mismatch with previous implicit declaration +src/main/1255C.c:456: warning: previous implicit declaration of `func_8002603C' +src/main/1255C.c: In function `func_800260DC': +src/main/1255C.c:797: warning: passing arg 1 of `func_80025C14' from incompatible pointer type +src/main/1255C.c:802: subscripted value is neither array nor pointer +src/main/1255C.c:807: warning: passing arg 3 of `func_80033F40' from incompatible pointer type +src/main/1255C.c:808: warning: passing arg 1 of `func_80025D14' from incompatible pointer type +src/main/1255C.c:818: warning: passing arg 2 of `StoreImage' from incompatible pointer type +src/main/1255C.c:820: warning: passing arg 1 of `func_80025C54' from incompatible pointer type +src/main/1255C.c: In function `func_800262D8': +src/main/1255C.c:843: warning: assignment makes pointer from integer without a cast +src/main/1255C.c:847: invalid operands to binary + +src/main/1255C.c:853: invalid operands to binary & +src/main/1255C.c: In function `func_80026A00': +src/main/1255C.c:907: warning: assignment from incompatible pointer type +src/main/1255C.c: In function `func_80026A0C': +src/main/1255C.c:912: warning: assignment from incompatible pointer type +src/main/1255C.c: In function `func_80026A20': +src/main/1255C.c:917: warning: assignment from incompatible pointer type +src/main/1255C.c: In function `func_80028CA0': +src/main/1255C.c:969: warning: dereferencing `void *' pointer +src/main/1255C.c:969: request for member `unk3' in something not a structure or union +src/main/1255C.c:970: warning: dereferencing `void *' pointer +src/main/1255C.c:970: request for member `unk7' in something not a structure or union +src/main/1255C.c:975: warning: dereferencing `void *' pointer +src/main/1255C.c:975: request for member `unk8' in something not a structure or union +src/main/1255C.c:976: warning: dereferencing `void *' pointer +src/main/1255C.c:976: request for member `unkA' in something not a structure or union +src/main/1255C.c:977: warning: dereferencing `void *' pointer +src/main/1255C.c:977: request for member `unkC' in something not a structure or union +src/main/1255C.c:978: warning: dereferencing `void *' pointer +src/main/1255C.c:978: request for member `unkD' in something not a structure or union +src/main/1255C.c:979: warning: dereferencing `void *' pointer +src/main/1255C.c:979: request for member `unk10' in something not a structure or union +src/main/1255C.c:980: warning: dereferencing `void *' pointer +src/main/1255C.c:980: request for member `unk12' in something not a structure or union +src/main/1255C.c:981: warning: dereferencing `void *' pointer +src/main/1255C.c:981: request for member `unkE' in something not a structure or union +src/main/1255C.c: In function `func_80028E00': +src/main/1255C.c:1027: warning: dereferencing `void *' pointer +src/main/1255C.c:1027: request for member `unk3' in something not a structure or union +src/main/1255C.c:1028: warning: dereferencing `void *' pointer +src/main/1255C.c:1028: request for member `unk7' in something not a structure or union +src/main/1255C.c:1031: warning: dereferencing `void *' pointer +src/main/1255C.c:1031: request for member `unk8' in something not a structure or union +src/main/1255C.c:1032: warning: dereferencing `void *' pointer +src/main/1255C.c:1032: request for member `unkA' in something not a structure or union +src/main/1255C.c:1033: warning: dereferencing `void *' pointer +src/main/1255C.c:1033: request for member `unkC' in something not a structure or union +src/main/1255C.c:1034: warning: dereferencing `void *' pointer +src/main/1255C.c:1034: request for member `unkD' in something not a structure or union +src/main/1255C.c:1035: warning: dereferencing `void *' pointer +src/main/1255C.c:1035: request for member `unk10' in something not a structure or union +src/main/1255C.c:1036: warning: dereferencing `void *' pointer +src/main/1255C.c:1036: request for member `unk12' in something not a structure or union +src/main/1255C.c:1037: warning: dereferencing `void *' pointer +src/main/1255C.c:1037: request for member `unkE' in something not a structure or union +src/main/1255C.c:1050: warning: dereferencing `void *' pointer +src/main/1255C.c:1050: request for member `unk3' in something not a structure or union +src/main/1255C.c:1051: warning: dereferencing `void *' pointer +src/main/1255C.c:1051: request for member `unk7' in something not a structure or union +src/main/1255C.c:1053: warning: dereferencing `void *' pointer +src/main/1255C.c:1053: request for member `unk8' in something not a structure or union +src/main/1255C.c:1054: warning: dereferencing `void *' pointer +src/main/1255C.c:1054: request for member `unkA' in something not a structure or union +src/main/1255C.c:1055: warning: dereferencing `void *' pointer +src/main/1255C.c:1055: request for member `unkC' in something not a structure or union +src/main/1255C.c:1056: warning: dereferencing `void *' pointer +src/main/1255C.c:1056: request for member `unkD' in something not a structure or union +src/main/1255C.c:1057: warning: dereferencing `void *' pointer +src/main/1255C.c:1057: request for member `unk10' in something not a structure or union +src/main/1255C.c:1058: warning: dereferencing `void *' pointer +src/main/1255C.c:1058: request for member `unk12' in something not a structure or union +src/main/1255C.c:1059: warning: dereferencing `void *' pointer +src/main/1255C.c:1059: request for member `unkE' in something not a structure or union +[11/85] psx cc src/main/akao.c +src/main/akao.c:161: parse error before `?' +src/main/akao.c: In function `func_8002B1F8': +src/main/akao.c:370: warning: passing arg 1 of `func_80029B78' makes pointer from integer without a cast +src/main/akao.c: In function `func_8002B2F8': +src/main/akao.c:389: warning: passing arg 1 of `func_80029B78' makes pointer from integer without a cast +src/main/akao.c: In function `func_80033A90': +src/main/akao.c:1133: `Savemap' undeclared (first use this function) +src/main/akao.c:1133: (Each undeclared identifier is reported only once +src/main/akao.c:1133: for each function it appears in.) +[12/85] psx cc src/main/psxsdk.c +src/main/psxsdk.c:31: parse error before `?' +src/main/psxsdk.c:207: warning: type mismatch with previous external decl +src/main/psxsdk.c:73: warning: previous external decl of `func_80034D2C' +src/main/psxsdk.c:207: warning: type mismatch with previous implicit declaration +src/main/psxsdk.c:73: warning: previous implicit declaration of `func_80034D2C' +src/main/psxsdk.c:207: warning: `func_80034D2C' was previously implicitly declared to return `int' +src/main/psxsdk.c: In function `func_80034D2C': +src/main/psxsdk.c:211: `jtbl_80034D14' undeclared (first use this function) +src/main/psxsdk.c:211: (Each undeclared identifier is reported only once +src/main/psxsdk.c:211: for each function it appears in.) +[13/85] psx cc src/main/18B8.c +src/main/18B8.c:174: warning: `D_80062FFC' initialized and declared `extern' +src/main/18B8.c:175: warning: `D_80063020' initialized and declared `extern' +src/main/18B8.c:176: warning: `D_80062F7C' initialized and declared `extern' +src/main/18B8.c:177: warning: `D_80062F10' initialized and declared `extern' +src/main/18B8.c:178: warning: `D_80062FBC' initialized and declared `extern' +src/main/18B8.c:179: warning: `D_80063020' initialized and declared `extern' +src/main/18B8.c:179: redefinition of `D_80063020' +src/main/18B8.c:175: `D_80063020' previously defined here +src/main/18B8.c: In function `func_80014B70': +src/main/18B8.c:686: warning: assignment from incompatible pointer type +src/main/18B8.c: At top level: +src/main/18B8.c:743: warning: type mismatch with previous external decl +src/main/18B8.c:570: warning: previous external decl of `func_80014C80' +src/main/18B8.c:743: warning: type mismatch with previous implicit declaration +src/main/18B8.c:570: warning: previous implicit declaration of `func_80014C80' +src/main/18B8.c:743: warning: `func_80014C80' was previously implicitly declared to return `int' +src/main/18B8.c: In function `func_80015668': +src/main/18B8.c:832: parse error before `?' +src/main/18B8.c:857: warning: assignment from incompatible pointer type +src/main/18B8.c:861: `var_t8' undeclared (first use this function) +src/main/18B8.c:861: (Each undeclared identifier is reported only once +src/main/18B8.c:861: for each function it appears in.) +src/main/18B8.c:863: subscripted value is neither array nor pointer +src/main/18B8.c:872: invalid operands to binary + +src/main/18B8.c:908: incompatible types in assignment +src/main/18B8.c:909: incompatible types in assignment +src/main/18B8.c:910: incompatible types in assignment +src/main/18B8.c:911: incompatible types in assignment +src/main/18B8.c: In function `func_800159B0': +src/main/18B8.c:995: warning: comparison is always 1 due to limited range of data type +src/main/18B8.c: At top level: +src/main/18B8.c:1022: warning: type mismatch with previous external decl +src/main/18B8.c:562: warning: previous external decl of `func_80015B44' +src/main/18B8.c:1022: warning: type mismatch with previous implicit declaration +src/main/18B8.c:562: warning: previous implicit declaration of `func_80015B44' +src/main/18B8.c:1022: warning: `func_80015B44' was previously implicitly declared to return `int' +src/main/18B8.c: In function `func_80015B50': +src/main/18B8.c:1031: invalid type argument of `->' +src/main/18B8.c:1031: invalid type argument of `->' +src/main/18B8.c:1032: invalid type argument of `->' +src/main/18B8.c:1032: invalid type argument of `->' +src/main/18B8.c: In function `func_80015B88': +src/main/18B8.c:1042: invalid type argument of `->' +src/main/18B8.c:1042: invalid type argument of `->' +src/main/18B8.c:1043: invalid type argument of `->' +src/main/18B8.c:1043: invalid type argument of `->' +src/main/18B8.c: In function `func_800166C0': +src/main/18B8.c:1126: warning: assignment makes pointer from integer without a cast +src/main/18B8.c:1137: warning: assignment makes pointer from integer without a cast +src/main/18B8.c:1152: warning: assignment makes pointer from integer without a cast +src/main/18B8.c:1160: warning: assignment makes pointer from integer without a cast +src/main/18B8.c: In function `func_80018220': +src/main/18B8.c:1214: invalid type argument of `->' +src/main/18B8.c:1214: invalid type argument of `->' +src/main/18B8.c:1219: invalid type argument of `->' +src/main/18B8.c:1219: invalid type argument of `->' +src/main/18B8.c:1222: invalid type argument of `->' +src/main/18B8.c:1222: invalid type argument of `->' +src/main/18B8.c:1225: invalid type argument of `->' +src/main/18B8.c:1225: invalid type argument of `->' +src/main/18B8.c: In function `func_800182FC': +src/main/18B8.c:1239: invalid type argument of `->' +src/main/18B8.c:1239: invalid type argument of `->' +src/main/18B8.c:1242: invalid type argument of `->' +src/main/18B8.c:1242: invalid type argument of `->' +src/main/18B8.c: In function `func_80019338': +src/main/18B8.c:1350: warning: assignment from incompatible pointer type +src/main/18B8.c: In function `func_80019DA0': +src/main/18B8.c:1462: invalid type argument of `->' +src/main/18B8.c:1463: invalid type argument of `->' +src/main/18B8.c:1466: invalid type argument of `->' +src/main/18B8.c: In function `func_80019E84': +src/main/18B8.c:1490: warning: assignment from incompatible pointer type +src/main/18B8.c:1503: warning: assignment from incompatible pointer type +src/main/18B8.c:1509: structure has no member named `unk1B' +src/main/18B8.c:1510: structure has no member named `unk1A' +src/main/18B8.c:1518: structure has no member named `unk1B' +src/main/18B8.c: In function `func_8001AE08': +src/main/18B8.c:1746: request for member `unk0' in something not a structure or union +src/main/18B8.c:1747: request for member `unk0' in something not a structure or union +src/main/18B8.c:1752: request for member `unk2' in something not a structure or union +src/main/18B8.c:1753: request for member `unk2' in something not a structure or union +src/main/18B8.c:1758: invalid type argument of `->' +src/main/18B8.c:1758: invalid type argument of `->' +src/main/18B8.c:1758: request for member `unk0' in something not a structure or union +src/main/18B8.c:1759: invalid type argument of `->' +src/main/18B8.c:1759: invalid type argument of `->' +src/main/18B8.c:1759: request for member `unk2' in something not a structure or union +src/main/18B8.c:1760: invalid type argument of `->' +src/main/18B8.c:1760: invalid type argument of `->' +src/main/18B8.c:1761: invalid type argument of `->' +src/main/18B8.c:1761: invalid type argument of `->' +src/main/18B8.c:1762: invalid type argument of `->' +src/main/18B8.c:1762: invalid type argument of `->' +src/main/18B8.c: In function `func_8001BC18': +src/main/18B8.c:1859: invalid type argument of `->' +src/main/18B8.c:1860: invalid type argument of `->' +src/main/18B8.c:1861: invalid type argument of `->' +src/main/18B8.c:1862: invalid type argument of `->' +src/main/18B8.c: At top level: +src/main/18B8.c:1868: warning: type mismatch with previous external decl +src/main/18B8.c:1620: warning: previous external decl of `func_8001BCE8' +src/main/18B8.c:1868: warning: type mismatch with previous implicit declaration +src/main/18B8.c:1620: warning: previous implicit declaration of `func_8001BCE8' +src/main/18B8.c:1868: warning: `func_8001BCE8' was previously implicitly declared to return `int' +src/main/18B8.c: In function `func_8001BD50': +src/main/18B8.c:1896: invalid type argument of `->' +src/main/18B8.c:1897: invalid type argument of `->' +src/main/18B8.c:1898: invalid type argument of `->' +src/main/18B8.c: In function `func_8001C980': +src/main/18B8.c:1963: request for member `unk0' in something not a structure or union +src/main/18B8.c:1965: request for member `unk0' in something not a structure or union +src/main/18B8.c:1971: request for member `unk2' in something not a structure or union +src/main/18B8.c:1986: request for member `unk2' in something not a structure or union +src/main/18B8.c:1988: request for member `unk0' in something not a structure or union +src/main/18B8.c:1988: request for member `unk0' in something not a structure or union +src/main/18B8.c:1988: request for member `unk2' in something not a structure or union +src/main/18B8.c:1988: request for member `unk0' in something not a structure or union +src/main/18B8.c:1989: request for member `unk0' in something not a structure or union +src/main/18B8.c:1989: request for member `unk2' in something not a structure or union +src/main/18B8.c:1994: request for member `unk2' in something not a structure or union +src/main/18B8.c:1994: request for member `unk0' in something not a structure or union +src/main/18B8.c:2007: request for member `unk2' in something not a structure or union +src/main/18B8.c:2009: request for member `unk2' in something not a structure or union +src/main/18B8.c:2009: request for member `unk2' in something not a structure or union +src/main/18B8.c:2009: request for member `unk0' in something not a structure or union +src/main/18B8.c:2011: request for member `unk2' in something not a structure or union +src/main/18B8.c:2011: request for member `unk0' in something not a structure or union +src/main/18B8.c:2012: request for member `unk2' in something not a structure or union +src/main/18B8.c:2012: request for member `unk2' in something not a structure or union +src/main/18B8.c:2012: request for member `unk0' in something not a structure or union +src/main/18B8.c: In function `func_8001FBAC': +src/main/18B8.c:2335: subscripted value is neither array nor pointer +src/main/18B8.c:2341: invalid operands to binary * +src/main/18B8.c:2348: invalid operands to binary * +src/main/18B8.c: In function `func_800211C4': +src/main/18B8.c:2458: request for member `unk4' in something not a structure or union +src/main/18B8.c:2458: warning: passing arg 3 of `func_80033E34' from incompatible pointer type +[14/85] psx ld build/us/main.ld +FAILED: build/us/main.elf +mipsel-linux-gnu-ld -nostdlib --no-check-sections -Map build/us/main.map -T build/us/main.ld -T build/us/undefined_syms.main.txt -T config/sym_extern.us.txt -T config/sym_ovl_export.us.txt -o build/us/main.elf build/us/asm/us/main/header.s.o build/us/asm/us/main/data/800.rodata.s.o build/us/asm/us/main/data/AB4.rodata.s.o build/us/asm/us/main/data/B94.rodata.s.o build/us/src/main/18B8.c.o build/us/src/main/1255C.c.o build/us/src/main/akao.c.o build/us/src/main/psxsdk.c.o build/us/asm/us/main/data/394E0.data.s.o build/us/src/main/ovl.c.o build/us/asm/us/main/data/39C50.data.s.o build/us/asm/us/main/data/536C4.bss.s.o +mipsel-linux-gnu-ld: build/us/asm/us/main/data/536C4.bss.s.o: in function `D_80062F10': +(.bss+0x4c): multiple definition of `D_80062F10'; build/us/src/main/18B8.c.o:src/main/18B8.c:(.sdata+0x178): first defined here +mipsel-linux-gnu-ld: build/us/asm/us/main/data/536C4.bss.s.o: in function `D_80062F7C': +(.bss+0xb8): multiple definition of `D_80062F7C'; build/us/src/main/18B8.c.o:src/main/18B8.c:(.sdata+0x174): first defined here +mipsel-linux-gnu-ld: build/us/asm/us/main/data/536C4.bss.s.o: in function `D_80062FBC': +(.bss+0xf8): multiple definition of `D_80062FBC'; build/us/src/main/18B8.c.o:src/main/18B8.c:(.sdata+0x17c): first defined here +mipsel-linux-gnu-ld: build/us/asm/us/main/data/536C4.bss.s.o: in function `D_80062FFC': +(.bss+0x138): multiple definition of `D_80062FFC'; build/us/src/main/18B8.c.o:src/main/18B8.c:(.sdata+0x170): first defined here +mipsel-linux-gnu-ld: build/us/asm/us/main/data/536C4.bss.s.o: in function `D_80063020': +(.bss+0x15c): multiple definition of `D_80063020'; build/us/src/main/18B8.c.o:src/main/18B8.c:(.sdata+0x171): first defined here +mipsel-linux-gnu-ld: warning: build/us/main.elf has a LOAD segment with RWX permissions +ninja: build stopped: subcommand failed. +Usage: + build [version] [flags] + +Flags: + -h, --help help for build + +exit status 1 +exit status 1 +make: *** [Makefile:43: rebuild] Error 1 +calvin@Begemot:~/GitHub/ff7-decomp-armstrca$ make build +wget -O bin/cc1-psx-26.gz https://github.com/Xeeynamo/ff7-decomp/releases/download/init/cc1-psx-26.gz +--2026-04-22 19:17:22-- https://github.com/Xeeynamo/ff7-decomp/releases/download/init/cc1-psx-26.gz +Resolving github.com (github.com)... 140.82.114.4 +Connecting to github.com (github.com)|140.82.114.4|:443... connected. +HTTP request sent, awaiting response... 302 Found +Location: https://release-assets.githubusercontent.com/github-production-release-asset/1060063534/420d0295-4a7d-4681-9a25-e9da0b499bf4?sp=r&sv=2018-11-09&sr=b&spr=https&se=2026-04-23T01%3A15%3A23Z&rscd=attachment%3B+filename%3Dcc1-psx-26.gz&rsct=application%2Foctet-stream&skoid=96c2d410-5711-43a1-aedd-ab1947aa7ab0&sktid=398a6654-997b-47e9-b12b-9515b896b4de&skt=2026-04-23T00%3A14%3A51Z&ske=2026-04-23T01%3A15%3A23Z&sks=b&skv=2018-11-09&sig=yA303xYATCN%2FH4GHiv3E6NaE%2FsMVdCbaSwdXCAZr5Lw%3D&jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmVsZWFzZS1hc3NldHMuZ2l0aHVidXNlcmNvbnRlbnQuY29tIiwia2V5Ijoia2V5MSIsImV4cCI6MTc3NjkwMzc0MiwibmJmIjoxNzc2OTAzNDQyLCJwYXRoIjoicmVsZWFzZWFzc2V0cHJvZHVjdGlvbi5ibG9iLmNvcmUud2luZG93cy5uZXQifQ.MttehX27NcgF2DYQp9bkQQTb7BhqXaDj5Wc082EQlXI&response-content-disposition=attachment%3B%20filename%3Dcc1-psx-26.gz&response-content-type=application%2Foctet-stream [following] +--2026-04-22 19:17:22-- https://release-assets.githubusercontent.com/github-production-release-asset/1060063534/420d0295-4a7d-4681-9a25-e9da0b499bf4?sp=r&sv=2018-11-09&sr=b&spr=https&se=2026-04-23T01%3A15%3A23Z&rscd=attachment%3B+filename%3Dcc1-psx-26.gz&rsct=application%2Foctet-stream&skoid=96c2d410-5711-43a1-aedd-ab1947aa7ab0&sktid=398a6654-997b-47e9-b12b-9515b896b4de&skt=2026-04-23T00%3A14%3A51Z&ske=2026-04-23T01%3A15%3A23Z&sks=b&skv=2018-11-09&sig=yA303xYATCN%2FH4GHiv3E6NaE%2FsMVdCbaSwdXCAZr5Lw%3D&jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmVsZWFzZS1hc3NldHMuZ2l0aHVidXNlcmNvbnRlbnQuY29tIiwia2V5Ijoia2V5MSIsImV4cCI6MTc3NjkwMzc0MiwibmJmIjoxNzc2OTAzNDQyLCJwYXRoIjoicmVsZWFzZWFzc2V0cHJvZHVjdGlvbi5ibG9iLmNvcmUud2luZG93cy5uZXQifQ.MttehX27NcgF2DYQp9bkQQTb7BhqXaDj5Wc082EQlXI&response-content-disposition=attachment%3B%20filename%3Dcc1-psx-26.gz&response-content-type=application%2Foctet-stream +Resolving release-assets.githubusercontent.com (release-assets.githubusercontent.com)... 185.199.108.133, 185.199.111.133, 185.199.109.133, ... +Connecting to release-assets.githubusercontent.com (release-assets.githubusercontent.com)|185.199.108.133|:443... connected. +HTTP request sent, awaiting response... 200 OK +Length: 1016568 (993K) [application/octet-stream] +Saving to: ‘bin/cc1-psx-26.gz’ + +bin/cc1-psx-26.gz 100%[=============================================>] 992.74K --.-KB/s in 0.02s + +2026-04-22 19:17:22 (39.2 MB/s) - ‘bin/cc1-psx-26.gz’ saved [1016568/1016568] + +sha256sum --check bin/cc1-psx-26.gz.sha256 +bin/cc1-psx-26.gz: OK +gzip -kcd bin/cc1-psx-26.gz > bin/cc1-psx-26 +touch bin/cc1-psx-26 +chmod +x bin/cc1-psx-26 +wget -O bin/cc1-psx-272.gz https://github.com/Xeeynamo/ff7-decomp/releases/download/init/cc1-psx-272.gz +--2026-04-22 19:17:22-- https://github.com/Xeeynamo/ff7-decomp/releases/download/init/cc1-psx-272.gz +Resolving github.com (github.com)... 140.82.114.4 +Connecting to github.com (github.com)|140.82.114.4|:443... connected. +HTTP request sent, awaiting response... 302 Found +Location: https://release-assets.githubusercontent.com/github-production-release-asset/1060063534/00f81ce4-4bc8-4bd0-ae45-19242fe2d056?sp=r&sv=2018-11-09&sr=b&spr=https&se=2026-04-23T01%3A13%3A34Z&rscd=attachment%3B+filename%3Dcc1-psx-272.gz&rsct=application%2Foctet-stream&skoid=96c2d410-5711-43a1-aedd-ab1947aa7ab0&sktid=398a6654-997b-47e9-b12b-9515b896b4de&skt=2026-04-23T00%3A12%3A42Z&ske=2026-04-23T01%3A13%3A34Z&sks=b&skv=2018-11-09&sig=1K4g0syjf6V6%2BSKLeLCW%2F%2BJ7tBuGAkb9%2BsmJZ1dSnso%3D&jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmVsZWFzZS1hc3NldHMuZ2l0aHVidXNlcmNvbnRlbnQuY29tIiwia2V5Ijoia2V5MSIsImV4cCI6MTc3NjkwMzc0MiwibmJmIjoxNzc2OTAzNDQyLCJwYXRoIjoicmVsZWFzZWFzc2V0cHJvZHVjdGlvbi5ibG9iLmNvcmUud2luZG93cy5uZXQifQ.MttehX27NcgF2DYQp9bkQQTb7BhqXaDj5Wc082EQlXI&response-content-disposition=attachment%3B%20filename%3Dcc1-psx-272.gz&response-content-type=application%2Foctet-stream [following] +--2026-04-22 19:17:22-- https://release-assets.githubusercontent.com/github-production-release-asset/1060063534/00f81ce4-4bc8-4bd0-ae45-19242fe2d056?sp=r&sv=2018-11-09&sr=b&spr=https&se=2026-04-23T01%3A13%3A34Z&rscd=attachment%3B+filename%3Dcc1-psx-272.gz&rsct=application%2Foctet-stream&skoid=96c2d410-5711-43a1-aedd-ab1947aa7ab0&sktid=398a6654-997b-47e9-b12b-9515b896b4de&skt=2026-04-23T00%3A12%3A42Z&ske=2026-04-23T01%3A13%3A34Z&sks=b&skv=2018-11-09&sig=1K4g0syjf6V6%2BSKLeLCW%2F%2BJ7tBuGAkb9%2BsmJZ1dSnso%3D&jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmVsZWFzZS1hc3NldHMuZ2l0aHVidXNlcmNvbnRlbnQuY29tIiwia2V5Ijoia2V5MSIsImV4cCI6MTc3NjkwMzc0MiwibmJmIjoxNzc2OTAzNDQyLCJwYXRoIjoicmVsZWFzZWFzc2V0cHJvZHVjdGlvbi5ibG9iLmNvcmUud2luZG93cy5uZXQifQ.MttehX27NcgF2DYQp9bkQQTb7BhqXaDj5Wc082EQlXI&response-content-disposition=attachment%3B%20filename%3Dcc1-psx-272.gz&response-content-type=application%2Foctet-stream +Resolving release-assets.githubusercontent.com (release-assets.githubusercontent.com)... 185.199.108.133, 185.199.111.133, 185.199.109.133, ... +Connecting to release-assets.githubusercontent.com (release-assets.githubusercontent.com)|185.199.108.133|:443... connected. +HTTP request sent, awaiting response... 200 OK +Length: 1039565 (1015K) [application/octet-stream] +Saving to: ‘bin/cc1-psx-272.gz’ + +bin/cc1-psx-272.gz 100%[=============================================>] 1015K --.-KB/s in 0.02s + +2026-04-22 19:17:22 (42.1 MB/s) - ‘bin/cc1-psx-272.gz’ saved [1039565/1039565] + +sha256sum --check bin/cc1-psx-272.gz.sha256 +bin/cc1-psx-272.gz: OK +gzip -kcd bin/cc1-psx-272.gz > bin/cc1-psx-272 +touch bin/cc1-psx-272 +chmod +x bin/cc1-psx-272 +[1/72] psx ld build/us/main.ld +FAILED: build/us/main.elf +mipsel-linux-gnu-ld -nostdlib --no-check-sections -Map build/us/main.map -T build/us/main.ld -T build/us/undefined_syms.main.txt -T config/sym_extern.us.txt -T config/sym_ovl_export.us.txt -o build/us/main.elf build/us/asm/us/main/header.s.o build/us/asm/us/main/data/800.rodata.s.o build/us/asm/us/main/data/AB4.rodata.s.o build/us/asm/us/main/data/B94.rodata.s.o build/us/src/main/18B8.c.o build/us/src/main/1255C.c.o build/us/src/main/akao.c.o build/us/src/main/psxsdk.c.o build/us/asm/us/main/data/394E0.data.s.o build/us/src/main/ovl.c.o build/us/asm/us/main/data/39C50.data.s.o build/us/asm/us/main/data/536C4.bss.s.o +mipsel-linux-gnu-ld: build/us/asm/us/main/data/536C4.bss.s.o: in function `D_80062F10': +(.bss+0x4c): multiple definition of `D_80062F10'; build/us/src/main/18B8.c.o:src/main/18B8.c:(.sdata+0x178): first defined here +mipsel-linux-gnu-ld: build/us/asm/us/main/data/536C4.bss.s.o: in function `D_80062F7C': +(.bss+0xb8): multiple definition of `D_80062F7C'; build/us/src/main/18B8.c.o:src/main/18B8.c:(.sdata+0x174): first defined here +mipsel-linux-gnu-ld: build/us/asm/us/main/data/536C4.bss.s.o: in function `D_80062FBC': +(.bss+0xf8): multiple definition of `D_80062FBC'; build/us/src/main/18B8.c.o:src/main/18B8.c:(.sdata+0x17c): first defined here +mipsel-linux-gnu-ld: build/us/asm/us/main/data/536C4.bss.s.o: in function `D_80062FFC': +(.bss+0x138): multiple definition of `D_80062FFC'; build/us/src/main/18B8.c.o:src/main/18B8.c:(.sdata+0x170): first defined here +mipsel-linux-gnu-ld: build/us/asm/us/main/data/536C4.bss.s.o: in function `D_80063020': +(.bss+0x15c): multiple definition of `D_80063020'; build/us/src/main/18B8.c.o:src/main/18B8.c:(.sdata+0x171): first defined here +mipsel-linux-gnu-ld: warning: build/us/main.elf has a LOAD segment with RWX permissions +ninja: build stopped: subcommand failed. +Usage: + build [version] [flags] + +Flags: + -h, --help help for build + +exit status 1 +exit status 1 +make: *** [Makefile:14: build] Error 1 +rm bin/cc1-psx-26.gz bin/cc1-psx-272.gz \ No newline at end of file diff --git a/automation/missing_types_reports.json b/automation/missing_types_reports.json new file mode 100644 index 0000000..d0f7b5e --- /dev/null +++ b/automation/missing_types_reports.json @@ -0,0 +1,6181 @@ +[ + { + "function_name": "func_800D4E24", + "file": "src/field/field.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80074EB0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB0" + }, + { + "type": "extern_variable", + "name": "D_80074EB4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB4" + }, + { + "type": "extern_variable", + "name": "D_80074EB8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB8" + }, + { + "type": "extern_variable", + "name": "D_800E0638", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E0638" + }, + { + "type": "extern_variable", + "name": "D_800E42D8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42D8" + }, + { + "type": "extern_variable", + "name": "D_800E42DA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42DA" + }, + { + "type": "extern_variable", + "name": "D_800E42DC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42DC" + }, + { + "type": "extern_variable", + "name": "D_800E42E0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E0" + }, + { + "type": "extern_variable", + "name": "D_800E42E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E4" + }, + { + "type": "extern_variable", + "name": "D_800E42E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E8" + }, + { + "type": "extern_variable", + "name": "D_800E42EA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42EA" + }, + { + "type": "extern_variable", + "name": "D_800E42EE", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42EE" + }, + { + "type": "extern_variable", + "name": "D_800E48E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E48E8" + }, + { + "type": "unknown_pointer", + "name": "var_t1", + "suggestion": "m2c could not determine type of pointer var_t1" + }, + { + "type": "unknown_pointer", + "name": "var_t1", + "suggestion": "m2c could not determine type of pointer var_t1" + } + ], + "timestamp": "2026-04-22T19:48:54.738761" + }, + { + "function_name": "func_800AB2B4", + "file": "src/field/field.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80074EB0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB0" + }, + { + "type": "extern_variable", + "name": "D_80074EB4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB4" + }, + { + "type": "extern_variable", + "name": "D_80074EB8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB8" + }, + { + "type": "extern_variable", + "name": "D_800E0638", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E0638" + }, + { + "type": "extern_variable", + "name": "D_800E42D8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42D8" + }, + { + "type": "extern_variable", + "name": "D_800E42DA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42DA" + }, + { + "type": "extern_variable", + "name": "D_800E42DC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42DC" + }, + { + "type": "extern_variable", + "name": "D_800E42E0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E0" + }, + { + "type": "extern_variable", + "name": "D_800E42E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E4" + }, + { + "type": "extern_variable", + "name": "D_800E42E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E8" + }, + { + "type": "extern_variable", + "name": "D_800E42EA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42EA" + }, + { + "type": "extern_variable", + "name": "D_800E42EE", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42EE" + }, + { + "type": "extern_variable", + "name": "D_800E48E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E48E8" + }, + { + "type": "unknown_pointer", + "name": "var_t1", + "suggestion": "m2c could not determine type of pointer var_t1" + }, + { + "type": "unknown_pointer", + "name": "var_t1", + "suggestion": "m2c could not determine type of pointer var_t1" + } + ], + "timestamp": "2026-04-22T19:48:55.388138" + }, + { + "function_name": "func_800A310C", + "file": "src/ending/ending.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_function", + "name": "InitGeom", + "return_type": "unknown", + "parameters": "", + "suggestion": "Define proper signature for InitGeom in header" + }, + { + "type": "extern_function", + "name": "PadInit", + "return_type": "unknown", + "parameters": "?", + "suggestion": "Define proper signature for PadInit in header" + }, + { + "type": "extern_function", + "name": "ResetCallback", + "return_type": "unknown", + "parameters": "", + "suggestion": "Define proper signature for ResetCallback in header" + }, + { + "type": "extern_function", + "name": "ResetGraph", + "return_type": "unknown", + "parameters": "?", + "suggestion": "Define proper signature for ResetGraph in header" + }, + { + "type": "extern_function", + "name": "StopCallback", + "return_type": "unknown", + "parameters": "", + "suggestion": "Define proper signature for StopCallback in header" + }, + { + "type": "extern_variable", + "name": "func_80033B70", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_80033B70" + }, + { + "type": "extern_variable", + "name": "func_80036298", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_80036298" + } + ], + "timestamp": "2026-04-22T19:49:00.475376" + }, + { + "function_name": "func_800DA1D4", + "file": "src/field/field.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80074EB0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB0" + }, + { + "type": "extern_variable", + "name": "D_80074EB4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB4" + }, + { + "type": "extern_variable", + "name": "D_80074EB8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB8" + }, + { + "type": "extern_variable", + "name": "D_800E0638", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E0638" + }, + { + "type": "extern_variable", + "name": "D_800E42D8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42D8" + }, + { + "type": "extern_variable", + "name": "D_800E42DA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42DA" + }, + { + "type": "extern_variable", + "name": "D_800E42DC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42DC" + }, + { + "type": "extern_variable", + "name": "D_800E42E0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E0" + }, + { + "type": "extern_variable", + "name": "D_800E42E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E4" + }, + { + "type": "extern_variable", + "name": "D_800E42E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E8" + }, + { + "type": "extern_variable", + "name": "D_800E42EA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42EA" + }, + { + "type": "extern_variable", + "name": "D_800E42EE", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42EE" + }, + { + "type": "extern_variable", + "name": "D_800E48E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E48E8" + }, + { + "type": "unknown_pointer", + "name": "var_t1", + "suggestion": "m2c could not determine type of pointer var_t1" + }, + { + "type": "unknown_pointer", + "name": "var_t1", + "suggestion": "m2c could not determine type of pointer var_t1" + } + ], + "timestamp": "2026-04-22T19:49:00.685281" + }, + { + "function_name": "func_80025A44", + "file": "src/main/1255C.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_function", + "name": "func_80048540", + "return_type": "s32", + "parameters": "?", + "suggestion": "Define proper signature for func_80048540 in header" + }, + { + "type": "extern_function", + "name": "VSync", + "return_type": "unknown", + "parameters": "?", + "suggestion": "Define proper signature for VSync in header" + }, + { + "type": "extern_variable", + "name": "D_80069800", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069800" + }, + { + "type": "extern_variable", + "name": "D_80071E4D", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80071E4D" + }, + { + "type": "extern_variable", + "name": "D_800738BC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800738BC" + }, + { + "type": "extern_variable", + "name": "D_800491D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800491D0" + }, + { + "type": "extern_variable", + "name": "func_80017678", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_80017678" + }, + { + "type": "extern_variable", + "name": "func_8001786C", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_8001786C" + }, + { + "type": "extern_variable", + "name": "func_80020058", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_80020058" + }, + { + "type": "extern_variable", + "name": "D_8009D85C", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D85C" + }, + { + "type": "extern_variable", + "name": "D_8009D85E", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D85E" + } + ], + "timestamp": "2026-04-22T19:49:00.750255" + }, + { + "function_name": "func_800E58CC", + "file": "src/battle/battle3.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_800FB064", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800FB064" + }, + { + "type": "extern_variable", + "name": "D_800FF060", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800FF060" + }, + { + "type": "extern_variable", + "name": "D_800FF064", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800FF064" + }, + { + "type": "extern_variable", + "name": "D_800FF068", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800FF068" + }, + { + "type": "extern_variable", + "name": "D_800FF06C", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800FF06C" + }, + { + "type": "extern_variable", + "name": "D_800FF070", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800FF070" + }, + { + "type": "extern_variable", + "name": "D_800FF074", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800FF074" + }, + { + "type": "extern_variable", + "name": "D_800FF094", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800FF094" + }, + { + "type": "extern_variable", + "name": "D_800FF098", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800FF098" + }, + { + "type": "extern_variable", + "name": "D_800FF0D8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800FF0D8" + }, + { + "type": "extern_variable", + "name": "D_800FF0DC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800FF0DC" + }, + { + "type": "extern_variable", + "name": "D_800FF0E0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800FF0E0" + }, + { + "type": "extern_variable", + "name": "D_80103154", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80103154" + }, + { + "type": "extern_variable", + "name": "D_80103158", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80103158" + }, + { + "type": "extern_variable", + "name": "D_80103160", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80103160" + }, + { + "type": "extern_variable", + "name": "D_80103188", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80103188" + }, + { + "type": "extern_variable", + "name": "D_801031CC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_801031CC" + }, + { + "type": "extern_variable", + "name": "D_801031D4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_801031D4" + }, + { + "type": "extern_variable", + "name": "D_800492FC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800492FC" + }, + { + "type": "extern_variable", + "name": "D_800F55D8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F55D8" + }, + { + "type": "extern_variable", + "name": "D_800F1E58", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F1E58" + }, + { + "type": "extern_variable", + "name": "D_800F1E5A", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F1E5A" + }, + { + "type": "extern_variable", + "name": "D_800F1E5C", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F1E5C" + }, + { + "type": "extern_variable", + "name": "D_800F1E5E", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F1E5E" + }, + { + "type": "extern_variable", + "name": "D_800F1E60", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F1E60" + }, + { + "type": "extern_variable", + "name": "D_800F1E62", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F1E62" + }, + { + "type": "extern_variable", + "name": "D_800F33B0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F33B0" + }, + { + "type": "extern_variable", + "name": "D_80163778", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80163778" + }, + { + "type": "extern_variable", + "name": "D_80163B70", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80163B70" + }, + { + "type": "unknown_pointer", + "name": "var_v0", + "suggestion": "m2c could not determine type of pointer var_v0" + }, + { + "type": "unknown_pointer", + "name": "var_v0_2", + "suggestion": "m2c could not determine type of pointer var_v0_2" + }, + { + "type": "unknown_pointer", + "name": "var_v0_3", + "suggestion": "m2c could not determine type of pointer var_v0_3" + }, + { + "type": "unknown_pointer", + "name": "var_v0_4", + "suggestion": "m2c could not determine type of pointer var_v0_4" + }, + { + "type": "unknown_pointer", + "name": "var_v0_5", + "suggestion": "m2c could not determine type of pointer var_v0_5" + }, + { + "type": "unknown_pointer", + "name": "var_v0_6", + "suggestion": "m2c could not determine type of pointer var_v0_6" + }, + { + "type": "unknown_pointer", + "name": "var_v0", + "suggestion": "m2c could not determine type of pointer var_v0" + } + ], + "timestamp": "2026-04-22T19:49:00.856699" + }, + { + "function_name": "func_800DA28C", + "file": "src/field/field.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80074EB0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB0" + }, + { + "type": "extern_variable", + "name": "D_80074EB4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB4" + }, + { + "type": "extern_variable", + "name": "D_80074EB8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB8" + }, + { + "type": "extern_variable", + "name": "D_800E0638", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E0638" + }, + { + "type": "extern_variable", + "name": "D_800E42D8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42D8" + }, + { + "type": "extern_variable", + "name": "D_800E42DA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42DA" + }, + { + "type": "extern_variable", + "name": "D_800E42DC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42DC" + }, + { + "type": "extern_variable", + "name": "D_800E42E0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E0" + }, + { + "type": "extern_variable", + "name": "D_800E42E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E4" + }, + { + "type": "extern_variable", + "name": "D_800E42E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E8" + }, + { + "type": "extern_variable", + "name": "D_800E42EA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42EA" + }, + { + "type": "extern_variable", + "name": "D_800E42EE", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42EE" + }, + { + "type": "extern_variable", + "name": "D_800E48E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E48E8" + }, + { + "type": "unknown_pointer", + "name": "var_t1", + "suggestion": "m2c could not determine type of pointer var_t1" + }, + { + "type": "unknown_pointer", + "name": "var_t1", + "suggestion": "m2c could not determine type of pointer var_t1" + } + ], + "timestamp": "2026-04-22T19:49:01.314431" + }, + { + "function_name": "func_800AB9C8", + "file": "src/field/field.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80074EB0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB0" + }, + { + "type": "extern_variable", + "name": "D_80074EB4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB4" + }, + { + "type": "extern_variable", + "name": "D_80074EB8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB8" + }, + { + "type": "extern_variable", + "name": "D_800E0638", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E0638" + }, + { + "type": "extern_variable", + "name": "D_800E42D8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42D8" + }, + { + "type": "extern_variable", + "name": "D_800E42DA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42DA" + }, + { + "type": "extern_variable", + "name": "D_800E42DC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42DC" + }, + { + "type": "extern_variable", + "name": "D_800E42E0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E0" + }, + { + "type": "extern_variable", + "name": "D_800E42E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E4" + }, + { + "type": "extern_variable", + "name": "D_800E42E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E8" + }, + { + "type": "extern_variable", + "name": "D_800E42EA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42EA" + }, + { + "type": "extern_variable", + "name": "D_800E42EE", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42EE" + }, + { + "type": "extern_variable", + "name": "D_800E48E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E48E8" + }, + { + "type": "unknown_pointer", + "name": "var_t1", + "suggestion": "m2c could not determine type of pointer var_t1" + }, + { + "type": "unknown_pointer", + "name": "var_t1", + "suggestion": "m2c could not determine type of pointer var_t1" + } + ], + "timestamp": "2026-04-22T19:49:01.885812" + }, + { + "function_name": "func_800DA2CC", + "file": "src/field/field.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80074EB0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB0" + }, + { + "type": "extern_variable", + "name": "D_80074EB4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB4" + }, + { + "type": "extern_variable", + "name": "D_80074EB8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB8" + }, + { + "type": "extern_variable", + "name": "D_800E0638", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E0638" + }, + { + "type": "extern_variable", + "name": "D_800E42D8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42D8" + }, + { + "type": "extern_variable", + "name": "D_800E42DA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42DA" + }, + { + "type": "extern_variable", + "name": "D_800E42DC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42DC" + }, + { + "type": "extern_variable", + "name": "D_800E42E0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E0" + }, + { + "type": "extern_variable", + "name": "D_800E42E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E4" + }, + { + "type": "extern_variable", + "name": "D_800E42E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E8" + }, + { + "type": "extern_variable", + "name": "D_800E42EA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42EA" + }, + { + "type": "extern_variable", + "name": "D_800E42EE", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42EE" + }, + { + "type": "extern_variable", + "name": "D_800E48E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E48E8" + }, + { + "type": "unknown_pointer", + "name": "var_t1", + "suggestion": "m2c could not determine type of pointer var_t1" + }, + { + "type": "unknown_pointer", + "name": "var_t1", + "suggestion": "m2c could not determine type of pointer var_t1" + } + ], + "timestamp": "2026-04-22T19:49:02.455098" + }, + { + "function_name": "func_800D4BFC", + "file": "src/field/field.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80074EB0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB0" + }, + { + "type": "extern_variable", + "name": "D_80074EB4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB4" + }, + { + "type": "extern_variable", + "name": "D_80074EB8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB8" + }, + { + "type": "extern_variable", + "name": "D_800E0638", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E0638" + }, + { + "type": "extern_variable", + "name": "D_800E42D8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42D8" + }, + { + "type": "extern_variable", + "name": "D_800E42DA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42DA" + }, + { + "type": "extern_variable", + "name": "D_800E42DC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42DC" + }, + { + "type": "extern_variable", + "name": "D_800E42E0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E0" + }, + { + "type": "extern_variable", + "name": "D_800E42E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E4" + }, + { + "type": "extern_variable", + "name": "D_800E42E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E8" + }, + { + "type": "extern_variable", + "name": "D_800E42EA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42EA" + }, + { + "type": "extern_variable", + "name": "D_800E42EE", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42EE" + }, + { + "type": "extern_variable", + "name": "D_800E48E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E48E8" + }, + { + "type": "unknown_pointer", + "name": "var_t1", + "suggestion": "m2c could not determine type of pointer var_t1" + }, + { + "type": "unknown_pointer", + "name": "var_t1", + "suggestion": "m2c could not determine type of pointer var_t1" + } + ], + "timestamp": "2026-04-22T19:49:03.013247" + }, + { + "function_name": "func_800134F4", + "file": "src/main/18B8.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80075D24", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D24" + }, + { + "type": "extern_variable", + "name": "D_80075D28", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D28" + }, + { + "type": "extern_variable", + "name": "D_80075DE8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075DE8" + }, + { + "type": "extern_variable", + "name": "D_8009D7E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E4" + }, + { + "type": "extern_variable", + "name": "D_8009D7E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E8" + }, + { + "type": "extern_variable", + "name": "D_8009D7EC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7EC" + }, + { + "type": "extern_variable", + "name": "D_8009D7ED", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7ED" + }, + { + "type": "extern_variable", + "name": "D_80069508", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069508" + }, + { + "type": "extern_variable", + "name": "D_800708C8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708C8" + }, + { + "type": "extern_variable", + "name": "D_800708D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708D0" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + } + ], + "timestamp": "2026-04-22T19:49:04.245127" + }, + { + "function_name": "func_800DA214", + "file": "src/field/field.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80074EB0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB0" + }, + { + "type": "extern_variable", + "name": "D_80074EB4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB4" + }, + { + "type": "extern_variable", + "name": "D_80074EB8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB8" + }, + { + "type": "extern_variable", + "name": "D_800E0638", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E0638" + }, + { + "type": "extern_variable", + "name": "D_800E42D8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42D8" + }, + { + "type": "extern_variable", + "name": "D_800E42DA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42DA" + }, + { + "type": "extern_variable", + "name": "D_800E42DC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42DC" + }, + { + "type": "extern_variable", + "name": "D_800E42E0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E0" + }, + { + "type": "extern_variable", + "name": "D_800E42E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E4" + }, + { + "type": "extern_variable", + "name": "D_800E42E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E8" + }, + { + "type": "extern_variable", + "name": "D_800E42EA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42EA" + }, + { + "type": "extern_variable", + "name": "D_800E42EE", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42EE" + }, + { + "type": "extern_variable", + "name": "D_800E48E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E48E8" + }, + { + "type": "unknown_pointer", + "name": "var_t1", + "suggestion": "m2c could not determine type of pointer var_t1" + }, + { + "type": "unknown_pointer", + "name": "var_t1", + "suggestion": "m2c could not determine type of pointer var_t1" + } + ], + "timestamp": "2026-04-22T19:49:04.261830" + }, + { + "function_name": "func_80025040", + "file": "src/main/1255C.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_function", + "name": "func_80048540", + "return_type": "s32", + "parameters": "?", + "suggestion": "Define proper signature for func_80048540 in header" + }, + { + "type": "extern_function", + "name": "VSync", + "return_type": "unknown", + "parameters": "?", + "suggestion": "Define proper signature for VSync in header" + }, + { + "type": "extern_variable", + "name": "D_80069800", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069800" + }, + { + "type": "extern_variable", + "name": "D_80071E4D", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80071E4D" + }, + { + "type": "extern_variable", + "name": "D_800738BC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800738BC" + }, + { + "type": "extern_variable", + "name": "D_800491D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800491D0" + }, + { + "type": "extern_variable", + "name": "func_80017678", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_80017678" + }, + { + "type": "extern_variable", + "name": "func_8001786C", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_8001786C" + }, + { + "type": "extern_variable", + "name": "func_80020058", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_80020058" + }, + { + "type": "extern_variable", + "name": "D_8009D85C", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D85C" + }, + { + "type": "extern_variable", + "name": "D_8009D85E", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D85E" + } + ], + "timestamp": "2026-04-22T19:49:04.271785" + }, + { + "function_name": "func_800D4FF0", + "file": "src/battle/battle2.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_800F4CEC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F4CEC" + }, + { + "type": "extern_variable", + "name": "D_800F4D2C", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F4D2C" + }, + { + "type": "extern_variable", + "name": "func_800D6998", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_800D6998" + }, + { + "type": "extern_variable", + "name": "func_800D6ACC", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_800D6ACC" + }, + { + "type": "extern_variable", + "name": "func_800D6C20", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_800D6C20" + }, + { + "type": "unaligned_cast", + "cast_type": "s32", + "suggestion": "Unaligned access to s32 - may need struct packing or alignment fix" + } + ], + "timestamp": "2026-04-22T19:49:04.680354" + }, + { + "function_name": "func_800D4B28", + "file": "src/field/field.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80074EB0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB0" + }, + { + "type": "extern_variable", + "name": "D_80074EB4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB4" + }, + { + "type": "extern_variable", + "name": "D_80074EB8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB8" + }, + { + "type": "extern_variable", + "name": "D_800E0638", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E0638" + }, + { + "type": "extern_variable", + "name": "D_800E42D8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42D8" + }, + { + "type": "extern_variable", + "name": "D_800E42DA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42DA" + }, + { + "type": "extern_variable", + "name": "D_800E42DC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42DC" + }, + { + "type": "extern_variable", + "name": "D_800E42E0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E0" + }, + { + "type": "extern_variable", + "name": "D_800E42E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E4" + }, + { + "type": "extern_variable", + "name": "D_800E42E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E8" + }, + { + "type": "extern_variable", + "name": "D_800E42EA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42EA" + }, + { + "type": "extern_variable", + "name": "D_800E42EE", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42EE" + }, + { + "type": "extern_variable", + "name": "D_800E48E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E48E8" + }, + { + "type": "unknown_pointer", + "name": "var_t1", + "suggestion": "m2c could not determine type of pointer var_t1" + }, + { + "type": "unknown_pointer", + "name": "var_t1", + "suggestion": "m2c could not determine type of pointer var_t1" + } + ], + "timestamp": "2026-04-22T19:49:05.208506" + }, + { + "function_name": "func_80025380", + "file": "src/main/1255C.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_function", + "name": "func_80048540", + "return_type": "s32", + "parameters": "?", + "suggestion": "Define proper signature for func_80048540 in header" + }, + { + "type": "extern_function", + "name": "VSync", + "return_type": "unknown", + "parameters": "?", + "suggestion": "Define proper signature for VSync in header" + }, + { + "type": "extern_variable", + "name": "D_80069800", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069800" + }, + { + "type": "extern_variable", + "name": "D_80071E4D", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80071E4D" + }, + { + "type": "extern_variable", + "name": "D_800738BC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800738BC" + }, + { + "type": "extern_variable", + "name": "D_800491D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800491D0" + }, + { + "type": "extern_variable", + "name": "func_80017678", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_80017678" + }, + { + "type": "extern_variable", + "name": "func_8001786C", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_8001786C" + }, + { + "type": "extern_variable", + "name": "func_80020058", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_80020058" + }, + { + "type": "extern_variable", + "name": "D_8009D85C", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D85C" + }, + { + "type": "extern_variable", + "name": "D_8009D85E", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D85E" + } + ], + "timestamp": "2026-04-22T19:49:05.220188" + }, + { + "function_name": "func_800182FC", + "file": "src/main/18B8.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80075D24", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D24" + }, + { + "type": "extern_variable", + "name": "D_80075D28", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D28" + }, + { + "type": "extern_variable", + "name": "D_80075DE8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075DE8" + }, + { + "type": "extern_variable", + "name": "D_8009D7E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E4" + }, + { + "type": "extern_variable", + "name": "D_8009D7E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E8" + }, + { + "type": "extern_variable", + "name": "D_8009D7EC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7EC" + }, + { + "type": "extern_variable", + "name": "D_8009D7ED", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7ED" + }, + { + "type": "extern_variable", + "name": "D_80069508", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069508" + }, + { + "type": "extern_variable", + "name": "D_800708C8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708C8" + }, + { + "type": "extern_variable", + "name": "D_800708D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708D0" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + } + ], + "timestamp": "2026-04-22T19:49:05.328139" + }, + { + "function_name": "func_800D83A8", + "file": "src/field/field.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80074EB0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB0" + }, + { + "type": "extern_variable", + "name": "D_80074EB4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB4" + }, + { + "type": "extern_variable", + "name": "D_80074EB8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB8" + }, + { + "type": "extern_variable", + "name": "D_800E0638", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E0638" + }, + { + "type": "extern_variable", + "name": "D_800E42D8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42D8" + }, + { + "type": "extern_variable", + "name": "D_800E42DA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42DA" + }, + { + "type": "extern_variable", + "name": "D_800E42DC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42DC" + }, + { + "type": "extern_variable", + "name": "D_800E42E0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E0" + }, + { + "type": "extern_variable", + "name": "D_800E42E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E4" + }, + { + "type": "extern_variable", + "name": "D_800E42E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E8" + }, + { + "type": "extern_variable", + "name": "D_800E42EA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42EA" + }, + { + "type": "extern_variable", + "name": "D_800E42EE", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42EE" + }, + { + "type": "extern_variable", + "name": "D_800E48E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E48E8" + }, + { + "type": "unknown_pointer", + "name": "var_t1", + "suggestion": "m2c could not determine type of pointer var_t1" + }, + { + "type": "unknown_pointer", + "name": "var_t1", + "suggestion": "m2c could not determine type of pointer var_t1" + } + ], + "timestamp": "2026-04-22T19:49:05.823841" + }, + { + "function_name": "func_800A21CC", + "file": "src/ending/ending.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_function", + "name": "InitGeom", + "return_type": "unknown", + "parameters": "", + "suggestion": "Define proper signature for InitGeom in header" + }, + { + "type": "extern_function", + "name": "PadInit", + "return_type": "unknown", + "parameters": "?", + "suggestion": "Define proper signature for PadInit in header" + }, + { + "type": "extern_function", + "name": "ResetCallback", + "return_type": "unknown", + "parameters": "", + "suggestion": "Define proper signature for ResetCallback in header" + }, + { + "type": "extern_function", + "name": "ResetGraph", + "return_type": "unknown", + "parameters": "?", + "suggestion": "Define proper signature for ResetGraph in header" + }, + { + "type": "extern_function", + "name": "StopCallback", + "return_type": "unknown", + "parameters": "", + "suggestion": "Define proper signature for StopCallback in header" + }, + { + "type": "extern_variable", + "name": "func_80033B70", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_80033B70" + }, + { + "type": "extern_variable", + "name": "func_80036298", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_80036298" + } + ], + "timestamp": "2026-04-22T19:49:06.980643" + }, + { + "function_name": "func_800D8420", + "file": "src/field/field.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80074EB0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB0" + }, + { + "type": "extern_variable", + "name": "D_80074EB4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB4" + }, + { + "type": "extern_variable", + "name": "D_80074EB8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB8" + }, + { + "type": "extern_variable", + "name": "D_800E0638", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E0638" + }, + { + "type": "extern_variable", + "name": "D_800E42D8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42D8" + }, + { + "type": "extern_variable", + "name": "D_800E42DA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42DA" + }, + { + "type": "extern_variable", + "name": "D_800E42DC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42DC" + }, + { + "type": "extern_variable", + "name": "D_800E42E0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E0" + }, + { + "type": "extern_variable", + "name": "D_800E42E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E4" + }, + { + "type": "extern_variable", + "name": "D_800E42E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E8" + }, + { + "type": "extern_variable", + "name": "D_800E42EA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42EA" + }, + { + "type": "extern_variable", + "name": "D_800E42EE", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42EE" + }, + { + "type": "extern_variable", + "name": "D_800E48E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E48E8" + }, + { + "type": "unknown_pointer", + "name": "var_t1", + "suggestion": "m2c could not determine type of pointer var_t1" + }, + { + "type": "unknown_pointer", + "name": "var_t1", + "suggestion": "m2c could not determine type of pointer var_t1" + } + ], + "timestamp": "2026-04-22T19:49:07.197448" + }, + { + "function_name": "func_800E1A2C", + "file": "src/battle/battle3.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_800FB064", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800FB064" + }, + { + "type": "extern_variable", + "name": "D_800FF060", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800FF060" + }, + { + "type": "extern_variable", + "name": "D_800FF064", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800FF064" + }, + { + "type": "extern_variable", + "name": "D_800FF068", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800FF068" + }, + { + "type": "extern_variable", + "name": "D_800FF06C", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800FF06C" + }, + { + "type": "extern_variable", + "name": "D_800FF070", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800FF070" + }, + { + "type": "extern_variable", + "name": "D_800FF074", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800FF074" + }, + { + "type": "extern_variable", + "name": "D_800FF094", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800FF094" + }, + { + "type": "extern_variable", + "name": "D_800FF098", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800FF098" + }, + { + "type": "extern_variable", + "name": "D_800FF0D8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800FF0D8" + }, + { + "type": "extern_variable", + "name": "D_800FF0DC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800FF0DC" + }, + { + "type": "extern_variable", + "name": "D_800FF0E0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800FF0E0" + }, + { + "type": "extern_variable", + "name": "D_80103154", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80103154" + }, + { + "type": "extern_variable", + "name": "D_80103158", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80103158" + }, + { + "type": "extern_variable", + "name": "D_80103160", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80103160" + }, + { + "type": "extern_variable", + "name": "D_80103188", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80103188" + }, + { + "type": "extern_variable", + "name": "D_801031CC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_801031CC" + }, + { + "type": "extern_variable", + "name": "D_801031D4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_801031D4" + }, + { + "type": "extern_variable", + "name": "D_800492FC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800492FC" + }, + { + "type": "extern_variable", + "name": "D_800F55D8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F55D8" + }, + { + "type": "extern_variable", + "name": "D_800F1E58", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F1E58" + }, + { + "type": "extern_variable", + "name": "D_800F1E5A", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F1E5A" + }, + { + "type": "extern_variable", + "name": "D_800F1E5C", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F1E5C" + }, + { + "type": "extern_variable", + "name": "D_800F1E5E", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F1E5E" + }, + { + "type": "extern_variable", + "name": "D_800F1E60", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F1E60" + }, + { + "type": "extern_variable", + "name": "D_800F1E62", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F1E62" + }, + { + "type": "extern_variable", + "name": "D_800F33B0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F33B0" + }, + { + "type": "extern_variable", + "name": "D_80163778", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80163778" + }, + { + "type": "extern_variable", + "name": "D_80163B70", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80163B70" + }, + { + "type": "unknown_pointer", + "name": "var_v0", + "suggestion": "m2c could not determine type of pointer var_v0" + }, + { + "type": "unknown_pointer", + "name": "var_v0_2", + "suggestion": "m2c could not determine type of pointer var_v0_2" + }, + { + "type": "unknown_pointer", + "name": "var_v0_3", + "suggestion": "m2c could not determine type of pointer var_v0_3" + }, + { + "type": "unknown_pointer", + "name": "var_v0_4", + "suggestion": "m2c could not determine type of pointer var_v0_4" + }, + { + "type": "unknown_pointer", + "name": "var_v0_5", + "suggestion": "m2c could not determine type of pointer var_v0_5" + }, + { + "type": "unknown_pointer", + "name": "var_v0_6", + "suggestion": "m2c could not determine type of pointer var_v0_6" + }, + { + "type": "unknown_pointer", + "name": "var_v0", + "suggestion": "m2c could not determine type of pointer var_v0" + } + ], + "timestamp": "2026-04-22T19:49:07.405004" + }, + { + "function_name": "func_8001B8A8", + "file": "src/main/18B8.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80075D24", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D24" + }, + { + "type": "extern_variable", + "name": "D_80075D28", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D28" + }, + { + "type": "extern_variable", + "name": "D_80075DE8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075DE8" + }, + { + "type": "extern_variable", + "name": "D_8009D7E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E4" + }, + { + "type": "extern_variable", + "name": "D_8009D7E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E8" + }, + { + "type": "extern_variable", + "name": "D_8009D7EC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7EC" + }, + { + "type": "extern_variable", + "name": "D_8009D7ED", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7ED" + }, + { + "type": "extern_variable", + "name": "D_80069508", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069508" + }, + { + "type": "extern_variable", + "name": "D_800708C8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708C8" + }, + { + "type": "extern_variable", + "name": "D_800708D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708D0" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + } + ], + "timestamp": "2026-04-22T19:49:07.497349" + }, + { + "function_name": "func_800A1E20", + "file": "src/ending/ending.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_function", + "name": "InitGeom", + "return_type": "unknown", + "parameters": "", + "suggestion": "Define proper signature for InitGeom in header" + }, + { + "type": "extern_function", + "name": "PadInit", + "return_type": "unknown", + "parameters": "?", + "suggestion": "Define proper signature for PadInit in header" + }, + { + "type": "extern_function", + "name": "ResetCallback", + "return_type": "unknown", + "parameters": "", + "suggestion": "Define proper signature for ResetCallback in header" + }, + { + "type": "extern_function", + "name": "ResetGraph", + "return_type": "unknown", + "parameters": "?", + "suggestion": "Define proper signature for ResetGraph in header" + }, + { + "type": "extern_function", + "name": "StopCallback", + "return_type": "unknown", + "parameters": "", + "suggestion": "Define proper signature for StopCallback in header" + }, + { + "type": "extern_variable", + "name": "func_80033B70", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_80033B70" + }, + { + "type": "extern_variable", + "name": "func_80036298", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_80036298" + } + ], + "timestamp": "2026-04-22T19:49:07.930788" + }, + { + "function_name": "func_800A635C", + "file": "src/field/field.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80074EB0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB0" + }, + { + "type": "extern_variable", + "name": "D_80074EB4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB4" + }, + { + "type": "extern_variable", + "name": "D_80074EB8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB8" + }, + { + "type": "extern_variable", + "name": "D_800E0638", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E0638" + }, + { + "type": "extern_variable", + "name": "D_800E42D8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42D8" + }, + { + "type": "extern_variable", + "name": "D_800E42DA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42DA" + }, + { + "type": "extern_variable", + "name": "D_800E42DC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42DC" + }, + { + "type": "extern_variable", + "name": "D_800E42E0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E0" + }, + { + "type": "extern_variable", + "name": "D_800E42E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E4" + }, + { + "type": "extern_variable", + "name": "D_800E42E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E8" + }, + { + "type": "extern_variable", + "name": "D_800E42EA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42EA" + }, + { + "type": "extern_variable", + "name": "D_800E42EE", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42EE" + }, + { + "type": "extern_variable", + "name": "D_800E48E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E48E8" + }, + { + "type": "unknown_pointer", + "name": "var_t1", + "suggestion": "m2c could not determine type of pointer var_t1" + }, + { + "type": "unknown_pointer", + "name": "var_t1", + "suggestion": "m2c could not determine type of pointer var_t1" + } + ], + "timestamp": "2026-04-22T19:49:08.171220" + }, + { + "function_name": "func_80019DA0", + "file": "src/main/18B8.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80075D24", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D24" + }, + { + "type": "extern_variable", + "name": "D_80075D28", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D28" + }, + { + "type": "extern_variable", + "name": "D_80075DE8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075DE8" + }, + { + "type": "extern_variable", + "name": "D_8009D7E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E4" + }, + { + "type": "extern_variable", + "name": "D_8009D7E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E8" + }, + { + "type": "extern_variable", + "name": "D_8009D7EC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7EC" + }, + { + "type": "extern_variable", + "name": "D_8009D7ED", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7ED" + }, + { + "type": "extern_variable", + "name": "D_80069508", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069508" + }, + { + "type": "extern_variable", + "name": "D_800708C8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708C8" + }, + { + "type": "extern_variable", + "name": "D_800708D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708D0" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + } + ], + "timestamp": "2026-04-22T19:49:08.368108" + }, + { + "function_name": "func_80025800", + "file": "src/main/1255C.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_function", + "name": "func_80048540", + "return_type": "s32", + "parameters": "?", + "suggestion": "Define proper signature for func_80048540 in header" + }, + { + "type": "extern_function", + "name": "VSync", + "return_type": "unknown", + "parameters": "?", + "suggestion": "Define proper signature for VSync in header" + }, + { + "type": "extern_variable", + "name": "D_80069800", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069800" + }, + { + "type": "extern_variable", + "name": "D_80071E4D", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80071E4D" + }, + { + "type": "extern_variable", + "name": "D_800738BC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800738BC" + }, + { + "type": "extern_variable", + "name": "D_800491D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800491D0" + }, + { + "type": "extern_variable", + "name": "func_80017678", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_80017678" + }, + { + "type": "extern_variable", + "name": "func_8001786C", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_8001786C" + }, + { + "type": "extern_variable", + "name": "func_80020058", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_80020058" + }, + { + "type": "extern_variable", + "name": "D_8009D85C", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D85C" + }, + { + "type": "extern_variable", + "name": "D_8009D85E", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D85E" + } + ], + "timestamp": "2026-04-22T19:49:09.466345" + }, + { + "function_name": "func_800D84CC", + "file": "src/field/field.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80074EB0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB0" + }, + { + "type": "extern_variable", + "name": "D_80074EB4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB4" + }, + { + "type": "extern_variable", + "name": "D_80074EB8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB8" + }, + { + "type": "extern_variable", + "name": "D_800E0638", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E0638" + }, + { + "type": "extern_variable", + "name": "D_800E42D8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42D8" + }, + { + "type": "extern_variable", + "name": "D_800E42DA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42DA" + }, + { + "type": "extern_variable", + "name": "D_800E42DC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42DC" + }, + { + "type": "extern_variable", + "name": "D_800E42E0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E0" + }, + { + "type": "extern_variable", + "name": "D_800E42E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E4" + }, + { + "type": "extern_variable", + "name": "D_800E42E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E8" + }, + { + "type": "extern_variable", + "name": "D_800E42EA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42EA" + }, + { + "type": "extern_variable", + "name": "D_800E42EE", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42EE" + }, + { + "type": "extern_variable", + "name": "D_800E48E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E48E8" + }, + { + "type": "unknown_pointer", + "name": "var_t1", + "suggestion": "m2c could not determine type of pointer var_t1" + }, + { + "type": "unknown_pointer", + "name": "var_t1", + "suggestion": "m2c could not determine type of pointer var_t1" + } + ], + "timestamp": "2026-04-22T19:49:09.493200" + }, + { + "function_name": "func_80011AEC", + "file": "src/main/18B8.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80075D24", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D24" + }, + { + "type": "extern_variable", + "name": "D_80075D28", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D28" + }, + { + "type": "extern_variable", + "name": "D_80075DE8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075DE8" + }, + { + "type": "extern_variable", + "name": "D_8009D7E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E4" + }, + { + "type": "extern_variable", + "name": "D_8009D7E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E8" + }, + { + "type": "extern_variable", + "name": "D_8009D7EC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7EC" + }, + { + "type": "extern_variable", + "name": "D_8009D7ED", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7ED" + }, + { + "type": "extern_variable", + "name": "D_80069508", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069508" + }, + { + "type": "extern_variable", + "name": "D_800708C8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708C8" + }, + { + "type": "extern_variable", + "name": "D_800708D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708D0" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + } + ], + "timestamp": "2026-04-22T19:49:09.657221" + }, + { + "function_name": "func_80025988", + "file": "src/main/1255C.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_function", + "name": "func_80048540", + "return_type": "s32", + "parameters": "?", + "suggestion": "Define proper signature for func_80048540 in header" + }, + { + "type": "extern_function", + "name": "VSync", + "return_type": "unknown", + "parameters": "?", + "suggestion": "Define proper signature for VSync in header" + }, + { + "type": "extern_variable", + "name": "D_80069800", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069800" + }, + { + "type": "extern_variable", + "name": "D_80071E4D", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80071E4D" + }, + { + "type": "extern_variable", + "name": "D_800738BC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800738BC" + }, + { + "type": "extern_variable", + "name": "D_800491D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800491D0" + }, + { + "type": "extern_variable", + "name": "func_80017678", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_80017678" + }, + { + "type": "extern_variable", + "name": "func_8001786C", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_8001786C" + }, + { + "type": "extern_variable", + "name": "func_80020058", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_80020058" + }, + { + "type": "extern_variable", + "name": "D_8009D85C", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D85C" + }, + { + "type": "extern_variable", + "name": "D_8009D85E", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D85E" + } + ], + "timestamp": "2026-04-22T19:49:10.231507" + }, + { + "function_name": "func_8001FAF8", + "file": "src/main/18B8.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80075D24", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D24" + }, + { + "type": "extern_variable", + "name": "D_80075D28", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D28" + }, + { + "type": "extern_variable", + "name": "D_80075DE8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075DE8" + }, + { + "type": "extern_variable", + "name": "D_8009D7E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E4" + }, + { + "type": "extern_variable", + "name": "D_8009D7E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E8" + }, + { + "type": "extern_variable", + "name": "D_8009D7EC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7EC" + }, + { + "type": "extern_variable", + "name": "D_8009D7ED", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7ED" + }, + { + "type": "extern_variable", + "name": "D_80069508", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069508" + }, + { + "type": "extern_variable", + "name": "D_800708C8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708C8" + }, + { + "type": "extern_variable", + "name": "D_800708D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708D0" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + } + ], + "timestamp": "2026-04-22T19:49:10.453647" + }, + { + "function_name": "func_8002382C", + "file": "src/main/1255C.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_function", + "name": "func_80048540", + "return_type": "s32", + "parameters": "?", + "suggestion": "Define proper signature for func_80048540 in header" + }, + { + "type": "extern_function", + "name": "VSync", + "return_type": "unknown", + "parameters": "?", + "suggestion": "Define proper signature for VSync in header" + }, + { + "type": "extern_variable", + "name": "D_80069800", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069800" + }, + { + "type": "extern_variable", + "name": "D_80071E4D", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80071E4D" + }, + { + "type": "extern_variable", + "name": "D_800738BC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800738BC" + }, + { + "type": "extern_variable", + "name": "D_800491D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800491D0" + }, + { + "type": "extern_variable", + "name": "func_80017678", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_80017678" + }, + { + "type": "extern_variable", + "name": "func_8001786C", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_8001786C" + }, + { + "type": "extern_variable", + "name": "func_80020058", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_80020058" + }, + { + "type": "extern_variable", + "name": "D_8009D85C", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D85C" + }, + { + "type": "extern_variable", + "name": "D_8009D85E", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D85E" + } + ], + "timestamp": "2026-04-22T19:49:10.938976" + }, + { + "function_name": "func_8001FE6C", + "file": "src/main/18B8.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80075D24", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D24" + }, + { + "type": "extern_variable", + "name": "D_80075D28", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D28" + }, + { + "type": "extern_variable", + "name": "D_80075DE8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075DE8" + }, + { + "type": "extern_variable", + "name": "D_8009D7E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E4" + }, + { + "type": "extern_variable", + "name": "D_8009D7E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E8" + }, + { + "type": "extern_variable", + "name": "D_8009D7EC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7EC" + }, + { + "type": "extern_variable", + "name": "D_8009D7ED", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7ED" + }, + { + "type": "extern_variable", + "name": "D_80069508", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069508" + }, + { + "type": "extern_variable", + "name": "D_800708C8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708C8" + }, + { + "type": "extern_variable", + "name": "D_800708D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708D0" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + } + ], + "timestamp": "2026-04-22T19:49:11.116506" + }, + { + "function_name": "func_80018220", + "file": "src/main/18B8.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80075D24", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D24" + }, + { + "type": "extern_variable", + "name": "D_80075D28", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D28" + }, + { + "type": "extern_variable", + "name": "D_80075DE8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075DE8" + }, + { + "type": "extern_variable", + "name": "D_8009D7E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E4" + }, + { + "type": "extern_variable", + "name": "D_8009D7E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E8" + }, + { + "type": "extern_variable", + "name": "D_8009D7EC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7EC" + }, + { + "type": "extern_variable", + "name": "D_8009D7ED", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7ED" + }, + { + "type": "extern_variable", + "name": "D_80069508", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069508" + }, + { + "type": "extern_variable", + "name": "D_800708C8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708C8" + }, + { + "type": "extern_variable", + "name": "D_800708D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708D0" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + } + ], + "timestamp": "2026-04-22T19:49:11.707947" + }, + { + "function_name": "func_800BB1B4", + "file": "src/field/field.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80074EB0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB0" + }, + { + "type": "extern_variable", + "name": "D_80074EB4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB4" + }, + { + "type": "extern_variable", + "name": "D_80074EB8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB8" + }, + { + "type": "extern_variable", + "name": "D_800E0638", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E0638" + }, + { + "type": "extern_variable", + "name": "D_800E42D8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42D8" + }, + { + "type": "extern_variable", + "name": "D_800E42DA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42DA" + }, + { + "type": "extern_variable", + "name": "D_800E42DC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42DC" + }, + { + "type": "extern_variable", + "name": "D_800E42E0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E0" + }, + { + "type": "extern_variable", + "name": "D_800E42E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E4" + }, + { + "type": "extern_variable", + "name": "D_800E42E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E8" + }, + { + "type": "extern_variable", + "name": "D_800E42EA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42EA" + }, + { + "type": "extern_variable", + "name": "D_800E42EE", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42EE" + }, + { + "type": "extern_variable", + "name": "D_800E48E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E48E8" + }, + { + "type": "unknown_pointer", + "name": "var_t1", + "suggestion": "m2c could not determine type of pointer var_t1" + }, + { + "type": "unknown_pointer", + "name": "var_t1", + "suggestion": "m2c could not determine type of pointer var_t1" + } + ], + "timestamp": "2026-04-22T19:49:12.738463" + }, + { + "function_name": "func_80023940", + "file": "src/main/1255C.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_function", + "name": "func_80048540", + "return_type": "s32", + "parameters": "?", + "suggestion": "Define proper signature for func_80048540 in header" + }, + { + "type": "extern_function", + "name": "VSync", + "return_type": "unknown", + "parameters": "?", + "suggestion": "Define proper signature for VSync in header" + }, + { + "type": "extern_variable", + "name": "D_80069800", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069800" + }, + { + "type": "extern_variable", + "name": "D_80071E4D", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80071E4D" + }, + { + "type": "extern_variable", + "name": "D_800738BC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800738BC" + }, + { + "type": "extern_variable", + "name": "D_800491D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800491D0" + }, + { + "type": "extern_variable", + "name": "func_80017678", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_80017678" + }, + { + "type": "extern_variable", + "name": "func_8001786C", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_8001786C" + }, + { + "type": "extern_variable", + "name": "func_80020058", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_80020058" + }, + { + "type": "extern_variable", + "name": "D_8009D85C", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D85C" + }, + { + "type": "extern_variable", + "name": "D_8009D85E", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D85E" + } + ], + "timestamp": "2026-04-22T19:49:12.814286" + }, + { + "function_name": "func_800119E4", + "file": "src/main/18B8.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80075D24", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D24" + }, + { + "type": "extern_variable", + "name": "D_80075D28", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D28" + }, + { + "type": "extern_variable", + "name": "D_80075DE8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075DE8" + }, + { + "type": "extern_variable", + "name": "D_8009D7E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E4" + }, + { + "type": "extern_variable", + "name": "D_8009D7E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E8" + }, + { + "type": "extern_variable", + "name": "D_8009D7EC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7EC" + }, + { + "type": "extern_variable", + "name": "D_8009D7ED", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7ED" + }, + { + "type": "extern_variable", + "name": "D_80069508", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069508" + }, + { + "type": "extern_variable", + "name": "D_800708C8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708C8" + }, + { + "type": "extern_variable", + "name": "D_800708D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708D0" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + } + ], + "timestamp": "2026-04-22T19:49:12.844308" + }, + { + "function_name": "func_80019E84", + "file": "src/main/18B8.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80075D24", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D24" + }, + { + "type": "extern_variable", + "name": "D_80075D28", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D28" + }, + { + "type": "extern_variable", + "name": "D_80075DE8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075DE8" + }, + { + "type": "extern_variable", + "name": "D_8009D7E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E4" + }, + { + "type": "extern_variable", + "name": "D_8009D7E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E8" + }, + { + "type": "extern_variable", + "name": "D_8009D7EC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7EC" + }, + { + "type": "extern_variable", + "name": "D_8009D7ED", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7ED" + }, + { + "type": "extern_variable", + "name": "D_80069508", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069508" + }, + { + "type": "extern_variable", + "name": "D_800708C8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708C8" + }, + { + "type": "extern_variable", + "name": "D_800708D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708D0" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + } + ], + "timestamp": "2026-04-22T19:49:13.441928" + }, + { + "function_name": "func_8001FBAC", + "file": "src/main/18B8.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80075D24", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D24" + }, + { + "type": "extern_variable", + "name": "D_80075D28", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D28" + }, + { + "type": "extern_variable", + "name": "D_80075DE8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075DE8" + }, + { + "type": "extern_variable", + "name": "D_8009D7E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E4" + }, + { + "type": "extern_variable", + "name": "D_8009D7E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E8" + }, + { + "type": "extern_variable", + "name": "D_8009D7EC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7EC" + }, + { + "type": "extern_variable", + "name": "D_8009D7ED", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7ED" + }, + { + "type": "extern_variable", + "name": "D_80069508", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069508" + }, + { + "type": "extern_variable", + "name": "D_800708C8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708C8" + }, + { + "type": "extern_variable", + "name": "D_800708D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708D0" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + } + ], + "timestamp": "2026-04-22T19:49:14.032060" + }, + { + "function_name": "func_800159B0", + "file": "src/main/18B8.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80075D24", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D24" + }, + { + "type": "extern_variable", + "name": "D_80075D28", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D28" + }, + { + "type": "extern_variable", + "name": "D_80075DE8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075DE8" + }, + { + "type": "extern_variable", + "name": "D_8009D7E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E4" + }, + { + "type": "extern_variable", + "name": "D_8009D7E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E8" + }, + { + "type": "extern_variable", + "name": "D_8009D7EC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7EC" + }, + { + "type": "extern_variable", + "name": "D_8009D7ED", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7ED" + }, + { + "type": "extern_variable", + "name": "D_80069508", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069508" + }, + { + "type": "extern_variable", + "name": "D_800708C8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708C8" + }, + { + "type": "extern_variable", + "name": "D_800708D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708D0" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + } + ], + "timestamp": "2026-04-22T19:49:14.620242" + }, + { + "function_name": "func_8001C980", + "file": "src/main/18B8.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80075D24", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D24" + }, + { + "type": "extern_variable", + "name": "D_80075D28", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D28" + }, + { + "type": "extern_variable", + "name": "D_80075DE8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075DE8" + }, + { + "type": "extern_variable", + "name": "D_8009D7E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E4" + }, + { + "type": "extern_variable", + "name": "D_8009D7E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E8" + }, + { + "type": "extern_variable", + "name": "D_8009D7EC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7EC" + }, + { + "type": "extern_variable", + "name": "D_8009D7ED", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7ED" + }, + { + "type": "extern_variable", + "name": "D_80069508", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069508" + }, + { + "type": "extern_variable", + "name": "D_800708C8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708C8" + }, + { + "type": "extern_variable", + "name": "D_800708D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708D0" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + } + ], + "timestamp": "2026-04-22T19:49:15.231087" + }, + { + "function_name": "func_800211C4", + "file": "src/main/18B8.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80075D24", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D24" + }, + { + "type": "extern_variable", + "name": "D_80075D28", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D28" + }, + { + "type": "extern_variable", + "name": "D_80075DE8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075DE8" + }, + { + "type": "extern_variable", + "name": "D_8009D7E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E4" + }, + { + "type": "extern_variable", + "name": "D_8009D7E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E8" + }, + { + "type": "extern_variable", + "name": "D_8009D7EC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7EC" + }, + { + "type": "extern_variable", + "name": "D_8009D7ED", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7ED" + }, + { + "type": "extern_variable", + "name": "D_80069508", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069508" + }, + { + "type": "extern_variable", + "name": "D_800708C8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708C8" + }, + { + "type": "extern_variable", + "name": "D_800708D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708D0" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + } + ], + "timestamp": "2026-04-22T19:49:15.796230" + }, + { + "function_name": "func_80028CA0", + "file": "src/main/1255C.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_function", + "name": "func_80048540", + "return_type": "s32", + "parameters": "?", + "suggestion": "Define proper signature for func_80048540 in header" + }, + { + "type": "extern_function", + "name": "VSync", + "return_type": "unknown", + "parameters": "?", + "suggestion": "Define proper signature for VSync in header" + }, + { + "type": "extern_variable", + "name": "D_80069800", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069800" + }, + { + "type": "extern_variable", + "name": "D_80071E4D", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80071E4D" + }, + { + "type": "extern_variable", + "name": "D_800738BC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800738BC" + }, + { + "type": "extern_variable", + "name": "D_800491D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800491D0" + }, + { + "type": "extern_variable", + "name": "func_80017678", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_80017678" + }, + { + "type": "extern_variable", + "name": "func_8001786C", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_8001786C" + }, + { + "type": "extern_variable", + "name": "func_80020058", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_80020058" + }, + { + "type": "extern_variable", + "name": "D_8009D85C", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D85C" + }, + { + "type": "extern_variable", + "name": "D_8009D85E", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D85E" + } + ], + "timestamp": "2026-04-22T19:49:16.878011" + }, + { + "function_name": "func_800B11B4", + "file": "src/battle/battle.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_function", + "name": "func_800B13B0", + "return_type": "s32", + "parameters": "?, s32**", + "suggestion": "Define proper signature for func_800B13B0 in header" + }, + { + "type": "extern_variable", + "name": "D_800F3A40", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F3A40" + }, + { + "type": "extern_variable", + "name": "D_800F3A20", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F3A20" + }, + { + "type": "extern_variable", + "name": "D_800E7BEC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E7BEC" + }, + { + "type": "extern_variable", + "name": "D_800F49F8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F49F8" + } + ], + "timestamp": "2026-04-22T19:49:17.133496" + }, + { + "function_name": "func_800CD400", + "file": "src/battle/battle2.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_800F4CEC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F4CEC" + }, + { + "type": "extern_variable", + "name": "D_800F4D2C", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F4D2C" + }, + { + "type": "extern_variable", + "name": "func_800D6998", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_800D6998" + }, + { + "type": "extern_variable", + "name": "func_800D6ACC", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_800D6ACC" + }, + { + "type": "extern_variable", + "name": "func_800D6C20", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_800D6C20" + }, + { + "type": "unaligned_cast", + "cast_type": "s32", + "suggestion": "Unaligned access to s32 - may need struct packing or alignment fix" + } + ], + "timestamp": "2026-04-22T19:49:17.291694" + }, + { + "function_name": "func_80025514", + "file": "src/main/1255C.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_function", + "name": "func_80048540", + "return_type": "s32", + "parameters": "?", + "suggestion": "Define proper signature for func_80048540 in header" + }, + { + "type": "extern_function", + "name": "VSync", + "return_type": "unknown", + "parameters": "?", + "suggestion": "Define proper signature for VSync in header" + }, + { + "type": "extern_variable", + "name": "D_80069800", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069800" + }, + { + "type": "extern_variable", + "name": "D_80071E4D", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80071E4D" + }, + { + "type": "extern_variable", + "name": "D_800738BC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800738BC" + }, + { + "type": "extern_variable", + "name": "D_800491D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800491D0" + }, + { + "type": "extern_variable", + "name": "func_80017678", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_80017678" + }, + { + "type": "extern_variable", + "name": "func_8001786C", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_8001786C" + }, + { + "type": "extern_variable", + "name": "func_80020058", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_80020058" + }, + { + "type": "extern_variable", + "name": "D_8009D85C", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D85C" + }, + { + "type": "extern_variable", + "name": "D_8009D85E", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D85E" + } + ], + "timestamp": "2026-04-22T19:49:17.724565" + }, + { + "function_name": "func_800CD5E4", + "file": "src/battle/battle2.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_800F4CEC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F4CEC" + }, + { + "type": "extern_variable", + "name": "D_800F4D2C", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F4D2C" + }, + { + "type": "extern_variable", + "name": "func_800D6998", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_800D6998" + }, + { + "type": "extern_variable", + "name": "func_800D6ACC", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_800D6ACC" + }, + { + "type": "extern_variable", + "name": "func_800D6C20", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_800D6C20" + }, + { + "type": "unaligned_cast", + "cast_type": "s32", + "suggestion": "Unaligned access to s32 - may need struct packing or alignment fix" + } + ], + "timestamp": "2026-04-22T19:49:18.365820" + }, + { + "function_name": "func_80026408", + "file": "src/main/1255C.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_function", + "name": "func_80048540", + "return_type": "s32", + "parameters": "?", + "suggestion": "Define proper signature for func_80048540 in header" + }, + { + "type": "extern_function", + "name": "VSync", + "return_type": "unknown", + "parameters": "?", + "suggestion": "Define proper signature for VSync in header" + }, + { + "type": "extern_variable", + "name": "D_80069800", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069800" + }, + { + "type": "extern_variable", + "name": "D_80071E4D", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80071E4D" + }, + { + "type": "extern_variable", + "name": "D_800738BC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800738BC" + }, + { + "type": "extern_variable", + "name": "D_800491D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800491D0" + }, + { + "type": "extern_variable", + "name": "func_80017678", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_80017678" + }, + { + "type": "extern_variable", + "name": "func_8001786C", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_8001786C" + }, + { + "type": "extern_variable", + "name": "func_80020058", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_80020058" + }, + { + "type": "extern_variable", + "name": "D_8009D85C", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D85C" + }, + { + "type": "extern_variable", + "name": "D_8009D85E", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D85E" + } + ], + "timestamp": "2026-04-22T19:49:18.557635" + }, + { + "function_name": "func_80024A04", + "file": "src/main/1255C.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_function", + "name": "func_80048540", + "return_type": "s32", + "parameters": "?", + "suggestion": "Define proper signature for func_80048540 in header" + }, + { + "type": "extern_function", + "name": "VSync", + "return_type": "unknown", + "parameters": "?", + "suggestion": "Define proper signature for VSync in header" + }, + { + "type": "extern_variable", + "name": "D_80069800", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069800" + }, + { + "type": "extern_variable", + "name": "D_80071E4D", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80071E4D" + }, + { + "type": "extern_variable", + "name": "D_800738BC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800738BC" + }, + { + "type": "extern_variable", + "name": "D_800491D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800491D0" + }, + { + "type": "extern_variable", + "name": "func_80017678", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_80017678" + }, + { + "type": "extern_variable", + "name": "func_8001786C", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_8001786C" + }, + { + "type": "extern_variable", + "name": "func_80020058", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_80020058" + }, + { + "type": "extern_variable", + "name": "D_8009D85C", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D85C" + }, + { + "type": "extern_variable", + "name": "D_8009D85E", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D85E" + } + ], + "timestamp": "2026-04-22T19:49:19.110337" + }, + { + "function_name": "func_80022FE0", + "file": "src/main/1255C.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_function", + "name": "func_80048540", + "return_type": "s32", + "parameters": "?", + "suggestion": "Define proper signature for func_80048540 in header" + }, + { + "type": "extern_function", + "name": "VSync", + "return_type": "unknown", + "parameters": "?", + "suggestion": "Define proper signature for VSync in header" + }, + { + "type": "extern_variable", + "name": "D_80069800", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069800" + }, + { + "type": "extern_variable", + "name": "D_80071E4D", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80071E4D" + }, + { + "type": "extern_variable", + "name": "D_800738BC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800738BC" + }, + { + "type": "extern_variable", + "name": "D_800491D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800491D0" + }, + { + "type": "extern_variable", + "name": "func_80017678", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_80017678" + }, + { + "type": "extern_variable", + "name": "func_8001786C", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_8001786C" + }, + { + "type": "extern_variable", + "name": "func_80020058", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_80020058" + }, + { + "type": "extern_variable", + "name": "D_8009D85C", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D85C" + }, + { + "type": "extern_variable", + "name": "D_8009D85E", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D85E" + } + ], + "timestamp": "2026-04-22T19:49:20.169709" + }, + { + "function_name": "func_8002120C", + "file": "src/main/18B8.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80075D24", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D24" + }, + { + "type": "extern_variable", + "name": "D_80075D28", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D28" + }, + { + "type": "extern_variable", + "name": "D_80075DE8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075DE8" + }, + { + "type": "extern_variable", + "name": "D_8009D7E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E4" + }, + { + "type": "extern_variable", + "name": "D_8009D7E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E8" + }, + { + "type": "extern_variable", + "name": "D_8009D7EC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7EC" + }, + { + "type": "extern_variable", + "name": "D_8009D7ED", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7ED" + }, + { + "type": "extern_variable", + "name": "D_80069508", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069508" + }, + { + "type": "extern_variable", + "name": "D_800708C8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708C8" + }, + { + "type": "extern_variable", + "name": "D_800708D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708D0" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + } + ], + "timestamp": "2026-04-22T19:49:20.263191" + }, + { + "function_name": "func_801D224C", + "file": "src/menu/savemenu.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_function", + "name": "sprintf", + "return_type": "unknown", + "parameters": "s8*, s8*, s8*", + "suggestion": "Define proper signature for sprintf in header" + }, + { + "type": "extern_variable", + "name": "D_801E6F38", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_801E6F38" + }, + { + "type": "extern_variable", + "name": "D_801E7138", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_801E7138" + }, + { + "type": "unknown_pointer", + "name": "var_a2_2", + "suggestion": "m2c could not determine type of pointer var_a2_2" + }, + { + "type": "unknown_pointer", + "name": "var_a3", + "suggestion": "m2c could not determine type of pointer var_a3" + }, + { + "type": "unaligned_cast", + "cast_type": "s32", + "suggestion": "Unaligned access to s32 - may need struct packing or alignment fix" + } + ], + "timestamp": "2026-04-22T19:49:20.475751" + }, + { + "function_name": "func_800D55F4", + "file": "src/battle/battle2.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_800F4CEC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F4CEC" + }, + { + "type": "extern_variable", + "name": "D_800F4D2C", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F4D2C" + }, + { + "type": "extern_variable", + "name": "func_800D6998", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_800D6998" + }, + { + "type": "extern_variable", + "name": "func_800D6ACC", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_800D6ACC" + }, + { + "type": "extern_variable", + "name": "func_800D6C20", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_800D6C20" + }, + { + "type": "unaligned_cast", + "cast_type": "s32", + "suggestion": "Unaligned access to s32 - may need struct packing or alignment fix" + } + ], + "timestamp": "2026-04-22T19:49:20.681711" + }, + { + "function_name": "func_8002368C", + "file": "src/main/1255C.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_function", + "name": "func_80048540", + "return_type": "s32", + "parameters": "?", + "suggestion": "Define proper signature for func_80048540 in header" + }, + { + "type": "extern_function", + "name": "VSync", + "return_type": "unknown", + "parameters": "?", + "suggestion": "Define proper signature for VSync in header" + }, + { + "type": "extern_variable", + "name": "D_80069800", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069800" + }, + { + "type": "extern_variable", + "name": "D_80071E4D", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80071E4D" + }, + { + "type": "extern_variable", + "name": "D_800738BC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800738BC" + }, + { + "type": "extern_variable", + "name": "D_800491D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800491D0" + }, + { + "type": "extern_variable", + "name": "func_80017678", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_80017678" + }, + { + "type": "extern_variable", + "name": "func_8001786C", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_8001786C" + }, + { + "type": "extern_variable", + "name": "func_80020058", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_80020058" + }, + { + "type": "extern_variable", + "name": "D_8009D85C", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D85C" + }, + { + "type": "extern_variable", + "name": "D_8009D85E", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D85E" + } + ], + "timestamp": "2026-04-22T19:49:21.146988" + }, + { + "function_name": "func_8001A4A8", + "file": "src/main/18B8.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80075D24", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D24" + }, + { + "type": "extern_variable", + "name": "D_80075D28", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D28" + }, + { + "type": "extern_variable", + "name": "D_80075DE8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075DE8" + }, + { + "type": "extern_variable", + "name": "D_8009D7E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E4" + }, + { + "type": "extern_variable", + "name": "D_8009D7E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E8" + }, + { + "type": "extern_variable", + "name": "D_8009D7EC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7EC" + }, + { + "type": "extern_variable", + "name": "D_8009D7ED", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7ED" + }, + { + "type": "extern_variable", + "name": "D_80069508", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069508" + }, + { + "type": "extern_variable", + "name": "D_800708C8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708C8" + }, + { + "type": "extern_variable", + "name": "D_800708D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708D0" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + } + ], + "timestamp": "2026-04-22T19:49:21.328318" + }, + { + "function_name": "func_800CD860", + "file": "src/battle/battle2.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_800F4CEC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F4CEC" + }, + { + "type": "extern_variable", + "name": "D_800F4D2C", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F4D2C" + }, + { + "type": "extern_variable", + "name": "func_800D6998", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_800D6998" + }, + { + "type": "extern_variable", + "name": "func_800D6ACC", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_800D6ACC" + }, + { + "type": "extern_variable", + "name": "func_800D6C20", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_800D6C20" + }, + { + "type": "unaligned_cast", + "cast_type": "s32", + "suggestion": "Unaligned access to s32 - may need struct packing or alignment fix" + } + ], + "timestamp": "2026-04-22T19:49:21.759187" + }, + { + "function_name": "func_80028E00", + "file": "src/main/1255C.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_function", + "name": "func_80048540", + "return_type": "s32", + "parameters": "?", + "suggestion": "Define proper signature for func_80048540 in header" + }, + { + "type": "extern_function", + "name": "VSync", + "return_type": "unknown", + "parameters": "?", + "suggestion": "Define proper signature for VSync in header" + }, + { + "type": "extern_variable", + "name": "D_80069800", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069800" + }, + { + "type": "extern_variable", + "name": "D_80071E4D", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80071E4D" + }, + { + "type": "extern_variable", + "name": "D_800738BC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800738BC" + }, + { + "type": "extern_variable", + "name": "D_800491D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800491D0" + }, + { + "type": "extern_variable", + "name": "func_80017678", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_80017678" + }, + { + "type": "extern_variable", + "name": "func_8001786C", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_8001786C" + }, + { + "type": "extern_variable", + "name": "func_80020058", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_80020058" + }, + { + "type": "extern_variable", + "name": "D_8009D85C", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D85C" + }, + { + "type": "extern_variable", + "name": "D_8009D85E", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D85E" + } + ], + "timestamp": "2026-04-22T19:49:21.935678" + }, + { + "function_name": "func_800A4134", + "file": "src/field/field.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80074EB0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB0" + }, + { + "type": "extern_variable", + "name": "D_80074EB4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB4" + }, + { + "type": "extern_variable", + "name": "D_80074EB8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB8" + }, + { + "type": "extern_variable", + "name": "D_800E0638", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E0638" + }, + { + "type": "extern_variable", + "name": "D_800E42D8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42D8" + }, + { + "type": "extern_variable", + "name": "D_800E42DA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42DA" + }, + { + "type": "extern_variable", + "name": "D_800E42DC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42DC" + }, + { + "type": "extern_variable", + "name": "D_800E42E0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E0" + }, + { + "type": "extern_variable", + "name": "D_800E42E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E4" + }, + { + "type": "extern_variable", + "name": "D_800E42E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E8" + }, + { + "type": "extern_variable", + "name": "D_800E42EA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42EA" + }, + { + "type": "extern_variable", + "name": "D_800E42EE", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42EE" + }, + { + "type": "extern_variable", + "name": "D_800E48E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E48E8" + }, + { + "type": "unknown_pointer", + "name": "var_t1", + "suggestion": "m2c could not determine type of pointer var_t1" + }, + { + "type": "unknown_pointer", + "name": "var_t1", + "suggestion": "m2c could not determine type of pointer var_t1" + } + ], + "timestamp": "2026-04-22T19:49:22.995885" + }, + { + "function_name": "func_80019064", + "file": "src/main/18B8.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80075D24", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D24" + }, + { + "type": "extern_variable", + "name": "D_80075D28", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D28" + }, + { + "type": "extern_variable", + "name": "D_80075DE8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075DE8" + }, + { + "type": "extern_variable", + "name": "D_8009D7E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E4" + }, + { + "type": "extern_variable", + "name": "D_8009D7E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E8" + }, + { + "type": "extern_variable", + "name": "D_8009D7EC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7EC" + }, + { + "type": "extern_variable", + "name": "D_8009D7ED", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7ED" + }, + { + "type": "extern_variable", + "name": "D_80069508", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069508" + }, + { + "type": "extern_variable", + "name": "D_800708C8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708C8" + }, + { + "type": "extern_variable", + "name": "D_800708D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708D0" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + } + ], + "timestamp": "2026-04-22T19:49:23.043726" + }, + { + "function_name": "func_800A73F8", + "file": "src/battle/battle.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_function", + "name": "func_800B13B0", + "return_type": "s32", + "parameters": "?, s32**", + "suggestion": "Define proper signature for func_800B13B0 in header" + }, + { + "type": "extern_variable", + "name": "D_800F3A40", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F3A40" + }, + { + "type": "extern_variable", + "name": "D_800F3A20", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F3A20" + }, + { + "type": "extern_variable", + "name": "D_800E7BEC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E7BEC" + }, + { + "type": "extern_variable", + "name": "D_800F49F8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F49F8" + } + ], + "timestamp": "2026-04-22T19:49:23.328645" + }, + { + "function_name": "func_800D7B1C", + "file": "src/battle/battle2.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_800F4CEC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F4CEC" + }, + { + "type": "extern_variable", + "name": "D_800F4D2C", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F4D2C" + }, + { + "type": "extern_variable", + "name": "func_800D6998", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_800D6998" + }, + { + "type": "extern_variable", + "name": "func_800D6ACC", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_800D6ACC" + }, + { + "type": "extern_variable", + "name": "func_800D6C20", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_800D6C20" + }, + { + "type": "unaligned_cast", + "cast_type": "s32", + "suggestion": "Unaligned access to s32 - may need struct packing or alignment fix" + } + ], + "timestamp": "2026-04-22T19:49:23.378987" + }, + { + "function_name": "func_800194BC", + "file": "src/main/18B8.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80075D24", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D24" + }, + { + "type": "extern_variable", + "name": "D_80075D28", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D28" + }, + { + "type": "extern_variable", + "name": "D_80075DE8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075DE8" + }, + { + "type": "extern_variable", + "name": "D_8009D7E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E4" + }, + { + "type": "extern_variable", + "name": "D_8009D7E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E8" + }, + { + "type": "extern_variable", + "name": "D_8009D7EC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7EC" + }, + { + "type": "extern_variable", + "name": "D_8009D7ED", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7ED" + }, + { + "type": "extern_variable", + "name": "D_80069508", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069508" + }, + { + "type": "extern_variable", + "name": "D_800708C8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708C8" + }, + { + "type": "extern_variable", + "name": "D_800708D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708D0" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + } + ], + "timestamp": "2026-04-22T19:49:23.904572" + }, + { + "function_name": "func_800D7BA4", + "file": "src/battle/battle2.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_800F4CEC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F4CEC" + }, + { + "type": "extern_variable", + "name": "D_800F4D2C", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F4D2C" + }, + { + "type": "extern_variable", + "name": "func_800D6998", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_800D6998" + }, + { + "type": "extern_variable", + "name": "func_800D6ACC", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_800D6ACC" + }, + { + "type": "extern_variable", + "name": "func_800D6C20", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_800D6C20" + }, + { + "type": "unaligned_cast", + "cast_type": "s32", + "suggestion": "Unaligned access to s32 - may need struct packing or alignment fix" + } + ], + "timestamp": "2026-04-22T19:49:24.330746" + }, + { + "function_name": "func_80018FC0", + "file": "src/main/18B8.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80075D24", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D24" + }, + { + "type": "extern_variable", + "name": "D_80075D28", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D28" + }, + { + "type": "extern_variable", + "name": "D_80075DE8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075DE8" + }, + { + "type": "extern_variable", + "name": "D_8009D7E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E4" + }, + { + "type": "extern_variable", + "name": "D_8009D7E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E8" + }, + { + "type": "extern_variable", + "name": "D_8009D7EC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7EC" + }, + { + "type": "extern_variable", + "name": "D_8009D7ED", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7ED" + }, + { + "type": "extern_variable", + "name": "D_80069508", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069508" + }, + { + "type": "extern_variable", + "name": "D_800708C8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708C8" + }, + { + "type": "extern_variable", + "name": "D_800708D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708D0" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + } + ], + "timestamp": "2026-04-22T19:49:24.574277" + }, + { + "function_name": "func_80018B14", + "file": "src/main/18B8.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80075D24", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D24" + }, + { + "type": "extern_variable", + "name": "D_80075D28", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D28" + }, + { + "type": "extern_variable", + "name": "D_80075DE8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075DE8" + }, + { + "type": "extern_variable", + "name": "D_8009D7E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E4" + }, + { + "type": "extern_variable", + "name": "D_8009D7E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E8" + }, + { + "type": "extern_variable", + "name": "D_8009D7EC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7EC" + }, + { + "type": "extern_variable", + "name": "D_8009D7ED", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7ED" + }, + { + "type": "extern_variable", + "name": "D_80069508", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069508" + }, + { + "type": "extern_variable", + "name": "D_800708C8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708C8" + }, + { + "type": "extern_variable", + "name": "D_800708D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708D0" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + } + ], + "timestamp": "2026-04-22T19:49:25.187217" + }, + { + "function_name": "func_80014BE4", + "file": "src/main/18B8.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80075D24", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D24" + }, + { + "type": "extern_variable", + "name": "D_80075D28", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D28" + }, + { + "type": "extern_variable", + "name": "D_80075DE8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075DE8" + }, + { + "type": "extern_variable", + "name": "D_8009D7E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E4" + }, + { + "type": "extern_variable", + "name": "D_8009D7E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E8" + }, + { + "type": "extern_variable", + "name": "D_8009D7EC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7EC" + }, + { + "type": "extern_variable", + "name": "D_8009D7ED", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7ED" + }, + { + "type": "extern_variable", + "name": "D_80069508", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069508" + }, + { + "type": "extern_variable", + "name": "D_800708C8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708C8" + }, + { + "type": "extern_variable", + "name": "D_800708D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708D0" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + } + ], + "timestamp": "2026-04-22T19:49:26.103628" + }, + { + "function_name": "func_800D828C", + "file": "src/field/field.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80074EB0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB0" + }, + { + "type": "extern_variable", + "name": "D_80074EB4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB4" + }, + { + "type": "extern_variable", + "name": "D_80074EB8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB8" + }, + { + "type": "extern_variable", + "name": "D_800E0638", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E0638" + }, + { + "type": "extern_variable", + "name": "D_800E42D8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42D8" + }, + { + "type": "extern_variable", + "name": "D_800E42DA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42DA" + }, + { + "type": "extern_variable", + "name": "D_800E42DC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42DC" + }, + { + "type": "extern_variable", + "name": "D_800E42E0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E0" + }, + { + "type": "extern_variable", + "name": "D_800E42E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E4" + }, + { + "type": "extern_variable", + "name": "D_800E42E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E8" + }, + { + "type": "extern_variable", + "name": "D_800E42EA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42EA" + }, + { + "type": "extern_variable", + "name": "D_800E42EE", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42EE" + }, + { + "type": "extern_variable", + "name": "D_800E48E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E48E8" + }, + { + "type": "unknown_pointer", + "name": "var_t1", + "suggestion": "m2c could not determine type of pointer var_t1" + }, + { + "type": "unknown_pointer", + "name": "var_t1", + "suggestion": "m2c could not determine type of pointer var_t1" + } + ], + "timestamp": "2026-04-22T19:49:26.143274" + }, + { + "function_name": "func_800D7C2C", + "file": "src/battle/battle2.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_800F4CEC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F4CEC" + }, + { + "type": "extern_variable", + "name": "D_800F4D2C", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F4D2C" + }, + { + "type": "extern_variable", + "name": "func_800D6998", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_800D6998" + }, + { + "type": "extern_variable", + "name": "func_800D6ACC", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_800D6ACC" + }, + { + "type": "extern_variable", + "name": "func_800D6C20", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_800D6C20" + }, + { + "type": "unaligned_cast", + "cast_type": "s32", + "suggestion": "Unaligned access to s32 - may need struct packing or alignment fix" + } + ], + "timestamp": "2026-04-22T19:49:26.412679" + }, + { + "function_name": "func_80014A84", + "file": "src/main/18B8.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80075D24", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D24" + }, + { + "type": "extern_variable", + "name": "D_80075D28", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D28" + }, + { + "type": "extern_variable", + "name": "D_80075DE8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075DE8" + }, + { + "type": "extern_variable", + "name": "D_8009D7E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E4" + }, + { + "type": "extern_variable", + "name": "D_8009D7E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E8" + }, + { + "type": "extern_variable", + "name": "D_8009D7EC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7EC" + }, + { + "type": "extern_variable", + "name": "D_8009D7ED", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7ED" + }, + { + "type": "extern_variable", + "name": "D_80069508", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069508" + }, + { + "type": "extern_variable", + "name": "D_800708C8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708C8" + }, + { + "type": "extern_variable", + "name": "D_800708D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708D0" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + } + ], + "timestamp": "2026-04-22T19:49:26.893989" + }, + { + "function_name": "func_800D8194", + "file": "src/field/field.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80074EB0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB0" + }, + { + "type": "extern_variable", + "name": "D_80074EB4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB4" + }, + { + "type": "extern_variable", + "name": "D_80074EB8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80074EB8" + }, + { + "type": "extern_variable", + "name": "D_800E0638", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E0638" + }, + { + "type": "extern_variable", + "name": "D_800E42D8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42D8" + }, + { + "type": "extern_variable", + "name": "D_800E42DA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42DA" + }, + { + "type": "extern_variable", + "name": "D_800E42DC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42DC" + }, + { + "type": "extern_variable", + "name": "D_800E42E0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E0" + }, + { + "type": "extern_variable", + "name": "D_800E42E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E4" + }, + { + "type": "extern_variable", + "name": "D_800E42E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42E8" + }, + { + "type": "extern_variable", + "name": "D_800E42EA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42EA" + }, + { + "type": "extern_variable", + "name": "D_800E42EE", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E42EE" + }, + { + "type": "extern_variable", + "name": "D_800E48E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800E48E8" + }, + { + "type": "unknown_pointer", + "name": "var_t1", + "suggestion": "m2c could not determine type of pointer var_t1" + }, + { + "type": "unknown_pointer", + "name": "var_t1", + "suggestion": "m2c could not determine type of pointer var_t1" + } + ], + "timestamp": "2026-04-22T19:49:26.913724" + }, + { + "function_name": "func_8001B834", + "file": "src/main/18B8.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80075D24", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D24" + }, + { + "type": "extern_variable", + "name": "D_80075D28", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D28" + }, + { + "type": "extern_variable", + "name": "D_80075DE8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075DE8" + }, + { + "type": "extern_variable", + "name": "D_8009D7E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E4" + }, + { + "type": "extern_variable", + "name": "D_8009D7E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E8" + }, + { + "type": "extern_variable", + "name": "D_8009D7EC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7EC" + }, + { + "type": "extern_variable", + "name": "D_8009D7ED", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7ED" + }, + { + "type": "extern_variable", + "name": "D_80069508", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069508" + }, + { + "type": "extern_variable", + "name": "D_800708C8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708C8" + }, + { + "type": "extern_variable", + "name": "D_800708D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708D0" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + } + ], + "timestamp": "2026-04-22T19:49:28.576126" + }, + { + "function_name": "func_80026090", + "file": "src/main/1255C.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_function", + "name": "func_80048540", + "return_type": "s32", + "parameters": "?", + "suggestion": "Define proper signature for func_80048540 in header" + }, + { + "type": "extern_function", + "name": "VSync", + "return_type": "unknown", + "parameters": "?", + "suggestion": "Define proper signature for VSync in header" + }, + { + "type": "extern_variable", + "name": "D_80069800", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069800" + }, + { + "type": "extern_variable", + "name": "D_80071E4D", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80071E4D" + }, + { + "type": "extern_variable", + "name": "D_800738BC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800738BC" + }, + { + "type": "extern_variable", + "name": "D_800491D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800491D0" + }, + { + "type": "extern_variable", + "name": "func_80017678", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_80017678" + }, + { + "type": "extern_variable", + "name": "func_8001786C", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_8001786C" + }, + { + "type": "extern_variable", + "name": "func_80020058", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_80020058" + }, + { + "type": "extern_variable", + "name": "D_8009D85C", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D85C" + }, + { + "type": "extern_variable", + "name": "D_8009D85E", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D85E" + } + ], + "timestamp": "2026-04-22T19:49:38.592150" + }, + { + "function_name": "func_80033A90", + "file": "src/main/akao.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [], + "timestamp": "2026-04-22T19:49:48.748419" + }, + { + "function_name": "func_800B798C", + "file": "src/battle/battle1.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "func_800C5BEC", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_800C5BEC" + }, + { + "type": "extern_variable", + "name": "D_801517F0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_801517F0" + }, + { + "type": "extern_variable", + "name": "D_800F7ED8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F7ED8" + }, + { + "type": "extern_variable", + "name": "D_800F7EDA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F7EDA" + }, + { + "type": "extern_variable", + "name": "D_800F9DA8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F9DA8" + } + ], + "timestamp": "2026-04-22T19:50:04.503099" + }, + { + "function_name": "func_800B3FAC", + "file": "src/battle/battle1.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "func_800C5BEC", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_800C5BEC" + }, + { + "type": "extern_variable", + "name": "D_801517F0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_801517F0" + }, + { + "type": "extern_variable", + "name": "D_800F7ED8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F7ED8" + }, + { + "type": "extern_variable", + "name": "D_800F7EDA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F7EDA" + }, + { + "type": "extern_variable", + "name": "D_800F9DA8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F9DA8" + } + ], + "timestamp": "2026-04-22T19:50:29.760023" + }, + { + "function_name": "func_800BFA98", + "file": "src/battle/battle1.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "func_800C5BEC", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_800C5BEC" + }, + { + "type": "extern_variable", + "name": "D_801517F0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_801517F0" + }, + { + "type": "extern_variable", + "name": "D_800F7ED8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F7ED8" + }, + { + "type": "extern_variable", + "name": "D_800F7EDA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F7EDA" + }, + { + "type": "extern_variable", + "name": "D_800F9DA8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F9DA8" + } + ], + "timestamp": "2026-04-22T19:50:34.925783" + }, + { + "function_name": "func_800BFB10", + "file": "src/battle/battle1.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "func_800C5BEC", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_800C5BEC" + }, + { + "type": "extern_variable", + "name": "D_801517F0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_801517F0" + }, + { + "type": "extern_variable", + "name": "D_800F7ED8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F7ED8" + }, + { + "type": "extern_variable", + "name": "D_800F7EDA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F7EDA" + }, + { + "type": "extern_variable", + "name": "D_800F9DA8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F9DA8" + } + ], + "timestamp": "2026-04-22T19:50:35.770248" + }, + { + "function_name": "func_800C20E8", + "file": "src/battle/battle1.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "func_800C5BEC", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_800C5BEC" + }, + { + "type": "extern_variable", + "name": "D_801517F0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_801517F0" + }, + { + "type": "extern_variable", + "name": "D_800F7ED8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F7ED8" + }, + { + "type": "extern_variable", + "name": "D_800F7EDA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F7EDA" + }, + { + "type": "extern_variable", + "name": "D_800F9DA8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F9DA8" + } + ], + "timestamp": "2026-04-22T19:50:43.205305" + }, + { + "function_name": "func_800BB684", + "file": "src/battle/battle1.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "func_800C5BEC", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_800C5BEC" + }, + { + "type": "extern_variable", + "name": "D_801517F0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_801517F0" + }, + { + "type": "extern_variable", + "name": "D_800F7ED8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F7ED8" + }, + { + "type": "extern_variable", + "name": "D_800F7EDA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F7EDA" + }, + { + "type": "extern_variable", + "name": "D_800F9DA8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F9DA8" + } + ], + "timestamp": "2026-04-22T19:50:43.886166" + }, + { + "function_name": "func_800BC1E0", + "file": "src/battle/battle1.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "func_800C5BEC", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_800C5BEC" + }, + { + "type": "extern_variable", + "name": "D_801517F0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_801517F0" + }, + { + "type": "extern_variable", + "name": "D_800F7ED8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F7ED8" + }, + { + "type": "extern_variable", + "name": "D_800F7EDA", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F7EDA" + }, + { + "type": "extern_variable", + "name": "D_800F9DA8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F9DA8" + } + ], + "timestamp": "2026-04-22T19:50:48.120759" + }, + { + "function_name": "func_8001DEF0", + "file": "src/main/18B8.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80075D24", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D24" + }, + { + "type": "extern_variable", + "name": "D_80075D28", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D28" + }, + { + "type": "extern_variable", + "name": "D_80075DE8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075DE8" + }, + { + "type": "extern_variable", + "name": "D_8009D7E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E4" + }, + { + "type": "extern_variable", + "name": "D_8009D7E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E8" + }, + { + "type": "extern_variable", + "name": "D_8009D7EC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7EC" + }, + { + "type": "extern_variable", + "name": "D_8009D7ED", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7ED" + }, + { + "type": "extern_variable", + "name": "D_80069508", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069508" + }, + { + "type": "extern_variable", + "name": "D_800708C8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708C8" + }, + { + "type": "extern_variable", + "name": "D_800708D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708D0" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + } + ], + "timestamp": "2026-04-22T19:56:20.640007" + }, + { + "function_name": "func_80014C44", + "file": "src/main/18B8.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80075D24", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D24" + }, + { + "type": "extern_variable", + "name": "D_80075D28", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D28" + }, + { + "type": "extern_variable", + "name": "D_80075DE8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075DE8" + }, + { + "type": "extern_variable", + "name": "D_8009D7E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E4" + }, + { + "type": "extern_variable", + "name": "D_8009D7E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E8" + }, + { + "type": "extern_variable", + "name": "D_8009D7EC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7EC" + }, + { + "type": "extern_variable", + "name": "D_8009D7ED", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7ED" + }, + { + "type": "extern_variable", + "name": "D_80069508", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069508" + }, + { + "type": "extern_variable", + "name": "D_800708C8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708C8" + }, + { + "type": "extern_variable", + "name": "D_800708D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708D0" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + } + ], + "timestamp": "2026-04-22T19:56:21.527396" + }, + { + "function_name": "func_8001A3B8", + "file": "src/main/18B8.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_80075D24", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D24" + }, + { + "type": "extern_variable", + "name": "D_80075D28", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075D28" + }, + { + "type": "extern_variable", + "name": "D_80075DE8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80075DE8" + }, + { + "type": "extern_variable", + "name": "D_8009D7E4", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E4" + }, + { + "type": "extern_variable", + "name": "D_8009D7E8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7E8" + }, + { + "type": "extern_variable", + "name": "D_8009D7EC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7EC" + }, + { + "type": "extern_variable", + "name": "D_8009D7ED", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_8009D7ED" + }, + { + "type": "extern_variable", + "name": "D_80069508", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_80069508" + }, + { + "type": "extern_variable", + "name": "D_800708C8", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708C8" + }, + { + "type": "extern_variable", + "name": "D_800708D0", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800708D0" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + }, + { + "type": "unknown_pointer", + "name": "var_t8", + "suggestion": "m2c could not determine type of pointer var_t8" + } + ], + "timestamp": "2026-04-22T19:56:22.188841" + }, + { + "function_name": "func_800CEB48", + "file": "src/battle/battle2.c", + "primary_error": "m2c added 1 decompilation failure comment(s) (dependency issues)", + "missing_items": [ + { + "type": "extern_variable", + "name": "D_800F4CEC", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F4CEC" + }, + { + "type": "extern_variable", + "name": "D_800F4D2C", + "declared_type": "s32", + "suggestion": "Unknown type for extern variable D_800F4D2C" + }, + { + "type": "extern_variable", + "name": "func_800D6998", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_800D6998" + }, + { + "type": "extern_variable", + "name": "func_800D6ACC", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_800D6ACC" + }, + { + "type": "extern_variable", + "name": "func_800D6C20", + "declared_type": "void", + "suggestion": "Unknown type for extern variable func_800D6C20" + }, + { + "type": "unaligned_cast", + "cast_type": "s32", + "suggestion": "Unaligned access to s32 - may need struct packing or alignment fix" + } + ], + "timestamp": "2026-04-23T13:14:10.335601" + } +] \ No newline at end of file diff --git a/automation/rank_all.md b/automation/rank_all.md new file mode 100644 index 0000000..256c7bf --- /dev/null +++ b/automation/rank_all.md @@ -0,0 +1,2312 @@ +# Function Rank (easiest → hardest) + +## battle + +| Score | Function | +| --- | --- | +| 0.197 | func_800B12DC.s | +| 0.200 | func_800D3520.s | +| 0.213 | func_800A4E00.s | +| 0.213 | func_800C5BEC.s | +| 0.217 | func_800B383C.s | +| 0.217 | func_800B38E0.s | +| 0.217 | func_800BB978.s | +| 0.217 | func_800BB4F8.s | +| 0.234 | func_800A6C04.s | +| 0.235 | func_800BB9B8.s | +| 0.235 | func_800BB9FC.s | +| 0.235 | func_800BBA40.s | +| 0.235 | func_800C03B8.s | +| 0.235 | func_800B1A5C.s | +| 0.246 | func_800B888C.s | +| 0.249 | func_800AD8DC.s | +| 0.253 | func_800A8D18.s | +| 0.253 | func_800A8C94.s | +| 0.253 | func_800A7090.s | +| 0.253 | func_800ADFC0.s | +| 0.253 | func_800AFE98.s | +| 0.266 | func_800E68B4.s | +| 0.268 | func_800D5774.s | +| 0.268 | func_800A3208.s | +| 0.268 | func_800A3240.s | +| 0.268 | func_800A55BC.s | +| 0.273 | func_800ADDE8.s | +| 0.273 | func_800B37A0.s | +| 0.285 | func_800C0900.s | +| 0.285 | func_800C0410.s | +| 0.293 | func_800B88CC.s | +| 0.293 | func_800B8360.s | +| 0.293 | func_800A8CC8.s | +| 0.293 | func_800B10B4.s | +| 0.294 | func_800DBEC8.s | +| 0.299 | func_800A5FB0.s | +| 0.304 | func_800AEB80.s | +| 0.305 | func_800AF834.s | +| 0.310 | func_800A67B8.s | +| 0.310 | func_800D8A88.s | +| 0.310 | func_800ADE84.s | +| 0.314 | func_800A66A4.s | +| 0.314 | func_800A6A70.s | +| 0.314 | func_800B2F70.s | +| 0.327 | func_800A3488.s | +| 0.328 | func_800B3FAC.s | +| 0.328 | func_800A5660.s | +| 0.337 | func_800AE25C.s | +| 0.355 | func_800A85FC.s | +| 0.360 | func_800D4FA8.s | +| 0.360 | func_800B1368.s | +| 0.362 | func_800A44D8.s | +| 0.368 | func_800A6B88.s | +| 0.369 | func_800AF594.s | +| 0.373 | func_800A661C.s | +| 0.374 | func_800B13B0.s | +| 0.378 | func_800B3968.s | +| 0.378 | func_800C614C.s | +| 0.378 | func_800A6E0C.s | +| 0.378 | func_800AEB20.s | +| 0.378 | func_800A73F8.s | +| 0.378 | func_800AD420.s | +| 0.378 | func_800AD890.s | +| 0.378 | func_800A6D3C.s | +| 0.380 | func_800A32C0.s | +| 0.383 | func_800D41FC.s | +| 0.383 | func_800A4F14.s | +| 0.392 | func_800B11B4.s | +| 0.396 | func_800B0E5C.s | +| 0.397 | func_800A853C.s | +| 0.397 | func_800B0EB4.s | +| 0.402 | func_800C627C.s | +| 0.407 | func_800B5CD4.s | +| 0.407 | func_800A6C5C.s | +| 0.407 | func_800D55A4.s | +| 0.407 | func_800A6CC0.s | +| 0.407 | func_800B1218.s | +| 0.409 | func_800B1304.s | +| 0.410 | func_800D51D4.s | +| 0.414 | func_800A4CC8.s | +| 0.417 | func_800B2EBC.s | +| 0.421 | func_800A6858.s | +| 0.421 | func_800A8DCC.s | +| 0.427 | func_800D3474.s | +| 0.428 | func_800A34CC.s | +| 0.432 | func_800D58D0.s | +| 0.434 | func_800D3354.s | +| 0.434 | func_800D83A4.s | +| 0.434 | func_800D32B4.s | +| 0.434 | func_800D8304.s | +| 0.434 | func_800AC6B4.s | +| 0.441 | func_800A55F4.s | +| 0.441 | func_800A283C.s | +| 0.445 | func_800AD088.s | +| 0.446 | func_800BC81C.s | +| 0.446 | func_800D34C8.s | +| 0.451 | func_800A65B0.s | +| 0.451 | func_800A4480.s | +| 0.451 | func_800BC2F0.s | +| 0.452 | func_800D3658.s | +| 0.457 | func_800B3C50.s | +| 0.457 | func_800D76B8.s | +| 0.457 | func_800A70C4.s | +| 0.457 | func_800A6AC4.s | +| 0.471 | func_800D3418.s | +| 0.472 | func_800D56A8.s | +| 0.477 | func_800B950C.s | +| 0.478 | func_800A2FD0.s | +| 0.478 | func_800E5FB4.s | +| 0.482 | func_800D3A6C.s | +| 0.482 | func_800ADFF4.s | +| 0.490 | func_800A61D4.s | +| 0.496 | func_800ACE14.s | +| 0.496 | func_800AA688.s | +| 0.496 | func_800A71F4.s | +| 0.502 | func_800A6D88.s | +| 0.502 | func_800A7254.s | +| 0.502 | func_800AE318.s | +| 0.503 | func_800B0B94.s | +| 0.503 | func_800B089C.s | +| 0.507 | func_800A311C.s | +| 0.507 | func_800A555C.s | +| 0.510 | func_800AD480.s | +| 0.515 | func_800A6B1C.s | +| 0.516 | func_800D72B4.s | +| 0.527 | func_800ADBBC.s | +| 0.527 | func_800B3A04.s | +| 0.527 | func_800B798C.s | +| 0.532 | func_800D5444.s | +| 0.546 | func_800D5230.s | +| 0.548 | func_800BC11C.s | +| 0.552 | func_800AB9C4.s | +| 0.552 | func_800AF1D4.s | +| 0.552 | func_800C20E8.s | +| 0.554 | func_800ACA4C.s | +| 0.557 | func_800D4CBC.s | +| 0.560 | func_800ADF38.s | +| 0.566 | func_800BBF7C.s | +| 0.566 | func_800BC04C.s | +| 0.566 | func_800BBEAC.s | +| 0.574 | func_800D55F4.s | +| 0.579 | func_800AD804.s | +| 0.582 | func_800D3F0C.s | +| 0.590 | func_800B1C1C.s | +| 0.594 | func_800AF494.s | +| 0.596 | func_800BA24C.s | +| 0.601 | func_800E58CC.s | +| 0.602 | func_800B3B84.s | +| 0.602 | func_800B3AB8.s | +| 0.604 | func_800A5E0C.s | +| 0.609 | func_800C1304.s | +| 0.610 | func_800B1268.s | +| 0.616 | func_800C5C18.s | +| 0.625 | func_800D09D0.s | +| 0.630 | func_800D6734.s | +| 0.630 | func_800D7B1C.s | +| 0.630 | func_800D7BA4.s | +| 0.640 | func_800B3030.s | +| 0.643 | func_800AB788.s | +| 0.644 | func_800E0530.s | +| 0.644 | func_800ACD88.s | +| 0.646 | func_800DF7CC.s | +| 0.648 | func_800C57B0.s | +| 0.649 | func_800D0958.s | +| 0.649 | func_800B1B64.s | +| 0.649 | func_800C0254.s | +| 0.653 | func_800DDC34.s | +| 0.653 | func_800AE2A0.s | +| 0.653 | func_800BFA98.s | +| 0.653 | func_800BFB10.s | +| 0.656 | func_800D508C.s | +| 0.661 | func_800A778C.s | +| 0.671 | func_800B8FCC.s | +| 0.672 | func_800BBA84.s | +| 0.672 | func_800E6018.s | +| 0.674 | func_800E1A2C.s | +| 0.676 | func_800B5C1C.s | +| 0.676 | func_800B153C.s | +| 0.678 | func_800D5138.s | +| 0.683 | func_801B1120.s | +| 0.693 | func_800AF264.s | +| 0.693 | func_800C2FD4.s | +| 0.693 | func_800DF24C.s | +| 0.694 | func_800C018C.s | +| 0.698 | func_800D7A88.s | +| 0.711 | func_800D3548.s | +| 0.714 | func_800DF530.s | +| 0.721 | func_800AE6C0.s | +| 0.725 | func_800E0794.s | +| 0.730 | func_800A64B4.s | +| 0.734 | func_800DF9F8.s | +| 0.738 | func_800B10F0.s | +| 0.756 | func_800A4860.s | +| 0.757 | func_800D5AC0.s | +| 0.757 | func_800AF3AC.s | +| 0.757 | func_800D61AC.s | +| 0.757 | func_800D415C.s | +| 0.773 | func_800D4FF0.s | +| 0.775 | func_800D6840.s | +| 0.776 | func_800ABA68.s | +| 0.776 | func_800D8468.s | +| 0.777 | func_800D52A0.s | +| 0.789 | func_800D4284.s | +| 0.789 | func_800A4E80.s | +| 0.795 | func_800B1624.s | +| 0.798 | func_800A56B0.s | +| 0.804 | func_800B1AA0.s | +| 0.806 | func_800BA2BC.s | +| 0.807 | func_800A5990.s | +| 0.809 | func_800BA360.s | +| 0.814 | func_800D70C0.s | +| 0.814 | func_800E5814.s | +| 0.824 | func_800D6394.s | +| 0.824 | func_800B8E48.s | +| 0.828 | func_800C2864.s | +| 0.829 | func_800D08B8.s | +| 0.835 | func_800A80DC.s | +| 0.837 | func_800A3354.s | +| 0.838 | func_800D7178.s | +| 0.838 | func_800D4C08.s | +| 0.838 | func_800DE3CC.s | +| 0.839 | func_800B141C.s | +| 0.840 | func_800B17F0.s | +| 0.846 | func_800A76CC.s | +| 0.846 | func_800C0314.s | +| 0.846 | func_800A7130.s | +| 0.848 | func_800D4368.s | +| 0.851 | func_800D461C.s | +| 0.851 | func_800D84F8.s | +| 0.854 | func_800B1C94.s | +| 0.856 | func_800C2F20.s | +| 0.858 | func_800D3AF0.s | +| 0.858 | func_800C61C0.s | +| 0.864 | func_800AF0C4.s | +| 0.867 | func_800AE764.s | +| 0.871 | func_800D54EC.s | +| 0.872 | func_800A4F60.s | +| 0.872 | func_800B16D0.s | +| 0.875 | func_800C5864.s | +| 0.879 | func_800ADC70.s | +| 0.879 | func_800ADD2C.s | +| 0.885 | func_800AD73C.s | +| 0.886 | func_800D3994.s | +| 0.886 | func_800A3534.s | +| 0.887 | func_800AE378.s | +| 0.888 | func_800BB684.s | +| 0.889 | func_800BB430.s | +| 0.898 | func_800B8EE4.s | +| 0.899 | func_800B45F0.s | +| 0.903 | func_800E15D8.s | +| 0.903 | func_800BC8B0.s | +| 0.903 | func_800BFF88.s | +| 0.904 | func_800E05E4.s | +| 0.905 | func_800A2894.s | +| 0.907 | func_800D7724.s | +| 0.912 | func_800C0088.s | +| 0.912 | func_800B8944.s | +| 0.916 | func_800E4A64.s | +| 0.916 | func_800B46B4.s | +| 0.917 | func_800C5ADC.s | +| 0.920 | func_800B0F04.s | +| 0.922 | func_800E53C8.s | +| 0.924 | func_800C7220.s | +| 0.926 | func_800A304C.s | +| 0.926 | func_800A4954.s | +| 0.926 | func_800C2150.s | +| 0.926 | func_800B0170.s | +| 0.928 | func_800BCA58.s | +| 0.932 | func_800A22C0.s | +| 0.932 | func_800D5350.s | +| 0.933 | func_800A8424.s | +| 0.934 | func_800BC754.s | +| 0.935 | func_800AD4EC.s | +| 0.936 | func_800DFA94.s | +| 0.936 | func_800A5EB0.s | +| 0.939 | func_801B13DC.s | +| 0.939 | func_800DDCE8.s | +| 0.939 | func_800BA11C.s | +| 0.940 | func_800B36B4.s | +| 0.947 | func_800D57C0.s | +| 0.949 | func_800A7458.s | +| 0.951 | func_800C2000.s | +| 0.951 | func_800E010C.s | +| 0.953 | func_800DE46C.s | +| 0.954 | func_800B079C.s | +| 0.955 | func_800AB674.s | +| 0.956 | func_800A68FC.s | +| 0.957 | func_800B2B5C.s | +| 0.957 | func_800BB538.s | +| 0.961 | func_800A784C.s | +| 0.963 | func_800B5E64.s | +| 0.964 | func_800DFE34.s | +| 0.964 | func_800D6998.s | +| 0.965 | func_800A72C8.s | +| 0.966 | func_800A4350.s | +| 0.966 | func_800DEB18.s | +| 0.966 | func_800D44E8.s | +| 0.969 | func_800C7340.s | +| 0.970 | func_800C59B8.s | +| 0.970 | func_800D7C2C.s | +| 0.970 | func_800DF5C8.s | +| 0.970 | func_800A5AC8.s | +| 0.972 | func_800DDE90.s | +| 0.973 | func_800BC348.s | +| 0.973 | func_800BC440.s | +| 0.973 | func_800BC538.s | +| 0.974 | func_800D6F78.s | +| 0.974 | func_800C44B4.s | +| 0.974 | func_800C4814.s | +| 0.975 | func_800C1394.s | +| 0.975 | func_800DE2B4.s | +| 0.976 | func_800BC630.s | +| 0.976 | func_800C3578.s | +| 0.976 | func_800C3CA8.s | +| 0.977 | func_800A2BF4.s | +| 0.978 | func_800B5FE8.s | +| 0.978 | func_800B5D38.s | +| 0.978 | func_800D7368.s | +| 0.979 | func_800DDAD8.s | +| 0.980 | func_800BC1E0.s | +| 0.982 | func_800D5938.s | +| 0.984 | func_800D751C.s | +| 0.985 | func_800A4BA4.s | +| 0.985 | func_800C14C0.s | +| 0.986 | func_800C3950.s | +| 0.987 | func_800B905C.s | +| 0.987 | func_800C0480.s | +| 0.987 | func_800C0970.s | +| 0.988 | func_800D6ACC.s | +| 0.988 | func_800B062C.s | +| 0.988 | func_800A50E0.s | +| 0.988 | func_800AE82C.s | +| 0.988 | func_800AA574.s | +| 0.988 | func_800C5694.s | +| 0.989 | func_800A35F8.s | +| 0.989 | func_800E4180.s | +| 0.989 | func_800D91DC.s | +| 0.989 | func_800A2DB0.s | +| 0.989 | func_800DE94C.s | +| 0.990 | func_800DBF8C.s | +| 0.990 | func_800B8A34.s | +| 0.990 | func_800E3E10.s | +| 0.990 | func_800D3BF0.s | +| 0.990 | func_800D376C.s | +| 0.991 | func_800C2704.s | +| 0.991 | func_800D6C20.s | +| 0.991 | func_800CD400.s | +| 0.991 | func_800DFFE4.s | +| 0.991 | func_800B2A2C.s | +| 0.991 | func_800C328C.s | +| 0.992 | func_800AEF68.s | +| 0.992 | func_800E6B94.s | +| 0.992 | func_800B18A8.s | +| 0.993 | func_801B1CB0.s | +| 0.993 | func_800D7888.s | +| 0.994 | func_800D491C.s | +| 0.994 | func_800AB830.s | +| 0.994 | func_800A3D4C.s | +| 0.995 | func_800AD5E8.s | +| 0.995 | func_800C3DE4.s | +| 0.995 | func_800D6260.s | +| 0.995 | func_800D650C.s | +| 0.995 | func_800C70AC.s | +| 0.995 | func_800B0234.s | +| 0.996 | func_800D4A64.s | +| 0.996 | func_800C40F4.s | +| 0.996 | func_800A2974.s | +| 0.997 | func_800AF874.s | +| 0.997 | func_800AB308.s | +| 0.997 | func_800A7560.s | +| 0.997 | func_800C64D4.s | +| 0.997 | func_800D9E0C.s | +| 0.998 | func_800E3FB4.s | +| 0.998 | func_800C6628.s | +| 0.998 | func_800A6000.s | +| 0.998 | func_800BB2A8.s | +| 0.998 | func_800D6D8C.s | +| 0.998 | func_800DF2CC.s | +| 0.998 | func_800B3E2C.s | +| 0.998 | func_800A6E9C.s | +| 0.998 | func_800E1AC0.s | +| 0.998 | func_800BE86C.s | +| 0.998 | func_800AD0FC.s | +| 0.998 | func_800B33A4.s | +| 0.998 | func_800D5B6C.s | +| 0.999 | func_801B0668.s | +| 0.999 | func_800C33F0.s | +| 0.999 | func_800AE954.s | +| 0.999 | func_800AA1C8.s | +| 0.999 | func_800BE69C.s | +| 0.999 | func_800B5AAC.s | +| 0.999 | func_800C5CC0.s | +| 0.999 | func_800AE080.s | +| 0.999 | func_800A8A6C.s | +| 0.999 | func_801B11BC.s | +| 0.999 | func_800C5E94.s | +| 0.999 | func_801B0F08.s | +| 0.999 | func_800C494C.s | +| 0.999 | func_800AA738.s | +| 0.999 | func_801B0050.s | +| 0.999 | func_800CD5E4.s | +| 1.000 | func_800A5BC8.s | +| 1.000 | func_800C3F44.s | +| 1.000 | func_800B430C.s | +| 1.000 | func_800AB480.s | +| 1.000 | func_800D4710.s | +| 1.000 | func_800B2CFC.s | +| 1.000 | func_801B1598.s | +| 1.000 | func_801B1734.s | +| 1.000 | func_800E6904.s | +| 1.000 | func_800C62F4.s | +| 1.000 | func_800D9BF4.s | +| 1.000 | func_800A6278.s | +| 1.000 | func_800AF65C.s | +| 1.000 | func_800E16B8.s | +| 1.000 | func_800C4DC8.s | +| 1.000 | func_800B7DB4.s | +| 1.000 | func_800B588C.s | +| 1.000 | func_800AA950.s | +| 1.000 | func_800C74E4.s | +| 1.000 | func_800B0C14.s | +| 1.000 | func_800BFDA0.s | +| 1.000 | func_800DDFEC.s | +| 1.000 | func_800B6B98.s | +| 1.000 | func_800C1104.s | +| 1.000 | func_800A5750.s | +| 1.000 | func_800D8B60.s | +| 1.000 | func_800B0378.s | +| 1.000 | func_800C1D8C.s | +| 1.000 | func_800C6CB8.s | +| 1.000 | func_800DBC18.s | +| 1.000 | func_800ACE88.s | +| 1.000 | func_800BE49C.s | +| 1.000 | func_800D87EC.s | +| 1.000 | func_800DFC40.s | +| 1.000 | func_800C3AA0.s | +| 1.000 | func_800BFB88.s | +| 1.000 | func_800DD85C.s | +| 1.000 | func_800B0910.s | +| 1.000 | func_800D85B0.s | +| 1.000 | func_800B7764.s | +| 1.000 | func_800C3068.s | +| 1.000 | func_800D4D90.s | +| 1.000 | func_800AD944.s | +| 1.000 | func_800B8B48.s | +| 1.000 | func_800C7924.s | +| 1.000 | func_800E0BE0.s | +| 1.000 | func_800E3B64.s | +| 1.000 | func_800E5530.s | +| 1.000 | func_800DE618.s | +| 1.000 | func_800C45EC.s | +| 1.000 | func_800C428C.s | +| 1.000 | func_800E33A0.s | +| 1.000 | func_800C76C8.s | +| 1.000 | func_800AFECC.s | +| 1.000 | func_800A81B8.s | +| 1.000 | func_800E3088.s | +| 1.000 | func_800BACEC.s | +| 1.000 | func_800D8D78.s | +| 1.000 | func_800C5170.s | +| 1.000 | func_800C2928.s | +| 1.000 | func_800E2C6C.s | +| 1.000 | func_800C2C1C.s | +| 1.000 | func_800AC73C.s | +| 1.000 | func_801B19AC.s | +| 1.000 | func_800AE42C.s | +| 1.000 | func_800C0B20.s | +| 1.000 | func_800A5250.s | +| 1.000 | func_800AEC10.s | +| 1.000 | func_800C36B4.s | +| 1.000 | func_800C0630.s | +| 1.000 | func_800B91CC.s | +| 1.000 | func_800ACB98.s | +| 1.000 | func_800B64CC.s | +| 1.000 | func_800C0DD8.s | +| 1.000 | func_800C679C.s | +| 1.000 | func_800A23E0.s | +| 1.000 | func_800B4E30.s | +| 1.000 | func_800A4540.s | +| 1.000 | func_800BBB20.s | +| 1.000 | func_800E08C4.s | +| 1.000 | func_800B3FFC.s | +| 1.000 | func_800B5138.s | +| 1.000 | func_800A38FC.s | +| 1.000 | func_800B54B8.s | +| 1.000 | func_800DCFD4.s | +| 1.000 | func_800DC0CC.s | +| 1.000 | func_800B4794.s | +| 1.000 | func_800DEC10.s | +| 1.000 | func_800B60E0.s | +| 1.000 | func_800DB818.s | +| 1.000 | func_800DA380.s | +| 1.000 | func_800D9FA4.s | +| 1.000 | func_800B677C.s | +| 1.000 | func_800C223C.s | +| 1.000 | func_800D93E4.s | +| 1.000 | func_800A3ED0.s | +| 1.000 | func_800BEA38.s | +| 1.000 | func_800BCB1C.s | +| 1.000 | func_800A1798.s | +| 1.000 | func_800A1158.s | +| 1.000 | func_801B1E0C.s | +| 1.000 | func_800E0E34.s | +| 1.000 | func_800B6D6C.s | +| 1.000 | func_800D7D3C.s | +| 1.000 | func_800B1D48.s | +| 1.000 | func_800C7C4C.s | +| 1.000 | func_800E1C40.s | +| 1.000 | func_800E2098.s | +| 1.000 | func_800CD860.s | +| 1.000 | func_800CEB48.s | +| 1.000 | func_800D5D28.s | +| 1.000 | func_800E368C.s | +| 1.000 | func_800D1530.s | +| 1.000 | func_800B79F0.s | +| 1.000 | func_800D29D4.s | +| 1.000 | func_800A79CC.s | +| 1.000 | func_800E4394.s | +| 1.000 | func_800AF9C8.s | +| 1.000 | func_800E4C08.s | +| 1.000 | func_800A866C.s | +| 1.000 | func_800A8E84.s | +| 1.000 | func_800A9DA0.s | +| 1.000 | func_800B9568.s | +| 1.000 | func_800E5978.s | +| 1.000 | func_801B08C0.s | +| 1.000 | func_800E60F8.s | +| 1.000 | func_800BA598.s | +| 1.000 | func_800AABBC.s | +| 1.000 | func_800ABB0C.s | +| 1.000 | func_800E6DCC.s | +| 1.000 | func_800E7170.s | + +## brom + +| Score | Function | +| --- | --- | +| 0.098 | func_800A015C.s | +| 0.170 | func_800A0514.s | +| 0.183 | func_800A01A0.s | +| 0.217 | func_800A0000.s | +| 0.346 | func_800A00CC.s | +| 0.749 | func_800A0534.s | +| 0.881 | func_800A05D4.s | + +## dschange + +| Score | Function | +| --- | --- | +| 1.000 | func_800A0000.s | +| 1.000 | func_800A0C58.s | + +## ending + +| Score | Function | +| --- | --- | +| 0.020 | func_800A2458.s | +| 0.092 | func_800A2248.s | +| 0.100 | func_800A1EE4.s | +| 0.110 | func_800A32FC.s | +| 0.110 | func_800A3308.s | +| 0.110 | func_800A32F0.s | +| 0.120 | func_800A20D4.s | +| 0.120 | func_800A1FA4.s | +| 0.120 | func_800A22D4.s | +| 0.120 | func_800A1ED4.s | +| 0.125 | func_800A24A8.s | +| 0.131 | func_800A23F8.s | +| 0.143 | func_800A32D8.s | +| 0.184 | func_800A2F1C.s | +| 0.184 | func_800A2E80.s | +| 0.185 | func_800A1FC8.s | +| 0.193 | func_800A2014.s | +| 0.200 | func_800A2190.s | +| 0.234 | func_800A2328.s | +| 0.235 | func_800A2274.s | +| 0.235 | func_800A22A4.s | +| 0.245 | func_800A2888.s | +| 0.253 | func_800A208C.s | +| 0.273 | func_800A2420.s | +| 0.315 | func_800A2934.s | +| 0.337 | func_800A22E4.s | +| 0.360 | func_800A1F48.s | +| 0.360 | func_800A1EEC.s | +| 0.416 | func_800A3314.s | +| 0.471 | func_800A12F0.s | +| 0.532 | func_800A2380.s | +| 0.582 | func_800A310C.s | +| 0.602 | func_800A21CC.s | +| 0.606 | func_800A20F8.s | +| 0.688 | func_800A343C.s | +| 0.746 | func_800A3178.s | +| 0.826 | func_800A34C4.s | +| 0.832 | func_800A09DC.s | +| 0.851 | func_800A2974.s | +| 0.859 | func_800A1E20.s | +| 0.912 | func_800A3368.s | +| 0.923 | func_800A0E68.s | +| 0.926 | func_800A3210.s | +| 0.958 | func_800A0AB8.s | +| 0.959 | func_800A16E4.s | +| 0.970 | func_800A273C.s | +| 0.975 | func_800A0BA8.s | +| 0.987 | func_800A139C.s | +| 0.989 | func_800A2504.s | +| 0.991 | func_800A11B4.s | +| 0.992 | func_800A2FB8.s | +| 0.996 | func_800A379C.s | +| 0.998 | func_800A17C0.s | +| 1.000 | func_800A0030.s | +| 1.000 | func_800A0CAC.s | +| 1.000 | func_800A358C.s | +| 1.000 | func_800A2C68.s | +| 1.000 | func_800A0F90.s | +| 1.000 | func_800A04C4.s | +| 1.000 | func_800A2A2C.s | +| 1.000 | func_800A14BC.s | +| 1.000 | func_800A19A4.s | + +## field + +| Score | Function | +| --- | --- | +| 0.170 | func_800A8600.s | +| 0.170 | func_800A8620.s | +| 0.213 | func_800C46A4.s | +| 0.217 | func_800D4E88.s | +| 0.235 | func_800C0BE8.s | +| 0.253 | func_800D8498.s | +| 0.268 | func_800AFDE4.s | +| 0.293 | func_800ABA34.s | +| 0.293 | func_800D4BC0.s | +| 0.310 | func_800D3B88.s | +| 0.310 | func_800D3C18.s | +| 0.310 | func_800C0EDC.s | +| 0.310 | func_800C0DE0.s | +| 0.315 | func_800DA194.s | +| 0.315 | func_800DA28C.s | +| 0.315 | func_800DA1D4.s | +| 0.332 | func_800C0E5C.s | +| 0.332 | func_800CC70C.s | +| 0.332 | func_800C0F58.s | +| 0.332 | func_800CC4D8.s | +| 0.337 | func_800DA2CC.s | +| 0.354 | func_800CBA28.s | +| 0.354 | func_800D3CA8.s | +| 0.354 | func_800CBDFC.s | +| 0.354 | func_800CB7C0.s | +| 0.354 | func_800CBB5C.s | +| 0.354 | func_800CB8F4.s | +| 0.355 | func_800CC5EC.s | +| 0.355 | func_800CC824.s | +| 0.355 | func_800C560C.s | +| 0.369 | func_800CF6C0.s | +| 0.373 | func_800D368C.s | +| 0.378 | func_800C493C.s | +| 0.378 | func_800CBF40.s | +| 0.378 | func_800CBCA4.s | +| 0.378 | func_800CC098.s | +| 0.378 | func_800CB858.s | +| 0.378 | func_800CBAC0.s | +| 0.378 | func_800CB98C.s | +| 0.378 | func_800C7CE8.s | +| 0.378 | func_800C814C.s | +| 0.378 | func_800C8514.s | +| 0.383 | func_800C4C9C.s | +| 0.398 | func_800AB2B4.s | +| 0.402 | func_800C1674.s | +| 0.402 | func_800CC134.s | +| 0.402 | func_800C17B8.s | +| 0.402 | func_800D3D40.s | +| 0.402 | func_800D4300.s | +| 0.416 | func_800CF66C.s | +| 0.421 | func_800D33FC.s | +| 0.426 | func_800D3264.s | +| 0.426 | func_800D3330.s | +| 0.426 | func_800C1714.s | +| 0.426 | func_800C0FD8.s | +| 0.426 | func_800CC9EC.s | +| 0.426 | func_800D1D3C.s | +| 0.446 | func_800D1FDC.s | +| 0.446 | func_800D1F20.s | +| 0.446 | func_800CC558.s | +| 0.451 | func_800C2F7C.s | +| 0.451 | func_800CCBBC.s | +| 0.451 | func_800C307C.s | +| 0.451 | func_800C2FFC.s | +| 0.471 | func_800CBE94.s | +| 0.471 | func_800CC358.s | +| 0.471 | func_800CC78C.s | +| 0.472 | func_800D48C0.s | +| 0.482 | func_800DA124.s | +| 0.485 | func_800B6AE4.s | +| 0.496 | func_800CBBF4.s | +| 0.496 | func_800CC1D4.s | +| 0.496 | func_800CC670.s | +| 0.496 | func_800CC8A8.s | +| 0.496 | func_800C4350.s | +| 0.497 | func_800D298C.s | +| 0.514 | func_800CEB20.s | +| 0.516 | func_800CB28C.s | +| 0.527 | func_800ABF0C.s | +| 0.527 | func_800CCCC8.s | +| 0.527 | func_800CCC3C.s | +| 0.532 | func_800A82A0.s | +| 0.532 | func_800D4E24.s | +| 0.541 | func_800D2098.s | +| 0.552 | func_800C3FA0.s | +| 0.552 | func_800C3EA0.s | +| 0.571 | func_800CBFDC.s | +| 0.571 | func_800CBD40.s | +| 0.577 | func_800CD16C.s | +| 0.577 | func_800CCA68.s | +| 0.577 | func_800C506C.s | +| 0.577 | func_800AB9C8.s | +| 0.577 | func_800D4BFC.s | +| 0.596 | func_800D3DCC.s | +| 0.601 | func_800D1B94.s | +| 0.601 | func_800D1C68.s | +| 0.601 | func_800CD5F0.s | +| 0.601 | func_800CD6B0.s | +| 0.601 | func_800CCB10.s | +| 0.601 | func_800C3F1C.s | +| 0.607 | func_800C2000.s | +| 0.607 | func_800C2970.s | +| 0.625 | func_800D2B60.s | +| 0.625 | func_800CB01C.s | +| 0.625 | func_800C401C.s | +| 0.626 | func_800D828C.s | +| 0.630 | func_800D8334.s | +| 0.644 | func_800CB1CC.s | +| 0.645 | func_800C2D54.s | +| 0.645 | func_800C2BFC.s | +| 0.645 | func_800C7C3C.s | +| 0.645 | func_800C81C0.s | +| 0.645 | func_800C8588.s | +| 0.648 | func_800D2A70.s | +| 0.648 | func_800CB5C0.s | +| 0.649 | func_800DA214.s | +| 0.651 | func_800A4134.s | +| 0.653 | func_800D83A8.s | +| 0.653 | func_800D8420.s | +| 0.656 | func_800CC284.s | +| 0.656 | func_800CC404.s | +| 0.671 | func_800D3E64.s | +| 0.684 | func_800D348C.s | +| 0.686 | func_800A4094.s | +| 0.688 | func_800CF200.s | +| 0.693 | func_800C4AE8.s | +| 0.693 | func_800CC944.s | +| 0.693 | func_800CB718.s | +| 0.693 | func_800CB450.s | +| 0.693 | func_800CFAF0.s | +| 0.698 | func_800A2F78.s | +| 0.710 | func_800CF2BC.s | +| 0.711 | func_800CB660.s | +| 0.712 | func_800BA534.s | +| 0.714 | func_800CD834.s | +| 0.714 | func_800CDA24.s | +| 0.714 | func_800CFB84.s | +| 0.722 | func_800BC438.s | +| 0.727 | func_800D28A8.s | +| 0.731 | func_800CAF60.s | +| 0.734 | func_800CD554.s | +| 0.745 | func_800D6D44.s | +| 0.749 | func_800AD7B8.s | +| 0.753 | func_800C42B0.s | +| 0.765 | func_800D2794.s | +| 0.770 | func_800CD770.s | +| 0.778 | func_800C45AC.s | +| 0.782 | func_800A635C.s | +| 0.785 | func_800C4BCC.s | +| 0.785 | func_800ACBA0.s | +| 0.786 | func_800CCFE8.s | +| 0.789 | func_800C46D0.s | +| 0.789 | func_800C5414.s | +| 0.789 | func_800D4378.s | +| 0.789 | func_800C54BC.s | +| 0.789 | func_800C5564.s | +| 0.789 | func_800D2E94.s | +| 0.789 | func_800C5194.s | +| 0.789 | func_800CD0C4.s | +| 0.789 | func_800C50EC.s | +| 0.793 | func_800C24A8.s | +| 0.795 | func_800D7C98.s | +| 0.799 | func_800D4780.s | +| 0.802 | func_800CF140.s | +| 0.805 | func_800C4804.s | +| 0.818 | func_800D8194.s | +| 0.832 | func_800D2F3C.s | +| 0.835 | func_800CB4F8.s | +| 0.835 | func_800D4160.s | +| 0.838 | func_800A48B8.s | +| 0.840 | func_800A1368.s | +| 0.840 | func_800ADC90.s | +| 0.846 | func_800CB0B8.s | +| 0.856 | func_800CF028.s | +| 0.866 | func_800C228C.s | +| 0.866 | func_800C1DE4.s | +| 0.866 | func_800C2754.s | +| 0.873 | func_800D184C.s | +| 0.873 | func_800CD214.s | +| 0.873 | func_800C1D24.s | +| 0.875 | func_800C5A2C.s | +| 0.882 | func_800DA4FC.s | +| 0.883 | func_800C6748.s | +| 0.887 | func_800C523C.s | +| 0.891 | func_800AB5E8.s | +| 0.891 | func_800CFC1C.s | +| 0.891 | func_800C728C.s | +| 0.891 | func_800CA95C.s | +| 0.891 | func_800CAA24.s | +| 0.891 | func_800D4420.s | +| 0.892 | func_800C31E4.s | +| 0.892 | func_800C30FC.s | +| 0.892 | func_800C32CC.s | +| 0.893 | func_800C1AB4.s | +| 0.897 | func_800C1EEC.s | +| 0.897 | func_800C2394.s | +| 0.897 | func_800C285C.s | +| 0.899 | func_800C4CE8.s | +| 0.899 | func_800C4DE8.s | +| 0.909 | func_800CA074.s | +| 0.914 | func_800A47F8.s | +| 0.916 | func_800AA870.s | +| 0.917 | func_800B0EDC.s | +| 0.925 | func_800C5668.s | +| 0.925 | func_800C684C.s | +| 0.925 | func_800AB310.s | +| 0.929 | func_800D3728.s | +| 0.929 | func_800D3840.s | +| 0.929 | func_800D3A70.s | +| 0.929 | func_800D3958.s | +| 0.939 | func_800CD91C.s | +| 0.939 | func_800CDB0C.s | +| 0.943 | func_800CF4CC.s | +| 0.943 | func_800BC338.s | +| 0.945 | func_800D4B28.s | +| 0.947 | func_800BEAD4.s | +| 0.947 | func_800C9C84.s | +| 0.947 | func_800C9D80.s | +| 0.947 | func_800C9B88.s | +| 0.947 | func_800C9E7C.s | +| 0.947 | func_800C9F78.s | +| 0.948 | func_800CA158.s | +| 0.948 | func_800CA394.s | +| 0.948 | func_800C532C.s | +| 0.950 | func_800CB354.s | +| 0.952 | func_800D85FC.s | +| 0.954 | func_800D4214.s | +| 0.957 | func_800CDC28.s | +| 0.957 | func_800D7970.s | +| 0.958 | func_800D3548.s | +| 0.961 | func_800CCE94.s | +| 0.961 | func_800CD2E8.s | +| 0.965 | func_800AA514.s | +| 0.967 | func_800A8858.s | +| 0.968 | func_800D6F6C.s | +| 0.969 | func_800D9F00.s | +| 0.971 | func_800D1DB8.s | +| 0.971 | func_800AB4AC.s | +| 0.972 | func_800D4038.s | +| 0.976 | func_800D1A80.s | +| 0.977 | func_800D775C.s | +| 0.977 | func_800D3F30.s | +| 0.977 | func_800D84CC.s | +| 0.979 | func_800CCD54.s | +| 0.979 | func_800D3004.s | +| 0.980 | func_800CF874.s | +| 0.980 | func_800C8F64.s | +| 0.980 | func_800CDD40.s | +| 0.980 | func_800B69C0.s | +| 0.981 | func_800D6E0C.s | +| 0.981 | func_800D785C.s | +| 0.981 | func_800CA254.s | +| 0.982 | func_800C5E80.s | +| 0.982 | func_800D152C.s | +| 0.986 | func_800CA490.s | +| 0.989 | func_800CF718.s | +| 0.989 | func_800CAC98.s | +| 0.989 | func_800CADFC.s | +| 0.989 | func_800C4EE8.s | +| 0.990 | func_800D9FFC.s | +| 0.990 | func_800CF9B8.s | +| 0.991 | func_800D3124.s | +| 0.991 | func_800D195C.s | +| 0.991 | func_800C5CE8.s | +| 0.991 | func_800C1BF4.s | +| 0.992 | func_800C2E00.s | +| 0.994 | func_800D0938.s | +| 0.995 | func_800C9A20.s | +| 0.995 | func_800CF368.s | +| 0.996 | func_800CFCE4.s | +| 0.996 | func_800C9080.s | +| 0.996 | func_800CD3F0.s | +| 0.996 | func_800D1200.s | +| 0.997 | func_800CA5D4.s | +| 0.997 | func_800C5740.s | +| 0.997 | func_800CAAEC.s | +| 0.997 | func_800A8E34.s | +| 0.998 | func_800AA180.s | +| 0.998 | func_800C0C18.s | +| 0.998 | func_800A6418.s | +| 0.998 | func_800AF96C.s | +| 0.998 | func_800B2DD4.s | +| 0.998 | func_800CEE44.s | +| 0.998 | func_800D4C68.s | +| 0.999 | func_800AA930.s | +| 0.999 | func_800A9B64.s | +| 0.999 | func_800CA77C.s | +| 0.999 | func_800AA348.s | +| 0.999 | func_800C5898.s | +| 0.999 | func_800CE054.s | +| 0.999 | func_800A424C.s | +| 0.999 | func_800A8640.s | +| 0.999 | func_800CDE8C.s | +| 0.999 | func_800A496C.s | +| 0.999 | func_800A14D8.s | +| 0.999 | func_800B1C7C.s | +| 0.999 | func_800CE6F4.s | +| 1.000 | func_800A2D5C.s | +| 1.000 | func_800D2C60.s | +| 1.000 | func_800CE904.s | +| 1.000 | func_800A4430.s | +| 1.000 | func_800AD858.s | +| 1.000 | func_800C40A4.s | +| 1.000 | func_800D707C.s | +| 1.000 | func_800C5B38.s | +| 1.000 | func_800C43C4.s | +| 1.000 | func_800C107C.s | +| 1.000 | func_800AA5E4.s | +| 1.000 | func_800D1350.s | +| 1.000 | func_800C1214.s | +| 1.000 | func_800D493C.s | +| 1.000 | func_800A9CE8.s | +| 1.000 | func_800ADAA4.s | +| 1.000 | func_800C3A20.s | +| 1.000 | func_800D1654.s | +| 1.000 | func_800D7D6C.s | +| 1.000 | func_800BB1B4.s | +| 1.000 | func_800CE214.s | +| 1.000 | func_800CE480.s | +| 1.000 | func_800C6D64.s | +| 1.000 | func_800A45D4.s | +| 1.000 | func_800D5A60.s | +| 1.000 | func_800BAF54.s | +| 1.000 | func_800C7354.s | +| 1.000 | func_800A9EEC.s | +| 1.000 | func_800C1858.s | +| 1.000 | func_800C6FD8.s | +| 1.000 | func_800C3C34.s | +| 1.000 | func_800D4EB4.s | +| 1.000 | func_800AF6EC.s | +| 1.000 | func_800D44E8.s | +| 1.000 | func_800B480C.s | +| 1.000 | func_800D7A58.s | +| 1.000 | func_800D579C.s | +| 1.000 | func_800AB728.s | +| 1.000 | func_800AE23C.s | +| 1.000 | func_800CEB94.s | +| 1.000 | func_800C826C.s | +| 1.000 | func_800C13B0.s | +| 1.000 | func_800B5260.s | +| 1.000 | func_800CFE78.s | +| 1.000 | func_800A8304.s | +| 1.000 | func_800D0180.s | +| 1.000 | func_800D9C04.s | +| 1.000 | func_800D0518.s | +| 1.000 | func_800ABFE8.s | +| 1.000 | func_800C63CC.s | +| 1.000 | func_800B2A00.s | +| 1.000 | func_800C8B98.s | +| 1.000 | func_800C91D8.s | +| 1.000 | func_800ABA70.s | +| 1.000 | func_800B4EAC.s | +| 1.000 | func_800BC9FC.s | +| 1.000 | func_800AFE1C.s | +| 1.000 | func_800AEE24.s | +| 1.000 | func_800AE4DC.s | +| 1.000 | func_800B0618.s | +| 1.000 | func_800ADD70.s | +| 1.000 | func_800BEE10.s | +| 1.000 | func_800BF3AC.s | +| 1.000 | func_800ACC5C.s | +| 1.000 | func_800B0A48.s | +| 1.000 | func_800AC35C.s | +| 1.000 | func_800B0FB0.s | +| 1.000 | func_800BF908.s | +| 1.000 | func_800BB3A8.s | +| 1.000 | func_800BC4D4.s | +| 1.000 | func_800AAB24.s | +| 1.000 | func_800C0248.s | +| 1.000 | func_800D0B4C.s | +| 1.000 | func_800B1E40.s | +| 1.000 | func_800B2598.s | +| 1.000 | func_800D5228.s | +| 1.000 | func_800BBF74.s | +| 1.000 | func_800B2F40.s | +| 1.000 | func_800D5C9C.s | +| 1.000 | func_800B4B04.s | +| 1.000 | func_800AFAC4.s | +| 1.000 | func_800C33B4.s | +| 1.000 | func_800B5504.s | +| 1.000 | func_800D726C.s | +| 1.000 | func_800C5FF4.s | +| 1.000 | func_800B62C4.s | +| 1.000 | func_800A8F88.s | +| 1.000 | func_800B6B4C.s | +| 1.000 | func_800BBBCC.s | +| 1.000 | func_800C6924.s | +| 1.000 | func_800A8968.s | +| 1.000 | func_800B79B8.s | +| 1.000 | func_800B86D8.s | +| 1.000 | func_800A65A4.s | +| 1.000 | func_800C75F0.s | +| 1.000 | func_800A5FB4.s | +| 1.000 | func_800A4BEC.s | +| 1.000 | func_800C7D5C.s | +| 1.000 | func_800D8710.s | +| 1.000 | func_800B8CF0.s | +| 1.000 | func_800B9B0C.s | +| 1.000 | func_800C8634.s | +| 1.000 | func_800BA7C4.s | +| 1.000 | func_800A364C.s | +| 1.000 | func_800A3020.s | +| 1.000 | func_800D2164.s | +| 1.000 | func_800A2314.s | +| 1.000 | func_800A16CC.s | +| 1.000 | func_800C955C.s | + +## main + +| Score | Function | +| --- | --- | +| 0.000 | D_8001029C.s | +| 0.011 | func_800197B8.s | +| 0.026 | func_8001A440.s | +| 0.035 | InitCARD.s | +| 0.045 | func_800299C8.s | +| 0.046 | func_80018D4C.s | +| 0.047 | StartCARD.s | +| 0.054 | func_80014804.s | +| 0.056 | func_80033BE0.s | +| 0.058 | func_80034150.s | +| 0.063 | func_800148B4.s | +| 0.063 | SsInitHot.s | +| 0.068 | func_8003408C.s | +| 0.073 | func_80026090.s | +| 0.092 | AverageSZ4.s | +| 0.092 | func_800425F8.s | +| 0.099 | rsin.s | +| 0.100 | StUnSetRing.s | +| 0.101 | CdReset.s | +| 0.106 | func_8001A174.s | +| 0.110 | func_8002C850.s | +| 0.110 | func_8002C81C.s | +| 0.110 | func_80036298.s | +| 0.110 | func_8003E2B0.s | +| 0.110 | PadStop.s | +| 0.110 | func_8003DE2C.s | +| 0.110 | DecDCToutSync.s | +| 0.110 | func_8003DD84.s | +| 0.110 | DecDCTout.s | +| 0.110 | func_800343F0.s | +| 0.110 | DecDCTinSync.s | +| 0.110 | StCdInterrupt2.s | +| 0.110 | func_80034F3C.s | +| 0.110 | func_8003DE4C.s | +| 0.110 | func_8002CF78.s | +| 0.110 | SetData32.s | +| 0.110 | SetDQB.s | +| 0.110 | func_800211B8.s | +| 0.110 | DecDCTBufSize.s | +| 0.110 | func_80023050.s | +| 0.110 | Lzc.s | +| 0.110 | SetDQA.s | +| 0.110 | func_80026A00.s | +| 0.110 | SetIR0.s | +| 0.110 | func_800155A4.s | +| 0.110 | func_80015B44.s | +| 0.110 | func_80026B64.s | +| 0.116 | func_8001A980.s | +| 0.118 | func_800294A4.s | +| 0.118 | DecDCTReset.s | +| 0.119 | func_800191A0.s | +| 0.120 | func_8002C408.s | +| 0.120 | func_8002BE2C.s | +| 0.120 | func_8002C0CC.s | +| 0.120 | func_8002BDCC.s | +| 0.120 | func_8002C3A8.s | +| 0.120 | func_8002C12C.s | +| 0.120 | func_80034104.s | +| 0.120 | func_80024A04.s | +| 0.120 | _card_clear.s | +| 0.120 | SpuSetPitchLFOVoice.s | +| 0.120 | CdMix.s | +| 0.120 | func_800293D0.s | +| 0.120 | SpuSetNoiseVoice.s | +| 0.120 | SpuSetReverbVoice.s | +| 0.120 | _SpuCallback.s | +| 0.120 | _SpuDataCallback.s | +| 0.120 | _addque.s | +| 0.120 | _cmp.s | +| 0.120 | DecDCToutCallback.s | +| 0.120 | DecDCTinCallback.s | +| 0.120 | func_8003E28C.s | +| 0.120 | CdGetSector.s | +| 0.120 | WaitEvent.s | +| 0.120 | firstfile.s | +| 0.120 | srand.s | +| 0.120 | func_8003FA9C.s | +| 0.120 | write.s | +| 0.120 | SetMem.s | +| 0.120 | SetSp.s | +| 0.120 | ChangeClearPAD.s | +| 0.120 | CdLastPos.s | +| 0.120 | nextfile.s | +| 0.120 | memset.s | +| 0.120 | strncmp.s | +| 0.120 | open.s | +| 0.120 | printf.s | +| 0.120 | strlen.s | +| 0.120 | ChangeClearRCnt.s | +| 0.120 | memcpy.s | +| 0.120 | puts.s | +| 0.120 | strcmp.s | +| 0.120 | SetVertex0.s | +| 0.120 | func_8003DCD8.s | +| 0.120 | DeliverEvent.s | +| 0.120 | SetVertex1.s | +| 0.120 | DisableEvent.s | +| 0.120 | SetVertex2.s | +| 0.120 | rand.s | +| 0.120 | EnableEvent.s | +| 0.120 | read.s | +| 0.120 | func_80034410.s | +| 0.120 | CloseEvent.s | +| 0.120 | SetGeomScreen.s | +| 0.120 | EnterCriticalSection.s | +| 0.120 | memchr.s | +| 0.120 | func_80023AC4.s | +| 0.120 | setjmp.s | +| 0.120 | StartCARD2.s | +| 0.120 | ExitCriticalSection.s | +| 0.120 | StartPAD.s | +| 0.120 | FlushCache.s | +| 0.120 | GPU_cw.s | +| 0.120 | StopPAD.s | +| 0.120 | format.s | +| 0.120 | ReturnFromException.s | +| 0.120 | exit.s | +| 0.120 | delete.s | +| 0.120 | SystemError.s | +| 0.120 | TestEvent.s | +| 0.120 | ResetEntryInt.s | +| 0.120 | UnDeliverEvent.s | +| 0.120 | close.s | +| 0.120 | ReadLZC.s | +| 0.120 | bcopy.s | +| 0.120 | ReadGeomScreen.s | +| 0.120 | AverageSZ3.s | +| 0.120 | _96_remove.s | +| 0.120 | GetGraphDebug.s | +| 0.120 | GetGraphType.s | +| 0.120 | PAD_init.s | +| 0.120 | GetVideoMode.s | +| 0.120 | HookEntryInt.s | +| 0.120 | PAD_dr.s | +| 0.120 | InitCARD2.s | +| 0.120 | InitHeap.s | +| 0.120 | InitPAD.s | +| 0.120 | CheckCallback.s | +| 0.120 | OpenTIM.s | +| 0.120 | _new_card.s | +| 0.120 | OpenEvent.s | +| 0.120 | func_8003DCF8.s | +| 0.120 | _bu_init.s | +| 0.120 | _card_auto.s | +| 0.120 | _card_info.s | +| 0.120 | func_8003DCE8.s | +| 0.120 | _card_write.s | +| 0.120 | _card_load.s | +| 0.121 | func_8001C788.s | +| 0.124 | func_80034F5C.s | +| 0.126 | func_80029A50.s | +| 0.130 | func_80018C94.s | +| 0.131 | PadInit.s | +| 0.131 | func_80034CAC.s | +| 0.131 | def_cbsync.s | +| 0.131 | def_cbready.s | +| 0.131 | def_cbread.s | +| 0.131 | VectorNormalS.s | +| 0.131 | SetTile1.s | +| 0.131 | func_80034D18.s | +| 0.131 | SetSXSYfifo.s | +| 0.131 | SetSZfifo3.s | +| 0.131 | SetRGBfifo.s | +| 0.131 | SetSprt.s | +| 0.131 | SetSprt16.s | +| 0.131 | SetPolyF4.s | +| 0.131 | SetPolyGT4.s | +| 0.131 | SetSprt8.s | +| 0.131 | SetPolyGT3.s | +| 0.131 | SetMAC123.s | +| 0.131 | func_8001C484.s | +| 0.131 | SetPolyG4.s | +| 0.131 | func_800148A0.s | +| 0.131 | SetPolyFT3.s | +| 0.131 | SetIR123.s | +| 0.131 | SetTile.s | +| 0.131 | SetRii.s | +| 0.131 | SetTile16.s | +| 0.131 | SetTile8.s | +| 0.131 | SetPolyG3.s | +| 0.131 | SetPolyF3.s | +| 0.131 | SetLineG2.s | +| 0.131 | SetPolyFT4.s | +| 0.131 | SetLineF2.s | +| 0.131 | func_80026A0C.s | +| 0.131 | func_80034430.s | +| 0.131 | SetBlockFill.s | +| 0.131 | func_80026A20.s | +| 0.140 | func_8002D410.s | +| 0.140 | func_8002D4A0.s | +| 0.141 | SpuStart.s | +| 0.143 | func_80041CD4.s | +| 0.143 | func_80029424.s | +| 0.143 | func_80029464.s | +| 0.143 | VectorNormal.s | +| 0.143 | GetClut.s | +| 0.143 | func_80041EFC.s | +| 0.143 | func_8003DE6C.s | +| 0.143 | GetIntrMask.s | +| 0.143 | _status.s | +| 0.143 | func_8003DDA4.s | +| 0.143 | TermPrim.s | +| 0.143 | _getctl.s | +| 0.143 | func_800269E8.s | +| 0.143 | func_8003DE84.s | +| 0.143 | ReadOTZ.s | +| 0.143 | func_8002C8C4.s | +| 0.143 | func_800269D0.s | +| 0.143 | SetVideoMode.s | +| 0.143 | SetSZfifo4.s | +| 0.145 | func_8002988C.s | +| 0.147 | func_80035CF0.s | +| 0.149 | func_80041AFC.s | +| 0.154 | SetSemiTrans.s | +| 0.154 | SetShadeTex.s | +| 0.156 | cd_read.s | +| 0.156 | StSetRing.s | +| 0.156 | func_800293F4.s | +| 0.156 | PadRead.s | +| 0.156 | SetDrawMove.s | +| 0.156 | NextPrim.s | +| 0.156 | SetIntrMask.s | +| 0.156 | IsEndPrim.s | +| 0.156 | NormalColor.s | +| 0.156 | DpqColor.s | +| 0.161 | func_8002D668.s | +| 0.161 | func_8002D530.s | +| 0.164 | SpuSetTransferMode.s | +| 0.164 | CdInit.s | +| 0.167 | func_8001A384.s | +| 0.167 | SpuSetIRQAddr.s | +| 0.170 | func_800211C4.s | +| 0.170 | set_alarm.s | +| 0.170 | AverageZ3.s | +| 0.170 | StSetMask.s | +| 0.170 | SetLineG3.s | +| 0.170 | SetFarColor.s | +| 0.170 | SetTransMatrix.s | +| 0.170 | NormalColorCol.s | +| 0.170 | SetGeomOffset.s | +| 0.170 | SetLineF3.s | +| 0.170 | SetLineG4.s | +| 0.170 | ReadGeomOffset.s | +| 0.170 | SetVertexTri.s | +| 0.170 | SetLineF4.s | +| 0.170 | SetBackColor.s | +| 0.178 | func_80034754.s | +| 0.181 | func_80014BE4.s | +| 0.181 | func_80048C58.s | +| 0.181 | SpuSetTransferCallback.s | +| 0.183 | func_800260DC.s | +| 0.185 | GetDispEnv.s | +| 0.185 | GetDrawEnv.s | +| 0.185 | func_8002BBB4.s | +| 0.185 | LocalLight.s | +| 0.185 | Intpl.s | +| 0.185 | AverageZ4.s | +| 0.185 | NormalColorDpq.s | +| 0.185 | CatPrim.s | +| 0.185 | ColorCol.s | +| 0.185 | VectorNormalSS.s | +| 0.190 | func_80035D64.s | +| 0.193 | func_80025174.s | +| 0.197 | _ExitCard.s | +| 0.197 | SetPriority.s | +| 0.197 | func_800346F8.s | +| 0.198 | func_80025B48.s | +| 0.198 | MargePrim.s | +| 0.200 | startIntrDMA.s | +| 0.200 | CD_initintr.s | +| 0.200 | SetTexWindow.s | +| 0.200 | func_8002BA5C.s | +| 0.200 | Square0.s | +| 0.200 | ColorDpq.s | +| 0.200 | Square12.s | +| 0.200 | LightColor.s | +| 0.200 | DpqColorLight.s | +| 0.210 | DMA_memclr.s | +| 0.210 | memclr.s | +| 0.210 | VSync_memclr.s | +| 0.210 | GPU_memset.s | +| 0.213 | setIntrVSync.s | +| 0.213 | func_80014C44.s | +| 0.214 | _spu_write.s | +| 0.214 | StGetBackloc.s | +| 0.214 | ResetRCnt.s | +| 0.214 | func_80019E4C.s | +| 0.214 | func_8003DDF4.s | +| 0.214 | func_80025B10.s | +| 0.214 | GetRCnt.s | +| 0.214 | func_8003DDBC.s | +| 0.216 | func_8001840C.s | +| 0.216 | func_80034350.s | +| 0.217 | _spu_read.s | +| 0.217 | OpenTMD.s | +| 0.217 | func_80026408.s | +| 0.217 | func_8001FA28.s | +| 0.217 | func_8002CC18.s | +| 0.217 | _ctl.s | +| 0.217 | func_8003345C.s | +| 0.217 | _spu_FsetDelayW.s | +| 0.217 | _spu_FsetDelayR.s | +| 0.219 | func_80014B08.s | +| 0.222 | func_8002120C.s | +| 0.228 | CdGetDiskType.s | +| 0.231 | func_80026258.s | +| 0.231 | func_80019D1C.s | +| 0.231 | SpuSetIRQCallback.s | +| 0.231 | DecDCTvlcSize.s | +| 0.231 | func_80048BBC.s | +| 0.231 | func_80029998.s | +| 0.231 | func_80015D14.s | +| 0.231 | _spu_FgetRXXa.s | +| 0.234 | startIntrVSync.s | +| 0.234 | SetDrawMode.s | +| 0.235 | func_800345BC.s | +| 0.235 | func_8001FA68.s | +| 0.235 | func_8001FAAC.s | +| 0.235 | SetDrawOffset.s | +| 0.235 | func_8003447C.s | +| 0.235 | func_800347B4.s | +| 0.235 | func_80031CB0.s | +| 0.235 | _param.s | +| 0.235 | RotTrans.s | +| 0.235 | SetLightMatrix.s | +| 0.235 | RestartCallback.s | +| 0.235 | RotTransSV.s | +| 0.235 | TransMatrix.s | +| 0.235 | ResetCallback.s | +| 0.235 | SetRotMatrix.s | +| 0.235 | VSyncCallbacks.s | +| 0.235 | DMACallback.s | +| 0.235 | SquareSL12.s | +| 0.235 | StopCallback.s | +| 0.235 | ApplyRotMatrix.s | +| 0.235 | InterruptCallback.s | +| 0.235 | func_800254E4.s | +| 0.235 | RotTransPers.s | +| 0.235 | SetColorMatrix.s | +| 0.235 | SquareSL0.s | +| 0.235 | func_8003CE0C.s | +| 0.235 | func_80034D2C.s | +| 0.235 | ChangeClearSIO.s | +| 0.238 | func_8002305C.s | +| 0.241 | func_8001A4A8.s | +| 0.243 | csqrt.s | +| 0.244 | func_8001A280.s | +| 0.245 | func_80041620.s | +| 0.245 | CD_memcpy.s | +| 0.245 | func_80029B78.s | +| 0.246 | func_80019440.s | +| 0.246 | func_80018390.s | +| 0.249 | func_800184C0.s | +| 0.249 | _patch_gte.s | +| 0.249 | func_8001DEF0.s | +| 0.250 | SpuSetTransferStartAddr.s | +| 0.253 | func_80022FE0.s | +| 0.253 | func_8002CEC0.s | +| 0.253 | func_8002CF1C.s | +| 0.253 | GetODE.s | +| 0.253 | StopRCnt.s | +| 0.253 | VSyncCallback.s | +| 0.253 | func_800257CC.s | +| 0.253 | func_8002C2CC.s | +| 0.253 | StartRCnt.s | +| 0.260 | func_8002D7A0.s | +| 0.260 | func_8002D8E8.s | +| 0.265 | CdRead2.s | +| 0.266 | func_80015C3C.s | +| 0.268 | func_800297A4.s | +| 0.268 | func_80029818.s | +| 0.268 | func_80014980.s | +| 0.268 | func_80015B50.s | +| 0.268 | func_80015B88.s | +| 0.268 | func_80034444.s | +| 0.273 | func_80026A34.s | +| 0.273 | SquareSS0.s | +| 0.273 | SquareSS12.s | +| 0.273 | func_8002BCCC.s | +| 0.273 | func_8002BFCC.s | +| 0.273 | func_80014B70.s | +| 0.281 | func_800146A4.s | +| 0.284 | startIntr.s | +| 0.284 | func_8001C498.s | +| 0.284 | SpuSetNoiseClock.s | +| 0.289 | func_80018E90.s | +| 0.289 | func_8003257C.s | +| 0.290 | func_80032C8C.s | +| 0.290 | func_80032CE8.s | +| 0.290 | get_ofs.s | +| 0.290 | _spu_FsetRXX.s | +| 0.291 | get_mode.s | +| 0.293 | func_80012840.s | +| 0.293 | func_8002E428.s | +| 0.293 | func_8001FF50.s | +| 0.293 | AddPrims.s | +| 0.293 | func_80014C80.s | +| 0.293 | DpqColor3.s | +| 0.293 | func_80033420.s | +| 0.293 | AddPrim.s | +| 0.293 | SetDefDispEnv.s | +| 0.293 | NormalColor3.s | +| 0.293 | func_8002001C.s | +| 0.305 | init_ring_status.s | +| 0.308 | func_80034600.s | +| 0.310 | func_8001DEB0.s | +| 0.310 | func_8002C884.s | +| 0.310 | func_8001DE70.s | +| 0.314 | func_8001117C.s | +| 0.314 | LoadClut.s | +| 0.315 | func_80033224.s | +| 0.315 | DumpClut.s | +| 0.327 | func_80032BB4.s | +| 0.327 | func_8001964C.s | +| 0.327 | func_80019608.s | +| 0.330 | func_800347F8.s | +| 0.330 | func_800344C0.s | +| 0.332 | _patch_card2.s | +| 0.332 | func_80019338.s | +| 0.332 | func_80031EEC.s | +| 0.337 | func_80031BA0.s | +| 0.337 | NormalColorCol3.s | +| 0.350 | func_80018028.s | +| 0.351 | func_80014E0C.s | +| 0.355 | func_8001FF8C.s | +| 0.355 | func_80015AFC.s | +| 0.355 | func_8001FFD4.s | +| 0.356 | ReadTIM.s | +| 0.356 | SpuInitMalloc.s | +| 0.360 | NormalColorDpq3.s | +| 0.360 | ReadRotMatrix.s | +| 0.360 | ReadLightMatrix.s | +| 0.368 | v_wait.s | +| 0.368 | func_80048540.s | +| 0.373 | SpuRead.s | +| 0.373 | func_80038F04.s | +| 0.374 | func_800348F4.s | +| 0.378 | func_800193F4.s | +| 0.379 | func_80032C20.s | +| 0.379 | func_80032718.s | +| 0.381 | memmove.s | +| 0.383 | StClearRing.s | +| 0.383 | func_80031AB0.s | +| 0.383 | _cwc.s | +| 0.392 | func_80025310.s | +| 0.392 | func_8002A748.s | +| 0.392 | func_8002A798.s | +| 0.397 | func_8002B1A8.s | +| 0.397 | _cwb.s | +| 0.399 | DecDCTin.s | +| 0.402 | func_8003252C.s | +| 0.407 | func_80021BAC.s | +| 0.407 | LoadImage.s | +| 0.407 | StoreImage.s | +| 0.407 | SpuGetReverbModeParam.s | +| 0.407 | LoadAverage0.s | +| 0.407 | LoadAverage12.s | +| 0.407 | ApplyMatrix.s | +| 0.407 | func_80034DB0.s | +| 0.407 | TransposeMatrix.s | +| 0.410 | func_80014A84.s | +| 0.417 | func_8001A3B8.s | +| 0.421 | func_80031E98.s | +| 0.423 | CdDiskReady.s | +| 0.428 | restartIntr.s | +| 0.428 | func_80032ABC.s | +| 0.428 | _spu_FwaitFs.s | +| 0.428 | _spu_FsetPCR.s | +| 0.430 | _SpuIsInAllocateArea.s | +| 0.432 | func_80034D5C.s | +| 0.432 | ReadColorMatrix.s | +| 0.432 | func_80036244.s | +| 0.440 | func_80034974.s | +| 0.446 | func_8001C5BC.s | +| 0.446 | func_8001BA54.s | +| 0.452 | func_8002CC44.s | +| 0.457 | _spu_r_.s | +| 0.457 | OuterProduct12.s | +| 0.457 | OuterProduct0.s | +| 0.457 | func_800331CC.s | +| 0.461 | func_8001C4E8.s | +| 0.465 | func_800135C0.s | +| 0.467 | sin_1.s | +| 0.477 | func_80013564.s | +| 0.477 | DrawSyncCallback.s | +| 0.478 | SpuSetVoiceLoopStartAddr.s | +| 0.478 | SpuSetVoiceStartAddr.s | +| 0.481 | SpuGetKeyStatus.s | +| 0.482 | func_80021E70.s | +| 0.482 | SetDrawArea.s | +| 0.485 | func_8001708C.s | +| 0.486 | func_8001A518.s | +| 0.486 | func_80025288.s | +| 0.496 | DecDCTPutEnv.s | +| 0.502 | _patch_card.s | +| 0.505 | _SpuIsInAllocateArea_.s | +| 0.507 | func_80021D5C.s | +| 0.507 | func_8001BD50.s | +| 0.507 | LoadAverageByte.s | +| 0.507 | RotTransPers3.s | +| 0.507 | ApplyMatrixSV.s | +| 0.507 | DrawPrim.s | +| 0.507 | RotAverage3.s | +| 0.510 | func_8002BBEC.s | +| 0.510 | func_8002C5C8.s | +| 0.510 | func_8002C6C8.s | +| 0.516 | func_8002CB78.s | +| 0.516 | func_8002C9E4.s | +| 0.518 | func_80041D28.s | +| 0.522 | func_80018E18.s | +| 0.522 | func_80018AB0.s | +| 0.527 | func_80033060.s | +| 0.527 | func_80032FFC.s | +| 0.527 | func_80032F98.s | +| 0.527 | func_80032F34.s | +| 0.527 | func_80032ED0.s | +| 0.527 | func_80032E08.s | +| 0.527 | func_80032E6C.s | +| 0.527 | func_800330C4.s | +| 0.528 | func_80032B30.s | +| 0.530 | func_80041E30.s | +| 0.532 | func_80011784.s | +| 0.535 | func_80032A28.s | +| 0.535 | func_800328F8.s | +| 0.535 | func_80032770.s | +| 0.536 | func_8001C3CC.s | +| 0.542 | func_80032D6C.s | +| 0.547 | func_80015BC0.s | +| 0.547 | func_8001BCE8.s | +| 0.547 | StopCARD2.s | +| 0.556 | _spu_FiDMA.s | +| 0.557 | func_80011BB4.s | +| 0.560 | func_8002BA98.s | +| 0.560 | func_8002C734.s | +| 0.560 | func_8002C634.s | +| 0.560 | func_8002BC58.s | +| 0.562 | rcos.s | +| 0.569 | SetRCnt.s | +| 0.574 | func_8002A6C4.s | +| 0.577 | SetGraphDebug.s | +| 0.577 | DrawSync.s | +| 0.582 | InitGeom.s | +| 0.591 | MDEC_out_sync.s | +| 0.591 | MDEC_in_sync.s | +| 0.596 | func_80019064.s | +| 0.596 | func_800134F4.s | +| 0.602 | SpuSetVoicePitch.s | +| 0.604 | func_8001A1C8.s | +| 0.606 | func_80021C4C.s | +| 0.609 | func_800155B0.s | +| 0.620 | func_800194BC.s | +| 0.620 | func_8001B834.s | +| 0.620 | func_80025040.s | +| 0.625 | func_80025668.s | +| 0.625 | DrawOTag.s | +| 0.625 | func_8001B570.s | +| 0.630 | StSetStream.s | +| 0.631 | func_80035658.s | +| 0.633 | func_8002BB20.s | +| 0.634 | SpuSetReverbDepth.s | +| 0.644 | trapIntrVSync.s | +| 0.649 | func_8003298C.s | +| 0.649 | func_80033C20.s | +| 0.650 | get_tw.s | +| 0.652 | func_8001C808.s | +| 0.652 | _spu_FsetRXXa.s | +| 0.653 | func_8001937C.s | +| 0.657 | func_80033CB8.s | +| 0.659 | get_dx.s | +| 0.662 | SpuSetVoiceVolumeAttr.s | +| 0.667 | func_80033264.s | +| 0.671 | func_800256DC.s | +| 0.672 | SpuSetVoiceSL.s | +| 0.672 | SpuSetVoiceVolume.s | +| 0.676 | MDEC_out.s | +| 0.683 | func_80035430.s | +| 0.684 | func_8001B4A0.s | +| 0.685 | func_8001FAF8.s | +| 0.689 | func_80036038.s | +| 0.692 | func_80025380.s | +| 0.693 | gteMIMefunc.s | +| 0.694 | func_80036190.s | +| 0.694 | SpuSetVoiceDR.s | +| 0.698 | MDEC_in.s | +| 0.698 | ClearImage.s | +| 0.698 | RotTransPers4.s | +| 0.698 | RotAverage4.s | +| 0.698 | CdPosToInt.s | +| 0.698 | LoadAverageCol.s | +| 0.698 | LoadTPage.s | +| 0.700 | func_80031CE0.s | +| 0.701 | func_8001C8D4.s | +| 0.709 | func_80034E00.s | +| 0.711 | func_800332EC.s | +| 0.714 | SetDefDrawEnv.s | +| 0.714 | stopIntr.s | +| 0.715 | _sync.s | +| 0.717 | func_80026B70.s | +| 0.721 | func_80031F30.s | +| 0.722 | SpuSetReverb.s | +| 0.724 | func_800484A8.s | +| 0.726 | SetDispMask.s | +| 0.734 | func_800185A8.s | +| 0.735 | func_800182FC.s | +| 0.738 | func_80029BAC.s | +| 0.738 | LoadAverageShort12.s | +| 0.738 | LoadAverageShort0.s | +| 0.738 | CD_vol.s | +| 0.742 | CD_searchdir.s | +| 0.745 | DecDCTGetEnv.s | +| 0.745 | InvSquareRoot.s | +| 0.751 | MDEC_reset.s | +| 0.753 | PushMatrix.s | +| 0.753 | PopMatrix.s | +| 0.757 | func_8001B8A8.s | +| 0.757 | func_80026A94.s | +| 0.758 | get_tim_addr.s | +| 0.758 | SpuSetVoiceSRAttr.s | +| 0.759 | func_80027354.s | +| 0.760 | func_80036100.s | +| 0.764 | func_800190E8.s | +| 0.764 | func_80018B14.s | +| 0.765 | func_80023788.s | +| 0.767 | func_8002FDA0.s | +| 0.768 | func_80018FC0.s | +| 0.772 | data_ready_callback.s | +| 0.773 | SpuSetVoiceARAttr.s | +| 0.783 | func_8002C300.s | +| 0.784 | func_80016F90.s | +| 0.785 | setIntrDMA.s | +| 0.786 | GetTPage.s | +| 0.789 | func_800129D0.s | +| 0.791 | func_80018220.s | +| 0.794 | func_80017E68.s | +| 0.796 | _version.s | +| 0.799 | func_80018A04.s | +| 0.802 | func_80019DA0.s | +| 0.802 | SetGraphQueue.s | +| 0.803 | SpuSetVoiceRRAttr.s | +| 0.803 | func_8003337C.s | +| 0.803 | SquareRoot0.s | +| 0.805 | ClearOTagR.s | +| 0.806 | RotAverageNclip3.s | +| 0.810 | func_80031AFC.s | +| 0.810 | func_80033128.s | +| 0.810 | func_80031BE4.s | +| 0.812 | func_8001FE6C.s | +| 0.814 | func_80019544.s | +| 0.817 | func_8002FF4C.s | +| 0.817 | func_80030148.s | +| 0.817 | MoveImage.s | +| 0.818 | DumpTPage.s | +| 0.821 | PutDrawEnv.s | +| 0.824 | func_80031820.s | +| 0.833 | StRingStatus.s | +| 0.835 | func_8001146C.s | +| 0.843 | func_8002CCDC.s | +| 0.843 | func_80013800.s | +| 0.856 | SquareRoot12.s | +| 0.858 | _SpuInit.s | +| 0.868 | func_80030038.s | +| 0.868 | func_80029E98.s | +| 0.871 | func_8001A780.s | +| 0.873 | func_8002B3B4.s | +| 0.874 | callback.s | +| 0.875 | MatrixNormal.s | +| 0.875 | DumpDispEnv.s | +| 0.879 | StFreeRing.s | +| 0.882 | func_80025988.s | +| 0.882 | func_80025800.s | +| 0.887 | func_80018BB8.s | +| 0.889 | func_8002CDD0.s | +| 0.890 | func_80017F38.s | +| 0.890 | func_8002C004.s | +| 0.890 | func_8002BD04.s | +| 0.895 | get_ce.s | +| 0.895 | get_cs.s | +| 0.898 | _otc.s | +| 0.899 | ClearOTag.s | +| 0.899 | _reset.s | +| 0.903 | RotAverageNclip4.s | +| 0.908 | func_80019254.s | +| 0.908 | func_80032804.s | +| 0.911 | func_8001BC18.s | +| 0.911 | func_80018934.s | +| 0.913 | __SN_ENTRY_POINT.s | +| 0.916 | func_8001B944.s | +| 0.921 | func_8002368C.s | +| 0.921 | func_80018ECC.s | +| 0.923 | SetFogNearFar.s | +| 0.923 | func_80034BB0.s | +| 0.923 | StGetNext.s | +| 0.925 | ResetGraph.s | +| 0.927 | func_8003A0E8.s | +| 0.927 | func_8002FE48.s | +| 0.928 | func_80035F14.s | +| 0.930 | func_800112E8.s | +| 0.930 | func_80025ED4.s | +| 0.930 | func_8002A43C.s | +| 0.933 | func_80011AEC.s | +| 0.934 | func_8001A684.s | +| 0.936 | func_8001B5E4.s | +| 0.938 | func_80025A44.s | +| 0.938 | func_800258BC.s | +| 0.940 | get_tmd_addr.s | +| 0.941 | func_80018834.s | +| 0.944 | checkRECT.s | +| 0.947 | CdControlB.s | +| 0.950 | func_8002CA84.s | +| 0.951 | func_8001A874.s | +| 0.953 | setIntr.s | +| 0.953 | func_80028484.s | +| 0.956 | func_8001AE08.s | +| 0.957 | CdControlF.s | +| 0.957 | func_800128B8.s | +| 0.958 | func_8001BB30.s | +| 0.959 | func_8001FBAC.s | +| 0.959 | func_8002D1E4.s | +| 0.961 | func_800138EC.s | +| 0.961 | CD_flush.s | +| 0.961 | func_80033A90.s | +| 0.964 | func_80032614.s | +| 0.964 | func_80019690.s | +| 0.966 | MulRotMatrix0.s | +| 0.967 | func_8002CFC0.s | +| 0.968 | func_80025514.s | +| 0.968 | CdControl.s | +| 0.969 | func_8002F738.s | +| 0.970 | MulRotMatrix.s | +| 0.970 | func_8002382C.s | +| 0.970 | func_80022B5C.s | +| 0.971 | func_80017108.s | +| 0.971 | func_80026F44.s | +| 0.972 | func_800150E4.s | +| 0.972 | func_80031D6C.s | +| 0.974 | main.s | +| 0.974 | func_8001B704.s | +| 0.975 | CD_datasync.s | +| 0.975 | func_8002C8DC.s | +| 0.976 | func_8002E23C.s | +| 0.976 | VSync.s | +| 0.976 | CD_initvol.s | +| 0.977 | func_80019E84.s | +| 0.977 | func_80024A3C.s | +| 0.978 | func_800318BC.s | +| 0.978 | func_80030234.s | +| 0.979 | func_800354CC.s | +| 0.979 | func_800159B0.s | +| 0.979 | timeout.s | +| 0.981 | get_alarm.s | +| 0.981 | func_800119E4.s | +| 0.982 | func_8002DF88.s | +| 0.982 | CD_getsector.s | +| 0.982 | func_80019F90.s | +| 0.983 | func_8001AB1C.s | +| 0.985 | SpuSetIRQ.s | +| 0.985 | CdIntToPos.s | +| 0.985 | SpuClearReverbWorkArea.s | +| 0.985 | SetGraphReverse.s | +| 0.985 | func_8001A9CC.s | +| 0.986 | csqrt_1.s | +| 0.986 | func_800262D8.s | +| 0.986 | func_8002A7E8.s | +| 0.987 | func_8001155C.s | +| 0.987 | func_800323CC.s | +| 0.987 | MulMatrix0.s | +| 0.988 | ratan2.s | +| 0.988 | func_80028CA0.s | +| 0.989 | MulMatrix.s | +| 0.989 | SetMulMatrix.s | +| 0.989 | MulMatrix2.s | +| 0.990 | func_80016808.s | +| 0.990 | func_8002D2D4.s | +| 0.991 | func_8002A958.s | +| 0.991 | func_80035DC8.s | +| 0.991 | func_800418D8.s | +| 0.993 | _spu_writeByIO.s | +| 0.993 | ScaleMatrixL.s | +| 0.994 | func_8001FCDC.s | +| 0.994 | CD_init.s | +| 0.995 | ScaleMatrix.s | +| 0.997 | func_800166C0.s | +| 0.997 | func_80023940.s | +| 0.997 | trapIntrDMA.s | +| 0.997 | func_80032274.s | +| 0.997 | func_8002A28C.s | +| 0.997 | DumpDrawEnv.s | +| 0.997 | func_80029F44.s | +| 0.998 | func_8001AC9C.s | +| 0.998 | func_8001C980.s | +| 0.998 | func_8002A510.s | +| 0.998 | CompMatrix.s | +| 0.999 | func_800487F0.s | +| 0.999 | func_80014E74.s | +| 0.999 | trapIntr.s | +| 0.999 | func_80015248.s | +| 0.999 | func_80041654.s | +| 0.999 | func_8002A094.s | +| 0.999 | func_8001F710.s | +| 0.999 | func_80033894.s | +| 0.999 | func_800320C4.s | +| 0.999 | func_80013624.s | +| 0.999 | ApplyMatrixLV.s | +| 1.000 | RotMatrixZ.s | +| 1.000 | RotMatrixY.s | +| 1.000 | RotMatrixX.s | +| 1.000 | func_80018630.s | +| 1.000 | _clr.s | +| 1.000 | CdSearchFile.s | +| 1.000 | _spu_init.s | +| 1.000 | func_80022DE4.s | +| 1.000 | CD_sync.s | +| 1.000 | SpuSetKey.s | +| 1.000 | func_8001CB48.s | +| 1.000 | CD_newmedia.s | +| 1.000 | func_80027990.s | +| 1.000 | CD_cachefile.s | +| 1.000 | func_80017678.s | +| 1.000 | _SpuSetAnyVoice.s | +| 1.000 | _spu_t.s | +| 1.000 | CD_ready.s | +| 1.000 | func_8002AFB8.s | +| 1.000 | SpuMallocWithStartAddr.s | +| 1.000 | _dws.s | +| 1.000 | SpuSetCommonAttr.s | +| 1.000 | func_8002708C.s | +| 1.000 | func_80029C48.s | +| 1.000 | _addque2.s | +| 1.000 | SetDrawEnv.s | +| 1.000 | func_80026C5C.s | +| 1.000 | _drs.s | +| 1.000 | func_80029114.s | +| 1.000 | func_8002DA7C.s | +| 1.000 | func_800485A0.s | +| 1.000 | func_8001EC70.s | +| 1.000 | func_800264A8.s | +| 1.000 | RotMatrixYXZ.s | +| 1.000 | RotMatrixZYX.s | +| 1.000 | RotMatrix.s | +| 1.000 | func_800140F4.s | +| 1.000 | func_80028E00.s | +| 1.000 | _spu_gcSPU.s | +| 1.000 | ReadTMD.s | +| 1.000 | _exeque.s | +| 1.000 | func_8001726C.s | +| 1.000 | func_8001C0EC.s | +| 1.000 | func_8001BDB0.s | +| 1.000 | func_800294BC.s | +| 1.000 | _SpuMallocSeparateTo3.s | +| 1.000 | func_80035744.s | +| 1.000 | func_800206E4.s | +| 1.000 | DecDCTvlc.s | +| 1.000 | func_80015668.s | +| 1.000 | PutDispEnv.s | +| 1.000 | func_800285AC.s | +| 1.000 | func_80028930.s | +| 1.000 | func_80028030.s | +| 1.000 | func_8002ED34.s | +| 1.000 | _spu_setReverbAttr.s | +| 1.000 | func_80027B84.s | +| 1.000 | func_800169B8.s | +| 1.000 | func_8003EF30.s | +| 1.000 | func_80019978.s | +| 1.000 | func_80016340.s | +| 1.000 | func_8002AABC.s | +| 1.000 | func_8001AEE4.s | +| 1.000 | func_80015D64.s | +| 1.000 | func_80040CA8.s | +| 1.000 | func_80027408.s | +| 1.000 | func_80013C9C.s | +| 1.000 | func_80030380.s | +| 1.000 | func_8002E478.s | +| 1.000 | func_8002E954.s | +| 1.000 | func_800212A8.s | +| 1.000 | func_80020B68.s | +| 1.000 | getintr.s | +| 1.000 | func_80023AD4.s | +| 1.000 | func_8001786C.s | +| 1.000 | func_8002F24C.s | +| 1.000 | sprintf.s | +| 1.000 | func_80020058.s | +| 1.000 | func_800308D4.s | +| 1.000 | func_80030E7C.s | +| 1.000 | func_800230C4.s | +| 1.000 | func_800131B8.s | +| 1.000 | func_8002F848.s | +| 1.000 | func_80012DB0.s | +| 1.000 | func_80021F58.s | +| 1.000 | func_8001F1BC.s | +| 1.000 | SpuSetReverbModeParam.s | +| 1.000 | func_80012A8C.s | +| 1.000 | func_80034FC8.s | +| 1.000 | unpack_packet.s | +| 1.000 | func_8001E040.s | +| 1.000 | func_8001D6A8.s | + +## menu + +| Score | Function | +| --- | --- | +| 0.778 | func_801D01C4.s | +| 0.785 | func_801D027C.s | +| 0.806 | func_801D1C2C.s | +| 0.848 | func_801D3478.s | +| 0.877 | func_801D0500.s | +| 0.916 | func_801D0324.s | +| 0.961 | func_801D0408.s | +| 0.998 | func_801D224C.s | +| 0.998 | func_801D1D40.s | +| 0.999 | func_801D1F40.s | +| 1.000 | func_801D2DA8.s | +| 1.000 | func_801D2408.s | +| 1.000 | func_801D080C.s | + +## world + +| Score | Function | +| --- | --- | +| 0.000 | func_800BBD20.s | +| 0.000 | func_800AC700.s | +| 0.004 | func_800A460C.s | +| 0.078 | func_800BB8E8.s | +| 0.127 | func_800AF110.s | +| 0.139 | func_800BBBB0.s | +| 0.150 | func_800B7A40.s | +| 0.153 | func_800AA640.s | +| 0.154 | func_800AF9A0.s | +| 0.156 | func_800B8720.s | +| 0.156 | func_800B7104.s | +| 0.156 | func_800B57C0.s | +| 0.156 | func_800A886C.s | +| 0.156 | func_800A1D38.s | +| 0.163 | func_800B6C84.s | +| 0.167 | func_800A6BCC.s | +| 0.167 | func_800A9174.s | +| 0.167 | func_800AA684.s | +| 0.167 | func_800A9154.s | +| 0.167 | func_800A9134.s | +| 0.167 | func_800A9910.s | +| 0.167 | func_800A9878.s | +| 0.167 | func_800A8F48.s | +| 0.167 | func_800A98E4.s | +| 0.167 | func_800A9A44.s | +| 0.167 | func_800A984C.s | +| 0.167 | func_800B2FA4.s | +| 0.167 | func_800A9AA4.s | +| 0.168 | func_800B6E78.s | +| 0.168 | func_800B832C.s | +| 0.170 | func_800B64D8.s | +| 0.170 | func_800B6570.s | +| 0.170 | func_800AA8D8.s | +| 0.181 | func_800B86E8.s | +| 0.181 | func_800B075C.s | +| 0.181 | func_800A9110.s | +| 0.181 | func_800B7B54.s | +| 0.181 | func_800A94D0.s | +| 0.181 | func_800A90EC.s | +| 0.181 | func_800B86C4.s | +| 0.182 | func_800A16E0.s | +| 0.185 | func_800A4080.s | +| 0.185 | func_800AE5B8.s | +| 0.185 | func_800AE5F0.s | +| 0.185 | func_800B7838.s | +| 0.185 | func_800B579C.s | +| 0.193 | func_800A91E0.s | +| 0.193 | func_800A91A4.s | +| 0.197 | func_800A94A8.s | +| 0.197 | func_800B7B78.s | +| 0.197 | func_800A9480.s | +| 0.197 | func_800BBA0C.s | +| 0.197 | func_800A1370.s | +| 0.198 | func_800A9AD0.s | +| 0.198 | func_800A9A70.s | +| 0.200 | func_800B650C.s | +| 0.200 | func_800B65A4.s | +| 0.200 | func_800A8AF4.s | +| 0.200 | func_800AE47C.s | +| 0.200 | func_800A31C0.s | +| 0.205 | func_800B2E90.s | +| 0.209 | func_800B858C.s | +| 0.209 | func_800A9988.s | +| 0.209 | func_800A8C70.s | +| 0.213 | func_800AB36C.s | +| 0.213 | func_800AA04C.s | +| 0.213 | func_800A94F4.s | +| 0.213 | func_800AA6A4.s | +| 0.213 | func_800A9820.s | +| 0.213 | func_800AA2B8.s | +| 0.213 | func_800B3018.s | +| 0.217 | func_800B0200.s | +| 0.217 | func_800B8D20.s | +| 0.217 | func_800B77F4.s | +| 0.226 | func_800A9018.s | +| 0.226 | func_800A8FCC.s | +| 0.227 | func_800A5970.s | +| 0.231 | func_800B84D8.s | +| 0.231 | func_800BCA48.s | +| 0.231 | func_800BB9A0.s | +| 0.231 | func_800A97E4.s | +| 0.231 | func_800BB9D0.s | +| 0.231 | func_800A97A8.s | +| 0.232 | func_800B79B8.s | +| 0.234 | func_800A1FAC.s | +| 0.235 | func_800B95E8.s | +| 0.240 | func_800A92F8.s | +| 0.245 | func_800A40F0.s | +| 0.245 | func_800A8A88.s | +| 0.246 | func_800A98A4.s | +| 0.246 | func_800AB8EC.s | +| 0.253 | func_800ADC3C.s | +| 0.254 | func_800AD928.s | +| 0.258 | func_800A99BC.s | +| 0.259 | func_800A8CA4.s | +| 0.263 | func_800AF1A8.s | +| 0.264 | func_800A8ABC.s | +| 0.268 | func_800A5924.s | +| 0.268 | func_800B77A8.s | +| 0.273 | func_800A7EA4.s | +| 0.273 | func_800B3044.s | +| 0.273 | func_800BB8B0.s | +| 0.279 | func_800A5A94.s | +| 0.289 | func_800BC9E8.s | +| 0.289 | func_800B7BD8.s | +| 0.293 | func_800B8488.s | +| 0.293 | func_800B8A5C.s | +| 0.293 | func_800B01C4.s | +| 0.293 | func_800B3350.s | +| 0.295 | func_800AB92C.s | +| 0.295 | func_800A929C.s | +| 0.295 | func_800A9240.s | +| 0.298 | func_800B7480.s | +| 0.300 | func_800B2FD0.s | +| 0.304 | func_800AA0E0.s | +| 0.304 | func_800AA098.s | +| 0.304 | func_800AA128.s | +| 0.304 | func_800AA170.s | +| 0.310 | func_800AF2A4.s | +| 0.310 | func_800AF324.s | +| 0.310 | func_800AF364.s | +| 0.310 | func_800A6B8C.s | +| 0.311 | func_800A5348.s | +| 0.317 | func_800A993C.s | +| 0.332 | func_800A8A1C.s | +| 0.340 | func_800B717C.s | +| 0.344 | func_800B5DD8.s | +| 0.345 | func_800ADA08.s | +| 0.350 | func_800B7AC0.s | +| 0.350 | func_800B37E0.s | +| 0.360 | func_800B017C.s | +| 0.363 | func_800AB570.s | +| 0.368 | func_800ABA18.s | +| 0.378 | func_800A9DB4.s | +| 0.378 | func_800B851C.s | +| 0.378 | func_800AF0B0.s | +| 0.390 | func_800A8CE4.s | +| 0.397 | func_800A4008.s | +| 0.402 | func_800ADFC0.s | +| 0.403 | func_800A0BE4.s | +| 0.407 | func_800B3300.s | +| 0.410 | func_800A8300.s | +| 0.414 | func_800AF1E8.s | +| 0.421 | func_800AD788.s | +| 0.421 | func_800C6598.s | +| 0.446 | func_800B0794.s | +| 0.447 | func_800B8760.s | +| 0.449 | func_800B338C.s | +| 0.451 | func_800AF24C.s | +| 0.471 | func_800A3EC8.s | +| 0.477 | func_800A1D54.s | +| 0.479 | func_800A692C.s | +| 0.480 | func_800A2108.s | +| 0.484 | func_800AB988.s | +| 0.490 | func_800AB48C.s | +| 0.503 | func_800A5A20.s | +| 0.507 | func_800B104C.s | +| 0.508 | func_800AD63C.s | +| 0.517 | func_800B3828.s | +| 0.520 | func_800B69A4.s | +| 0.532 | func_800B6A4C.s | +| 0.532 | func_800B8CBC.s | +| 0.536 | func_800AB4F4.s | +| 0.548 | func_800B65E0.s | +| 0.552 | func_800B8A98.s | +| 0.565 | func_800A4138.s | +| 0.566 | func_800A3F4C.s | +| 0.566 | func_800A5B88.s | +| 0.567 | func_800B85D4.s | +| 0.581 | func_800ADC80.s | +| 0.586 | func_800A4F08.s | +| 0.591 | func_800B6E08.s | +| 0.604 | func_800AD804.s | +| 0.610 | func_800B7620.s | +| 0.621 | func_800AA238.s | +| 0.621 | func_800AA1B8.s | +| 0.623 | func_800AFFBC.s | +| 0.625 | func_800AE0BC.s | +| 0.638 | func_800A2088.s | +| 0.644 | func_800ADE30.s | +| 0.647 | func_800A52A4.s | +| 0.653 | func_800B5274.s | +| 0.665 | func_800A6884.s | +| 0.669 | func_800A9064.s | +| 0.670 | func_800B0098.s | +| 0.672 | func_800A5208.s | +| 0.675 | func_800A0C54.s | +| 0.687 | func_800AAA00.s | +| 0.693 | func_800A59A0.s | +| 0.706 | func_800AA580.s | +| 0.718 | func_800ABA78.s | +| 0.718 | func_800A8898.s | +| 0.727 | func_800AB398.s | +| 0.730 | func_800B392C.s | +| 0.745 | func_800BA938.s | +| 0.749 | func_800C0808.s | +| 0.757 | func_800A0B48.s | +| 0.765 | func_800B63F0.s | +| 0.772 | func_800A60D8.s | +| 0.785 | func_800BFBF0.s | +| 0.786 | func_800A63FC.s | +| 0.786 | func_800AA6D0.s | +| 0.787 | func_800ADD4C.s | +| 0.792 | func_800AE024.s | +| 0.793 | func_800B7714.s | +| 0.793 | func_800B0D98.s | +| 0.795 | func_800BB7DC.s | +| 0.800 | func_800B57DC.s | +| 0.802 | func_800B6348.s | +| 0.805 | func_800AD970.s | +| 0.808 | func_800A5AD8.s | +| 0.817 | func_800A12AC.s | +| 0.828 | func_800B6D10.s | +| 0.841 | func_800A96D0.s | +| 0.843 | func_800AC3C0.s | +| 0.848 | func_800A67A8.s | +| 0.851 | func_800A9B04.s | +| 0.856 | func_800B0250.s | +| 0.861 | func_800B667C.s | +| 0.867 | func_800A806C.s | +| 0.875 | func_800A9C64.s | +| 0.885 | func_800B40B4.s | +| 0.889 | func_800BCA78.s | +| 0.903 | func_800ADA64.s | +| 0.904 | func_800B0670.s | +| 0.909 | func_800BCB2C.s | +| 0.911 | func_800A44C4.s | +| 0.916 | func_800A5C08.s | +| 0.917 | func_800C2450.s | +| 0.919 | func_800B58F8.s | +| 0.926 | func_800A891C.s | +| 0.943 | func_800A7F38.s | +| 0.945 | func_800B89C4.s | +| 0.948 | func_800B624C.s | +| 0.949 | func_800ABE58.s | +| 0.950 | func_800AA8F8.s | +| 0.951 | func_800B21E4.s | +| 0.956 | func_800ADEA8.s | +| 0.957 | func_800BB568.s | +| 0.957 | func_800A8E50.s | +| 0.957 | func_800A8D58.s | +| 0.959 | func_800A1DF0.s | +| 0.959 | func_800A5FB4.s | +| 0.963 | func_800A8B30.s | +| 0.966 | func_800B2638.s | +| 0.966 | func_800B0E84.s | +| 0.968 | func_800B271C.s | +| 0.968 | func_800BAB60.s | +| 0.972 | func_800AE4B8.s | +| 0.973 | func_800B10AC.s | +| 0.974 | func_800AA7DC.s | +| 0.975 | func_800A31F8.s | +| 0.976 | func_800A53A8.s | +| 0.977 | func_800BB350.s | +| 0.977 | func_800ADB30.s | +| 0.981 | func_800BAA00.s | +| 0.982 | func_800B7228.s | +| 0.982 | func_800AB5E4.s | +| 0.983 | func_800BB450.s | +| 0.985 | func_800A57C8.s | +| 0.988 | func_800A9520.s | +| 0.988 | func_800B787C.s | +| 0.990 | func_800A5D00.s | +| 0.991 | func_800B307C.s | +| 0.992 | func_800B6B28.s | +| 0.994 | func_800B0334.s | +| 0.994 | func_800A5E28.s | +| 0.994 | func_800B0BF4.s | +| 0.994 | func_800A4DDC.s | +| 0.995 | func_800AC484.s | +| 0.996 | func_800A3964.s | +| 0.996 | func_800A9E14.s | +| 0.996 | func_800AE8AC.s | +| 0.996 | func_800A3C74.s | +| 0.997 | func_800ABB24.s | +| 0.997 | func_800B6EFC.s | +| 0.998 | func_800A36AC.s | +| 0.998 | func_800BC1CC.s | +| 0.998 | func_800C1FD8.s | +| 0.998 | func_800B04AC.s | +| 0.998 | func_800A9334.s | +| 0.998 | func_800B8B00.s | +| 0.998 | func_800A86C4.s | +| 0.999 | func_800A141C.s | +| 1.000 | func_800A4268.s | +| 1.000 | func_800A6FC0.s | +| 1.000 | func_800A6994.s | +| 1.000 | func_800B5C7C.s | +| 1.000 | func_800BAC70.s | +| 1.000 | func_800BB650.s | +| 1.000 | func_800AB6E4.s | +| 1.000 | func_800A6168.s | +| 1.000 | func_800A64AC.s | +| 1.000 | func_800A54F0.s | +| 1.000 | func_800B87D8.s | +| 1.000 | func_800AE638.s | +| 1.000 | func_800AA304.s | +| 1.000 | func_800B98F0.s | +| 1.000 | func_800A6C3C.s | +| 1.000 | func_800A4F78.s | +| 1.000 | func_800B39B4.s | +| 1.000 | func_800AF9DC.s | +| 1.000 | func_800AE180.s | +| 1.000 | func_800B6724.s | +| 1.000 | func_800A19FC.s | +| 1.000 | func_800B59F4.s | +| 1.000 | func_800BCECC.s | +| 1.000 | func_800B190C.s | +| 1.000 | func_800B8D4C.s | +| 1.000 | func_800B3418.s | +| 1.000 | func_800C1D58.s | +| 1.000 | func_800A1710.s | +| 1.000 | func_800AFCC8.s | +| 1.000 | func_800A3304.s | +| 1.000 | func_800B1650.s | +| 1.000 | func_800B962C.s | +| 1.000 | func_800C08A8.s | +| 1.000 | func_800ABFC0.s | +| 1.000 | func_800BCBE8.s | +| 1.000 | func_800B7C7C.s | +| 1.000 | func_800A835C.s | +| 1.000 | func_800B2304.s | +| 1.000 | func_800C3DB0.s | +| 1.000 | func_800B29CC.s | +| 1.000 | func_800B5E28.s | +| 1.000 | func_800B0810.s | +| 1.000 | func_800B9B2C.s | +| 1.000 | func_800C0B48.s | +| 1.000 | func_800A71E8.s | +| 1.000 | func_800B4244.s | +| 1.000 | func_800B90C0.s | +| 1.000 | func_800B1C80.s | +| 1.000 | func_800A21B4.s | +| 1.000 | func_800BAE60.s | +| 1.000 | func_800AF3A4.s | +| 1.000 | func_800BFCAC.s | +| 1.000 | func_800C02F4.s | +| 1.000 | func_800B11C4.s | +| 1.000 | func_800AEA48.s | +| 1.000 | func_800BC420.s | +| 1.000 | func_800C1490.s | +| 1.000 | func_800B45DC.s | +| 1.000 | func_800AAB18.s | +| 1.000 | func_800C2130.s | +| 1.000 | func_800B3C40.s | +| 1.000 | func_800C2524.s | +| 1.000 | func_800C31F0.s | +| 1.000 | func_800C3948.s | +| 1.000 | func_800B5314.s | +| 1.000 | func_800C4148.s | +| 1.000 | func_800C4FB4.s | +| 1.000 | func_800C5CD4.s | +| 1.000 | func_800C6104.s | +| 1.000 | func_800A0D2C.s | diff --git a/automation/rank_all.py b/automation/rank_all.py new file mode 100644 index 0000000..ab04869 --- /dev/null +++ b/automation/rank_all.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +"""Run `./mako.sh rank ` for each module and combine results into a Markdown file.""" + +import subprocess +import sys +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parent.parent +MAKO = REPO_ROOT / "mako.sh" +OUTPUT = REPO_ROOT / "automation" / "rank_all.md" + +def discover_modules() -> list[str]: + asm_dir = REPO_ROOT / "asm" / "us" + return sorted(p.name for p in asm_dir.iterdir() if p.is_dir()) + + +def rank_module(module: str) -> list[str]: + result = subprocess.run( + [str(MAKO), "rank", module], + capture_output=True, + text=True, + cwd=REPO_ROOT, + ) + if result.returncode != 0: + print(f" WARNING: rank failed for {module}: {result.stderr.strip()}", file=sys.stderr) + return [] + lines = [l for l in result.stdout.splitlines() if l.strip()] + return lines + + +def main() -> None: + modules = discover_modules() + sections: list[str] = ["# Function Rank (easiest → hardest)\n"] + + for module in modules: + print(f"Ranking {module}...") + lines = rank_module(module) + sections.append(f"## {module}\n") + if lines: + rows = ["| Score | Function |", "| --- | --- |"] + for line in lines: + parts = line.split(": ", 1) + if len(parts) == 2: + score, func = parts + rows.append(f"| {score} | {func} |") + else: + rows.append(f"| — | {line} |") + sections.append("\n".join(rows)) + else: + sections.append("_No non-decompiled functions._") + sections.append("") + + output = "\n".join(sections) + OUTPUT.write_text(output, encoding="utf-8") + print(f"\nWrote {OUTPUT}") + + +if __name__ == "__main__": + main() diff --git a/automation/requirements.txt b/automation/requirements.txt new file mode 100644 index 0000000..cd674f4 --- /dev/null +++ b/automation/requirements.txt @@ -0,0 +1,6 @@ +# Chunk 1: Discovery & Database +# No external dependencies needed! Uses Python stdlib only. + +# Future chunks will add: +# requests>=2.31.0 # For API calls (Chunk 5) +# rich>=13.0.0 # For pretty CLI output (Chunk 6) diff --git a/automation/revert_nonmatching.py b/automation/revert_nonmatching.py new file mode 100644 index 0000000..342bf9a --- /dev/null +++ b/automation/revert_nonmatching.py @@ -0,0 +1,240 @@ +#!/usr/bin/env python3 +""" +Revert all decompiled/verified functions to INCLUDE_ASM stubs, then rebuild. + +This establishes a clean baseline where `make rebuild` passes all SHA1 checks +and creates the `expected/` directory that objdiff-cli needs for binary matching. +After running this script, restart the automation agent — it will use objdiff-cli +to verify each function against the reference before keeping decompiled code. + +Usage: + cd automation/ + python revert_nonmatching.py # Revert all + rebuild + python revert_nonmatching.py --dry-run # Preview without changes + python revert_nonmatching.py --module battle --skip-build + python revert_nonmatching.py --skip-build # Just revert, no rebuild +""" +import argparse +import re +import subprocess +import sys +from pathlib import Path +from typing import Dict, List, Optional, Tuple + +from database import DecompDatabase + +PROJECT_ROOT = Path(__file__).parent.parent + + +def get_include_asm_dir(asm_file_path: str) -> Optional[str]: + """Derive the INCLUDE_ASM directory argument from the DB asm_file_path. + + e.g. "asm/us/main/nonmatchings/18B8/func_80010000.s" + → "asm/us/main/nonmatchings/18B8" + """ + if not asm_file_path: + return None + return str(Path(asm_file_path).parent) + + +def replace_func_with_stub(content: str, func_name: str, asm_dir: str) -> Tuple[str, bool]: + """Replace a C function body definition with an INCLUDE_ASM stub. + + Locates the function definition by matching its header line ending with '{' + (not a prototype ending with ';'), walks brace-counting to the matching '}', + and replaces the entire range with a single INCLUDE_ASM line. + + Returns (new_content, was_replaced). + """ + pattern = re.compile( + r'^[^\s\n][^\n]*\b' + re.escape(func_name) + r'\s*\([^)]*\)[^;{]*\{', + re.MULTILINE, + ) + m = pattern.search(content) + if not m: + return content, False + + # Start of the definition (include the return-type line which starts at the + # previous newline, or at the very beginning of the file). + def_start = content.rfind('\n', 0, m.start()) + 1 + + # Walk from the opening '{' to find the matching closing '}' + depth = 0 + end_pos = None + for i in range(m.end() - 1, len(content)): + if content[i] == '{': + depth += 1 + elif content[i] == '}': + depth -= 1 + if depth == 0: + end_pos = i + break + if end_pos is None: + return content, False + + # Include the trailing newline after '}' + after_end = end_pos + 1 + if after_end < len(content) and content[after_end] == '\n': + after_end += 1 + + stub = f'INCLUDE_ASM("{asm_dir}", {func_name});\n' + return content[:def_start] + stub + content[after_end:], True + + +def run_rebuild(verbose: bool = False) -> bool: + """Run `make rebuild` from the project root and return True on success.""" + print("\nRunning make rebuild to establish expected/ baseline...") + result = subprocess.run( + ['make', 'rebuild'], + cwd=str(PROJECT_ROOT), + capture_output=not verbose, + text=True, + ) + if result.returncode == 0: + print("✅ make rebuild succeeded — expected/ baseline established") + return True + else: + print("❌ make rebuild failed") + if not verbose: + # Print the tail of the output to show what went wrong + combined = (result.stdout or '') + (result.stderr or '') + print(combined[-3000:]) + return False + + +def main(): + parser = argparse.ArgumentParser( + description='Revert decompiled functions to INCLUDE_ASM stubs for objdiff baseline') + parser.add_argument('--dry-run', action='store_true', + help='Show what would be done without writing changes') + parser.add_argument('--module', type=str, + help='Only process a specific module (e.g. battle, field)') + parser.add_argument('--skip-build', action='store_true', + help='Revert files but skip the make rebuild step') + parser.add_argument('--verbose', '-v', action='store_true', + help='Verbose output (also shows full build log)') + args = parser.parse_args() + + db = DecompDatabase() + + # Collect all functions that have been decompiled in any form + statuses = ['decompiled', 'verified', 'decompiled_needs_refine'] + functions: List[Dict] = [] + for status in statuses: + functions.extend(db.get_functions_by_status(status, module=args.module)) + + if not functions: + print("No decompiled/verified functions found — nothing to revert") + return + + print(f"Found {len(functions)} function(s) with statuses: {statuses}") + if args.module: + print(f" (filtered to module: {args.module})") + + # Group by C file so each file is read/written only once + by_file: Dict[str, List] = {} + for func in functions: + c_file = func.get('c_file_path') + if not c_file: + print(f" Warning: {func['name']} has no c_file_path, skipping") + continue + by_file.setdefault(c_file, []).append(func) + + print(f"Across {len(by_file)} C file(s)\n") + + reverted_total = 0 + skipped_total = 0 + reverted_names: List[str] = [] + + for rel_c_path, funcs_in_file in sorted(by_file.items()): + full_path = PROJECT_ROOT / rel_c_path + if not full_path.exists(): + print(f" ⚠️ File not found: {rel_c_path}") + skipped_total += len(funcs_in_file) + continue + + content = full_path.read_text() + file_reverted = 0 + + for func in funcs_in_file: + func_name = func['name'] + asm_dir = get_include_asm_dir(func.get('asm_file_path') or '') + + if not asm_dir: + print(f" ⚠️ {func_name}: no asm_file_path in DB — skipping") + skipped_total += 1 + continue + + # Already a stub? Nothing to do. + already_stub = re.search( + rf'INCLUDE_ASM\s*\(\s*"[^"]*"\s*,\s*{re.escape(func_name)}\s*\)', + content, + ) + if already_stub: + if args.verbose: + print(f" ⏭ {func_name}: already INCLUDE_ASM stub") + skipped_total += 1 + continue + + new_content, replaced = replace_func_with_stub(content, func_name, asm_dir) + if replaced: + content = new_content + file_reverted += 1 + reverted_names.append(func_name) + if args.verbose: + print(f" ✅ {func_name}: replaced with INCLUDE_ASM stub") + else: + if args.verbose: + print(f" ⚠️ {func_name}: body not found in file — already a stub?") + # Treat as already-stubbed (body not found means it was already replaced) + reverted_names.append(func_name) + file_reverted += 1 + + if file_reverted > 0: + if not args.dry_run: + full_path.write_text(content) + print(f" 📝 {rel_c_path}: reverted {file_reverted} function(s)") + else: + print(f" [DRY RUN] {rel_c_path}: would revert {file_reverted} function(s)") + + reverted_total += file_reverted + + print(f"\nReverted: {reverted_total} Skipped: {skipped_total}") + + if args.dry_run: + print("\n[DRY RUN] No files written, no DB changes, no rebuild.") + if not args.skip_build: + print("[DRY RUN] Would run: make rebuild") + return + + # Update DB: mark all reverted functions back to 'todo' + if reverted_names: + print("\nUpdating database...") + for func_name in reverted_names: + db.update_function_status( + func_name, 'todo', + notes='Reverted to INCLUDE_ASM stub for objdiff baseline rebuild') + print(f" Marked {len(reverted_names)} function(s) as 'todo'") + + if args.skip_build: + print("\nSkipping rebuild (--skip-build). Run `make rebuild` manually when ready.") + return + + success = run_rebuild(verbose=args.verbose) + if not success: + print("\n⚠️ Build failed after revert. Common causes:") + print(" - Remaining compile errors in C files (e.g. type conflicts in field.c/world.c)") + print(" - These are pre-existing issues unrelated to decompiled functions.") + print(" Re-run with --verbose for the full build output.") + sys.exit(1) + else: + print("\n✅ Baseline established.") + print(" The expected/ directory now has reference object files for objdiff-cli.") + print(" Next steps:") + print(" 1. Restart the automation agent — it will now verify each") + print(" decompiled function against the binary before keeping it.") + print(" 2. Run: python agent.py --run --verbose") + + +if __name__ == '__main__': + main() diff --git a/automation/review_llm_fixes.py b/automation/review_llm_fixes.py new file mode 100755 index 0000000..f9b2454 --- /dev/null +++ b/automation/review_llm_fixes.py @@ -0,0 +1,254 @@ +#!/usr/bin/env python3 +""" +Review LLM Auto-Fixes + +Helper tool to review functions that were automatically fixed by the LLM. +Shows functions marked as 'decompiled_needs_refine' from LLM fixes. + +Usage: + python review_llm_fixes.py --list # List all LLM-fixed functions + python review_llm_fixes.py --log # Show audit log + python review_llm_fixes.py --promote func # Promote to 'decompiled' after manual review + python review_llm_fixes.py --stats # Statistics on LLM fixes +""" + +import argparse +import sqlite3 +import json +from pathlib import Path +from datetime import datetime + +PROJECT_ROOT = Path(__file__).parent.parent +DB_PATH = Path(__file__).parent / "functions.db" +AUDIT_LOG = Path(__file__).parent / "llm_fixes_audit.log" + + +def list_llm_fixes(): + """List all functions with LLM auto-fixes.""" + conn = sqlite3.connect(DB_PATH) + conn.row_factory = sqlite3.Row + cursor = conn.cursor() + + # Find functions with LLM fix notes + cursor.execute(""" + SELECT name, status, c_file_path, notes, updated_at + FROM functions + WHERE notes LIKE '%LLM auto-fix%' + ORDER BY updated_at DESC + """) + + results = cursor.fetchall() + + if not results: + print("No LLM-fixed functions found.") + return + + print(f"\n{'='*80}") + print(f"LLM AUTO-FIXED FUNCTIONS ({len(results)} total)") + print(f"{'='*80}\n") + + needs_refine = [] + decompiled = [] + + for row in results: + # Try to parse JSON notes + try: + notes_data = json.loads(row['notes']) + if 'llm_analysis' in notes_data: + # This is just analysis, not a fix + continue + except (json.JSONDecodeError, TypeError): + pass + + # Check if it's an actual fix + if 'LLM auto-fix' not in row['notes']: + continue + + # Extract confidence + confidence = 'unknown' + if '(high confidence)' in row['notes']: + confidence = 'high' + elif '(medium confidence)' in row['notes']: + confidence = 'medium' + elif '(low confidence)' in row['notes']: + confidence = 'low' + + entry = { + 'name': row['name'], + 'status': row['status'], + 'file': row['c_file_path'], + 'confidence': confidence, + 'updated': row['updated_at'], + 'notes': row['notes'] + } + + if row['status'] == 'decompiled_needs_refine': + needs_refine.append(entry) + else: + decompiled.append(entry) + + # Show functions needing review + if needs_refine: + print(f"⚠️ NEEDS MANUAL REVIEW ({len(needs_refine)} functions):") + print(f"{'-'*80}") + for entry in needs_refine: + print(f" {entry['name']}") + print(f" File: {entry['file']}") + print(f" Confidence: {entry['confidence']}") + print(f" Updated: {entry['updated']}") + explanation = entry['notes'].split('): ', 1)[-1] if '): ' in entry['notes'] else '' + if explanation: + print(f" Fix: {explanation[:100]}...") + print() + + # Show already-decompiled (high confidence) + if decompiled: + print(f"\n✅ HIGH CONFIDENCE (already marked 'decompiled' - {len(decompiled)} functions):") + print(f"{'-'*80}") + for entry in decompiled[:5]: # Show first 5 + print(f" {entry['name']} ({entry['file']})") + if len(decompiled) > 5: + print(f" ... and {len(decompiled) - 5} more") + + conn.close() + + +def show_audit_log(): + """Display the audit log.""" + if not AUDIT_LOG.exists(): + print("No audit log found.") + return + + print(f"\n{'='*80}") + print("LLM FIX AUDIT LOG") + print(f"{'='*80}\n") + + with open(AUDIT_LOG, 'r') as f: + lines = f.readlines() + + if not lines: + print("Audit log is empty.") + return + + print(f"{'Timestamp':<20} {'Function':<25} {'Confidence':<10} {'Error Type'}") + print(f"{'-'*80}") + + for line in lines[-20:]: # Show last 20 + parts = line.strip().split('\t') + if len(parts) >= 6: + timestamp = parts[0].split('T')[0] # Just date + func_name = parts[1] + confidence = parts[3] + error_type = parts[4][:30] if len(parts[4]) > 30 else parts[4] + print(f"{timestamp:<20} {func_name:<25} {confidence:<10} {error_type}") + + if len(lines) > 20: + print(f"\n... showing last 20 of {len(lines)} entries") + + +def promote_function(func_name): + """Promote a function from needs_refine to decompiled after manual review.""" + conn = sqlite3.connect(DB_PATH) + cursor = conn.cursor() + + # Check current status + cursor.execute("SELECT status, notes FROM functions WHERE name = ?", (func_name,)) + row = cursor.fetchone() + + if not row: + print(f"Function {func_name} not found in database.") + return + + status, notes = row + + if status != 'decompiled_needs_refine': + print(f"Function {func_name} has status '{status}', not 'decompiled_needs_refine'.") + print("Only functions flagged for review can be promoted.") + return + + # Update status + cursor.execute(""" + UPDATE functions + SET status = 'decompiled', + notes = ?, + updated_at = CURRENT_TIMESTAMP + WHERE name = ? + """, (f"{notes} [Manually reviewed and promoted]", func_name)) + + conn.commit() + conn.close() + + print(f"✅ Promoted {func_name} to 'decompiled' status.") + print(f" Function has been manually reviewed and approved.") + + +def show_statistics(): + """Show statistics on LLM fixes.""" + conn = sqlite3.connect(DB_PATH) + cursor = conn.cursor() + + # Count LLM fixes by status + cursor.execute(""" + SELECT status, COUNT(*) as count + FROM functions + WHERE notes LIKE '%LLM auto-fix%' + GROUP BY status + """) + + stats = dict(cursor.fetchall()) + + # Count by confidence (from audit log) + confidence_counts = {'high': 0, 'medium': 0, 'low': 0} + if AUDIT_LOG.exists(): + with open(AUDIT_LOG, 'r') as f: + for line in f: + parts = line.strip().split('\t') + if len(parts) >= 4: + conf = parts[3] + if conf in confidence_counts: + confidence_counts[conf] += 1 + + print(f"\n{'='*60}") + print("LLM FIX STATISTICS") + print(f"{'='*60}\n") + + print("By Status:") + total = sum(stats.values()) + for status, count in stats.items(): + print(f" {status}: {count} ({count/total*100:.1f}%)") + + print(f"\nBy Confidence:") + conf_total = sum(confidence_counts.values()) + if conf_total > 0: + for conf, count in confidence_counts.items(): + print(f" {conf}: {count} ({count/conf_total*100:.1f}%)") + + print(f"\nTotal LLM fixes attempted: {conf_total}") + print(f"Functions needing review: {stats.get('decompiled_needs_refine', 0)}") + + conn.close() + + +def main(): + parser = argparse.ArgumentParser(description='Review LLM auto-fixes') + parser.add_argument('--list', action='store_true', help='List all LLM-fixed functions') + parser.add_argument('--log', action='store_true', help='Show audit log') + parser.add_argument('--stats', action='store_true', help='Show statistics') + parser.add_argument('--promote', metavar='FUNC', help='Promote function to decompiled after review') + + args = parser.parse_args() + + if args.list: + list_llm_fixes() + elif args.log: + show_audit_log() + elif args.stats: + show_statistics() + elif args.promote: + promote_function(args.promote) + else: + parser.print_help() + + +if __name__ == '__main__': + main() diff --git a/include/decomp_decls.h b/include/decomp_decls.h new file mode 100644 index 0000000..25d9ce7 --- /dev/null +++ b/include/decomp_decls.h @@ -0,0 +1,408 @@ +/* AUTO-GENERATED by automation/generate_decls.py — do not edit manually */ +/* Forward declarations for all decompiled functions, used as m2c context. */ +#ifndef DECOMP_DECLS_H +#define DECOMP_DECLS_H + +#include "common.h" + +void BATTLE_FlushImageQueue(void); +void BATTLE_ResetImageQueue(void); +s32 SYS_gil(void); +void SetReverbMode(s32 in_ReverbMode); +void SetupGamepad(void); +void __main(void); +void func_800111E4(void); +void func_80011274(void); +void func_8001171C(void); +void func_80011860(void); +void func_80011920(void); +void func_80011938(void); +void func_800140A4(void); +s32 func_800144D8(s32 file_no); +void func_800144F0(s32 file_no); +void func_80014510(s32 file_no); +void func_80014540(void); +void func_80014608(void); +void func_80014610(void); +void func_800146A4(void); +void func_80014750(void); +void func_80014934(void); +void func_800149E0(void); +void func_80014A00(s32* dst, s32* src, s32 len); +s32 func_80014A38(u32 arg0); +s32 func_80014A58(u32 arg0); +void func_80014B54(void); +s32 func_80014BA8(s32 arg0); +void func_80014C44(s32 arg0); +void func_80014C70(void); +s32 func_80014CBC(s32 arg0, s32 arg1); +u8* func_80014D58(u8* arg0, u8* arg1, s32 arg2); +u16* func_80014D9C(s32 arg0, s32 arg1, s32 arg2); +void func_80014DD0(s32 arg0, s32 arg1, u8* arg2); +u16* func_800151F4(s32 arg0); +s32 func_8001521C(s32 arg0); +void func_80015654(s32 arg0); +s32 func_80015C3C(u8* src, void* dst, s32 id); +s32 func_80016320(s32* arg0); +void func_80017238(u32 arg0, u32* arg1, u8* arg2); +void func_80019D74(u8 arg0, u8 arg1); +void func_8001A384(u8 arg0, s32 arg1); +void func_8001A3B8(s32 arg0, s32 arg1, s32 arg2); +void func_8001A5B4(u8 arg0, u8 arg1, s32 arg2); +s32 func_8001AC9C(u8 arg0, s32 arg1); +void func_8001C3C4(void); +void func_8001C58C(void); +void func_8001CDA4(void); +void func_8001CF3C(s16 x, s16 y, s16 w, s16 h, u16 tx, u16 ty, u16 tw, u16 th, s16 clut, s32 tex); +void func_8001D180(s16 x, s16 y, s16 w, s16 h, u16 tx, u16 ty, u16 tw, u16 th, s16 clut, s32 tex); +void func_8001D3C0(s16 x, s16 y); +void func_8001D47C(s16 x0, s16 x1, s16 y, s32 color); +void func_8001D56C(s16 x0, s16 y0, s16 x1, s16 y1, s16 is_yellow); +void func_8001DEF0(u8* menu_colors); +void func_8001EB2C(s16 x, s16 y); +void func_8001EF84(s32 x, s32 y, s32 n, s32 len); +void func_8001F6AC(void); +u8 func_8001F6B4(void); +void func_8001F6C0(s32 arg0, s8 arg1); +void func_8001F6E4(s16 arg0, s16 arg1, s16 arg2); +void func_8001FAF0(void); +void func_80021258(s32 arg0); +void func_80021280(s32 arg0); +void func_80024D88(s32 arg0); +void func_80024DD4(s32 arg0); +void func_80024E18(s32 arg0); +void func_80024E5C(void); +void func_80024E94(void); +void func_80024ECC(void); +void func_80024F04(void); +void func_80024F3C(s32 arg0); +void func_80024F80(s32 arg0); +void func_80024FC4(s32 arg0); +void func_80025008(void); +void func_800250B4(void); +void func_800250EC(s32 arg0); +void func_80025130(s32 arg0); +void func_80025360(void); +s32 func_8002542C(s32 arg0); +void func_800254D8(void); +void func_80025648(void); +void func_80025650(void); +s32 func_80025658(void); +s32* func_80025758(s32 arg0); +s32* func_80025774(s32 arg0); +void func_800257C4(void); +void func_80025DF8(void); +void func_80026034(void); +s32 func_8002603C(u8 arg0); +void func_800269C0(void* arg0); +void func_80026B5C(void); +void func_8002BE8C(s32 arg0); +void func_8002BEB4(s32 arg0); +void func_8002BEDC(s32 arg0); +void func_8002BF04(s32 arg0); +void func_8002BF2C(s32 arg0); +void func_8002BF54(s32 arg0); +void func_8002BF7C(s32 arg0); +void func_8002BFA4(s32 arg0); +void func_8002C18C(s32 arg0); +void func_8002C1B4(s32 arg0); +void func_8002C1DC(s32 arg0); +void func_8002C204(s32 arg0); +void func_8002C22C(s32 arg0); +void func_8002C254(s32 arg0); +void func_8002C27C(s32 arg0); +void func_8002C2A4(s32 arg0); +void func_8002C468(s32 arg0); +void func_8002C490(s32 arg0); +void func_8002C4B8(s32 arg0); +void func_8002C4E0(s32 arg0); +void func_8002C508(s32 arg0); +void func_8002C530(s32 arg0); +void func_8002C558(s32 arg0); +void func_8002C580(s32 arg0); +void func_8002C7A8(void); +void func_8002C7C8(void); +void func_8002C7E8(void); +void func_8002CCBC(void); +void func_8002CCCC(void); +void func_8002CFA0(void); +void func_8002E1A8(void); +u8 func_80031A70(u8** arg0); +void func_80032D50(void); +void func_80032D64(void); +void func_80033B70(void); +int func_80033DE4(int sector_no); +void func_80034048(void); +void func_80034420(void); +void func_80034428(void); +void func_80034A58(void); +void func_80034A90(void); +u32 func_80034B44(void); +void func_800A1498(void); +s32 func_800A1D14(void); +void func_800A2040(void); +s32 func_800A21A4(void); +void func_800A23BC(s32 arg0); +void func_800A2B28(s32 arg0); +void func_800A2CC4(s32 arg0); +u8 func_800A2D0C(void); +void func_800A2D68(u8 arg0); +void func_800A2EFC(void); +void func_800A2F24(void); +void func_800A317C(void); +void func_800A31A0(s32 arg0, s32 arg1, s32 arg2, s32 arg3); +s32 func_800A31E8(void); +void func_800A3278(void); +void func_800A329C(void); +s32 func_800A32F4(void); +void func_800A345C(void); +void func_800A368C(s32 arg0); +s32 func_800A37F8(s32 arg0); +s32 func_800A3828(void); +void func_800A38C8(void); +void func_800A3908(void); +void func_800A3DFC(void); +void func_800A3E4C(void); +void func_800A3E98(s32 arg0, s32 arg1, s32 arg2, s32 arg3, s32 arg4); +void func_800A3E9C(s32 arg0); +void func_800A40B8(s32 arg0); +void func_800A41E8(s32 arg0); +void func_800A4494(s32 arg0); +void func_800A44A4(s32 arg0); +void func_800A44B4(s32 arg0); +void func_800A45C4(s32 arg0); +void func_800A45D4(s32 arg0); +void func_800A45E4(s32 arg0); +s32 func_800A45F4(void); +void func_800A4844(s32 arg0); +s32 func_800A4A80(void); +void func_800A4ACC(s16 arg0, u16 arg1); +void func_800A4AF4(void); +u8 func_800A4B3C(s32 index, s32 arg1); +void func_800A4B9C(void); +u8 func_800A4CA8(s32 arg0); +void func_800A4D2C(s32 arg0); +void func_800A4D88(s32 arg0); +void func_800A4E40(void); +u8 func_800A5A5C(void); +s32 func_800A5A88(void); +s32 func_800A5AA8(void); +s8* func_800A5F90(s32 arg0); +void func_800A64A0(s32 arg0, s8 arg1); +void func_800A653C(s32 arg0); +void func_800A6590(s32 arg0); +void func_800A6720(s32 arg0, s16 arg1); +void func_800A6748(s32 arg0); +void func_800A6798(s32 arg0, s32 arg1); +void func_800A6834(s32 arg0); +void func_800A6A3C(s32 arg0, s32 arg1); +void func_800A6BFC(void); +void func_800A6C00(s32 arg0); +void func_800A6D10(s32 arg0); +void func_800A6DFC(void); +void func_800A6E04(void); +void func_800A6E6C(s32 arg0, s32 arg1); +void func_800A7034(s32 arg0, s16 arg1); +void func_800A7060(s32 arg0, s32 arg1); +void func_800A71E0(void); +s32 func_800A71E8(s32 arg0); +void func_800A73C0(void); +void func_800A73D8(void); +void func_800A76AC(void); +void func_800A7784(void); +void func_800A7940(void); +void func_800A795C(void); +void func_800A7988(void); +void func_800A79A8(void); +void func_800A7F18(void); +s32 func_800A82F0(void); +void func_800A8528(void); +void func_800A85A0(void); +void func_800A85B4(void); +void func_800A8888(s32 arg0); +void func_800A8D04(void); +void func_800A8D60(s32 arg0); +void func_800A8E34(void); +void func_800A8E54(s32 arg0); +void func_800A8F74(void); +void func_800A8FA0(void); +s32 func_800A921C(s32 arg0, u8 arg1); +void func_800A9678(s16 arg0); +void func_800A96A4(s16 arg0); +void func_800A9A04(s8 arg0); +void func_800A9A24(s16 arg0); +void func_800A9D5C(s32 arg0); +void func_800A9D88(s32 arg0); +s32 func_800AA6E8(s32 arg0, s32 arg1); +void func_800AB2AC(void); +void func_800ACA24(void); +void func_800AD324(s32 arg0, s32 arg1, s32 arg2, s32 arg3); +void func_800AD924(void); +void func_800ADC70(void); +void func_800ADE5C(void); +void func_800ADED8(void); +void func_800ADF04(void); +void func_800AE050(void); +void func_800AE058(void); +void func_800AE060(void); +void func_800AE068(void); +void func_800AE070(void); +void func_800AE078(void); +void func_800AE234(void); +s32 func_800AE628(void); +void func_800AEBF0(void); +void func_800AF0A0(s32 arg0); +void func_800AF1A8(s32 arg0); +void func_800AF320(s32 arg0, s32 arg1, s32 arg2); +void func_800AF380(s32 arg0); +void func_800AF470(s32 arg0); +void func_800AF63C(s32 arg0); +s32 func_800AF96C(s32 arg0); +s32 func_800B0240(void); +int func_800B0B8C(void); +void func_800B0DF8(void); +void func_800B0FFC(s32 arg0, s32 arg1, s32 arg2, s16* arg3); +void func_800B1060(s32 arg0); +void func_800B108C(s32 arg0); +void func_800B28CC(s32 arg0); +s32 func_800B2C60(s32 arg0); +u8 func_800B2F30(void); +u16 func_800B2F50(void); +void func_800B30E4(void); +void func_800B5FC4(s16 arg0); +void func_800B64A0(void); +void func_800B6AEC(void); +void func_800B6DCC(void); +void func_800B7134(void); +s32 func_800B7200(void); +void func_800B76A8(void); +void func_800B7820(void); +s32 func_800B785C(void); +s32 func_800B786C(void); +void func_800B7B1C(u8 arg0); +u16 func_800B7B3C(void); +u8 func_800B7BA0(void); +u8 func_800B7BC0(void); +void func_800B7C1C(void); +void func_800B7FB4(void); +void func_800B8234(s32 arg0); +void func_800B8438(void); +void func_800BA65C(s32 arg0); +void func_800BB90C(void); +s32 func_800BBA44(void); +void func_800BBC4C(void); +s16 func_800BCA38(void); +s32 func_800BEE10(s16 arg0, s16 arg1); +s32 func_800C03FC(s32 arg0, s32 arg1); +s32 func_800C0B54(void); +void func_800C2CA8(void); +void func_800C49EC(void); +void func_800C4A40(void); +void func_800C4A94(void); +s32 func_800C60F4(void); +void func_800C64AC(void); +s16 func_800CD558(s16 arg0, u8* arg1); +void func_800CDDA4(void); +void func_800CDF6C(s32 arg0, s16 arg1); +void func_800CE970(void); +void func_800CF5BC(void); +void func_800CF8C0(s16 arg0, s16 arg1, u8 arg2); +void func_800CFB14(void); +void func_800CFCB0(void); +void func_800CFE60(void); +void func_800D01C0(void); +void func_800D0578(void); +void func_800D061C(void); +void func_800D06B8(void); +void func_800D0760(void); +void func_800D088C(s32 loc, s32 len); +void func_800D0A44(void); +void func_800D0A4C(void); +void func_800D0B4C(u8 arg0); +void func_800D0C80(u8 arg0); +void func_800D1110(u8 arg0); +s32 func_800D35D8(u8* arg0, s32* arg1, s32 arg2); +void func_800D3D88(void); +void func_800D3E8C(s32 arg0); +void func_800D3F8C(void); +s32 func_800D54BC(s32 arg0); +s32 func_800D574C(s32 arg0); +void func_800D6814(s32 arg0); +void func_800D8A04(void); +s32 func_800D8A0C(s32 arg0); +void func_800D8A24(void); +void func_800D8A2C(void); +void func_800D8A70(void); +void func_800D8A78(s8 arg0); +void func_800D8B2C(void); +void func_800D93DC(void); +u8 func_800D9DEC(s16 arg0); +void func_800DCF58(void); +void func_800DCF60(s16 arg0, s16 arg1); +void func_800DCF94(s16 arg0); +void func_800DE5D8(void); +void func_800DE5E0(void); +void func_800DE5E8(void); +void func_800DE5F0(void); +void func_800DE5F8(void); +void func_800DE600(void); +void func_800DE608(void); +void func_800DE610(void); +void func_800DE910(void); +void func_800DE918(void); +void func_800DEB10(void); +void func_800DF244(void); +void func_800DF528(void); +void func_800DF7BC(void); +void func_800DF7C4(void); +void func_800DF8F0(void); +void func_800DF8F8(void); +void func_800DF900(void); +void func_800DF9F0(void); +void func_800DFC38(void); +void func_800DFFDC(void); +void func_800E026C(void); +void func_800E0274(void); +void func_800E0294(void); +void func_800E03C8(void); +void func_800E03D0(void); +void func_800E03F0(void); +void func_800E0528(void); +void func_800E078C(void); +void func_800E084C(void); +void func_800E2054(s32 arg0, s32 arg1); +s32 func_800E54EC(void); +void func_800E58B0(void); +s32 func_800E5960(s32 arg0); +s32 func_800E5FB4(u32 arg0, s32 arg1); +s32 func_800E6820(void); +void func_801B0000(int arg0, int arg1); +void func_801B0490(s32 sceneID); +void func_801B085C(s32 arg0); +void func_801B137C(s32 arg0); +s32 func_801B14E8(u32 arg0); +s32 func_801B1530(u32* arg0); +void func_801B2308(void); +s32 func_801B2738(s32 arg0); +s32 func_801B2770(s32 arg0); +void func_801D0000(void); +void func_801D00C4(void); +s32 func_801D01C4(s32 arg0); +void func_801D05C0(u8 arg0); +void func_801D05C4(s32 arg0); +void func_801D069C(void); +int func_801D06B0(s32 arg0); +void func_801D0704(s32 arg0); +s32 func_801D1774(void); +u16 func_801D1950(u16 len, u8* data); +void func_801D19C4(void); +void func_801D1BA4(void); +u16 func_801D1C2C(s32 arg0); +s32 func_801D2184(s8 arg0); +void func_801D21F0(u8* arg0, u8* arg1); +void func_801D3668(s32 arg0); +s32 func_801D3698(s32 arg0, s32 arg1); +void func_801D370C(s32 x, s32 y, s32 slot_no); +s32 func_801D4CC0(void); + +#endif /* DECOMP_DECLS_H */ diff --git a/include/decomp_decls_battle.h b/include/decomp_decls_battle.h new file mode 100644 index 0000000..6e3bc79 --- /dev/null +++ b/include/decomp_decls_battle.h @@ -0,0 +1,195 @@ +/* AUTO-GENERATED by automation/generate_decls.py — do not edit manually */ +/* Per-module declarations for 'battle' — only valid in battle m2c context */ +/* struct types referenced here are defined by the module's own preprocessed headers */ + +#include "common.h" + +#include "../src/battle/battle_private.h" + +void BATTLE_EnqueueClearImage(RECT* rect); +void BATTLE_EnqueueMoveImage(RECT* rect, s32 x, s32 y); +void BATTLE_FlushImageQueue(void); +void BATTLE_ResetImageQueue(void); +void func_800A23BC(s32 arg0); +void func_800A2B28(s32 arg0); +void func_800A2CC4(s32 arg0); +u8 func_800A2D0C(void); +void func_800A2D68(u8 arg0); +void func_800A2EFC(void); +void func_800A2F24(void); +Unk800A2F4C* func_800A2F4C(void); +void func_800A317C(void); +void func_800A31A0(s32 arg0, s32 arg1, s32 arg2, s32 arg3); +void func_800A3278(void); +void func_800A329C(void); +void func_800A345C(void); +s32 func_800A37F8(s32 arg0); +s32 func_800A3828(void); +void func_800A3E98(s32 arg0, s32 arg1, s32 arg2, s32 arg3, s32 arg4); +void func_800A4844(s32 arg0); +s32 func_800A4A80(void); +void func_800A4ACC(s16 arg0, u16 arg1); +void func_800A4AF4(void); +u8 func_800A4B3C(s32 index, s32 arg1); +void func_800A4B9C(void); +u8 func_800A4CA8(s32 arg0); +void func_800A4D2C(s32 arg0); +void func_800A4D88(s32 arg0); +void func_800A4E40(void); +u8 func_800A5A5C(void); +s32 func_800A5A88(void); +s32 func_800A5AA8(void); +s8* func_800A5F90(s32 arg0); +void func_800A64A0(s32 arg0, s8 arg1); +void func_800A653C(s32 arg0); +void func_800A6590(s32 arg0); +void func_800A6720(s32 arg0, s16 arg1); +void func_800A6748(s32 arg0); +void func_800A6798(s32 arg0, s32 arg1); +void func_800A6834(s32 arg0); +void func_800A6A3C(s32 arg0, s32 arg1); +void func_800A6BFC(void); +void func_800A6D10(s32 arg0); +void func_800A6DFC(void); +void func_800A6E04(void); +void func_800A6E6C(s32 arg0, s32 arg1); +void func_800A7034(s32 arg0, s16 arg1); +void func_800A7060(s32 arg0, s32 arg1); +void func_800A71E0(void); +s32 func_800A71E8(s32 arg0); +void func_800A73C0(void); +void func_800A73D8(void); +void func_800A76AC(void); +void func_800A7784(void); +void func_800A7940(void); +void func_800A795C(void); +void func_800A7988(void); +void func_800A79A8(void); +void func_800A8528(void); +void func_800A85A0(void); +void func_800A85B4(void); +void func_800A8D04(void); +void func_800A8D60(s32 arg0); +void func_800A8E34(void); +void func_800A8E54(s32 arg0); +s32 func_800AA6E8(s32 arg0, s32 arg1); +void func_800ACA24(void); +void func_800AD324(s32 arg0, s32 arg1, s32 arg2, s32 arg3); +void func_800AD924(void); +void func_800ADE5C(void); +void func_800ADED8(void); +void func_800ADF04(void); +void func_800AE050(void); +void func_800AE058(void); +void func_800AE060(void); +void func_800AE068(void); +void func_800AE070(void); +void func_800AE078(void); +void func_800AE234(void); +void func_800AEBF0(void); +void func_800AF1A8(s32 arg0); +void func_800AF320(s32 arg0, s32 arg1, s32 arg2); +void func_800AF380(s32 arg0); +void func_800AF470(s32 arg0); +void func_800AF63C(s32 arg0); +int func_800B0B8C(void); +void func_800B0DF8(void); +void func_800B0FFC(s32 arg0, s32 arg1, s32 arg2, s16* arg3); +void func_800B1060(s32 arg0); +void func_800B108C(s32 arg0); +s32 func_800B2C60(s32 arg0); +u8 func_800B2F30(void); +u16 func_800B2F50(void); +void func_800B30E4(void); +void func_800B5FC4(s16 arg0); +void func_800B7FB4(void); +void func_800B8234(s32 arg0); +void func_800B8438(void); +void func_800BB67C(s32 arg0, Unk800BB67C* arg1); +void func_800BB90C(void); +s32 func_800C03FC(s32 arg0, s32 arg1); +s32 func_800C60F4(void); +void func_800C64AC(void); +s16 func_800CD558(s16 arg0, u8* arg1); +void func_800CDDA4(void); +void func_800CDF6C(s32 arg0, s16 arg1); +void func_800CE970(void); +void func_800CF5BC(void); +void func_800CF8C0(s16 arg0, s16 arg1, u8 arg2); +void func_800CFB14(void); +void func_800CFCB0(void); +void func_800CFE60(void); +void func_800D01C0(void); +void func_800D0578(void); +void func_800D061C(void); +void func_800D06B8(void); +void func_800D0760(void); +void func_800D088C(s32 loc, s32 len); +void func_800D0A44(void); +void func_800D0A4C(void); +void func_800D0B4C(u8 arg0); +void func_800D0C80(u8 arg0); +void func_800D1110(u8 arg0); +s32 func_800D35D8(u8* arg0, s32* arg1, s32 arg2); +void func_800D3D88(void); +void func_800D3E8C(s32 arg0); +void func_800D3F8C(void); +s32 func_800D54BC(s32 arg0); +s32 func_800D574C(s32 arg0); +void func_800D6814(s32 arg0); +void func_800D8A04(void); +s32 func_800D8A0C(s32 arg0); +void func_800D8A24(void); +void func_800D8A2C(void); +void func_800D8A70(void); +void func_800D8A78(s8 arg0); +void func_800D8B2C(void); +void func_800D93DC(void); +u8 func_800D9DEC(s16 arg0); +void func_800DCF58(void); +void func_800DCF60(s16 arg0, s16 arg1); +void func_800DCF94(s16 arg0); +void func_800DE5D8(void); +void func_800DE5E0(void); +void func_800DE5E8(void); +void func_800DE5F0(void); +void func_800DE5F8(void); +void func_800DE600(void); +void func_800DE608(void); +void func_800DE610(void); +void func_800DE910(void); +void func_800DE918(void); +void func_800DEB10(void); +void func_800DF244(void); +void func_800DF528(void); +void func_800DF7BC(void); +void func_800DF7C4(void); +void func_800DF8F0(void); +void func_800DF8F8(void); +void func_800DF900(void); +void func_800DF9F0(void); +void func_800DFC38(void); +void func_800DFFDC(void); +void func_800E026C(void); +void func_800E0274(void); +void func_800E0294(void); +void func_800E03C8(void); +void func_800E03D0(void); +void func_800E03F0(void); +void func_800E0528(void); +void func_800E078C(void); +void func_800E084C(void); +void func_800E2054(s32 arg0, s32 arg1); +s32 func_800E54EC(void); +void func_800E58B0(void); +s32 func_800E5960(s32 arg0); +s32 func_800E5FB4(u32 arg0, s32 arg1); +s32 func_800E6820(void); +void func_801B0490(s32 sceneID); +void func_801B085C(s32 arg0); +void func_801B137C(s32 arg0); +s32 func_801B14E8(u32 arg0); +s32 func_801B1530(u32* arg0); +void func_801B2308(void); +s32 func_801B2738(s32 arg0); +s32 func_801B2770(s32 arg0); diff --git a/include/decomp_decls_field.h b/include/decomp_decls_field.h new file mode 100644 index 0000000..56314e0 --- /dev/null +++ b/include/decomp_decls_field.h @@ -0,0 +1,15 @@ +/* AUTO-GENERATED by automation/generate_decls.py — do not edit manually */ +/* Per-module declarations for 'field' — only valid in field m2c context */ +/* struct types referenced here are defined by the module's own preprocessed headers */ + +#include "common.h" + +void func_800A1498(void); +void func_800AB2AC(void); +void func_800BA65C(s32 arg0); +s32 func_800BEE10(s16 arg0, s16 arg1); +s32 func_800C0B54(void); +void func_800C2CA8(void); +void func_800C49EC(void); +void func_800C4A40(void); +void func_800C4A94(void); diff --git a/include/decomp_decls_magic.h b/include/decomp_decls_magic.h new file mode 100644 index 0000000..2e7f3c9 --- /dev/null +++ b/include/decomp_decls_magic.h @@ -0,0 +1,7 @@ +/* AUTO-GENERATED by automation/generate_decls.py — do not edit manually */ +/* Per-module declarations for 'magic' — only valid in magic m2c context */ +/* struct types referenced here are defined by the module's own preprocessed headers */ + +#include "common.h" + +void func_801B0000(int arg0, int arg1); diff --git a/include/decomp_decls_main.h b/include/decomp_decls_main.h new file mode 100644 index 0000000..c9fed28 --- /dev/null +++ b/include/decomp_decls_main.h @@ -0,0 +1,147 @@ +/* AUTO-GENERATED by automation/generate_decls.py — do not edit manually */ +/* Per-module declarations for 'main' — only valid in main m2c context */ +/* struct types referenced here are defined by the module's own preprocessed headers */ + +#include "common.h" + +#include "../src/main/main_private.h" + +s32 SYS_gil(void); +void SetReverbMode(s32 in_ReverbMode); +void SetupGamepad(void); +void __main(void); +void func_800111E4(void); +void func_80011274(void); +void func_8001171C(void); +void func_80011860(void); +void func_80011920(void); +void func_80011938(void); +void func_800140A4(void); +s32 func_800144D8(s32 file_no); +void func_800144F0(s32 file_no); +void func_80014510(s32 file_no); +void func_80014540(void); +void func_80014608(void); +void func_80014610(void); +void func_800146A4(void); +void func_80014750(void); +void func_80014934(void); +void func_800149E0(void); +void func_80014A00(s32* dst, s32* src, s32 len); +s32 func_80014A38(u32 arg0); +s32 func_80014A58(u32 arg0); +void func_80014B54(void); +s32 func_80014BA8(s32 arg0); +void func_80014C44(s32 arg0); +void func_80014C70(void); +s32 func_80014CBC(s32 arg0, s32 arg1); +u8* func_80014D58(u8* arg0, u8* arg1, s32 arg2); +u16* func_80014D9C(s32 arg0, s32 arg1, s32 arg2); +void func_80014DD0(s32 arg0, s32 arg1, u8* arg2); +u16* func_800151F4(s32 arg0); +s32 func_8001521C(s32 arg0); +void func_80015654(s32 arg0); +s32 func_80015C3C(u8* src, void* dst, s32 id); +void func_80015CA0(GzHeader* src, s32* dst); +s32 func_80016320(s32* arg0); +void func_80017238(u32 arg0, u32* arg1, u8* arg2); +void func_80019D74(u8 arg0, u8 arg1); +void func_8001A384(u8 arg0, s32 arg1); +void func_8001A3B8(s32 arg0, s32 arg1, s32 arg2); +void func_8001A5B4(u8 arg0, u8 arg1, s32 arg2); +s32 func_8001AC9C(u8 arg0, s32 arg1); +void func_8001C3C4(void); +void func_8001C58C(void); +void func_8001CDA4(void); +void func_8001CF3C(s16 x, s16 y, s16 w, s16 h, u16 tx, u16 ty, u16 tw, u16 th, s16 clut, s32 tex); +void func_8001D180(s16 x, s16 y, s16 w, s16 h, u16 tx, u16 ty, u16 tw, u16 th, s16 clut, s32 tex); +void func_8001D3C0(s16 x, s16 y); +void func_8001D47C(s16 x0, s16 x1, s16 y, s32 color); +void func_8001D56C(s16 x0, s16 y0, s16 x1, s16 y1, s16 is_yellow); +void func_8001DE0C(Unk8001DE0C* arg0, s16 arg1, s16 arg2, s16 arg3, s32 arg4); +void func_8001DE24(Unk8001DE0C* arg0, s32 arg1, s32 arg2); +void func_8001DE40(Unk8001DE0C* arg0, Unk8001DE0C* arg1); +void func_8001DEF0(u8* menu_colors); +void func_8001DF24(RECT* rect, u8 arg1, u8 arg2, u8 arg3); +void func_8001EB2C(s16 x, s16 y); +void func_8001EF84(s32 x, s32 y, s32 n, s32 len); +void func_8001F6AC(void); +u8 func_8001F6B4(void); +void func_8001F6C0(s32 arg0, s8 arg1); +void func_8001F6E4(s16 arg0, s16 arg1, s16 arg2); +void func_8001FAF0(void); +void func_80021044(DRAWENV* draw_env, DISPENV* disp_env); +void func_80021258(s32 arg0); +void func_80021280(s32 arg0); +void func_80024D88(s32 arg0); +void func_80024DD4(s32 arg0); +void func_80024E18(s32 arg0); +void func_80024E5C(void); +void func_80024E94(void); +void func_80024ECC(void); +void func_80024F04(void); +void func_80024F3C(s32 arg0); +void func_80024F80(s32 arg0); +void func_80024FC4(s32 arg0); +void func_80025008(void); +void func_800250B4(void); +void func_800250EC(s32 arg0); +void func_80025130(s32 arg0); +void func_80025360(void); +s32 func_8002542C(s32 arg0); +void func_800254D8(void); +void func_80025648(void); +void func_80025650(void); +s32 func_80025658(void); +s32* func_80025758(s32 arg0); +s32* func_80025774(s32 arg0); +Unk8009D84C* func_80025788(s32 arg0); +void func_800257C4(void); +void func_80025DF8(void); +void func_80026034(void); +s32 func_8002603C(u8 arg0); +void func_80026448(Unk80026448* arg0, s32 arg1, s32 arg2, s32 arg3, s32 arg4, s32 arg5, s32 arg6, s32 arg7, s32 arg8, s32 arg9, s32 arg10, s32 arg11, s32 arg12, u16 arg13); +void func_800269C0(void* arg0); +void func_80026B5C(void); +void func_8002BE8C(s32 arg0); +void func_8002BEB4(s32 arg0); +void func_8002BEDC(s32 arg0); +void func_8002BF04(s32 arg0); +void func_8002BF2C(s32 arg0); +void func_8002BF54(s32 arg0); +void func_8002BF7C(s32 arg0); +void func_8002BFA4(s32 arg0); +void func_8002C18C(s32 arg0); +void func_8002C1B4(s32 arg0); +void func_8002C1DC(s32 arg0); +void func_8002C204(s32 arg0); +void func_8002C22C(s32 arg0); +void func_8002C254(s32 arg0); +void func_8002C27C(s32 arg0); +void func_8002C2A4(s32 arg0); +void func_8002C468(s32 arg0); +void func_8002C490(s32 arg0); +void func_8002C4B8(s32 arg0); +void func_8002C4E0(s32 arg0); +void func_8002C508(s32 arg0); +void func_8002C530(s32 arg0); +void func_8002C558(s32 arg0); +void func_8002C580(s32 arg0); +void func_8002C7A8(void); +void func_8002C7C8(void); +void func_8002C7E8(void); +void func_8002CCBC(void); +void func_8002CCCC(void); +void func_8002CFA0(void); +void func_8002E1A8(void); +u8 func_80031A70(u8** arg0); +void func_80032D50(void); +void func_80032D64(void); +void func_80033B70(void); +int func_80033DE4(int sector_no); +void func_80034048(void); +void func_80034420(void); +void func_80034428(void); +void func_80034A58(void); +void func_80034A90(void); +u32 func_80034B44(void); diff --git a/include/decomp_decls_menu.h b/include/decomp_decls_menu.h new file mode 100644 index 0000000..1f52bf2 --- /dev/null +++ b/include/decomp_decls_menu.h @@ -0,0 +1,25 @@ +/* AUTO-GENERATED by automation/generate_decls.py — do not edit manually */ +/* Per-module declarations for 'menu' — only valid in menu m2c context */ +/* struct types referenced here are defined by the module's own preprocessed headers */ + +#include "common.h" + +void func_801D0000(void); +void func_801D00C4(void); +s32 func_801D01C4(s32 arg0); +void func_801D05C0(u8 arg0); +void func_801D05C4(s32 arg0); +void func_801D069C(void); +int func_801D06B0(s32 arg0); +void func_801D0704(s32 arg0); +s32 func_801D1774(void); +u16 func_801D1950(u16 len, u8* data); +void func_801D19C4(void); +void func_801D1BA4(void); +u16 func_801D1C2C(s32 arg0); +s32 func_801D2184(s8 arg0); +void func_801D21F0(u8* arg0, u8* arg1); +void func_801D3668(s32 arg0); +s32 func_801D3698(s32 arg0, s32 arg1); +void func_801D370C(s32 x, s32 y, s32 slot_no); +s32 func_801D4CC0(void); diff --git a/include/decomp_decls_world.h b/include/decomp_decls_world.h new file mode 100644 index 0000000..0017a69 --- /dev/null +++ b/include/decomp_decls_world.h @@ -0,0 +1,62 @@ +/* AUTO-GENERATED by automation/generate_decls.py — do not edit manually */ +/* Per-module declarations for 'world' — only valid in world m2c context */ +/* struct types referenced here are defined by the module's own preprocessed headers */ + +#include "common.h" + +s32 func_800A1D14(void); +void func_800A2040(void); +s32 func_800A21A4(void); +s32 func_800A31E8(void); +s32 func_800A32F4(void); +void func_800A368C(s32 arg0); +void func_800A38C8(void); +void func_800A3908(void); +void func_800A3DFC(void); +void func_800A3E4C(void); +void func_800A3E9C(s32 arg0); +void func_800A40B8(s32 arg0); +void func_800A41E8(s32 arg0); +void func_800A4494(s32 arg0); +void func_800A44A4(s32 arg0); +void func_800A44B4(s32 arg0); +void func_800A45C4(s32 arg0); +void func_800A45D4(s32 arg0); +void func_800A45E4(s32 arg0); +s32 func_800A45F4(void); +void func_800A6C00(s32 arg0); +void func_800A7F18(void); +s32 func_800A82F0(void); +void func_800A8888(s32 arg0); +void func_800A8F74(void); +void func_800A8FA0(void); +s32 func_800A921C(s32 arg0, u8 arg1); +void func_800A9678(s16 arg0); +void func_800A96A4(s16 arg0); +void func_800A9A04(s8 arg0); +void func_800A9A24(s16 arg0); +void func_800A9D5C(s32 arg0); +void func_800A9D88(s32 arg0); +void func_800ADC70(void); +s32 func_800AE628(void); +void func_800AF0A0(s32 arg0); +s32 func_800AF96C(s32 arg0); +s32 func_800B0240(void); +void func_800B28CC(s32 arg0); +void func_800B64A0(void); +void func_800B6AEC(void); +void func_800B6DCC(void); +void func_800B7134(void); +s32 func_800B7200(void); +void func_800B76A8(void); +void func_800B7820(void); +s32 func_800B785C(void); +s32 func_800B786C(void); +void func_800B7B1C(u8 arg0); +u16 func_800B7B3C(void); +u8 func_800B7BA0(void); +u8 func_800B7BC0(void); +void func_800B7C1C(void); +s32 func_800BBA44(void); +void func_800BBC4C(void); +s16 func_800BCA38(void); diff --git a/src/battle/battle2.c b/src/battle/battle2.c index 3576e70..45838e1 100644 --- a/src/battle/battle2.c +++ b/src/battle/battle2.c @@ -39,6 +39,11 @@ void func_801B0040(s16, u8); void func_801B0054(s16, u8); void func_801B0084(s16, u8); +extern u8 D_800F10EC[]; +extern u8 D_800F11E8[]; +extern u8 D_800F1304[]; +extern s32 D_800F14D4; + static s32 func_800C7B60(s16 arg0, s16 nItems, u8* arg2) { BattleModelSub* var_a0; s32 var_a1; @@ -1155,14 +1160,10 @@ INCLUDE_ASM("asm/us/battle/nonmatchings/battle2", func_800D6394); INCLUDE_ASM("asm/us/battle/nonmatchings/battle2", func_800D650C); -extern u8 D_800F10EC[]; -extern u8 D_800F11E8[]; -extern u8 D_800F1304[]; u8* const D_800A0DC8[] = {D_800F10EC, D_800F11E8, D_800F1304}; INCLUDE_ASM("asm/us/battle/nonmatchings/battle2", func_800D6734); void func_800D6734(s32, s32); -extern s32 D_800F14D4; static void func_800D67BC(s32 arg0) { D_800F14D4 = 0x88; diff --git a/src/ending/ending.c b/src/ending/ending.c index 003733a..42abf20 100644 --- a/src/ending/ending.c +++ b/src/ending/ending.c @@ -1,5 +1,7 @@ #include "common.h" +s32 func_80034410(); // extern + INCLUDE_ASM("asm/us/ending/nonmatchings/ending", func_800A0030); INCLUDE_ASM("asm/us/ending/nonmatchings/ending", func_800A04C4); diff --git a/src/main/18B8.c b/src/main/18B8.c index 631cf50..66ccf71 100644 --- a/src/main/18B8.c +++ b/src/main/18B8.c @@ -169,6 +169,9 @@ void func_8001B834(s32); void func_8001BD50(u8, u8, u8); u8 func_8001F6B4(); +extern s32 D_80048D24; // field.X sector +extern u32 D_80048D28; // field.X size + void __main(void) {} INCLUDE_ASM("asm/us/main/nonmatchings/18B8", __SN_ENTRY_POINT); @@ -230,8 +233,6 @@ INCLUDE_ASM("asm/us/main/nonmatchings/18B8", func_80011784); void func_800A16CC(); // field loop void func_800CF60C(); // field load -extern s32 D_80048D24; // field.X sector -extern u32 D_80048D28; // field.X size void func_80011860(void) { if (D_800965EC != 5 && D_800965EC != 13) { diff --git a/src/main/akao.c b/src/main/akao.c index e2d2122..84fe789 100644 --- a/src/main/akao.c +++ b/src/main/akao.c @@ -137,6 +137,8 @@ void func_8002BA08(Unk8002B7E0* arg0); void func_8002B8B4(Unk8002B7E0* arg0); void func_8002B668(Unk8002B7E0* arg0); +extern u16 D_80062FC8; + INCLUDE_ASM("asm/us/main/nonmatchings/akao", func_800293D0); INCLUDE_ASM("asm/us/main/nonmatchings/akao", func_800293F4); @@ -247,8 +249,6 @@ void func_8002B2F8(Unk8002B7E0* arg0) { INCLUDE_ASM("asm/us/main/nonmatchings/akao", func_8002B3B4); -extern u16 D_80062FC8; - void func_8002B5A8(Unk8002B7E0* arg0) { if (D_8009A14E) { D_80062FC8 = arg0->unk10 ? arg0->unk10 : 0x10; diff --git a/src/menu/bginmenu.c b/src/menu/bginmenu.c index 5c6d513..dc61d38 100644 --- a/src/menu/bginmenu.c +++ b/src/menu/bginmenu.c @@ -20,6 +20,9 @@ extern u8 D_801D085C[2]; extern Unk80026448 D_801D0860[]; extern s8 D_801D086B; +extern u8 D_8009C778[]; // Savemap.party +extern u8 D_8009C798[]; // Savemap.party + void func_801D0000(void) { volatile s32 padding; func_80026448(&D_801D0860[0], 0, 0, 1, 3, 0, 0, 1, 3, 0, 0, 0, 1, 0); @@ -52,8 +55,6 @@ static void func_801D01BC(void) {} INCLUDE_ASM("asm/us/menu/nonmatchings/bginmenu", func_801D01C4); #else // -O1 -extern u8 D_8009C778[]; // Savemap.party -extern u8 D_8009C798[]; // Savemap.party s32 func_801D01C4(s32 arg0) { s32 var_a1; s32 var_a2;