diff options
| author | ruki <[email protected]> | 2025-12-09 00:29:51 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2025-12-09 00:29:51 +0800 |
| commit | ba293bc4b8840da34220e1f54313d531d18dde8e (patch) | |
| tree | e6b6325ccf446b845b26a3a21f06f0bd84914170 /core/src/xmake/binutils/elf | |
| parent | f1726a8f0f63160ae2185f28b38a740caf6d1ab1 (diff) | |
add binary readsyms
Diffstat (limited to 'core/src/xmake/binutils/elf')
| -rw-r--r-- | core/src/xmake/binutils/elf/prefix.h | 69 | ||||
| -rw-r--r-- | core/src/xmake/binutils/elf/readsyms.c | 325 |
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*)§ion, 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*)§ion, 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; +} + + |
