/*!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_macho" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ tb_bool_t xm_binutils_macho_read_symbols_32(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua, xm_macho_context_t* context) { tb_assert_and_check_return_val(istream && lua && context, tb_false); // find LC_SYMTAB command xm_macho_symtab_command_t symtab_cmd; tb_bool_t found_symtab = tb_false; tb_uint32_t offset = sizeof(xm_macho_header_32_t); for (tb_uint32_t i = 0; i < context->ncmds; i++) { tb_uint32_t cmd; tb_uint32_t cmdsize; if (!tb_stream_seek(istream, base_offset + offset)) { return tb_false; } if (!tb_stream_bread(istream, (tb_byte_t*)&cmd, 4)) { return tb_false; } if (!tb_stream_bread(istream, (tb_byte_t*)&cmdsize, 4)) { return tb_false; } if (context->swap) { cmd = tb_bits_swap_u32(cmd); cmdsize = tb_bits_swap_u32(cmdsize); } if (cmd == XM_MACHO_LC_SYMTAB) { if (!tb_stream_seek(istream, base_offset + offset)) { return tb_false; } if (!tb_stream_bread(istream, (tb_byte_t*)&symtab_cmd, sizeof(symtab_cmd))) { return tb_false; } xm_binutils_macho_swap_symtab_command(&symtab_cmd, context->swap); found_symtab = tb_true; break; } offset += cmdsize; } if (!found_symtab) { lua_newtable(lua); return tb_true; } // create result table lua_newtable(lua); // read symbols if (!tb_stream_seek(istream, base_offset + symtab_cmd.symoff)) { return tb_false; } tb_uint32_t result_count = 0; for (tb_uint32_t i = 0; i < symtab_cmd.nsyms; i++) { xm_macho_nlist_t nlist; if (!tb_stream_bread(istream, (tb_byte_t*)&nlist, sizeof(nlist))) { return tb_false; } xm_binutils_macho_swap_nlist_32(&nlist, context->swap); // skip NULL symbols if (nlist.strx == 0) { continue; } // get symbol name tb_char_t name[256]; if (!xm_binutils_macho_read_string(istream, base_offset + symtab_cmd.stroff, nlist.strx, name, sizeof(name)) || !name[0]) { continue; } // skip internal symbols (starting with .) if (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); // type (nm-style: T/t/D/d/B/b/U) tb_char_t type_char = xm_binutils_macho_get_symbol_type_char(nlist.type, nlist.sect); tb_char_t type_str[2] = {type_char, '\0'}; lua_pushstring(lua, "type"); lua_pushstring(lua, type_str); lua_settable(lua, -3); lua_settable(lua, -3); result_count++; } return tb_true; } tb_bool_t xm_binutils_macho_read_symbols_64(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua, xm_macho_context_t* context) { tb_assert_and_check_return_val(istream && lua && context, tb_false); // find LC_SYMTAB command xm_macho_symtab_command_t symtab_cmd; tb_bool_t found_symtab = tb_false; tb_uint32_t offset = sizeof(xm_macho_header_64_t); for (tb_uint32_t i = 0; i < context->ncmds; i++) { tb_uint32_t cmd; tb_uint32_t cmdsize; if (!tb_stream_seek(istream, base_offset + offset)) { return tb_false; } if (!tb_stream_bread(istream, (tb_byte_t*)&cmd, 4)) { return tb_false; } if (!tb_stream_bread(istream, (tb_byte_t*)&cmdsize, 4)) { return tb_false; } if (context->swap) { cmd = tb_bits_swap_u32(cmd); cmdsize = tb_bits_swap_u32(cmdsize); } if (cmd == XM_MACHO_LC_SYMTAB) { if (!tb_stream_seek(istream, base_offset + offset)) { return tb_false; } if (!tb_stream_bread(istream, (tb_byte_t*)&symtab_cmd, sizeof(symtab_cmd))) { return tb_false; } xm_binutils_macho_swap_symtab_command(&symtab_cmd, context->swap); found_symtab = tb_true; break; } offset += cmdsize; } if (!found_symtab) { lua_newtable(lua); return tb_true; } // create result table lua_newtable(lua); // read symbols if (!tb_stream_seek(istream, base_offset + symtab_cmd.symoff)) { return tb_false; } tb_uint32_t result_count = 0; for (tb_uint32_t i = 0; i < symtab_cmd.nsyms; i++) { xm_macho_nlist_64_t nlist; if (!tb_stream_bread(istream, (tb_byte_t*)&nlist, sizeof(nlist))) { return tb_false; } xm_binutils_macho_swap_nlist_64(&nlist, context->swap); // skip NULL symbols if (nlist.strx == 0) { continue; } // get symbol name tb_char_t name[256]; if (!xm_binutils_macho_read_string(istream, base_offset + symtab_cmd.stroff, nlist.strx, name, sizeof(name)) || !name[0]) { continue; } // skip internal symbols (starting with .) if (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); // type (nm-style: T/t/D/d/B/b/U) tb_char_t type_char = xm_binutils_macho_get_symbol_type_char(nlist.type, nlist.sect); tb_char_t type_str[2] = {type_char, '\0'}; lua_pushstring(lua, "type"); lua_pushstring(lua, type_str); lua_settable(lua, -3); lua_settable(lua, -3); result_count++; } return tb_true; } tb_bool_t xm_binutils_macho_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) { tb_assert_and_check_return_val(istream && lua, tb_false); // init Mach-O context xm_macho_context_t context; if (!xm_binutils_macho_context_init(istream, base_offset, &context)) { return tb_false; } if (!context.is64) { return xm_binutils_macho_read_symbols_32(istream, base_offset, lua, &context); } else { return xm_binutils_macho_read_symbols_64(istream, base_offset, lua, &context); } }