mirror of
https://github.com/morluto/rea.git
synced 2026-10-11 21:39:55 +00:00
* feat(ghidra): admit soft-float MIPS32r2 ELF with integer-register float storage Soft-float o32 executables (Linux kernel builds, bare-metal firmware) were refused because their ABI flags record declares no CPR1 and FP ABI 3. Ghidra's MIPS32 compiler specifications model only hard-float o32, so typed float/double signatures (DWARF) would be bound to $f12/$f14/$f0 and the decompiler loses the real dataflow: `return sel ? a : b` decompiled to `return in_f0;`, and callers passed phantom FPU inputs. Admit ELF32 ET_EXEC o32 MIPS32r2 targets whose ABI record declares soft-float with no CPR1, and commit `mips_soft_float_storage: o32-integer-registers-v1` in their analysis profile only (hard-float profile digests are unchanged). ReaGhidraMipsSoftFloat.java runs after auto-analysis and, for each function with a float/double formal type, either keeps the types with the storage Ghidra's o32 model assigns to a same-size integer (pair alignment, stack spill), or, for auto-parameters such as hidden struct-return pointers, swaps float types for same-size integers under dynamic storage. No function is left on hard-float storage. The report is written last; the provider client requires it exactly when the profile commits the policy and refuses the session before any operation otherwise. Verification: real Ghidra 12.1.4 lane (verify:ghidra:mips) now builds hard- and soft-float fixtures in both byte orders and checks exact parameter/return storage through inspect_native_api, caller constants, snapshot profile and Evidence outcome; test:fast, verify:package and an installed-tarball soft-float run pass. * fix(ghidra): model soft-float MIPS as a prototype for every typed callable Review feedback on #1949: rewriting storage per Function left external functions and indirect calls through typed function pointers on Ghidra's hard-float o32 prototype, which still read $f12/$f14/$f0 while the session reported success. A negative control confirms it: without the change, `(*rea_mips_soft_callback)(8.5f, 9.5f, sel)` decompiles to `(*rea_mips_soft_callback)(in_f12, in_f14, sel)`. ReaGhidraMipsSoftFloat.java now derives a `__rea_soft_float` prototype from the program's own default o32 model (encoded, float pentries and float-consuming rules removed, so byte-order-specific aggregate rules and the hidden struct-return pointer are kept), installs it as a specification extension, and assigns it with dynamic storage to every non-thunk function, external function and function-pointer definition whose formal types use float or double. Thunks follow their targets. Float types are kept everywhere, so the integer-retype fallback is removed. The script fails without writing its report if the derived prototype or any reassigned function still uses an FPU register. The policy becomes `o32-soft-float-prototype-v1` with a {functions, definitions} report. The soft-float fixture adds an indirect call through a typed pointer; the real-Ghidra lane requires its constants with no FPU inputs and the struct return's `float scale` in $a1. * test(ghidra): pin ODDSPREG acceptance for soft-float MIPS ABI records Review on #1949 suggested requiring flags1 == 0 for soft-float, since MIPS_AFL_FLAGS1_ODDSPREG names CPR1 registers. GCC 5.2 kernel modules, LLVM/Rust firmware and Clang -msoft-float objects all record flags1 = 1 with FP ABI soft-float: it is the MIPS32 o32 toolchain default and selects nothing without CPR1. Keep accepting it, say why at the check, and test that soft-float with ODDSPREG is admitted while any other general flag is refused.
36 lines
946 B
TypeScript
36 lines
946 B
TypeScript
import type { MipsElfMetadata } from "../../../src/domain/binaryTargetTypes.js";
|
|
|
|
export type MipsFloatAbi = "hard" | "soft";
|
|
export interface MipsReadelfFacts {
|
|
mips: MipsElfMetadata;
|
|
symbols: Record<string, string>;
|
|
}
|
|
export function parseMipsReadelf(
|
|
text: string,
|
|
byteOrder: string,
|
|
floatAbi?: MipsFloatAbi,
|
|
): MipsReadelfFacts;
|
|
export function inspectMipsReadelf(
|
|
path: string,
|
|
byteOrder: string,
|
|
floatAbi?: MipsFloatAbi,
|
|
): Promise<
|
|
MipsReadelfFacts & { command: string; version: string; raw: string }
|
|
>;
|
|
export function assertMipsLoadedImage(
|
|
observations: unknown,
|
|
byteOrder: string,
|
|
sha256: string,
|
|
): void;
|
|
export function assertMipsProbe(
|
|
move: unknown,
|
|
branch: unknown,
|
|
byteOrder: string,
|
|
address: string,
|
|
): void;
|
|
export function assertMipsGlobal(bytes: string, byteOrder: string): void;
|
|
export function assertMipsSoftFloatStorage(
|
|
boundaries: Record<string, unknown>,
|
|
byteOrder: string,
|
|
): void;
|