diff options
| author | ruki <[email protected]> | 2025-12-11 23:42:48 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2025-12-12 09:00:44 +0800 |
| commit | 65b4b2932a7c2fd6dab3fe60597055d1440bddc5 (patch) | |
| tree | 440e1f56021740a82f79cb6ebac277645f7cf91c | |
| parent | b0eb30a4becb5b6d925aa77418ce30c7f1f79d69 (diff) | |
improve readsyms
| -rw-r--r-- | core/src/xmake/binutils/ar/extractlib.c | 2 | ||||
| -rw-r--r-- | core/src/xmake/binutils/ar/prefix.h | 11 | ||||
| -rw-r--r-- | core/src/xmake/binutils/ar/readsyms.c | 246 | ||||
| -rw-r--r-- | core/src/xmake/binutils/coff/readsyms.c | 18 | ||||
| -rw-r--r-- | core/src/xmake/binutils/elf/readsyms.c | 37 | ||||
| -rw-r--r-- | core/src/xmake/binutils/macho/readsyms.c | 34 | ||||
| -rw-r--r-- | core/src/xmake/binutils/readsyms.c | 65 | ||||
| -rw-r--r-- | xmake/modules/utils/binary/readsyms.lua | 93 | ||||
| -rw-r--r-- | xmake/rules/utils/symbols/export_all/export_all.lua | 62 |
9 files changed, 406 insertions, 162 deletions
diff --git a/core/src/xmake/binutils/ar/extractlib.c b/core/src/xmake/binutils/ar/extractlib.c index fc9657f0e..32ec4e547 100644 --- a/core/src/xmake/binutils/ar/extractlib.c +++ b/core/src/xmake/binutils/ar/extractlib.c @@ -205,7 +205,7 @@ tb_bool_t xm_binutils_ar_extract(tb_stream_ref_t istream, tb_char_t const *outpu tb_size_t outputdir_len = tb_strlen(outputdir); // check AR magic (!<arch>\n) - if (!xm_binutils_ar_check_magic(istream)) { + if (!xm_binutils_ar_check_magic(istream, 0)) { return tb_false; } diff --git a/core/src/xmake/binutils/ar/prefix.h b/core/src/xmake/binutils/ar/prefix.h index 6f4d0f35b..fd534f0bb 100644 --- a/core/src/xmake/binutils/ar/prefix.h +++ b/core/src/xmake/binutils/ar/prefix.h @@ -32,9 +32,9 @@ /* ////////////////////////////////////////////////////////////////////////////////////// * forward declarations */ -extern tb_bool_t xm_binutils_coff_read_symbols(tb_stream_ref_t istream, lua_State *lua); -extern tb_bool_t xm_binutils_elf_read_symbols(tb_stream_ref_t istream, lua_State *lua); -extern tb_bool_t xm_binutils_macho_read_symbols(tb_stream_ref_t istream, lua_State *lua); +extern tb_bool_t xm_binutils_coff_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua); +extern tb_bool_t xm_binutils_elf_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua); +extern tb_bool_t xm_binutils_macho_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua); extern tb_int_t xm_binutils_detect_format(tb_stream_ref_t istream); /* ////////////////////////////////////////////////////////////////////////////////////// @@ -81,11 +81,12 @@ static __tb_inline__ tb_int64_t xm_binutils_ar_parse_decimal(tb_char_t const *st /* check AR magic (!<arch>\n) * * @param istream the input stream + * @param base_offset the base offset * @return tb_true on success, tb_false on failure */ -static __tb_inline__ tb_bool_t xm_binutils_ar_check_magic(tb_stream_ref_t istream) { +static __tb_inline__ tb_bool_t xm_binutils_ar_check_magic(tb_stream_ref_t istream, tb_hize_t base_offset) { tb_uint8_t magic[8]; - if (!tb_stream_seek(istream, 0)) { + if (!tb_stream_seek(istream, base_offset)) { return tb_false; } if (!tb_stream_bread(istream, magic, 8)) { diff --git a/core/src/xmake/binutils/ar/readsyms.c b/core/src/xmake/binutils/ar/readsyms.c index 6d738565e..5bb5731c6 100644 --- a/core/src/xmake/binutils/ar/readsyms.c +++ b/core/src/xmake/binutils/ar/readsyms.c @@ -25,19 +25,251 @@ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// + * private implementation + */ + +/* get member name from AR header, handling extended names (#N/L format) + * + * @param istream the input stream + * @param header the AR header + * @param name output buffer for the name + * @param name_size size of the name buffer + * @param name_len output: actual name length + * @param bytes_read output: total bytes read from stream (including newline, for extended names) + * @return tb_true on success, tb_false on failure + */ +static tb_bool_t xm_binutils_ar_get_member_name(tb_stream_ref_t istream, xm_ar_header_t const* header, tb_char_t* name, tb_size_t name_size, tb_size_t* name_len, tb_hize_t* bytes_read) { + tb_assert_and_check_return_val(istream && header && name && name_size > 0 && name_len && bytes_read, tb_false); + *bytes_read = 0; + + // check for extended name format (#N/L or #1/N) + // In BSD AR format: + // - #1/N means name is directly after header, N is total length (including name) + // - #N/L means name length is N, total length is L + // - #1/N can also mean name is in long name table at offset 1 + // We'll try to read the name directly from stream first + if (header->name[0] == '#') { + // find the '/' separator + tb_size_t slash_pos = 0; + for (tb_size_t i = 1; i < 16; i++) { + if (header->name[i] == '/') { + slash_pos = i; + break; + } + } + + if (slash_pos > 0 && slash_pos < 16) { + // parse the number before '/' (could be name length or offset) + tb_int64_t first_num = xm_binutils_ar_parse_decimal(header->name + 1, slash_pos - 1); + // parse the number after '/' (total length) + tb_int64_t total_length = xm_binutils_ar_parse_decimal(header->name + slash_pos + 1, 16 - slash_pos - 1); + + if (first_num <= 0 || total_length <= 0) { + return tb_false; + } + + // In BSD AR format, extended name is directly after header + // The name data starts immediately after the header, no newline + // Read exactly total_length bytes for the name section + tb_byte_t c; + tb_size_t name_bytes = 0; + tb_hize_t bytes_read_so_far = 0; + + // Read name characters until we hit null terminator or reach total_length + while (bytes_read_so_far < (tb_hize_t)total_length && name_bytes < name_size - 1) { + if (!tb_stream_bread(istream, &c, 1)) { + return tb_false; + } + bytes_read_so_far++; + + if (c == '\0') { + // Stop reading name at null terminator, but continue reading to reach total_length + break; + } + // Include all characters in the name, including newlines if present + name[name_bytes++] = (tb_char_t)c; + } + name[name_bytes] = '\0'; + *name_len = name_bytes; + + // Skip remaining bytes to reach total_length (there may be padding or null terminators) + if (bytes_read_so_far < (tb_hize_t)total_length) { + tb_hize_t remaining_to_read = (tb_hize_t)total_length - bytes_read_so_far; + if (!tb_stream_skip(istream, remaining_to_read)) { + return tb_false; + } + } + + // Total bytes read = name + padding = total_length + *bytes_read = (tb_hize_t)total_length; + return tb_true; + } + } + + // regular name (null-terminated or space-padded) + tb_size_t i = 0; + for (i = 0; i < 16 && i < name_size - 1; i++) { + if (header->name[i] == ' ' || header->name[i] == '\0' || header->name[i] == '/') { + break; + } + name[i] = header->name[i]; + } + name[i] = '\0'; + *name_len = i; + *bytes_read = 0; // Regular names are in header, not read from stream + return tb_true; +} + +/* check if member is a symbol table (should be skipped) + * + * @param name the member name + * @return tb_true if it's a symbol table, tb_false otherwise + */ +static __tb_inline__ tb_bool_t xm_binutils_ar_is_symbol_table(tb_char_t const* name) { + tb_assert_and_check_return_val(name, tb_false); + return (tb_strcmp(name, "__.SYMDEF") == 0 || tb_strcmp(name, "__.SYMDEF SORTED") == 0 || + tb_strcmp(name, "/") == 0 || tb_strcmp(name, "//") == 0 || + tb_strncmp(name, "__.SYMDEF", 9) == 0); +} + +/* check if member is an object file (based on extension) + * + * @param name the member name + * @return tb_true if it's likely an object file, tb_false otherwise + */ +static __tb_inline__ tb_bool_t xm_binutils_ar_is_object_file(tb_char_t const* name) { + tb_assert_and_check_return_val(name, tb_false); + tb_size_t len = tb_strlen(name); + if (len == 0) return tb_false; + + // check common object file extensions + if (len >= 2 && name[len - 2] == '.' && name[len - 1] == 'o') return tb_true; + if (len >= 4 && tb_strcmp(name + len - 4, ".obj") == 0) return tb_true; + + // check if it's a COFF/ELF/Mach-O file by detecting format + // For now, we'll extract all non-symbol-table members + return tb_true; +} + +/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* read symbols from AR archive * - * @param istream the input stream - * @param lua the lua state - * @return tb_true on success, tb_false on failure + * @param istream the input stream + * @param base_offset the base offset + * @param lua the lua state + * @return tb_true on success, tb_false on failure */ -tb_bool_t xm_binutils_ar_read_symbols(tb_stream_ref_t istream, lua_State *lua) { +tb_bool_t xm_binutils_ar_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); - // TODO: implement AR archive symbol reading - // This feature is not yet implemented - return tb_false; + // check AR magic (!<arch>\n) + if (!xm_binutils_ar_check_magic(istream, base_offset)) { + return tb_false; + } + + tb_bool_t ok = tb_true; + tb_size_t object_count = 0; + + // iterate through AR members + while (ok) { + // read AR header + // AR header is exactly 60 bytes: name[16] + date[12] + uid[6] + gid[6] + mode[8] + size[10] + fmag[2] + xm_ar_header_t header; + if (!tb_stream_bread(istream, (tb_byte_t*)&header, sizeof(header))) { + // end of file + break; + } + + // parse member size + tb_int64_t member_size = xm_binutils_ar_parse_decimal(header.size, 10); + if (member_size < 0) { + ok = tb_false; + break; + } + + // get member name + tb_char_t member_name[256] = {0}; + tb_size_t name_len = 0; + tb_hize_t name_bytes_read = 0; + + // get member name (handles both regular and extended name formats) + tb_bool_t skip = tb_false; + if (!xm_binutils_ar_get_member_name(istream, &header, member_name, sizeof(member_name), &name_len, &name_bytes_read)) { + skip = tb_true; + } else if (xm_binutils_ar_is_symbol_table(member_name)) { + // skip symbol tables + skip = tb_true; + } else if (!xm_binutils_ar_is_object_file(member_name)) { + // only extract object files + skip = tb_true; + } + + if (skip) { + // skip remaining data + padding using sequential read + tb_hize_t skip_size = (tb_hize_t)member_size - name_bytes_read; + if (member_size % 2) skip_size++; // add padding + if (!tb_stream_skip(istream, skip_size)) { + ok = tb_false; + break; + } + continue; + } + + // save current position + tb_hize_t current_pos = tb_stream_offset(istream); + + // detect format + tb_int_t format = xm_binutils_detect_format(istream); + if (format != XM_BINUTILS_FORMAT_UNKNOWN && format != XM_BINUTILS_FORMAT_AR) { + // create entry table + lua_newtable(lua); + + // object name + lua_pushstring(lua, "objectfile"); + lua_pushstring(lua, member_name); + lua_settable(lua, -3); + + // symbols + lua_pushstring(lua, "symbols"); + tb_bool_t read_ok = tb_false; + if (format == XM_BINUTILS_FORMAT_COFF) { + read_ok = xm_binutils_coff_read_symbols(istream, current_pos, lua); + } else if (format == XM_BINUTILS_FORMAT_ELF) { + read_ok = xm_binutils_elf_read_symbols(istream, current_pos, lua); + } else if (format == XM_BINUTILS_FORMAT_MACHO) { + read_ok = xm_binutils_macho_read_symbols(istream, current_pos, lua); + } + + if (read_ok) { + lua_settable(lua, -3); + lua_rawseti(lua, -2, (int)(++object_count)); + } else { + lua_pop(lua, 2); // pop symbols key and entry table + } + } + + // skip to next member + tb_hize_t member_data_read = tb_stream_offset(istream) - current_pos; + tb_hize_t remaining_size = (tb_hize_t)member_size - name_bytes_read - member_data_read; + if (member_size % 2) remaining_size++; // add padding + + if (remaining_size > 0) { + if (!tb_stream_skip(istream, remaining_size)) { + ok = tb_false; + break; + } + } else if (remaining_size < 0) { + // should not happen if readsyms functions respect boundaries, but just in case + // seek back to correct position + if (!tb_stream_seek(istream, current_pos + (tb_hize_t)member_size - name_bytes_read + (member_size % 2))) { + ok = tb_false; + break; + } + } + } + + return ok; } diff --git a/core/src/xmake/binutils/coff/readsyms.c b/core/src/xmake/binutils/coff/readsyms.c index 836fa9962..705a543ce 100644 --- a/core/src/xmake/binutils/coff/readsyms.c +++ b/core/src/xmake/binutils/coff/readsyms.c @@ -34,7 +34,7 @@ * private implementation */ -static tb_bool_t xm_binutils_coff_read_import_symbols(tb_stream_ref_t istream, lua_State *lua, xm_coff_header_t const* header) { +static tb_bool_t xm_binutils_coff_read_import_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua, xm_coff_header_t const* header) { // create result table lua_newtable(lua); @@ -52,7 +52,7 @@ static tb_bool_t xm_binutils_coff_read_import_symbols(tb_stream_ref_t istream, l * because it does not contain the symbol table. */ xm_coff_anon_header_t anon_header; - if (!tb_stream_seek(istream, 0)) { + if (!tb_stream_seek(istream, base_offset)) { return tb_false; } if (!tb_stream_bread(istream, (tb_byte_t*)&anon_header, sizeof(anon_header))) { @@ -61,7 +61,7 @@ static tb_bool_t xm_binutils_coff_read_import_symbols(tb_stream_ref_t istream, l } else { // import header xm_coff_import_header_t import_header; - if (!tb_stream_seek(istream, 0)) { + if (!tb_stream_seek(istream, base_offset)) { return tb_false; } if (!tb_stream_bread(istream, (tb_byte_t*)&import_header, sizeof(import_header))) { @@ -103,12 +103,12 @@ static tb_bool_t xm_binutils_coff_read_import_symbols(tb_stream_ref_t istream, l return tb_true; } -tb_bool_t xm_binutils_coff_read_symbols(tb_stream_ref_t istream, lua_State *lua) { +tb_bool_t xm_binutils_coff_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); // read COFF header xm_coff_header_t header; - if (!tb_stream_seek(istream, 0)) { + if (!tb_stream_seek(istream, base_offset)) { return tb_false; } if (!tb_stream_bread(istream, (tb_byte_t*)&header, sizeof(header))) { @@ -117,7 +117,7 @@ tb_bool_t xm_binutils_coff_read_symbols(tb_stream_ref_t istream, lua_State *lua) // check if it is an import object if (header.machine == 0 && header.nsects == 0xffff) { - return xm_binutils_coff_read_import_symbols(istream, lua, &header); + return xm_binutils_coff_read_import_symbols(istream, base_offset, lua, &header); } // check if there are symbols @@ -140,7 +140,7 @@ tb_bool_t xm_binutils_coff_read_symbols(tb_stream_ref_t istream, lua_State *lua) tb_hize_t saved_pos = tb_stream_offset(istream); // section headers are after COFF header and optional header tb_uint32_t section_offset = sizeof(xm_coff_header_t) + (header.opthdr > 0 ? header.opthdr : 0); - if (tb_stream_seek(istream, section_offset)) { + if (tb_stream_seek(istream, base_offset + section_offset)) { for (tb_uint16_t i = 0; i < header.nsects; i++) { if (!tb_stream_bread(istream, (tb_byte_t*)§ions[i], sizeof(xm_coff_section_t))) { break; @@ -152,7 +152,7 @@ tb_bool_t xm_binutils_coff_read_symbols(tb_stream_ref_t istream, lua_State *lua) } // read symbols - if (!tb_stream_seek(istream, header.symtabofs)) { + if (!tb_stream_seek(istream, base_offset + header.symtabofs)) { if (sections) { tb_free(sections); } @@ -171,7 +171,7 @@ tb_bool_t xm_binutils_coff_read_symbols(tb_stream_ref_t istream, lua_State *lua) tb_bool_t skip = tb_false; tb_char_t name[256] = {0}; - if (!xm_binutils_coff_get_symbol_name(istream, &sym, strtab_offset, name, sizeof(name)) || !name[0]) { + if (!xm_binutils_coff_get_symbol_name(istream, &sym, base_offset + strtab_offset, name, sizeof(name)) || !name[0]) { skip = tb_true; } else if (name[0] == '.') { skip = tb_true; diff --git a/core/src/xmake/binutils/elf/readsyms.c b/core/src/xmake/binutils/elf/readsyms.c index 3aa489381..7e7544bea 100644 --- a/core/src/xmake/binutils/elf/readsyms.c +++ b/core/src/xmake/binutils/elf/readsyms.c @@ -34,12 +34,12 @@ * private implementation */ -tb_bool_t xm_binutils_elf_read_symbols_32(tb_stream_ref_t istream, lua_State *lua) { +tb_bool_t xm_binutils_elf_read_symbols_32(tb_stream_ref_t istream, tb_hize_t base_offset, 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)) { + if (!tb_stream_seek(istream, base_offset)) { return tb_false; } if (!tb_stream_bread(istream, (tb_byte_t*)&header, sizeof(header))) { @@ -52,7 +52,7 @@ tb_bool_t xm_binutils_elf_read_symbols_32(tb_stream_ref_t istream, lua_State *lu tb_bool_t found_symtab = tb_false; tb_bool_t found_strtab = tb_false; - if (!tb_stream_seek(istream, header.e_shoff)) { + if (!tb_stream_seek(istream, base_offset + header.e_shoff)) { return tb_false; } @@ -82,7 +82,7 @@ tb_bool_t xm_binutils_elf_read_symbols_32(tb_stream_ref_t istream, lua_State *lu // 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))) { + if (!tb_stream_seek(istream, base_offset + 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))) { @@ -101,7 +101,7 @@ tb_bool_t xm_binutils_elf_read_symbols_32(tb_stream_ref_t istream, lua_State *lu // 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)) { + if (!tb_stream_seek(istream, base_offset + symtab_section.sh_offset)) { return tb_false; } @@ -125,7 +125,7 @@ tb_bool_t xm_binutils_elf_read_symbols_32(tb_stream_ref_t istream, lua_State *lu // 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]) { + if (!xm_binutils_elf_read_string(istream, base_offset + strtab_section.sh_offset, sym.st_name, name, sizeof(name)) || !name[0]) { continue; } @@ -163,12 +163,12 @@ tb_bool_t xm_binutils_elf_read_symbols_32(tb_stream_ref_t istream, lua_State *lu return tb_true; } -tb_bool_t xm_binutils_elf_read_symbols_64(tb_stream_ref_t istream, lua_State *lua) { +tb_bool_t xm_binutils_elf_read_symbols_64(tb_stream_ref_t istream, tb_hize_t base_offset, 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)) { + if (!tb_stream_seek(istream, base_offset)) { return tb_false; } if (!tb_stream_bread(istream, (tb_byte_t*)&header, sizeof(header))) { @@ -181,7 +181,7 @@ tb_bool_t xm_binutils_elf_read_symbols_64(tb_stream_ref_t istream, lua_State *lu tb_bool_t found_symtab = tb_false; tb_bool_t found_strtab = tb_false; - if (!tb_stream_seek(istream, header.e_shoff)) { + if (!tb_stream_seek(istream, base_offset + header.e_shoff)) { return tb_false; } @@ -209,7 +209,7 @@ tb_bool_t xm_binutils_elf_read_symbols_64(tb_stream_ref_t istream, lua_State *lu // 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))) { + if (!tb_stream_seek(istream, base_offset + 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))) { @@ -228,7 +228,7 @@ tb_bool_t xm_binutils_elf_read_symbols_64(tb_stream_ref_t istream, lua_State *lu // 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)) { + if (!tb_stream_seek(istream, base_offset + symtab_section.sh_offset)) { return tb_false; } @@ -252,7 +252,7 @@ tb_bool_t xm_binutils_elf_read_symbols_64(tb_stream_ref_t istream, lua_State *lu // 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]) { + if (!xm_binutils_elf_read_string(istream, base_offset + strtab_section.sh_offset, sym.st_name, name, sizeof(name)) || !name[0]) { continue; } @@ -290,12 +290,15 @@ tb_bool_t xm_binutils_elf_read_symbols_64(tb_stream_ref_t istream, lua_State *lu return tb_true; } -tb_bool_t xm_binutils_elf_read_symbols(tb_stream_ref_t istream, lua_State *lua) { +tb_bool_t xm_binutils_elf_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); // read and check ELF magic tb_uint8_t magic[4]; - if (!xm_binutils_read_magic(istream, magic, 4)) { + if (!tb_stream_seek(istream, base_offset)) { + return tb_false; + } + if (!tb_stream_bread(istream, magic, 4)) { return tb_false; } if (magic[0] != 0x7f || magic[1] != 'E' || magic[2] != 'L' || magic[3] != 'F') { @@ -304,7 +307,7 @@ tb_bool_t xm_binutils_elf_read_symbols(tb_stream_ref_t istream, lua_State *lua) // check ELF class (32-bit or 64-bit) tb_uint8_t elf_class; - if (!tb_stream_seek(istream, 4)) { + if (!tb_stream_seek(istream, base_offset + 4)) { return tb_false; } if (!tb_stream_bread(istream, (tb_byte_t*)&elf_class, 1)) { @@ -312,9 +315,9 @@ tb_bool_t xm_binutils_elf_read_symbols(tb_stream_ref_t istream, lua_State *lua) } if (elf_class == 1) { - return xm_binutils_elf_read_symbols_32(istream, lua); + return xm_binutils_elf_read_symbols_32(istream, base_offset, lua); } else if (elf_class == 2) { - return xm_binutils_elf_read_symbols_64(istream, lua); + return xm_binutils_elf_read_symbols_64(istream, base_offset, lua); } return tb_false; diff --git a/core/src/xmake/binutils/macho/readsyms.c b/core/src/xmake/binutils/macho/readsyms.c index dde7739e8..4c3fbafa6 100644 --- a/core/src/xmake/binutils/macho/readsyms.c +++ b/core/src/xmake/binutils/macho/readsyms.c @@ -92,12 +92,12 @@ static __tb_inline__ tb_void_t xm_binutils_macho_swap_nlist_64(xm_macho_nlist_64 } } -tb_bool_t xm_binutils_macho_read_symbols_32(tb_stream_ref_t istream, lua_State *lua, tb_bool_t swap_bytes) { +tb_bool_t xm_binutils_macho_read_symbols_32(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua, tb_bool_t swap_bytes) { tb_assert_and_check_return_val(istream && lua, tb_false); // read Mach-O header xm_macho_header_t header; - if (!tb_stream_seek(istream, 0)) { + if (!tb_stream_seek(istream, base_offset)) { return tb_false; } if (!tb_stream_bread(istream, (tb_byte_t*)&header, sizeof(header))) { @@ -114,7 +114,7 @@ tb_bool_t xm_binutils_macho_read_symbols_32(tb_stream_ref_t istream, lua_State * tb_uint32_t cmd; tb_uint32_t cmdsize; - if (!tb_stream_seek(istream, offset)) { + if (!tb_stream_seek(istream, base_offset + offset)) { return tb_false; } if (!tb_stream_bread(istream, (tb_byte_t*)&cmd, 4)) { @@ -125,7 +125,7 @@ tb_bool_t xm_binutils_macho_read_symbols_32(tb_stream_ref_t istream, lua_State * } if (cmd == XM_MACHO_LC_SYMTAB) { - if (!tb_stream_seek(istream, offset)) { + if (!tb_stream_seek(istream, base_offset + offset)) { return tb_false; } if (!tb_stream_bread(istream, (tb_byte_t*)&symtab_cmd, sizeof(symtab_cmd))) { @@ -147,7 +147,7 @@ tb_bool_t xm_binutils_macho_read_symbols_32(tb_stream_ref_t istream, lua_State * lua_newtable(lua); // read symbols - if (!tb_stream_seek(istream, symtab_cmd.symoff)) { + if (!tb_stream_seek(istream, base_offset + symtab_cmd.symoff)) { return tb_false; } @@ -166,7 +166,7 @@ tb_bool_t xm_binutils_macho_read_symbols_32(tb_stream_ref_t istream, lua_State * // get symbol name tb_char_t name[256]; - if (!xm_binutils_macho_read_string(istream, symtab_cmd.stroff, nlist.strx, name, sizeof(name)) || !name[0]) { + if (!xm_binutils_macho_read_string(istream, base_offset + symtab_cmd.stroff, nlist.strx, name, sizeof(name)) || !name[0]) { continue; } @@ -198,12 +198,12 @@ tb_bool_t xm_binutils_macho_read_symbols_32(tb_stream_ref_t istream, lua_State * return tb_true; } -tb_bool_t xm_binutils_macho_read_symbols_64(tb_stream_ref_t istream, lua_State *lua, tb_bool_t swap_bytes) { +tb_bool_t xm_binutils_macho_read_symbols_64(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua, tb_bool_t swap_bytes) { tb_assert_and_check_return_val(istream && lua, tb_false); // read Mach-O header xm_macho_header_64_t header; - if (!tb_stream_seek(istream, 0)) { + if (!tb_stream_seek(istream, base_offset)) { return tb_false; } if (!tb_stream_bread(istream, (tb_byte_t*)&header, sizeof(header))) { @@ -220,7 +220,7 @@ tb_bool_t xm_binutils_macho_read_symbols_64(tb_stream_ref_t istream, lua_State * tb_uint32_t cmd; tb_uint32_t cmdsize; - if (!tb_stream_seek(istream, offset)) { + if (!tb_stream_seek(istream, base_offset + offset)) { return tb_false; } if (!tb_stream_bread(istream, (tb_byte_t*)&cmd, 4)) { @@ -236,7 +236,7 @@ tb_bool_t xm_binutils_macho_read_symbols_64(tb_stream_ref_t istream, lua_State * } if (cmd == XM_MACHO_LC_SYMTAB) { - if (!tb_stream_seek(istream, offset)) { + if (!tb_stream_seek(istream, base_offset + offset)) { return tb_false; } if (!tb_stream_bread(istream, (tb_byte_t*)&symtab_cmd, sizeof(symtab_cmd))) { @@ -259,7 +259,7 @@ tb_bool_t xm_binutils_macho_read_symbols_64(tb_stream_ref_t istream, lua_State * lua_newtable(lua); // read symbols - if (!tb_stream_seek(istream, symtab_cmd.symoff)) { + if (!tb_stream_seek(istream, base_offset + symtab_cmd.symoff)) { return tb_false; } @@ -278,7 +278,7 @@ tb_bool_t xm_binutils_macho_read_symbols_64(tb_stream_ref_t istream, lua_State * // get symbol name tb_char_t name[256]; - if (!xm_binutils_macho_read_string(istream, symtab_cmd.stroff, nlist.strx, name, sizeof(name)) || !name[0]) { + if (!xm_binutils_macho_read_string(istream, base_offset + symtab_cmd.stroff, nlist.strx, name, sizeof(name)) || !name[0]) { continue; } @@ -310,9 +310,13 @@ tb_bool_t xm_binutils_macho_read_symbols_64(tb_stream_ref_t istream, lua_State * return tb_true; } -tb_bool_t xm_binutils_macho_read_symbols(tb_stream_ref_t istream, lua_State *lua) { +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); + if (!tb_stream_seek(istream, base_offset)) { + return tb_false; + } + // read and check magic tb_uint8_t magic_bytes[4]; if (!xm_binutils_read_magic(istream, magic_bytes, 4)) { @@ -327,9 +331,9 @@ tb_bool_t xm_binutils_macho_read_symbols(tb_stream_ref_t istream, lua_State *lua } if (is_32bit) { - return xm_binutils_macho_read_symbols_32(istream, lua, swap_bytes); + return xm_binutils_macho_read_symbols_32(istream, base_offset, lua, swap_bytes); } else { - return xm_binutils_macho_read_symbols_64(istream, lua, swap_bytes); + return xm_binutils_macho_read_symbols_64(istream, base_offset, lua, swap_bytes); } } diff --git a/core/src/xmake/binutils/readsyms.c b/core/src/xmake/binutils/readsyms.c index 73908a562..5a1b40d3c 100644 --- a/core/src/xmake/binutils/readsyms.c +++ b/core/src/xmake/binutils/readsyms.c @@ -36,10 +36,10 @@ /* ////////////////////////////////////////////////////////////////////////////////////// * forward declarations */ -extern tb_bool_t xm_binutils_coff_read_symbols(tb_stream_ref_t istream, lua_State *lua); -extern tb_bool_t xm_binutils_elf_read_symbols(tb_stream_ref_t istream, lua_State *lua); -extern tb_bool_t xm_binutils_macho_read_symbols(tb_stream_ref_t istream, lua_State *lua); -extern tb_bool_t xm_binutils_ar_read_symbols(tb_stream_ref_t istream, lua_State *lua); +extern tb_bool_t xm_binutils_coff_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua); +extern tb_bool_t xm_binutils_elf_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua); +extern tb_bool_t xm_binutils_macho_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua); +extern tb_bool_t xm_binutils_ar_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua); /* ////////////////////////////////////////////////////////////////////////////////////// * implementation @@ -81,40 +81,51 @@ tb_int_t xm_binutils_readsyms(lua_State *lua) { break; } + // create result list + lua_newtable(lua); + // read symbols based on format if (format == XM_BINUTILS_FORMAT_AR) { // AR archive (.a or .lib) - if (!xm_binutils_ar_read_symbols(istream, lua)) { + if (!xm_binutils_ar_read_symbols(istream, 0, lua)) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "readsyms: read AR archive symbols failed"); break; } - } else if (format == XM_BINUTILS_FORMAT_COFF) { - // COFF - if (!xm_binutils_coff_read_symbols(istream, lua)) { - lua_pushboolean(lua, tb_false); - lua_pushfstring(lua, "readsyms: read COFF symbols failed"); - break; - } - } else if (format == XM_BINUTILS_FORMAT_ELF) { - // ELF - if (!xm_binutils_elf_read_symbols(istream, lua)) { - lua_pushboolean(lua, tb_false); - lua_pushfstring(lua, "readsyms: read ELF symbols failed"); - break; + } else { + // single object file (COFF, ELF, Mach-O) + // create entry table + lua_newtable(lua); + + // object name + lua_pushstring(lua, "objectfile"); + tb_char_t const* name = tb_strrchr(objectfile, '/'); + if (!name) name = tb_strrchr(objectfile, '\\'); + if (!name) name = objectfile; + else name++; + lua_pushstring(lua, name); + lua_settable(lua, -3); + + // symbols + lua_pushstring(lua, "symbols"); + tb_bool_t read_ok = tb_false; + if (format == XM_BINUTILS_FORMAT_COFF) { + read_ok = xm_binutils_coff_read_symbols(istream, 0, lua); + } else if (format == XM_BINUTILS_FORMAT_ELF) { + read_ok = xm_binutils_elf_read_symbols(istream, 0, lua); + } else if (format == XM_BINUTILS_FORMAT_MACHO) { + read_ok = xm_binutils_macho_read_symbols(istream, 0, lua); } - } else if (format == XM_BINUTILS_FORMAT_MACHO) { - // Mach-O - if (!xm_binutils_macho_read_symbols(istream, lua)) { + + if (read_ok) { + lua_settable(lua, -3); + lua_rawseti(lua, -2, 1); + } else { + lua_pop(lua, 2); // pop entry table and result list lua_pushboolean(lua, tb_false); - lua_pushfstring(lua, "readsyms: read Mach-O symbols failed"); + lua_pushfstring(lua, "readsyms: read symbols failed"); break; } - } else { - // unknown or unsupported format - lua_pushboolean(lua, tb_false); - lua_pushfstring(lua, "readsyms: unsupported or unknown file format"); - break; } ok = tb_true; diff --git a/xmake/modules/utils/binary/readsyms.lua b/xmake/modules/utils/binary/readsyms.lua index 6058e8121..d8aa8674a 100644 --- a/xmake/modules/utils/binary/readsyms.lua +++ b/xmake/modules/utils/binary/readsyms.lua @@ -38,69 +38,62 @@ end -- -- @param binaryfile the object file path (required) function dump(binaryfile) - local symbols = _get_symbols(binaryfile) - if symbols and #symbols > 0 then - -- calculate column widths for alignment - local max_name_len = 0 - local max_type_len = 0 + local objects = _get_symbols(binaryfile) + if objects and #objects > 0 then + for _, obj in ipairs(objects) do + local symbols = obj.symbols + if symbols and #symbols > 0 then + -- print object file + print("") + cprint("${bright}Object: %s", obj.objectfile) + print(string.rep("-", 80)) - for i, sym in ipairs(symbols) do - if sym.name then - max_name_len = math.max(max_name_len, #sym.name) - end - if sym.type then - max_type_len = math.max(max_type_len, #sym.type) - end - end + -- calculate column widths for alignment + local max_name_len = 0 + local max_type_len = 0 - -- calculate column widths - local type_width = math.max(max_type_len, 4) - local name_width = math.max(max_name_len, 4) + for i, sym in ipairs(symbols) do + if sym.name then + max_name_len = math.max(max_name_len, #sym.name) + end + if sym.type then + max_type_len = math.max(max_type_len, #sym.type) + end + end - -- print header - print("") - print("Symbols:") - local header_format = " %-" .. type_width .. "s %s" - print(string.format(header_format, "TYPE", "NAME")) - print(string.rep("-", 80)) + -- calculate column widths + local type_width = math.max(max_type_len, 4) + local name_width = math.max(max_name_len, 4) - -- print symbols - local format_str = " %-" .. type_width .. "s %s" + -- print header + local header_format = " %-" .. type_width .. "s %s" + print(string.format(header_format, "TYPE", "NAME")) - for i, sym in ipairs(symbols) do - local type_str = sym.type or "unknown" - local name_str = sym.name or "" + -- print symbols + local format_str = " %-" .. type_width .. "s %s" - print(string.format(format_str, type_str, name_str)) + for i, sym in ipairs(symbols) do + local type_str = sym.type or "unknown" + local name_str = sym.name or "" + + print(string.format(format_str, type_str, name_str)) + end + print("") + cprint("${bright}%d symbols found!", #symbols) + end end - print("") - cprint("${bright}%d symbols found!", #symbols) else print("") cprint("${bright}No symbols found!") end end --- read symbols from object file(s) (auto-detect format: ELF, COFF, Mach-O) +-- read symbols from object file (auto-detect format: ELF, COFF, Mach-O) -- --- @param binaryfiles the object file path or table of object files (required) --- @return the symbols table (all symbols from all files if table is provided) -function main(binaryfiles) - assert(binaryfiles, "usage: xmake l utils.binary.readsyms <binaryfile> or readsyms(binaryfiles)") - - local all_symbols = {} - if type(binaryfiles) == "string" then - return _get_symbols(binaryfiles) - else - for _, binaryfile in ipairs(binaryfiles) do - local symbols = _get_symbols(binaryfile) - if symbols then - for _, sym in ipairs(symbols) do - table.insert(all_symbols, sym) - end - end - end - return all_symbols - end +-- @param binaryfile the object file path (required) +-- @return the symbols table +function main(binaryfile) + assert(binaryfile, "usage: xmake l utils.binary.readsyms <binaryfile>") + return _get_symbols(binaryfile) end diff --git a/xmake/rules/utils/symbols/export_all/export_all.lua b/xmake/rules/utils/symbols/export_all/export_all.lua index 6e077aaf3..fa75038d1 100644 --- a/xmake/rules/utils/symbols/export_all/export_all.lua +++ b/xmake/rules/utils/symbols/export_all/export_all.lua @@ -158,38 +158,38 @@ function _get_allsymbols_by_readsyms(target, opt) _get_sourcefiles_map(target, sourcefiles_map) end local objectfiles = target:objectfiles() - local symbols = readsyms(objectfiles) - if symbols then - for _, sym in ipairs(symbols) do - if sym.name and sym.type then - -- only export function symbols (T/t) for DLL exports - -- skip data (D/d), bss (B/b), other sections (S/s), and undefined (U) symbols - if sym.type == "T" or sym.type == "t" then - local symbol = sym.name - -- we need ignore DllMain, https://github.com/xmake-io/xmake/issues/3992 - if target:is_arch("x86") and symbol:startswith("_") and not symbol:startswith("__") and not symbol:startswith("_DllMain@") then - symbol = symbol:sub(2) - end - if export_filter then - -- find sourcefile for this symbol (approximate match) - local sourcefile = nil - for objfile, srcfile in pairs(sourcefiles_map) do - if objfile:find(path.basename(symbol), 1, true) then - sourcefile = srcfile - break - end - end - if export_filter(symbol, {sourcefile = sourcefile}) then - allsymbols:insert(symbol) - end - elseif not symbol:startswith("__") then - if export_classes or not symbol:startswith("?") then - if export_classes then - if not symbol:startswith("??_G") and not symbol:startswith("??_E") then - allsymbols:insert(symbol) + for _, objectfile in ipairs(objectfiles) do + local objects = readsyms(objectfile) + if objects then + local sourcefile = sourcefiles_map[objectfile] + for _, obj in ipairs(objects) do + local symbols = obj.symbols + if symbols then + for _, sym in ipairs(symbols) do + if sym.name and sym.type then + -- only export function symbols (T/t) for DLL exports + -- skip data (D/d), bss (B/b), other sections (S/s), and undefined (U) symbols + if sym.type == "T" or sym.type == "t" then + local symbol = sym.name + -- we need ignore DllMain, https://github.com/xmake-io/xmake/issues/3992 + if target:is_arch("x86") and symbol:startswith("_") and not symbol:startswith("__") and not symbol:startswith("_DllMain@") then + symbol = symbol:sub(2) + end + if export_filter then + if export_filter(symbol, {sourcefile = sourcefile}) then + allsymbols:insert(symbol) + end + elseif not symbol:startswith("__") then + if export_classes or not symbol:startswith("?") then + if export_classes then + if not symbol:startswith("??_G") and not symbol:startswith("??_E") then + allsymbols:insert(symbol) + end + else + allsymbols:insert(symbol) + end + end end - else - allsymbols:insert(symbol) end end end |
