[GH-ISSUE #4781] ELF admission rejects Hexagon (EM_HEXAGON, 164): missing case in elfArchitecture() — Ghidra 12.1 can load it #2486

Closed
opened 2026-10-17 21:05:33 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @hubris-arch on GitHub (Oct 17, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/4781

ELF admission rejects Hexagon (EM_HEXAGON, 164): missing case in elfArchitecture() — Ghidra 12.1 can load it

Summary

open_binary refuses a well-formed Qualcomm Hexagon DSP ELF object
(e_machine = 164, EM_HEXAGON, rendered by readelf as "QUALCOMM DSP6 Processor") when the
ghidra provider is selected:

Cannot open artifact: unsupported ELF architecture.

The rejection happens in REA's own admission layer, not in the engine: the installed
Ghidra 12.1.4 PUBLIC ships a Hexagon processor (Hexagon:LE:32:default, compiled
hexagon.sla), rea doctor --provider ghidra passes every check, and the same REA+Ghidra
setup opens an x86_64 ELF without any issue (positive control below). Since REA already
requires Ghidra 12.1.x, the engine capability is already present on every supported install
of the current release line.

Environment

  • OS: Linux Mint 22.3, x86_64 · Node 22.23.2 · OpenJDK 21.0.12 (64-bit, full JDK)
  • REA: rea-agents 6.5.0 (/usr/bin/rea)
  • Provider engine: Ghidra 12.1.4 PUBLIC (GHIDRA_INSTALL_DIR) — Hexagon module present:
    Ghidra/Processors/Hexagon/data/languages/ has hexagon.ldefs
    (language id Hexagon:LE:32:default) and the compiled hexagon.sla (238,802 bytes)
  • rea doctor --provider ghidra --json: all Ghidra checks green (version 12.1.4, headless,
    java 21.0.12, native decompiler linux_x86_64)

Steps to reproduce

  1. Take a Qualcomm Hexagon DSP shared object, e.g. chre_pal.so (ELF32, little-endian,
    ET_DYN, e_machine = 164; not stripped, has .symtab and .debug_info).

  2. Call open_binary with the Ghidra provider:

    {
      "path": "/home/albert/mobian/work/hexagon-re/phone/sensors/dsp/sdsp/chre_pal.so",
      "provider_id": "ghidra"
    }
    
  3. The raw-binary route is closed too: its architecture enum is
    6502 | x86 | x86_64 | arm | arm64, which excludes Hexagon.

Observed result

{"error":{"code":"target_unavailable","category":"unsupported_target",
"message":"Cannot open artifact: unsupported ELF architecture.","retryable":false,
"remediation":{"action":"Review the reported file-format reason and select a supported, well-formed target."},
"details":{"path":"…/chre_pal.so","reason":"unsupported ELF architecture","constraint":"file_format_rejected"}}}

Positive control (same REA, same provider, same command)

Windows-style check with a supported architecture on the very same setup:

Target e_machine Result
/usr/bin/ls 62 (EM_X86_64) opens: {"format":"elf","architecture":"x86_64"}, session open: true
chre_pal.so 164 (EM_HEXAGON) rejected: unsupported ELF architecture

So this is not a broken install, a missing engine or a malformed target.

Source-level trace

src/domain/binaryTarget.ts (main):

// line 212
const architecture = elfArchitecture(machine);
if (architecture === undefined) return err("unsupported ELF architecture");  // line 213
// lines 547-566
const elfArchitecture = (
  machine: number,
): Exclude<BinaryArchitecture, RawOnlyArchitecture> | undefined => {
  switch (machine) {
    case 3:     return "x86";
    case 62:    return "x86_64";
    case 8:     return "mips";      // EM_MIPS
    case 20:    return "powerpc";   // EM_PPC
    case 40:    return "arm";
    case 183:   return "arm64";
    case 243:   return "riscv";     // EM_RISCV
  }
  return undefined;
};

164 (EM_HEXAGON) is absent from the switch, so the target never reaches the provider.
(The same trace shape was reported in #3483 for EM_XTENSA = 94.)

Evidence

$ readelf -h chre_pal.so | grep -E 'Class|Data|Type|Machine'
Class:    ELF32
Data:     2's complement, little endian
Type:     DYN (Shared object file)
Machine:  QUALCOMM DSP6 Processor      # e_machine = 0xa4 = 164 = EM_HEXAGON

Symbols/debug info present (not stripped):

$ readelf -sW chre_pal.so          | awk '$4=="FUNC"' | wc -l   → 12
$ readelf -sW libchre_slpi_skel.so | awk '$4=="FUNC"' | wc -l   → 3026

The sibling object libchre_slpi_skel.so has 3,026 functions with symbols and DWARF, and is
directly localizable with them — e.g. an abort-site string:

CHRE fatal@/home/work/beryllium-q-stable-build/vendor/qcom/non-hlos-sdm845-la201/slpi_proc/chre/chre/src/system/chre/platform/slpi/init.cc:251

Engine side already supports it:

$ grep 'Hexagon:' .../Ghidra/Processors/Hexagon/data/languages/hexagon.ldefs
            id="Hexagon:LE:32:default">
$ ls -l .../Ghidra/Processors/Hexagon/data/languages/hexagon.sla   → 238802 bytes

Impact

Hexagon DSP objects are the userspace side of Qualcomm's SLPI/ADSP sensor and audio stacks
(libchre_slpi_skel.so, libFastRPC_*_skel.so, fastrpc_shell_N, audio modules, …). They
ship with symbols and DWARF on devices that expose their firmware, which makes them a very
tractable static-analysis target — and today REA cannot load them at all, even though the
engine it drives can. Users are forced to leave REA and drive Ghidra directly.

Request / suggested remediation

Minimal change consistent with the existing lanes (the maintainer knows the BinaryArchitecture
union and downstream provider mapping better than I do):

  1. Add HEXAGON = 164 to the ELF admission path:
    case 164: // EM_HEXAGON (Qualcomm DSP6/QDSP6); 32-bit, byte order declared in the header.
      return "hexagon";
    
    plus the corresponding member in BinaryArchitecture and the provider-side acceptance.
    Unlike MIPS/RISC-V/PowerPC, Hexagon has no extra ELF family facts to surface here.
  2. Alternatively, expose a "provider-chosen architecture / language override" path for ELF
    targets so the provider decides whether it can import the file (Ghidra's loader already
    resolves Hexagon:LE:32:default on its own).

Related: #3483 (Xtensa, open — same "unsupported ELF architecture" class), #2063 (RISC-V lane,
closed). I can reproduce against any development build and re-test a fix with the same Hexagon
objects.


Motivation (real target)

This is not a synthetic request. The target set is the DSP-side userspace of a Snapdragon 845
(Xiaomi POCO F1) running mainline Linux: the device's SLPI firmware (slpi.mbn) currently
crash-loops under the mainline kernel, and its CHRE sensor stack records a fatal whose exact
source line can be resolved from the DWARF that these objects still carry
(chre/platform/slpi/init.cc:251). Being able to load these ELF objects in REA — instead of
leaving REA to drive Ghidra by hand — is what makes that investigation repeatable.

Originally created by @hubris-arch on GitHub (Oct 17, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/4781 # ELF admission rejects Hexagon (`EM_HEXAGON`, 164): missing case in `elfArchitecture()` — Ghidra 12.1 can load it ## Summary `open_binary` refuses a well-formed Qualcomm Hexagon DSP ELF object (`e_machine = 164`, `EM_HEXAGON`, rendered by `readelf` as "QUALCOMM DSP6 Processor") when the `ghidra` provider is selected: ``` Cannot open artifact: unsupported ELF architecture. ``` The rejection happens in REA's own admission layer, not in the engine: the installed **Ghidra 12.1.4 PUBLIC ships a Hexagon processor** (`Hexagon:LE:32:default`, compiled `hexagon.sla`), `rea doctor --provider ghidra` passes every check, and the same REA+Ghidra setup opens an x86_64 ELF without any issue (positive control below). Since REA already requires Ghidra 12.1.x, the engine capability is already present on every supported install of the current release line. ## Environment - OS: Linux Mint 22.3, x86_64 · Node 22.23.2 · OpenJDK 21.0.12 (64-bit, full JDK) - REA: `rea-agents` **6.5.0** (`/usr/bin/rea`) - Provider engine: **Ghidra 12.1.4 PUBLIC** (`GHIDRA_INSTALL_DIR`) — Hexagon module present: `Ghidra/Processors/Hexagon/data/languages/` has `hexagon.ldefs` (language id `Hexagon:LE:32:default`) and the compiled `hexagon.sla` (238,802 bytes) - `rea doctor --provider ghidra --json`: all Ghidra checks green (version `12.1.4`, headless, `java` `21.0.12`, native decompiler `linux_x86_64`) ## Steps to reproduce 1. Take a Qualcomm Hexagon DSP shared object, e.g. `chre_pal.so` (ELF32, little-endian, `ET_DYN`, `e_machine = 164`; not stripped, has `.symtab` and `.debug_info`). 2. Call `open_binary` with the Ghidra provider: ```json { "path": "/home/albert/mobian/work/hexagon-re/phone/sensors/dsp/sdsp/chre_pal.so", "provider_id": "ghidra" } ``` 3. The `raw-binary` route is closed too: its `architecture` enum is `6502 | x86 | x86_64 | arm | arm64`, which excludes Hexagon. ## Observed result ```json {"error":{"code":"target_unavailable","category":"unsupported_target", "message":"Cannot open artifact: unsupported ELF architecture.","retryable":false, "remediation":{"action":"Review the reported file-format reason and select a supported, well-formed target."}, "details":{"path":"…/chre_pal.so","reason":"unsupported ELF architecture","constraint":"file_format_rejected"}}} ``` ### Positive control (same REA, same provider, same command) Windows-style check with a supported architecture on the very same setup: | Target | `e_machine` | Result | |---|---|---| | `/usr/bin/ls` | 62 (`EM_X86_64`) | **opens**: `{"format":"elf","architecture":"x86_64"}`, session `open: true` | | `chre_pal.so` | **164 (`EM_HEXAGON`)** | rejected: `unsupported ELF architecture` | So this is not a broken install, a missing engine or a malformed target. ## Source-level trace `src/domain/binaryTarget.ts` (main): ```ts // line 212 const architecture = elfArchitecture(machine); if (architecture === undefined) return err("unsupported ELF architecture"); // line 213 ``` ```ts // lines 547-566 const elfArchitecture = ( machine: number, ): Exclude<BinaryArchitecture, RawOnlyArchitecture> | undefined => { switch (machine) { case 3: return "x86"; case 62: return "x86_64"; case 8: return "mips"; // EM_MIPS case 20: return "powerpc"; // EM_PPC case 40: return "arm"; case 183: return "arm64"; case 243: return "riscv"; // EM_RISCV } return undefined; }; ``` `164` (`EM_HEXAGON`) is absent from the switch, so the target never reaches the provider. (The same trace shape was reported in #3483 for `EM_XTENSA` = 94.) ## Evidence ``` $ readelf -h chre_pal.so | grep -E 'Class|Data|Type|Machine' Class: ELF32 Data: 2's complement, little endian Type: DYN (Shared object file) Machine: QUALCOMM DSP6 Processor # e_machine = 0xa4 = 164 = EM_HEXAGON ``` Symbols/debug info present (not stripped): ``` $ readelf -sW chre_pal.so | awk '$4=="FUNC"' | wc -l → 12 $ readelf -sW libchre_slpi_skel.so | awk '$4=="FUNC"' | wc -l → 3026 ``` The sibling object `libchre_slpi_skel.so` has 3,026 functions with symbols and DWARF, and is directly localizable with them — e.g. an abort-site string: ``` CHRE fatal@/home/work/beryllium-q-stable-build/vendor/qcom/non-hlos-sdm845-la201/slpi_proc/chre/chre/src/system/chre/platform/slpi/init.cc:251 ``` Engine side already supports it: ``` $ grep 'Hexagon:' .../Ghidra/Processors/Hexagon/data/languages/hexagon.ldefs id="Hexagon:LE:32:default"> $ ls -l .../Ghidra/Processors/Hexagon/data/languages/hexagon.sla → 238802 bytes ``` ## Impact Hexagon DSP objects are the userspace side of Qualcomm's SLPI/ADSP sensor and audio stacks (`libchre_slpi_skel.so`, `libFastRPC_*_skel.so`, `fastrpc_shell_N`, audio modules, …). They ship with symbols and DWARF on devices that expose their firmware, which makes them a very tractable static-analysis target — and today REA cannot load them at all, even though the engine it drives can. Users are forced to leave REA and drive Ghidra directly. ## Request / suggested remediation Minimal change consistent with the existing lanes (the maintainer knows the `BinaryArchitecture` union and downstream provider mapping better than I do): 1. Add `HEXAGON = 164` to the ELF admission path: ```ts case 164: // EM_HEXAGON (Qualcomm DSP6/QDSP6); 32-bit, byte order declared in the header. return "hexagon"; ``` plus the corresponding member in `BinaryArchitecture` and the provider-side acceptance. Unlike MIPS/RISC-V/PowerPC, Hexagon has no extra ELF family facts to surface here. 2. Alternatively, expose a "provider-chosen architecture / language override" path for ELF targets so the provider decides whether it can import the file (Ghidra's loader already resolves `Hexagon:LE:32:default` on its own). Related: #3483 (Xtensa, open — same "unsupported ELF architecture" class), #2063 (RISC-V lane, closed). I can reproduce against any development build and re-test a fix with the same Hexagon objects. --- ### Motivation (real target) This is not a synthetic request. The target set is the DSP-side userspace of a Snapdragon 845 (Xiaomi POCO F1) running mainline Linux: the device's SLPI firmware (`slpi.mbn`) currently crash-loops under the mainline kernel, and its CHRE sensor stack records a fatal whose exact source line can be resolved from the DWARF that these objects still carry (`chre/platform/slpi/init.cc:251`). Being able to load these ELF objects in REA — instead of leaving REA to drive Ghidra by hand — is what makes that investigation repeatable.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#2486
No description provided.