summaryrefslogtreecommitdiff
path: root/core/src/xmake/binutils/elf
diff options
context:
space:
mode:
authorruki <[email protected]>2025-12-09 00:29:51 +0800
committerruki <[email protected]>2025-12-09 00:29:51 +0800
commitba293bc4b8840da34220e1f54313d531d18dde8e (patch)
treee6b6325ccf446b845b26a3a21f06f0bd84914170 /core/src/xmake/binutils/elf
parentf1726a8f0f63160ae2185f28b38a740caf6d1ab1 (diff)
add binary readsyms
Diffstat (limited to 'core/src/xmake/binutils/elf')
-rw-r--r--core/src/xmake/binutils/elf/prefix.h69
-rw-r--r--core/src/xmake/binutils/elf/readsyms.c325
2 files changed, 394 insertions, 0 deletions
diff --git a/core/src/xmake/binutils/elf/prefix.h b/core/src/xmake/binutils/elf/prefix.h
index d1a13afb8..97d05a661 100644
--- a/core/src/xmake/binutils/elf/prefix.h
+++ b/core/src/xmake/binutils/elf/prefix.h
@@ -266,5 +266,74 @@ static __tb_inline__ tb_bool_t xm_binutils_elf_is_64bit(tb_char_t const *arch) {
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_uint32_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 string from ELF symbol info
+ *
+ * @param st_info the symbol info byte
+ * @return the type string
+ */
+static __tb_inline__ tb_char_t const *xm_binutils_elf_get_symbol_type(tb_uint8_t st_info) {
+ tb_uint8_t type = st_info & 0xf;
+ switch (type) {
+ case 0: return "notype";
+ case 1: return "object";
+ case 2: return "func";
+ case 3: return "section";
+ case 4: return "file";
+ default: return "unknown";
+ }
+}
+
+/* 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
diff --git a/core/src/xmake/binutils/elf/readsyms.c b/core/src/xmake/binutils/elf/readsyms.c
new file mode 100644
index 000000000..ce6653bfe
--- /dev/null
+++ b/core/src/xmake/binutils/elf/readsyms.c
@@ -0,0 +1,325 @@
+/*!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 readsyms.c
+ *
+ */
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * trace
+ */
+#define TB_TRACE_MODULE_NAME "readsyms_elf"
+#define TB_TRACE_MODULE_DEBUG (0)
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * includes
+ */
+#include "prefix.h"
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * private implementation
+ */
+
+tb_bool_t xm_binutils_elf_read_symbols_32(tb_stream_ref_t istream, lua_State *lua) {
+ tb_assert_and_check_return_val(istream && lua, tb_false);
+
+ // read ELF header
+ xm_elf32_header_t header;
+ if (!tb_stream_seek(istream, 0)) {
+ return tb_false;
+ }
+ if (!tb_stream_bread(istream, (tb_byte_t*)&header, sizeof(header))) {
+ return tb_false;
+ }
+
+ // find .symtab section
+ xm_elf32_section_t symtab_section;
+ xm_elf32_section_t strtab_section;
+ tb_bool_t found_symtab = tb_false;
+ tb_bool_t found_strtab = tb_false;
+
+ if (!tb_stream_seek(istream, header.e_shoff)) {
+ return tb_false;
+ }
+
+ for (tb_uint16_t i = 0; i < header.e_shnum; i++) {
+ xm_elf32_section_t section;
+ if (!tb_stream_bread(istream, (tb_byte_t*)&section, sizeof(section))) {
+ return tb_false;
+ }
+
+ if (section.sh_type == XM_ELF_SHT_SYMTAB) {
+ symtab_section = section;
+ found_symtab = tb_true;
+ } else if (section.sh_type == XM_ELF_SHT_STRTAB && section.sh_link == 0) {
+ // .strtab is linked from .symtab, but we need to find it
+ // check if this is the string table for symbols
+ if (found_symtab && symtab_section.sh_link == i) {
+ strtab_section = section;
+ found_strtab = tb_true;
+ }
+ }
+ }
+
+ if (!found_symtab) {
+ lua_newtable(lua);
+ return tb_true;
+ }
+
+ // find string table
+ if (!found_strtab && symtab_section.sh_link < header.e_shnum) {
+ if (!tb_stream_seek(istream, header.e_shoff + symtab_section.sh_link * sizeof(xm_elf32_section_t))) {
+ return tb_false;
+ }
+ if (!tb_stream_bread(istream, (tb_byte_t*)&strtab_section, sizeof(strtab_section))) {
+ return tb_false;
+ }
+ found_strtab = tb_true;
+ }
+
+ if (!found_strtab) {
+ lua_newtable(lua);
+ return tb_true;
+ }
+
+ // create result table
+ lua_newtable(lua);
+
+ // read symbols
+ tb_uint32_t sym_count = symtab_section.sh_size / sizeof(xm_elf32_symbol_t);
+ if (!tb_stream_seek(istream, symtab_section.sh_offset)) {
+ return tb_false;
+ }
+
+ tb_uint32_t result_count = 0;
+ for (tb_uint32_t i = 0; i < sym_count; i++) {
+ xm_elf32_symbol_t sym;
+ if (!tb_stream_bread(istream, (tb_byte_t*)&sym, sizeof(sym))) {
+ return tb_false;
+ }
+
+ // skip NULL symbol
+ if (sym.st_name == 0 && sym.st_value == 0 && sym.st_size == 0) {
+ continue;
+ }
+
+ // get symbol name
+ tb_char_t name[256];
+ if (!xm_binutils_elf_read_string(istream, strtab_section.sh_offset, sym.st_name, name, sizeof(name)) || !name[0]) {
+ continue;
+ }
+
+ // create symbol table entry
+ lua_pushinteger(lua, result_count + 1);
+ lua_newtable(lua);
+
+ // name
+ lua_pushstring(lua, "name");
+ lua_pushstring(lua, name);
+ lua_settable(lua, -3);
+
+ // value
+ lua_pushstring(lua, "value");
+ lua_pushinteger(lua, sym.st_value);
+ lua_settable(lua, -3);
+
+ // size
+ lua_pushstring(lua, "size");
+ lua_pushinteger(lua, sym.st_size);
+ lua_settable(lua, -3);
+
+ // section
+ lua_pushstring(lua, "section");
+ lua_pushinteger(lua, sym.st_shndx);
+ lua_settable(lua, -3);
+
+ // type
+ lua_pushstring(lua, "type");
+ lua_pushstring(lua, xm_binutils_elf_get_symbol_type(sym.st_info));
+ lua_settable(lua, -3);
+
+ // bind
+ lua_pushstring(lua, "bind");
+ lua_pushstring(lua, xm_binutils_elf_get_symbol_bind(sym.st_info));
+ lua_settable(lua, -3);
+
+ lua_settable(lua, -3);
+ result_count++;
+ }
+
+ return tb_true;
+}
+
+tb_bool_t xm_binutils_elf_read_symbols_64(tb_stream_ref_t istream, lua_State *lua) {
+ tb_assert_and_check_return_val(istream && lua, tb_false);
+
+ // read ELF header
+ xm_elf64_header_t header;
+ if (!tb_stream_seek(istream, 0)) {
+ return tb_false;
+ }
+ if (!tb_stream_bread(istream, (tb_byte_t*)&header, sizeof(header))) {
+ return tb_false;
+ }
+
+ // find .symtab section
+ xm_elf64_section_t symtab_section;
+ xm_elf64_section_t strtab_section;
+ tb_bool_t found_symtab = tb_false;
+ tb_bool_t found_strtab = tb_false;
+
+ if (!tb_stream_seek(istream, header.e_shoff)) {
+ return tb_false;
+ }
+
+ for (tb_uint16_t i = 0; i < header.e_shnum; i++) {
+ xm_elf64_section_t section;
+ if (!tb_stream_bread(istream, (tb_byte_t*)&section, sizeof(section))) {
+ return tb_false;
+ }
+
+ if (section.sh_type == XM_ELF_SHT_SYMTAB) {
+ symtab_section = section;
+ found_symtab = tb_true;
+ } else if (section.sh_type == XM_ELF_SHT_STRTAB && section.sh_link == 0) {
+ if (found_symtab && symtab_section.sh_link == i) {
+ strtab_section = section;
+ found_strtab = tb_true;
+ }
+ }
+ }
+
+ if (!found_symtab) {
+ lua_newtable(lua);
+ return tb_true;
+ }
+
+ // find string table
+ if (!found_strtab && symtab_section.sh_link < header.e_shnum) {
+ if (!tb_stream_seek(istream, header.e_shoff + symtab_section.sh_link * sizeof(xm_elf64_section_t))) {
+ return tb_false;
+ }
+ if (!tb_stream_bread(istream, (tb_byte_t*)&strtab_section, sizeof(strtab_section))) {
+ return tb_false;
+ }
+ found_strtab = tb_true;
+ }
+
+ if (!found_strtab) {
+ lua_newtable(lua);
+ return tb_true;
+ }
+
+ // create result table
+ lua_newtable(lua);
+
+ // read symbols
+ tb_uint32_t sym_count = (tb_uint32_t)(symtab_section.sh_size / sizeof(xm_elf64_symbol_t));
+ if (!tb_stream_seek(istream, symtab_section.sh_offset)) {
+ return tb_false;
+ }
+
+ tb_uint32_t result_count = 0;
+ for (tb_uint32_t i = 0; i < sym_count; i++) {
+ xm_elf64_symbol_t sym;
+ if (!tb_stream_bread(istream, (tb_byte_t*)&sym, sizeof(sym))) {
+ return tb_false;
+ }
+
+ // skip NULL symbol
+ if (sym.st_name == 0 && sym.st_value == 0 && sym.st_size == 0) {
+ continue;
+ }
+
+ // get symbol name
+ tb_char_t name[256];
+ if (!xm_binutils_elf_read_string(istream, strtab_section.sh_offset, sym.st_name, name, sizeof(name)) || !name[0]) {
+ continue;
+ }
+
+ // create symbol table entry
+ lua_pushinteger(lua, result_count + 1);
+ lua_newtable(lua);
+
+ // name
+ lua_pushstring(lua, "name");
+ lua_pushstring(lua, name);
+ lua_settable(lua, -3);
+
+ // value
+ lua_pushstring(lua, "value");
+ lua_pushinteger(lua, sym.st_value);
+ lua_settable(lua, -3);
+
+ // size
+ lua_pushstring(lua, "size");
+ lua_pushinteger(lua, sym.st_size);
+ lua_settable(lua, -3);
+
+ // section
+ lua_pushstring(lua, "section");
+ lua_pushinteger(lua, sym.st_shndx);
+ lua_settable(lua, -3);
+
+ // type
+ lua_pushstring(lua, "type");
+ lua_pushstring(lua, xm_binutils_elf_get_symbol_type(sym.st_info));
+ lua_settable(lua, -3);
+
+ // bind
+ lua_pushstring(lua, "bind");
+ lua_pushstring(lua, xm_binutils_elf_get_symbol_bind(sym.st_info));
+ lua_settable(lua, -3);
+
+ lua_settable(lua, -3);
+ result_count++;
+ }
+
+ return tb_true;
+}
+
+tb_bool_t xm_binutils_elf_read_symbols(tb_stream_ref_t istream, lua_State *lua) {
+ tb_assert_and_check_return_val(istream && lua, tb_false);
+
+ // read and check ELF magic
+ tb_uint8_t magic[4];
+ if (!xm_binutils_read_magic(istream, magic, 4)) {
+ return tb_false;
+ }
+ if (magic[0] != 0x7f || magic[1] != 'E' || magic[2] != 'L' || magic[3] != 'F') {
+ return tb_false;
+ }
+
+ // check ELF class (32-bit or 64-bit)
+ tb_uint8_t elf_class;
+ if (!tb_stream_seek(istream, 4)) {
+ return tb_false;
+ }
+ if (!tb_stream_bread(istream, (tb_byte_t*)&elf_class, 1)) {
+ return tb_false;
+ }
+
+ if (elf_class == 1) {
+ return xm_binutils_elf_read_symbols_32(istream, lua);
+ } else if (elf_class == 2) {
+ return xm_binutils_elf_read_symbols_64(istream, lua);
+ }
+
+ return tb_false;
+}
+
+