summaryrefslogtreecommitdiff
path: root/core/src/xmake/binutils/elf/prefix.h
diff options
context:
space:
mode:
authorruki <[email protected]>2025-12-09 22:09:11 +0800
committerGitHub <[email protected]>2025-12-09 22:09:11 +0800
commitf2dcbc2e1450c84ed192e57c7f8b03e51717d71e (patch)
tree6abc959ce5b5ea6a19823021bb00ae364eb8e66b /core/src/xmake/binutils/elf/prefix.h
parent35d91e1636263028b8431cea85b0fd7854392a8a (diff)
parent19859fd57908ea9b08b8b6baa426051d2e7c7814 (diff)
Merge pull request #7109 from xmake-io/binutils
Improve binutils to readsyms from binary file
Diffstat (limited to 'core/src/xmake/binutils/elf/prefix.h')
-rw-r--r--core/src/xmake/binutils/elf/prefix.h354
1 files changed, 354 insertions, 0 deletions
diff --git a/core/src/xmake/binutils/elf/prefix.h b/core/src/xmake/binutils/elf/prefix.h
new file mode 100644
index 000000000..bd3cc9129
--- /dev/null
+++ b/core/src/xmake/binutils/elf/prefix.h
@@ -0,0 +1,354 @@
+/*!A cross-platform build utility based on Lua
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Copyright (C) 2015-present, Xmake Open Source Community.
+ *
+ * @author ruki
+ * @file prefix.h
+ *
+ */
+#ifndef XM_BINUTILS_ELF_PREFIX_H
+#define XM_BINUTILS_ELF_PREFIX_H
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * includes
+ */
+#include "../prefix.h"
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * macros
+ */
+#define XM_ELF_MACHINE_NONE 0x00
+#define XM_ELF_MACHINE_SPARC 0x02
+#define XM_ELF_MACHINE_I386 0x03
+#define XM_ELF_MACHINE_MIPS 0x08
+#define XM_ELF_MACHINE_POWERPC 0x14
+#define XM_ELF_MACHINE_POWERPC64 0x15
+#define XM_ELF_MACHINE_S390 0x16
+#define XM_ELF_MACHINE_ARM 0x28
+#define XM_ELF_MACHINE_SUPERH 0x2a
+#define XM_ELF_MACHINE_SPARC64 0x2b
+#define XM_ELF_MACHINE_IA_64 0x32
+#define XM_ELF_MACHINE_X86_64 0x3e
+#define XM_ELF_MACHINE_RISCV 0xf3
+#define XM_ELF_MACHINE_ARM64 0xb7
+#define XM_ELF_MACHINE_WASM 0xe7
+#define XM_ELF_MACHINE_LOONGARCH 0x102
+
+#define XM_ELF_SHT_PROGBITS 0x1
+#define XM_ELF_SHT_SYMTAB 0x2
+#define XM_ELF_SHT_STRTAB 0x3
+
+#define XM_ELF_SHF_ALLOC 0x2
+#define XM_ELF_SHF_WRITE 0x1
+
+#define XM_ELF_STB_GLOBAL 0x1
+#define XM_ELF_STT_OBJECT 0x1
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * types
+ */
+#include "tbox/prefix/packed.h"
+typedef struct __xm_elf32_header_t {
+ tb_uint8_t e_ident[16];
+ tb_uint16_t e_type;
+ tb_uint16_t e_machine;
+ tb_uint32_t e_version;
+ tb_uint32_t e_entry;
+ tb_uint32_t e_phoff;
+ tb_uint32_t e_shoff;
+ tb_uint32_t e_flags;
+ tb_uint16_t e_ehsize;
+ tb_uint16_t e_phentsize;
+ tb_uint16_t e_phnum;
+ tb_uint16_t e_shentsize;
+ tb_uint16_t e_shnum;
+ tb_uint16_t e_shstrndx;
+} __tb_packed__ xm_elf32_header_t;
+
+typedef struct __xm_elf32_section_t {
+ tb_uint32_t sh_name;
+ tb_uint32_t sh_type;
+ tb_uint32_t sh_flags;
+ tb_uint32_t sh_addr;
+ tb_uint32_t sh_offset;
+ tb_uint32_t sh_size;
+ tb_uint32_t sh_link;
+ tb_uint32_t sh_info;
+ tb_uint32_t sh_addralign;
+ tb_uint32_t sh_entsize;
+} __tb_packed__ xm_elf32_section_t;
+
+typedef struct __xm_elf32_symbol_t {
+ tb_uint32_t st_name;
+ tb_uint32_t st_value;
+ tb_uint32_t st_size;
+ tb_uint8_t st_info;
+ tb_uint8_t st_other;
+ tb_uint16_t st_shndx;
+} __tb_packed__ xm_elf32_symbol_t;
+
+typedef struct __xm_elf64_header_t {
+ tb_uint8_t e_ident[16];
+ tb_uint16_t e_type;
+ tb_uint16_t e_machine;
+ tb_uint32_t e_version;
+ tb_uint64_t e_entry;
+ tb_uint64_t e_phoff;
+ tb_uint64_t e_shoff;
+ tb_uint32_t e_flags;
+ tb_uint16_t e_ehsize;
+ tb_uint16_t e_phentsize;
+ tb_uint16_t e_phnum;
+ tb_uint16_t e_shentsize;
+ tb_uint16_t e_shnum;
+ tb_uint16_t e_shstrndx;
+} __tb_packed__ xm_elf64_header_t;
+
+typedef struct __xm_elf64_section_t {
+ tb_uint32_t sh_name;
+ tb_uint32_t sh_type;
+ tb_uint64_t sh_flags;
+ tb_uint64_t sh_addr;
+ tb_uint64_t sh_offset;
+ tb_uint64_t sh_size;
+ tb_uint32_t sh_link;
+ tb_uint32_t sh_info;
+ tb_uint64_t sh_addralign;
+ tb_uint64_t sh_entsize;
+} __tb_packed__ xm_elf64_section_t;
+
+typedef struct __xm_elf64_symbol_t {
+ tb_uint32_t st_name;
+ tb_uint8_t st_info;
+ tb_uint8_t st_other;
+ tb_uint16_t st_shndx;
+ tb_uint64_t st_value;
+ tb_uint64_t st_size;
+} __tb_packed__ xm_elf64_symbol_t;
+#include "tbox/prefix/packed.h"
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * inline implementation
+ */
+
+/* get machine type from architecture string
+ *
+ * @param arch the architecture string (e.g., "x86_64", "i386", "arm64", "riscv")
+ * @return the machine type
+ */
+static __tb_inline__ tb_uint16_t xm_binutils_elf_get_machine(tb_char_t const *arch) {
+ if (!arch) {
+ return XM_ELF_MACHINE_X86_64;
+ }
+ // x86/x86_64
+ if (tb_strcmp(arch, "x86_64") == 0 || tb_strcmp(arch, "x64") == 0) {
+ return XM_ELF_MACHINE_X86_64;
+ } else if (tb_strcmp(arch, "i386") == 0 || tb_strcmp(arch, "x86") == 0) {
+ return XM_ELF_MACHINE_I386;
+ }
+ // ARM
+ else if (tb_strcmp(arch, "arm64") == 0 || tb_strcmp(arch, "aarch64") == 0 ||
+ tb_strcmp(arch, "arm64-v8a") == 0) {
+ return XM_ELF_MACHINE_ARM64;
+ } else if (tb_strcmp(arch, "arm") == 0 || tb_strcmp(arch, "armv7") == 0 ||
+ tb_strcmp(arch, "armeabi-v7a") == 0 || tb_strcmp(arch, "armv6") == 0 ||
+ tb_strcmp(arch, "armv5") == 0) {
+ return XM_ELF_MACHINE_ARM;
+ }
+ // MIPS (MIPS and MIPS64 use same machine type, distinguished by ELF class)
+ else if (tb_strncmp(arch, "mips", 4) == 0) {
+ return XM_ELF_MACHINE_MIPS;
+ }
+ // PowerPC
+ else if (tb_strncmp(arch, "ppc64", 5) == 0 || tb_strncmp(arch, "powerpc64", 9) == 0) {
+ return XM_ELF_MACHINE_POWERPC64;
+ } else if (tb_strncmp(arch, "ppc", 3) == 0 || tb_strncmp(arch, "powerpc", 7) == 0) {
+ return XM_ELF_MACHINE_POWERPC;
+ }
+ // RISC-V (RISC-V and RISC-V64 use different machine types)
+ else if (tb_strncmp(arch, "riscv64", 7) == 0 ||
+ (tb_strncmp(arch, "riscv", 5) == 0 && tb_strstr(arch, "64"))) {
+ return XM_ELF_MACHINE_RISCV; // RISC-V 64-bit uses same machine type, distinguished by ELF class
+ } else if (tb_strncmp(arch, "riscv", 5) == 0) {
+ return XM_ELF_MACHINE_RISCV;
+ }
+ // SPARC
+ else if (tb_strncmp(arch, "sparc64", 7) == 0) {
+ return XM_ELF_MACHINE_SPARC64;
+ } else if (tb_strncmp(arch, "sparc", 5) == 0) {
+ return XM_ELF_MACHINE_SPARC;
+ }
+ // s390x
+ else if (tb_strcmp(arch, "s390x") == 0 || tb_strcmp(arch, "s390") == 0) {
+ return XM_ELF_MACHINE_S390;
+ }
+ // LoongArch (LoongArch and LoongArch64 use same machine type, distinguished by ELF class)
+ else if (tb_strncmp(arch, "loongarch", 9) == 0 || tb_strncmp(arch, "loong64", 7) == 0) {
+ return XM_ELF_MACHINE_LOONGARCH;
+ }
+ // WebAssembly (WASM and WASM64 use same machine type, distinguished by ELF class)
+ else if (tb_strncmp(arch, "wasm", 4) == 0) {
+ return XM_ELF_MACHINE_WASM;
+ }
+ // SuperH
+ else if (tb_strncmp(arch, "sh", 2) == 0 || tb_strncmp(arch, "superh", 6) == 0) {
+ return XM_ELF_MACHINE_SUPERH;
+ }
+ // IA-64 (Itanium)
+ else if (tb_strcmp(arch, "ia64") == 0 || tb_strcmp(arch, "itanium") == 0) {
+ return XM_ELF_MACHINE_IA_64;
+ }
+ return XM_ELF_MACHINE_X86_64;
+}
+
+/* check if architecture is 64-bit
+ *
+ * @param arch the architecture string
+ * @return tb_true if 64-bit, tb_false otherwise
+ */
+static __tb_inline__ tb_bool_t xm_binutils_elf_is_64bit(tb_char_t const *arch) {
+ if (!arch) {
+ return tb_true;
+ }
+ // x86_64
+ if (tb_strcmp(arch, "x86_64") == 0 || tb_strcmp(arch, "x64") == 0) {
+ return tb_true;
+ }
+ // ARM64
+ else if (tb_strcmp(arch, "arm64") == 0 || tb_strcmp(arch, "aarch64") == 0 ||
+ tb_strcmp(arch, "arm64-v8a") == 0) {
+ return tb_true;
+ }
+ // MIPS64
+ else if (tb_strncmp(arch, "mips64", 6) == 0) {
+ return tb_true;
+ }
+ // PowerPC64
+ else if (tb_strncmp(arch, "ppc64", 5) == 0 || tb_strncmp(arch, "powerpc64", 9) == 0) {
+ return tb_true;
+ }
+ // RISC-V 64
+ else if (tb_strncmp(arch, "riscv64", 7) == 0 ||
+ (tb_strncmp(arch, "riscv", 5) == 0 && tb_strstr(arch, "64"))) {
+ return tb_true;
+ }
+ // SPARC64
+ else if (tb_strncmp(arch, "sparc64", 7) == 0) {
+ return tb_true;
+ }
+ // s390x
+ else if (tb_strcmp(arch, "s390x") == 0) {
+ return tb_true;
+ }
+ // LoongArch64
+ else if (tb_strncmp(arch, "loongarch64", 11) == 0) {
+ return tb_true;
+ }
+ // WebAssembly 64
+ else if (tb_strcmp(arch, "wasm64") == 0) {
+ return tb_true;
+ }
+ // IA-64
+ else if (tb_strcmp(arch, "ia64") == 0 || tb_strcmp(arch, "itanium") == 0) {
+ return tb_true;
+ }
+ return tb_false;
+}
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * readsyms inline implementation
+ */
+
+/* read string from ELF string table
+ *
+ * @param istream the input stream
+ * @param strtab_offset the string table offset
+ * @param offset the string offset
+ * @return the string (static buffer, valid until next call)
+ */
+static __tb_inline__ tb_bool_t xm_binutils_elf_read_string(tb_stream_ref_t istream, tb_uint64_t strtab_offset, tb_uint32_t offset, tb_char_t *name, tb_size_t name_size) {
+ tb_assert_and_check_return_val(istream && name && name_size > 0, tb_false);
+
+ tb_hize_t saved_pos = tb_stream_offset(istream);
+ if (!tb_stream_seek(istream, strtab_offset + offset)) {
+ return tb_false;
+ }
+
+ tb_size_t pos = 0;
+ tb_byte_t c;
+ while (pos < name_size - 1) {
+ if (!tb_stream_bread(istream, &c, 1)) {
+ tb_stream_seek(istream, saved_pos);
+ return tb_false;
+ }
+ if (c == 0) {
+ break;
+ }
+ name[pos++] = (tb_char_t)c;
+ }
+ name[pos] = '\0';
+
+ tb_stream_seek(istream, saved_pos);
+ return tb_true;
+}
+
+/* get symbol type character (nm-style) from ELF symbol
+ *
+ * @param st_info the symbol info byte
+ * @param st_shndx the section index (0 = undefined)
+ * @return the type character (T/t/D/d/B/b/U)
+ */
+static __tb_inline__ tb_char_t xm_binutils_elf_get_symbol_type_char(tb_uint8_t st_info, tb_uint16_t st_shndx) {
+ // undefined symbol
+ if (st_shndx == 0) {
+ return 'U';
+ }
+
+ // check bind (global = uppercase, local = lowercase)
+ tb_uint8_t bind = (st_info >> 4) & 0xf;
+ tb_bool_t is_global = (bind == 1); // STB_GLOBAL
+
+ // check type
+ tb_uint8_t type = st_info & 0xf;
+ if (type == 2) { // STT_FUNC
+ return is_global ? 'T' : 't'; // text (function)
+ } else if (type == 1) { // STT_OBJECT
+ // For object symbols, we need section info to determine data/bss
+ // For simplicity, we'll use 'D' for data, 'B' for bss
+ // This is a heuristic - in practice, we'd need to check section flags
+ return is_global ? 'D' : 'd'; // data (assume data section)
+ }
+
+ // other types
+ return is_global ? 'S' : 's'; // other section
+}
+
+/* get symbol bind string from ELF symbol info
+ *
+ * @param st_info the symbol info byte
+ * @return the bind string
+ */
+static __tb_inline__ tb_char_t const *xm_binutils_elf_get_symbol_bind(tb_uint8_t st_info) {
+ tb_uint8_t bind = (st_info >> 4) & 0xf;
+ switch (bind) {
+ case 0: return "local";
+ case 1: return "global";
+ case 2: return "weak";
+ default: return "unknown";
+ }
+}
+
+#endif
+