librz/bin: autodetect legacy TMS320C1x/C2x/C5x COFF objects

The legacy TMS320 fixed-point families ship as 16-bit big-endian COFF
objects whose magic and machine identifiers were not recognised by the
COFF loader. Teach the COFF format backend and the bin plugin to detect
and load them so the new tms320 c2x/c5x analysis can operate on real
object files.
This commit is contained in:
Anton Kochkov 2026-06-29 21:10:08 +00:00 committed by NOT XVilka
parent fee84c7f5c
commit 68471f8736
3 changed files with 34 additions and 0 deletions

View file

@ -91,6 +91,11 @@ static bool coff_is_magic(ut16 arch) {
/* fall-thru */ /* fall-thru */
case COFF_FILE_MACHINE_TI_2: case COFF_FILE_MACHINE_TI_2:
/* fall-thru */ /* fall-thru */
case COFF_FILE_TARGET_TI_TMS320C1x2x5x:
/* first-generation TI fixed-point COFF (C1x/C2x/C5x): the target id
* doubles as the file magic, unlike the later COFF1/COFF2 (0xc1/0xc2)
* which carry a separate target id field. */
/* fall-thru */
case COFF_FILE_MACHINE_MIL1750: case COFF_FILE_MACHINE_MIL1750:
return true; return true;
default: default:
@ -138,6 +143,7 @@ RZ_API bool rz_coff_supported_arch(RzBuffer *b) {
RZ_API ut32 rz_coff_addr_scale(RZ_NONNULL struct rz_bin_coff_obj *obj) { RZ_API ut32 rz_coff_addr_scale(RZ_NONNULL struct rz_bin_coff_obj *obj) {
rz_return_val_if_fail(obj, 1); rz_return_val_if_fail(obj, 1);
switch (obj->target_id) { switch (obj->target_id) {
case COFF_FILE_TARGET_TI_TMS320C1x2x5x:
case COFF_FILE_TARGET_TI_TMS320C5400: case COFF_FILE_TARGET_TI_TMS320C5400:
case COFF_FILE_TARGET_TI_TMS320C2800: case COFF_FILE_TARGET_TI_TMS320C2800:
return 2; return 2;
@ -258,6 +264,9 @@ static bool bin_coff_init_hdr(RzBuffer *b, struct rz_bin_coff_obj *obj, ut64 *of
return false; return false;
} else if (coff_is_ti_machine(obj)) { } else if (coff_is_ti_machine(obj)) {
return rz_buf_read_ble16_offset(b, offset, &obj->target_id, obj->big_endian); return rz_buf_read_ble16_offset(b, offset, &obj->target_id, obj->big_endian);
} else if (obj->hdr.f_magic == COFF_FILE_TARGET_TI_TMS320C1x2x5x) {
// Original TI COFF has no separate field: the magic is the target id.
obj->target_id = obj->hdr.f_magic;
} }
return true; return true;
} }

View file

@ -49,6 +49,7 @@
#define COFF_FILE_MACHINE_TI_2 0x00c2 #define COFF_FILE_MACHINE_TI_2 0x00c2
#define COFF_FILE_MACHINE_MIL1750 0x00db #define COFF_FILE_MACHINE_MIL1750 0x00db
#define COFF_FILE_TARGET_TI_TMS320C1x2x5x 0x0092
#define COFF_FILE_TARGET_TI_TMS320C3x4x 0x0093 #define COFF_FILE_TARGET_TI_TMS320C3x4x 0x0093
#define COFF_FILE_TARGET_TI_TMS470 0x0097 #define COFF_FILE_TARGET_TI_TMS470 0x0097
#define COFF_FILE_TARGET_TI_TMS320C5400 0x0098 #define COFF_FILE_TARGET_TI_TMS320C5400 0x0098

View file

@ -648,10 +648,34 @@ static RzBinInfo *coff_info(RzBinFile *bf) {
ret->cpu = rz_str_dup("r10000"); ret->cpu = rz_str_dup("r10000");
ret->bits = 32; ret->bits = 32;
break; break;
case COFF_FILE_TARGET_TI_TMS320C1x2x5x:
// Original TI COFF (version 0) carried the target id directly in the
// file header's f_magic, so a target-id constant is matched here on the
// same field that holds COFF_FILE_MACHINE_TI_1/_2 for newer files.
// COFF1/COFF2 moved the id into the separate target_id field, handled
// by the COFF_FILE_MACHINE_TI_1/_2 case below.
// The id is shared by the C1x/C2x/C5x assemblers, so default to the C2x
// disassembler (override with -c c5x for a C5x image).
ret->machine = rz_str_dup("TMS320C1x/C2x/C5x");
ret->cpu = rz_str_dup("c2x");
ret->arch = rz_str_dup("tms320");
ret->bits = 16;
break;
case COFF_FILE_MACHINE_TI_1: case COFF_FILE_MACHINE_TI_1:
/* fall-thru */ /* fall-thru */
case COFF_FILE_MACHINE_TI_2: case COFF_FILE_MACHINE_TI_2:
switch (obj->target_id) { switch (obj->target_id) {
case COFF_FILE_TARGET_TI_TMS320C1x2x5x:
// First-generation TI fixed-point COFF id, shared by the TMS320C1x/
// C2x/C5x assemblers. Map it to the legacy single-accumulator C2x
// disassembler by default; override with -c for a C5x image. (The
// id is rarely present on raw firmware dumps; verify on real object
// files before relying on autodetection.)
ret->machine = rz_str_dup("TMS320C1x/C2x/C5x");
ret->cpu = rz_str_dup("c2x");
ret->arch = rz_str_dup("tms320");
ret->bits = 16;
break;
case COFF_FILE_TARGET_TI_TMS320C3x4x: case COFF_FILE_TARGET_TI_TMS320C3x4x:
ret->machine = rz_str_dup("TMS320C3x/4x"); ret->machine = rz_str_dup("TMS320C3x/4x");
/* TMS320C3x/C4x is a floating-point DSP family that /* TMS320C3x/C4x is a floating-point DSP family that