diff --git a/librz/bin/format/elf/elf_info.c b/librz/bin/format/elf/elf_info.c index df6675c586f..aa4095c861b 100644 --- a/librz/bin/format/elf/elf_info.c +++ b/librz/bin/format/elf/elf_info.c @@ -4,7 +4,9 @@ // SPDX-FileCopyrightText: 2008-2020 alvaro_fe // SPDX-License-Identifier: LGPL-3.0-only +#include "core/core_private.h" #include "elf.h" +#include "rz_types_base.h" #define EF_MIPS_ABI_O32 0x00001000 /* O32 ABI. */ #define EF_MIPS_ABI_O64 0x00002000 /* O32 extended for 64 bit. */ @@ -37,6 +39,11 @@ struct cpu_mips_translation { const char *name; }; +struct cpu_arm_translation { + Elf_(Half) arch; + const char *name; +}; + struct arch_translation { Elf_(Half) arch; const char *name; @@ -241,6 +248,32 @@ static const struct cpu_mips_translation cpu_mips_translation_table[] = { { EF_MIPS_ARCH_64R2, "mips64r2" }, }; +static const struct cpu_arm_translation cpu_arm_translation_table[] = { + { ARM_VER_PRE_V4, "ARM Pre-v4"}, + { ARM_VER_V4, "ARM v4"}, + { ARM_VER_V4T, "ARM v4T"}, + { ARM_VER_V5T, "ARM v5T"}, + { ARM_VER_V5TE, "ARM v5TE"}, + { ARM_VER_V5TEJ, "ARM v5TEJ"}, + { ARM_VER_V6, "ARM v6"}, + { ARM_VER_V6KZ, "ARM v6KZ"}, + { ARM_VER_V6T2, "ARM v6T2"}, + { ARM_VER_V6K, "ARM v6K"}, + { ARM_VER_V7, "ARM v7"}, + { ARM_VER_V6_M, "ARM v6-M"}, + { ARM_VER_V6S_M, "ARM v6S-M"}, + { ARM_VER_V7E_M, "ARM v7E-M"}, + { ARM_VER_V8_A, "ARM v8-A"}, + { ARM_VER_V8_R, "ARM v8-R"}, + { ARM_VER_V8_M_BASELINE, "ARM v8-M.baseline"}, + { ARM_VER_V8_M_MAINLINE, "ARM v8-M.mainline"}, + { ARM_VER_V8_1_A, "ARM v8.1-A"}, + { ARM_VER_V8_2_A, "ARM v8.2-A"}, + { ARM_VER_V8_3_A, "ARM v8.3-A"}, + { ARM_VER_V8_1_M_MAINLINE, "ARM v8.1-M.mainline"}, + { ARM_VER_V9_A, "ARM v9-A"}, +}; + static const struct arch_translation arch_translation_table[] = { { EM_ARC, "arc" }, { EM_ARC_A5, "arc" }, @@ -845,6 +878,143 @@ static char *get_cpu_mips(ELFOBJ *bin) { return strdup(" Unknown mips ISA"); } +static char *read_arm_build_attributes(char *ptr, ut32 bytes_to_read, bool isbig) { + while (bytes_to_read > 0) { + ut64 arm_tag = 0; + int len = 0; + rz_uleb128_decode((ut8 *)ptr, &len, &arm_tag); + ptr += len; + bytes_to_read -= len; + arm_tag = arm_tag % 128; + switch (arm_tag) { + case TAG_CPU_ARCH: { + ut64 cpu_arch = 0; + rz_uleb128_decode((ut8 *)ptr, &len, &cpu_arch); + ptr += len; + bytes_to_read -= len; + for (size_t i = 0; i < RZ_ARRAY_SIZE(cpu_arm_translation_table); i++) { + if (cpu_arch == cpu_arm_translation_table[i].arch) { + return strdup(cpu_arm_translation_table[i].name); + } + } + break; + } + case TAG_CPU_ARCH_PROFILE: + return strdup("Tag_CPU_ARCH_PROFILE"); + case TAG_CPU_RAW_NAME: + case TAG_CPU_NAME: + case TAG_COMPATIBILITY: + len = strlen(ptr) + 1; + bytes_to_read -= len; + ptr += len; + break; + case TAG_ARM_ISA_USE: + case TAG_THUMB_ISA_USE: + case TAG_FP_ARCH: + case TAG_WMMX_ARCH: + case TAG_ADVANCED_SIMD_ARCH: + case TAG_PCS_CONFIG: + case TAG_ABI_PCS_R9_USE: + case TAG_ABI_PCS_RW_DATA: + case TAG_ABI_PCS_RO_DATA: + case TAG_ABI_PCS_GOT_USE: + case TAG_ABI_PCS_WCHAR_T: + case TAG_ABI_ENUM_SIZE: + case TAG_ABI_ALIGN_NEEDED: + case TAG_ABI_ALIGN_PRESERVED: + case TAG_ABI_FP_ROUNDING: + case TAG_ABI_FP_DENORMAL: + case TAG_ABI_FP_EXCEPTIONS: + case TAG_ABI_FP_USER_EXCEPTIONS: + case TAG_ABI_FP_NUMBER_MODEL: + case TAG_ABI_HARDFP_USE: + case TAG_ABI_VFP_ARGS: + case TAG_ABI_WMMX_ARGS: + case TAG_ABI_OPTIMIZATION_GOALS: + case TAG_ABI_FP_OPTIMIZATION_GOALS: + rz_uleb128_decode((ut8 *)ptr, &len, NULL); + ptr += len; + bytes_to_read -= len; + break; + default: + if (arm_tag > 32) { + if (arm_tag & 1) { + len = strlen(ptr) + 1; + bytes_to_read -= len; + ptr += len; + } else { + rz_uleb128_decode((ut8 *)ptr, &len, NULL); + ptr += len; + bytes_to_read -= len; + } + } + } + } + return strdup(" Unknown arm ISA"); +} + +static char *read_arm_aeabi_section(char *ptr, ut32 bytes_to_read, bool isbig) { + while (bytes_to_read > 0) { + ut8 sub_subsection = rz_read_ble8(ptr); // Will always be 1, 2 or 3, hence no need for uleb128 decoding. + ut32 sub_subsection_size = rz_read_ble32(ptr + 1, isbig); + + if (sub_subsection == ARM_TAG_FILE) { + char *str = read_arm_build_attributes(ptr + 5, sub_subsection_size - 5, isbig); + if (strcmp(str, " Unknown arm ISA")) { + return str; + } + } + ptr += sub_subsection_size; + bytes_to_read -= sub_subsection_size; + } + return strdup(" Unknown arm ISA"); +} + +/** + * Processor-specific section types explained in: + * 1. https://github.com/ARM-software/abi-aa/blob/main/aaelf32/aaelf32.rst + * 2. https://github.com/ARM-software/abi-aa/blob/main/addenda32/addenda32.rst + */ +static char *get_cpu_arm(ELFOBJ *bin) { + RzBinElfSection *section = Elf_(rz_bin_elf_get_section_with_name)(bin, ".ARM.attributes"); + if (!section) { + return strdup(" Unknown arm ISA"); + } + + ut64 offset = section->offset; + ut64 size = section->size; + if (size < 1) { + return strdup(" Unknown arm ISA"); + } + + char *result = malloc(size + 1); + if (!result) { + return strdup(" Unknown arm ISA"); + } + + if (rz_buf_read_at(bin->b, offset, (ut8 *)result, size) < 1) { + free(result); + return strdup(" Unknown arm ISA"); + } + + char *subsection_ptr = result + 1; // Point to the first subsection (first byte is the format-version) + bool isbig = Elf_(rz_bin_elf_is_big_endian)(bin); + + while (subsection_ptr - result < size) { + char *ptr = subsection_ptr; + ut32 subsection_size = rz_read_ble32(ptr, isbig); + ptr += 4; + + if (!strcmp(ptr, "aeabi")) { + ptr += strlen("aeabi") + 1; // +1 for the null byte + return read_arm_aeabi_section(ptr, subsection_size - 10, isbig); + } + subsection_ptr += subsection_size; + } + + return strdup(" Unknown arm ISA"); +} + static bool is_elf_class64(ELFOBJ *bin) { return bin->ehdr.e_ident[EI_CLASS] == ELFCLASS64; } @@ -1460,7 +1630,7 @@ RZ_OWN char *Elf_(rz_bin_elf_get_arch)(RZ_NONNULL ELFOBJ *bin) { * \param elf type * \return allocated string * - * Only work on mips right now. Use the elf header to deduce the cpu + * Only work on mips and arm right now. Use the elf header to deduce the cpu */ RZ_OWN char *Elf_(rz_bin_elf_get_cpu)(RZ_NONNULL ELFOBJ *bin) { rz_return_val_if_fail(bin, NULL); @@ -1471,6 +1641,8 @@ RZ_OWN char *Elf_(rz_bin_elf_get_cpu)(RZ_NONNULL ELFOBJ *bin) { if (bin->ehdr.e_machine == EM_MIPS) { return get_cpu_mips(bin); + } else if (bin->ehdr.e_machine == EM_ARM) { + return get_cpu_arm(bin); } return NULL; diff --git a/librz/bin/format/elf/glibc_elf.h b/librz/bin/format/elf/glibc_elf.h index 63b8bb91f82..c88b5690bf3 100644 --- a/librz/bin/format/elf/glibc_elf.h +++ b/librz/bin/format/elf/glibc_elf.h @@ -2712,6 +2712,106 @@ enum { #define SHT_ARM_PREEMPTMAP (SHT_LOPROC + 2) /* Preemption details. */ #define SHT_ARM_ATTRIBUTES (SHT_LOPROC + 3) /* ARM attributes section. */ +/* Constants defining public attributes sub-subsections. */ +#define ARM_TAG_FILE 1 +#define ARM_TAG_SECTION 2 +#define ARM_TAG_SYMBOL 3 + +/* ARM target-related attributes. */ +#define TAG_CPU_RAW_NAME 4 +#define TAG_CPU_NAME 5 +#define TAG_CPU_ARCH 6 +#define TAG_CPU_ARCH_PROFILE 7 +#define TAG_ARM_ISA_USE 8 +#define TAG_THUMB_ISA_USE 9 +#define TAG_FP_ARCH 10 +#define TAG_WMMX_ARCH 11 +#define TAG_ADVANCED_SIMD_ARCH 12 +#define TAG_CPU_UNALIGNED_ACCESS 34 +#define TAG_FP_HP_EXTENSION 36 +#define TAG_MPEXTENSION_USE 42 +#define TAG_DIV_USE 44 +#define TAG_DSP_EXTENSION 46 +#define TAG_MVE_ARCH 48 +#define TAG_PAC_EXTENSION 50 +#define TAG_BTI_EXTENSION 52 +#define TAG_T2EE_USE 66 +#define TAG_VIRTUALIZATION_USE 68 + +/* ARM procedure call-related attributes. */ +#define TAG_PCS_CONFIG 13 +#define TAG_ABI_PCS_R9_USE 14 +#define TAG_ABI_PCS_RW_DATA 15 +#define TAG_ABI_PCS_RO_DATA 16 +#define TAG_ABI_PCS_GOT_USE 17 +#define TAG_ABI_PCS_WCHAR_T 18 +#define TAG_ABI_FP_ROUNDING 19 +#define TAG_ABI_FP_DENORMAL 20 +#define TAG_ABI_FP_EXCEPTIONS 21 +#define TAG_ABI_FP_USER_EXCEPTIONS 22 +#define TAG_ABI_FP_NUMBER_MODEL 23 +#define TAG_ABI_ALIGN_NEEDED 24 +#define TAG_ABI_ALIGN_PRESERVED 25 +#define TAG_ABI_ENUM_SIZE 26 +#define TAG_ABI_HARDFP_USE 27 +#define TAG_ABI_VFP_ARGS 28 +#define TAG_ABI_WMMX_ARGS 29 +#define TAG_ABI_FP_16BIT_FORMAT 38 +#define TAG_FRAMEPOINTER_USE 72 +#define TAG_BTI_USE 74 + +/* ARM miscellaneous attributes. */ +#define TAG_PACRET_USE 76 + +/* ARM optimization attributes. */ +#define TAG_ABI_OPTIMIZATION_GOALS 30 +#define TAG_ABI_FP_OPTIMIZATION_GOALS 31 + +/* ARM generic compatibility tag. */ +#define TAG_COMPATIBILITY 32 + +/* ARM secondary compatibility tag. */ +#define TAG_ALSO_COMPATIBLE_WITH 65 + +/* ARM conformance tag. */ +#define TAG_CONFORMANCE 67 + +/* ARM no defaults tag. */ +#define TAG_NODEFAULTS 64 + +/* ARM CPU Arch Version */ +#define ARM_VER_PRE_V4 0 +#define ARM_VER_V4 1 +#define ARM_VER_V4T 2 +#define ARM_VER_V5T 3 +#define ARM_VER_V5TE 4 +#define ARM_VER_V5TEJ 5 +#define ARM_VER_V6 6 +#define ARM_VER_V6KZ 7 +#define ARM_VER_V6T2 8 +#define ARM_VER_V6K 9 +#define ARM_VER_V7 10 +#define ARM_VER_V6_M 11 +#define ARM_VER_V6S_M 12 +#define ARM_VER_V7E_M 13 +#define ARM_VER_V8_A 14 +#define ARM_VER_V8_R 15 +#define ARM_VER_V8_M_BASELINE 16 +#define ARM_VER_V8_M_MAINLINE 17 +#define ARM_VER_V8_1_A 18 +#define ARM_VER_V8_2_A 19 +#define ARM_VER_V8_3_A 20 +#define ARM_VER_V8_1_M_MAINLINE 21 +#define ARM_VER_V9_A 22 + +/* ARM CPU Arch Profile */ +#define ARM_PROFILE_0 0 +#define ARM_PROFILE_A 0x41 +#define ARM_PROFILE_R 0x52 +#define ARM_PROFILE_M 0x4d +#define ARM_PROFILE_S 0x53 + + /* AArch64 relocs. */ #define RZ_AARCH64_NONE 0 /* No relocation. */