Skip to content

Commit

Permalink
librz/arch: fix various MIPS CPU info and ensure compatibility where …
Browse files Browse the repository at this point in the history
…possible. (#4888)
  • Loading branch information
wargio authored Feb 9, 2025
1 parent 6047120 commit 8ea5650
Show file tree
Hide file tree
Showing 9 changed files with 152 additions and 51 deletions.
98 changes: 75 additions & 23 deletions librz/arch/p/arch_mips_cs.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,40 @@
#include <deprecated_arch_helper.h>
#include <capstone/capstone.h>

#define EXTRA_CPUS "r2300,r2600,r2800,r2000a,r2000,r3000a,r3000,r10000"
/**
* The MIPS32 and MIPS64 ISAs are a common source of confusion.
*
* The MIPS64 ISA level is actually a superset of the MIPS5 ISA, so it includes all instructions from MIPS5 and earlier ISAs.
* The MIPS5 ISA level was designed by Silicon Graphics back in 1994, but never actually got used in a real life CPU.
* It lives on as part of the MIPS64 ISA.
*
* MIPS32 is the 32-bit subset of MIPS64, it exists because most applications only require 32-bit processing.
* MIPS3 can also run at 32-bit mode.
*
* | MIPS ISA | bits | CPUs Covered |
* + -------- + ------ + ------------------------------------------------------------------- +
* | MIPS 1 | 32-bit | r2000, r3000 |
* | MIPS 2 | 32-bit | r6000 |
* | MIPS 3 | 64-bit | r4000, r4400, r4600, r4700 |
* | MIPS 4 | 64-bit | r5000, rm5000, rm7000, r8000, r9000, r10000, r12000, r14000, r16000 |
* | MIPS 5 | 64-bit | None ? |
* | MIPS32 | 32-bit | AMD Alchemy series, 4kc, 4km... MIPS32 (r2-r6) ISA. |
* | MIPS64 | 64-bit | Broadcom SiByte SB1, 5kc... MIPS64 (r2-r6) ISA. |
*
* Source: https://wiki.gentoo.org/wiki/Handbook:MIPS/Blocks/HWReqs
*/

#define EXTRA_CPUS_32 "r2300,r2600,r2800,r2000a,r2000,r3000a,r3000,r6000"
#define EXTRA_CPUS_64 "r4000,r4400,r4600,r4700,r5000,rm5000,rm7000,r8000,r9000,r10000,r12000,r14000,r16000"
#define EXTRA_CPUS EXTRA_CPUS_32 "," EXTRA_CPUS_64

#if CS_NEXT_VERSION < 6
// first cpu is default
#define CAPSTONE_CPUS "mips32,mips1,mips2,mips3,mips4,mips16,mips32r6,mips64,micromips"
#define CAPSTONE_FEATURES ""
#else
// first cpu is default
#define CAPSTONE_CPUS "mips3,mips1,mips2,mips32r2,mips32r3,mips32r5,mips32r6,mips4,mips5,mips64r2,mips64r3,mips64r5,mips64r6,octeon,octeonp,nanomips,nms1,i7200,micromips,micro32r3,micro32r6"
#define CAPSTONE_CPUS "mips32,mips1,mips2,mips32r2,mips32r3,mips32r5,mips32r6,mips3,mips4,mips5,mips64r2,mips64r3,mips64r5,mips64r6,octeon,octeonp,nanomips,nms1,i7200,micromips,micro32r3,micro32r6"
#define CAPSTONE_FEATURES "noptr64,nofloat"
#endif

Expand Down Expand Up @@ -49,7 +74,8 @@ static bool cs_mode_from_cpu(const char *cpu, int bits, bool big_endian, cs_mode
return_on_cpu("mips1", CS_MODE_MIPS2); // mips1 is subset of mips2
return_on_cpu("mips2", CS_MODE_MIPS2);
return_on_cpu("mips3", CS_MODE_MIPS3);
return_on_cpu("mips4", CS_MODE_MIPS32); // old capstone uses the same
return_on_cpu("mips4", CS_MODE_MIPS64); // old capstone uses the same
return_on_cpu("mips5", CS_MODE_MIPS64); // old capstone uses the same
return_on_cpu("mips16", CS_MODE_MIPS32); // old capstone uses the same
return_on_cpu("mips32", CS_MODE_MIPS32);
return_on_cpu("mips32r6", CS_MODE_MIPS32R6);
Expand All @@ -60,14 +86,27 @@ static bool cs_mode_from_cpu(const char *cpu, int bits, bool big_endian, cs_mode
return_on_cpu("mips64r6", CS_MODE_MIPS64); // fallback to mips64

// extra cpus
return_on_cpu("r2300", CS_MODE_MIPS2);
return_on_cpu("r2600", CS_MODE_MIPS2);
return_on_cpu("r2800", CS_MODE_MIPS2);
return_on_cpu("r2000a", CS_MODE_MIPS2);
return_on_cpu("r2000", CS_MODE_MIPS2);
return_on_cpu("r3000a", CS_MODE_MIPS2); // ISA mips2
return_on_cpu("r3000", CS_MODE_MIPS2); // ISA mips2
return_on_cpu("r10000", CS_MODE_MIPS32); // old capstone uses the same
return_on_cpu("r2300", CS_MODE_MIPS2); // mips1 is subset of mips2
return_on_cpu("r2600", CS_MODE_MIPS2); // mips1 is subset of mips2
return_on_cpu("r2800", CS_MODE_MIPS2); // mips1 is subset of mips2
return_on_cpu("r2000a", CS_MODE_MIPS2); // mips1 is subset of mips2
return_on_cpu("r2000", CS_MODE_MIPS2); // mips1 is subset of mips2
return_on_cpu("r3000a", CS_MODE_MIPS2); // mips1 is subset of mips2
return_on_cpu("r3000", CS_MODE_MIPS2); // mips1 is subset of mips2
return_on_cpu("r6000", CS_MODE_MIPS2);
return_on_cpu("r4000", CS_MODE_MIPS3);
return_on_cpu("r4400", CS_MODE_MIPS3);
return_on_cpu("r4600", CS_MODE_MIPS3);
return_on_cpu("r4700", CS_MODE_MIPS3);
return_on_cpu("r5000", CS_MODE_MIPS4);
return_on_cpu("rm5000", CS_MODE_MIPS4);
return_on_cpu("rm7000", CS_MODE_MIPS4);
return_on_cpu("r8000", CS_MODE_MIPS4);
return_on_cpu("r9000", CS_MODE_MIPS4);
return_on_cpu("r10000", CS_MODE_MIPS4);
return_on_cpu("r12000", CS_MODE_MIPS4);
return_on_cpu("r14000", CS_MODE_MIPS4);
return_on_cpu("r16000", CS_MODE_MIPS4);
}

#else // CS_NEXT_VERSION >= 6
Expand Down Expand Up @@ -101,14 +140,14 @@ static bool cs_mode_from_cpu(const char *cpu, int bits, bool big_endian, cs_mode
return_or_add_on_cpu("mips1", CS_MODE_MIPS1);
return_or_add_on_cpu("mips2", CS_MODE_MIPS2);
return_or_add_on_cpu("mips16", CS_MODE_MIPS16);
return_or_add_on_cpu("mips32", CS_MODE_MIPS3); // we always map the generic mips32 as mips3
return_or_add_on_cpu("mips32", CS_MODE_MIPS3); // we always map the generic mips32 as mips3 32bits
return_or_add_on_cpu("mips32r2", CS_MODE_MIPS32R2);
return_or_add_on_cpu("mips32r3", CS_MODE_MIPS32R3);
return_or_add_on_cpu("mips32r5", CS_MODE_MIPS32R5);
return_or_add_on_cpu("mips32r6", CS_MODE_MIPS32R6);
return_or_add_on_cpu("mips3", CS_MODE_MIPS3);
return_or_add_on_cpu("mips4", CS_MODE_MIPS4);
return_or_add_on_cpu("mips5", CS_MODE_MIPS5);
return_or_add_on_cpu("mips3", CS_MODE_MIPS3); // implements mips64
return_or_add_on_cpu("mips4", CS_MODE_MIPS4); // implements mips64
return_or_add_on_cpu("mips5", CS_MODE_MIPS5); // implements mips64
return_or_add_on_cpu("mips64", CS_MODE_MIPS64);
return_or_add_on_cpu("mips64r2", CS_MODE_MIPS64); // fallback to mips64
return_or_add_on_cpu("mips64r3", CS_MODE_MIPS64R3);
Expand All @@ -131,22 +170,35 @@ static bool cs_mode_from_cpu(const char *cpu, int bits, bool big_endian, cs_mode
return_on_cpu("micro32r6", CS_MODE_MICRO32R6);

// extra cpus
return_on_cpu("r2300", CS_MODE_MIPS2);
return_on_cpu("r2600", CS_MODE_MIPS2);
return_on_cpu("r2800", CS_MODE_MIPS2);
return_on_cpu("r2000a", CS_MODE_MIPS2);
return_on_cpu("r2000", CS_MODE_MIPS2);
return_on_cpu("r3000a", CS_MODE_MIPS2); // ISA mips2
return_on_cpu("r3000", CS_MODE_MIPS2); // ISA mips2
return_on_cpu("r2300", CS_MODE_MIPS1);
return_on_cpu("r2600", CS_MODE_MIPS1);
return_on_cpu("r2800", CS_MODE_MIPS1);
return_on_cpu("r2000a", CS_MODE_MIPS1);
return_on_cpu("r2000", CS_MODE_MIPS1);
return_on_cpu("r3000a", CS_MODE_MIPS1);
return_on_cpu("r3000", CS_MODE_MIPS1);
return_on_cpu("r6000", CS_MODE_MIPS2);
return_on_cpu("r4000", CS_MODE_MIPS3);
return_on_cpu("r4400", CS_MODE_MIPS3);
return_on_cpu("r4600", CS_MODE_MIPS3);
return_on_cpu("r4700", CS_MODE_MIPS3);
return_on_cpu("r5000", CS_MODE_MIPS4);
return_on_cpu("rm5000", CS_MODE_MIPS4);
return_on_cpu("rm7000", CS_MODE_MIPS4);
return_on_cpu("r8000", CS_MODE_MIPS4);
return_on_cpu("r9000", CS_MODE_MIPS4);
return_on_cpu("r10000", CS_MODE_MIPS4);
return_on_cpu("r12000", CS_MODE_MIPS4);
return_on_cpu("r14000", CS_MODE_MIPS4);
return_on_cpu("r16000", CS_MODE_MIPS4);
}

switch (bits) {
case 64: // generic mips64
*mode = _mode | CS_MODE_MIPS64;
break;
case 32: // generic mips32
*mode = _mode | CS_MODE_MIPS3;
*mode = _mode | CS_MODE_MIPS2;
break;
case 16: // generic mips16
*mode = _mode | CS_MODE_MIPS16;
Expand Down
8 changes: 4 additions & 4 deletions librz/bin/format/elf/elf_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -260,9 +260,9 @@ static const struct cpu_mips_translation gnu_mips_mach_translation_table[] = {
static const struct mips_bits_translation mips_bits_translation_table[] = {
{ EF_MIPS_ARCH_1, 32 },
{ EF_MIPS_ARCH_2, 32 },
{ EF_MIPS_ARCH_3, 32 },
{ EF_MIPS_ARCH_4, 32 },
{ EF_MIPS_ARCH_5, 32 },
{ EF_MIPS_ARCH_3, 64 },
{ EF_MIPS_ARCH_4, 64 },
{ EF_MIPS_ARCH_5, 64 },
{ EF_MIPS_ARCH_32, 32 },
{ EF_MIPS_ARCH_64, 64 },
{ EF_MIPS_ARCH_32R2, 32 },
Expand All @@ -272,7 +272,7 @@ static const struct mips_bits_translation mips_bits_translation_table[] = {
};

static const struct cpu_mips_translation gnu_mips_arch_translation_table32[] = {
{ EF_MIPS_ARCH_1, "mips5" }, // also used for generic mips, so we default to mips5
{ EF_MIPS_ARCH_1, "mips3" }, // also used for generic mips, so we default to mips3 at 32 bits mode.
{ EF_MIPS_ARCH_2, "mips2" },
{ EF_MIPS_ARCH_3, "mips3" },
{ EF_MIPS_ARCH_4, "mips4" },
Expand Down
6 changes: 3 additions & 3 deletions librz/bin/format/le/le.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@ static const char *le_get_cpu_type(rz_bin_le_obj_t *bin) {
case 3: return "80486";
case 0x20: return "N10";
case 0x21: return "N11";
case 0x40: return "R3000";
case 0x41: return "R6000";
case 0x42: return "R4000";
case 0x40: return "r3000";
case 0x41: return "r6000";
case 0x42: return "r4000";
default: return "Unknown";
}
}
Expand Down
1 change: 1 addition & 0 deletions librz/bin/format/pe/pe.h
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ char *PE_(rz_bin_pe_get_arch)(RzBinPEObj *bin);
char *PE_(rz_bin_pe_get_cc)(RzBinPEObj *bin);
char *PE_(rz_bin_pe_get_compiler)(RzBinPEObj *bin);
char *PE_(rz_bin_pe_get_machine)(RzBinPEObj *bin);
char *PE_(rz_bin_pe_get_cpu)(RzBinPEObj *bin);
char *PE_(rz_bin_pe_get_os)(RzBinPEObj *bin);
char *PE_(rz_bin_pe_get_class)(RzBinPEObj *bin);
int PE_(rz_bin_pe_get_bits)(RzBinPEObj *bin);
Expand Down
57 changes: 44 additions & 13 deletions librz/bin/format/pe/pe_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ bool PE_(rz_bin_pe_has_canary)(const RzBinPEObj *bin) {

// TODO: make it const! like in elf
char *PE_(rz_bin_pe_get_machine)(RzBinPEObj *bin) {
char *machine = NULL;
const char *machine = NULL;

if (bin && bin->nt_headers) {
switch (bin->nt_headers->file_header.Machine) {
Expand Down Expand Up @@ -71,6 +71,24 @@ char *PE_(rz_bin_pe_get_machine)(RzBinPEObj *bin) {
return rz_str_dup(machine);
}

char *PE_(rz_bin_pe_get_cpu)(RzBinPEObj *bin) {
const char *cpu = NULL;

if (bin && bin->nt_headers) {
switch (bin->nt_headers->file_header.Machine) {
case PE_IMAGE_FILE_MACHINE_MIPS16: cpu = "mips16"; break;
case PE_IMAGE_FILE_MACHINE_MIPSFPU: cpu = "mips2"; break;
case PE_IMAGE_FILE_MACHINE_MIPSFPU16: cpu = "mips16"; break;
case PE_IMAGE_FILE_MACHINE_R10000: cpu = "r10000"; break;
case PE_IMAGE_FILE_MACHINE_R3000: cpu = "r3000"; break;
case PE_IMAGE_FILE_MACHINE_R4000: cpu = "r4000"; break;
case PE_IMAGE_FILE_MACHINE_WCEMIPSV2: cpu = "mips2"; break; // ISA MIPS32
default: return NULL;
}
}
return rz_str_dup(cpu);
}

// TODO: make it const! like in elf
char *PE_(rz_bin_pe_get_os)(RzBinPEObj *bin) {
char *os;
Expand Down Expand Up @@ -139,6 +157,9 @@ char *PE_(rz_bin_pe_get_arch)(RzBinPEObj *bin) {
case PE_IMAGE_FILE_MACHINE_MIPSFPU:
case PE_IMAGE_FILE_MACHINE_MIPSFPU16:
case PE_IMAGE_FILE_MACHINE_WCEMIPSV2:
case PE_IMAGE_FILE_MACHINE_R10000:
case PE_IMAGE_FILE_MACHINE_R3000:
case PE_IMAGE_FILE_MACHINE_R4000:
arch = rz_str_dup("mips");
break;
case PE_IMAGE_FILE_MACHINE_POWERPC:
Expand Down Expand Up @@ -323,19 +344,29 @@ int PE_(bin_pe_get_actual_checksum)(RzBinPEObj *bin) {
}

int PE_(rz_bin_pe_get_bits)(RzBinPEObj *bin) {
int bits = 32;
if (bin && bin->nt_headers) {
if (is_arm(bin) && is_thumb(bin)) {
bits = 16;
} else {
switch (bin->nt_headers->optional_header.Magic) {
case PE_IMAGE_FILE_TYPE_PE32: bits = 32; break;
case PE_IMAGE_FILE_TYPE_PE32PLUS: bits = 64; break;
default: bits = -1;
}
}
if (!(bin && bin->nt_headers)) {
return 32;
}
return bits;
switch (bin->nt_headers->file_header.Machine) {
case PE_IMAGE_FILE_MACHINE_ARM: return is_thumb(bin) ? 16 : 32; // Arm32
case PE_IMAGE_FILE_MACHINE_ARM64: return 64; // Aarch64
case PE_IMAGE_FILE_MACHINE_ARMNT: return 16; // ARM Thumb-2
case PE_IMAGE_FILE_MACHINE_THUMB: return 16; // ARM Thumb/Thumb-2
case PE_IMAGE_FILE_MACHINE_MIPS16: return 32;
case PE_IMAGE_FILE_MACHINE_MIPSFPU: return 32;
case PE_IMAGE_FILE_MACHINE_MIPSFPU16: return 32;
case PE_IMAGE_FILE_MACHINE_WCEMIPSV2: return 32; // MIPS WCE v2
case PE_IMAGE_FILE_MACHINE_R10000: return 64;
case PE_IMAGE_FILE_MACHINE_R3000: return 32;
case PE_IMAGE_FILE_MACHINE_R4000: return 64;
default: break;
}
switch (bin->nt_headers->optional_header.Magic) {
case PE_IMAGE_FILE_TYPE_PE32: return 32;
case PE_IMAGE_FILE_TYPE_PE32PLUS: return 64;
default: break;
}
return 32;
}

#define HASCHR(x) (bin->nt_headers->file_header.Characteristics & (x))
Expand Down
4 changes: 3 additions & 1 deletion librz/bin/p/bin_coff.c
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,9 @@ static RzBinInfo *info(RzBinFile *bf) {

switch (obj->hdr.f_magic) {
case COFF_FILE_MACHINE_R4000:
ret->cpu = rz_str_dup("mips4");
ret->cpu = rz_str_dup("mips3");
ret->bits = 64;
break;
/* fall-thru */
case COFF_FILE_MACHINE_MIPS16:
if (!ret->cpu) {
Expand Down
1 change: 1 addition & 0 deletions librz/bin/p/bin_pe.inc
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,7 @@ static RzBinInfo *info(RzBinFile *bf) {
ret->rclass = rz_str_dup("pe");
ret->os = PE_(rz_bin_pe_get_os)(bf->o->bin_obj);
ret->arch = PE_(rz_bin_pe_get_arch)(bf->o->bin_obj);
ret->cpu = PE_(rz_bin_pe_get_cpu)(bf->o->bin_obj);
ret->machine = PE_(rz_bin_pe_get_machine)(bf->o->bin_obj);
ret->subsystem = PE_(rz_bin_pe_get_subsystem)(bf->o->bin_obj);
ret->default_cc = PE_(rz_bin_pe_get_cc)(bf->o->bin_obj);
Expand Down
24 changes: 19 additions & 5 deletions test/db/cmd/cmd_eval
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ zoom.to=0
EOF
RUN

NAME=e analysis.gp(mips)
NAME=e analysis.gp (mips)
FILE=bins/elf/analysis/mips64r2-cc1
CMDS=e analysis.gp
EXPECT=<<EOF
Expand All @@ -33,7 +33,7 @@ EOF
RUN

NAME=e asm.os
FILE=bins/elf/analysis/hello-linux-x86_64
FILE==
CMDS=e asm.os=?
EXPECT=<<EOF
ios
Expand All @@ -50,19 +50,20 @@ EOF
RUN

NAME=e asm.cpu
FILE=bins/elf/analysis/hello-linux-x86_64
FILE==
CMDS=<<EOF
e asm.arch=mips
e asm.cpu=?
EOF
EXPECT=<<EOF
mips3
mips32
mips1
mips2
mips32r2
mips32r3
mips32r5
mips32r6
mips3
mips4
mips5
mips64r2
Expand All @@ -84,7 +85,20 @@ r2000a
r2000
r3000a
r3000
r6000
r4000
r4400
r4600
r4700
r5000
rm5000
rm7000
r8000
r9000
r10000
r12000
r14000
r16000
noptr64
nofloat
EOF
Expand Down Expand Up @@ -132,7 +146,7 @@ EOF
RUN

NAME=el commands test
FILE=bins/elf/analysis/hello-linux-x86_64
FILE==
CMDS=<<EOF
elj zoom
elJ zoom
Expand Down
4 changes: 2 additions & 2 deletions test/db/cmd/cmd_i
Original file line number Diff line number Diff line change
Expand Up @@ -321,8 +321,8 @@ EOF
EXPECT=<<EOF
offset size arch machine
----------------------------------------------------------------------
0x00000000 266108 mips_32 mips5 noreorder pic c MIPS R3000 big-endian
[{"arch":"mips","bits":32,"offset":0,"size":266108,"cpu":"mips5","features":"noreorder pic cpic o32 n32","machine":"MIPS R3000 big-endian"}]
0x00000000 266108 mips_32 mips3 noreorder pic c MIPS R3000 big-endian
[{"arch":"mips","bits":32,"offset":0,"size":266108,"cpu":"mips3","features":"noreorder pic cpic o32 n32","machine":"MIPS R3000 big-endian"}]
EOF
RUN

Expand Down

0 comments on commit 8ea5650

Please sign in to comment.