From d4473b3be02d429a72347914a6fc7e5688ad98e5 Mon Sep 17 00:00:00 2001 From: midipix Date: Jan 22 2024 03:49:50 +0000 Subject: slbt_get_archive_meta(): initial implementation. --- diff --git a/include/slibtool/slibtool.h b/include/slibtool/slibtool.h index a742037..1743262 100644 --- a/include/slibtool/slibtool.h +++ b/include/slibtool/slibtool.h @@ -7,6 +7,7 @@ #include #include "slibtool_api.h" +#include "slibtool_arbits.h" #ifdef __cplusplus extern "C" { @@ -96,6 +97,13 @@ enum slbt_custom_error { SLBT_ERR_LCONF_MAP, SLBT_ERR_LCONF_PARSE, SLBT_ERR_AR_FAIL, + SLBT_ERR_AR_EMPTY_FILE, + SLBT_ERR_AR_INVALID_SIGNATURE, + SLBT_ERR_AR_INVALID_HEADER, + SLBT_ERR_AR_TRUNCATED_DATA, + SLBT_ERR_AR_DUPLICATE_LONG_NAMES, + SLBT_ERR_AR_DUPLICATE_ARMAP_MEMBER, + SLBT_ERR_AR_MISPLACED_ARMAP_MEMBER, }; /* execution modes */ @@ -277,6 +285,31 @@ struct slbt_driver_ctx { void * any; }; +struct slbt_raw_archive { + void * map_addr; + size_t map_size; +}; + +struct slbt_archive_meta { + struct slbt_raw_archive r_archive; + struct ar_raw_signature * r_signature; + + struct ar_meta_signature * m_signature; + + struct ar_meta_member_info ** a_memberv; + struct ar_meta_member_info * a_namestrs; + + struct ar_meta_armap_info a_armap_primary; + struct ar_meta_armap_info a_armap_pecoff; +}; + +struct slbt_archive_ctx { + const char * const * path; + const struct slbt_raw_archive * map; + const struct slbt_archive_meta *meta; + void * any; +}; + /* raw input api */ slbt_api int slbt_map_input (const struct slbt_driver_ctx *, int, const char *, int, @@ -323,6 +356,13 @@ slbt_api int slbt_copy_file (const struct slbt_driver_ctx *, struct slbt_api int slbt_dump_machine (const char * compiler, char * machine, size_t bufsize); slbt_api int slbt_realpath (int, const char *, int, char *, size_t); +/* archiver api */ +slbt_api int slbt_get_archive_meta (const struct slbt_driver_ctx *, + const struct slbt_raw_archive *, + struct slbt_archive_meta **); + +slbt_api void slbt_free_archive_meta (struct slbt_archive_meta *); + /* utility api */ slbt_api int slbt_main (char **, char **, const struct slbt_fd_ctx *); diff --git a/include/slibtool/slibtool_arbits.h b/include/slibtool/slibtool_arbits.h new file mode 100644 index 0000000..9a5ab4d --- /dev/null +++ b/include/slibtool/slibtool_arbits.h @@ -0,0 +1,176 @@ +#ifndef SLIBTOOL_ARBITS_H +#define SLIBTOOL_ARBITS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define AR_SIGNATURE "!\n" + +#define AR_MEMBER_ATTR_DEFAULT (0x00) +#define AR_MEMBER_ATTR_ASCII (0x01) +#define AR_MEMBER_ATTR_UTF8 (0x02) +#define AR_MEMBER_ATTR_ARMAP (0x04) +#define AR_MEMBER_ATTR_OBJECT (0x08) +#define AR_MEMBER_ATTR_SYMDEFS (0x10) +#define AR_MEMBER_ATTR_NAMESTRS (0x20) +#define AR_MEMBER_ATTR_LINKINFO (0x40) +#define AR_MEMBER_ATTR_ARCHIVE (0x80) + +#define AR_HEADER_ATTR_DEFAULT (0x00) +#define AR_HEADER_ATTR_FILE_ID (0x01) +#define AR_HEADER_ATTR_NAME_REF (0x02) +#define AR_HEADER_ATTR_BSD (0x10) +#define AR_HEADER_ATTR_SYSV (0x20) + +#define AR_ARMAP_ATTR_PLAIN (0x0000) +#define AR_ARMAP_ATTR_SORTED (0x0001) +#define AR_ARMAP_ATTR_BSD (0x0010) +#define AR_ARMAP_ATTR_SYSV (0x0020) +#define AR_ARMAP_ATTR_COFF (0x0040) +#define AR_ARMAP_ATTR_LE_32 (0x0100) +#define AR_ARMAP_ATTR_LE_64 (0x0200) +#define AR_ARMAP_ATTR_BE_32 (0x0400) +#define AR_ARMAP_ATTR_BE_64 (0x0800) + +#define AR_OBJECT_ATTR_NONE (0X0000) +#define AR_OBJECT_ATTR_ELF (0x0001) +#define AR_OBJECT_ATTR_COFF (0x0002) +#define AR_OBJECT_ATTR_MACHO (0x0004) +#define AR_OBJECT_ATTR_LE_32 (0x0100) +#define AR_OBJECT_ATTR_LE_64 (0x0200) +#define AR_OBJECT_ATTR_BE_32 (0x0400) +#define AR_OBJECT_ATTR_BE_64 (0x0800) + +struct ar_raw_signature { + char ar_signature [0x08]; /* 0x00 */ +}; + +struct ar_raw_file_header { + char ar_file_id [0x10]; /* 0x00 */ + char ar_time_date_stamp [0x0c]; /* 0x10 */ + char ar_uid [0x06]; /* 0x1c */ + char ar_gid [0x06]; /* 0x22 */ + char ar_file_mode [0x08]; /* 0x28 */ + char ar_file_size [0x0a]; /* 0x30 */ + char ar_end_tag [0x02]; /* 0x3a */ +}; + +struct ar_raw_armap_ref_32 { + unsigned char ar_name_offset [0x04]; /* 0x00 */ + unsigned char ar_member_offset [0x04]; /* 0x04 */ +}; + +struct ar_raw_armap_ref_64 { + unsigned char ar_name_offset [0x08]; /* 0x00 */ + unsigned char ar_member_offset [0x08]; /* 0x08 */ +}; + +struct ar_raw_armap_bsd_32 { + unsigned char (*ar_size_of_refs) [0x04]; + unsigned char (*ar_first_name_offset) [0x04]; + unsigned char (*ar_size_of_strs) [0x04]; + const char * (*ar_string_table); +}; + +struct ar_raw_armap_bsd_64 { + unsigned char (*ar_size_of_refs) [0x08]; + unsigned char (*ar_first_name_offset) [0x08]; + unsigned char (*ar_size_of_strs) [0x08]; + const char * (*ar_string_table); +}; + +struct ar_raw_armap_sysv_32 { + unsigned char (*ar_num_of_syms) [0x04]; + unsigned char (*ar_first_ref_offset) [0x04]; + const char * (*ar_string_table); +}; + +struct ar_raw_armap_sysv_64 { + unsigned char (*ar_num_of_syms) [0x08]; + unsigned char (*ar_first_ref_offset) [0x08]; + const char * (*ar_string_table); +}; + +struct ar_raw_armap_xcoff_32 { + unsigned char (*ar_num_of_members) [0x04]; + unsigned char (*ar_first_member_offset) [0x04]; + unsigned char (*ar_num_of_symbols) [0x04]; + unsigned char (*ar_sym_member_indices) [0x02]; + char (*ar_string_table) []; +}; + +struct ar_meta_signature { + const char * ar_signature; +}; + +struct ar_meta_file_header { + const char * ar_member_name; + uint64_t ar_time_date_stamp; + uint32_t ar_uid; + uint32_t ar_gid; + uint32_t ar_file_mode; + uint64_t ar_file_size; + uint32_t ar_header_attr; +}; + +struct ar_meta_member_info { + struct ar_meta_file_header ar_file_header; + uint32_t ar_member_attr; + uint32_t ar_object_attr; + uint64_t ar_object_size; + void * ar_object_data; +}; + +struct ar_meta_armap_ref_32 { + uint32_t ar_name_offset; + uint32_t ar_member_offset; +}; + +struct ar_meta_armap_ref_64 { + uint64_t ar_name_offset; + uint64_t ar_member_offset; +}; + +struct ar_meta_armap_common_32 { + struct ar_meta_member_info * ar_member; + struct ar_raw_armap_bsd_32 * ar_armap_bsd; + struct ar_raw_armap_sysv_32 * ar_armap_sysv; + struct ar_raw_armap_xcoff_32 * ar_armap_xcoff; + uint32_t ar_armap_attr; + uint32_t ar_num_of_symbols; + uint32_t ar_num_of_members; + uint32_t ar_first_member_offset; + uint32_t ar_size_of_refs; + uint32_t ar_size_of_strs; + uint16_t * ar_sym_member_indices; + const char * ar_string_table; +}; + +struct ar_meta_armap_common_64 { + struct ar_meta_member_info * ar_member; + struct ar_raw_armap_bsd_64 * ar_armap_bsd; + struct ar_raw_armap_sysv_64 * ar_armap_sysv; + void * ar_armap_xcoff; + uint32_t ar_armap_attr; + uint64_t ar_num_of_symbols; + uint64_t ar_num_of_members; + uint64_t ar_first_member_offset; + uint64_t ar_size_of_refs; + uint64_t ar_size_of_strs; + uint16_t * ar_sym_member_indices; + const char * ar_string_table; +}; + +struct ar_meta_armap_info { + const struct ar_meta_armap_common_32 * ar_armap_common_32; + const struct ar_meta_armap_common_64 * ar_armap_common_64; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/project/common.mk b/project/common.mk index 8fffae8..d8cda7b 100644 --- a/project/common.mk +++ b/project/common.mk @@ -1,4 +1,5 @@ API_SRCS = \ + src/arbits/slbt_archive_meta.c \ src/driver/slbt_amain.c \ src/driver/slbt_driver_ctx.c \ src/helper/slbt_archive_import.c \ diff --git a/project/headers.mk b/project/headers.mk index 0d22e4c..71b49aa 100644 --- a/project/headers.mk +++ b/project/headers.mk @@ -1,6 +1,7 @@ API_HEADERS = \ $(PROJECT_DIR)/include/$(PACKAGE)/slibtool.h \ $(PROJECT_DIR)/include/$(PACKAGE)/slibtool_api.h \ + $(PROJECT_DIR)/include/$(PACKAGE)/slibtool_arbits.h \ INTERNAL_HEADERS = \ $(PROJECT_DIR)/src/internal/argv/argv.h \ diff --git a/project/tree.mk b/project/tree.mk index 42564b8..9e5383f 100644 --- a/project/tree.mk +++ b/project/tree.mk @@ -1,5 +1,6 @@ tree.tag: mkdir -p src + mkdir -p src/arbits mkdir -p src/driver mkdir -p src/helper mkdir -p src/internal diff --git a/src/arbits/slbt_archive_meta.c b/src/arbits/slbt_archive_meta.c new file mode 100644 index 0000000..260ca76 --- /dev/null +++ b/src/arbits/slbt_archive_meta.c @@ -0,0 +1,922 @@ +/*******************************************************************/ +/* slibtool: a skinny libtool implementation, written in C */ +/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */ +/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */ +/*******************************************************************/ + +#include +#include +#include +#include +#include + +#include +#include +#include "slibtool_ar_impl.h" +#include "slibtool_driver_impl.h" +#include "slibtool_errinfo_impl.h" + +/* decimal values in archive header are right padded with ascii spaces */ +#define AR_DEC_PADDING (0x20) + +/* archive file members are right padded as needed with ascii newline */ +#define AR_OBJ_PADDING (0x0A) + +/* initial number of elements in the transient, on-stack vector */ +# define AR_STACK_VECTOR_ELEMENTS (0x10) + +/* transient header info vector */ +struct ar_header_info { + struct ar_raw_file_header * phdr; + uint32_t attr; +}; + +static const char ar_signature[] = AR_SIGNATURE; + +static int slbt_free_archive_meta_impl(struct slbt_archive_meta_impl * meta, int ret) +{ + if (meta) { + if (meta->hdrinfov) + free(meta->hdrinfov); + + if (meta->namestrs) + free(meta->namestrs); + + if (meta->memberv) + free(meta->memberv); + + if (meta->members) + free(meta->members); + + if (meta->symstrv) + free(meta->symstrv); + + free(meta); + } + + return ret; +} + + +static int slbt_ar_read_octal(const char * mark, int len, uint32_t * dec) +{ + int i; + uint64_t res; + + for (; len && (mark[len-1]==AR_DEC_PADDING); ) + len--; + + for (i=0,res=0; i= '0') && (mark[i] <= '7')) { + res *= 8; + res += (mark[i] - '0'); + } else { + return -1; + } + } + + *dec = res; + + return 0; +} + +static int slbt_ar_read_decimal_64(const char * mark, int len, uint64_t * dec) +{ + int i; + uint64_t res; + + for (; len && (mark[len-1]==AR_DEC_PADDING); ) + len--; + + for (i=0,res=0; i= '0') && (mark[i] <= '9')) { + res *= 10; + res += (mark[i] - '0'); + } else { + return -1; + } + } + + *dec = res; + + return 0; +} + +static int slbt_ar_read_decimal_32(const char * mark, int len, uint32_t * dec) +{ + uint64_t res; + + if (slbt_ar_read_decimal_64(mark,len,&res) < 0) + return -1; + + *dec = res; + + return 0; +} + +static uint32_t slbt_ar_get_member_attr(struct ar_meta_member_info * m) +{ + const char * hdrname; + uint32_t hdrattr; + const char * data; + const char * data_cap; + const unsigned char * udata; + unsigned char uch; + const size_t siglen = sizeof(struct ar_raw_signature); + + hdrname = m->ar_file_header.ar_member_name; + hdrattr = m->ar_file_header.ar_header_attr; + + data = m->ar_object_data; + data_cap = &data[m->ar_file_header.ar_file_size]; + + if (hdrattr & AR_HEADER_ATTR_SYSV) { + /* long names member? */ + if ((hdrname[0] == '/') && (hdrname[1] == '/')) + return AR_MEMBER_ATTR_NAMESTRS; + + /* mips 64-bit armap member? */ + else if (!strncmp(hdrname,"/SYM64/",7)) + return AR_MEMBER_ATTR_ARMAP; + + /* armap member? */ + else if (hdrname[0] == '/' && (hdrname[1] == '\0')) + return AR_MEMBER_ATTR_ARMAP; + + /* nested archive? */ + else if (m->ar_file_header.ar_file_size >= siglen) + if (!strncmp(data,ar_signature,siglen)) + return AR_MEMBER_ATTR_ARCHIVE; + + } else if (hdrattr & AR_HEADER_ATTR_BSD) { + if (!strcmp(hdrname,"__.SYMDEF")) + return AR_MEMBER_ATTR_ARMAP; + + else if (!strcmp(hdrname,"__.SYMDEF SORTED")) + return AR_MEMBER_ATTR_ARMAP; + + else if (!strcmp(hdrname,"__.SYMDEF_64")) + return AR_MEMBER_ATTR_ARMAP; + + else if (!strcmp(hdrname,"__.SYMDEF_64 SORTED")) + return AR_MEMBER_ATTR_ARMAP; + } + + /* ascii only data? */ + for (; data= 0x80) + break; + + data++; + } + + if (data == data_cap) + return AR_MEMBER_ATTR_ASCII; + + data = m->ar_object_data; + udata = (unsigned char *)data; + + /* elf object? [quick and dirty] */ + if (m->ar_file_header.ar_file_size >= 5) + if ((udata[0] == 0x7f) + && (udata[1] == 'E') + && (udata[2] == 'L') + && (udata[3] == 'F')) + if ((m->ar_object_attr = AR_OBJECT_ATTR_ELF)) + return AR_MEMBER_ATTR_OBJECT; + + /* coff i386 object? [quick and dirty] */ + if (m->ar_file_header.ar_file_size >= 2) + if ((udata[0] == 0x4c) && (udata[1] == 0x01)) + if ((m->ar_object_attr = AR_OBJECT_ATTR_COFF)) + return AR_MEMBER_ATTR_OBJECT; + + /* coff x86_64 object? [quick and dirty] */ + if (m->ar_file_header.ar_file_size >= 2) + if ((udata[0] == 0x64) && (udata[1] == 0x86)) + if ((m->ar_object_attr = AR_OBJECT_ATTR_COFF)) + return AR_MEMBER_ATTR_OBJECT; + + /* big endian 32-bit macho object? [quick and dirty] */ + if (m->ar_file_header.ar_file_size >= 4) + if ((udata[0] == 0xfe) && (udata[1] == 0xed)) + if ((udata[2] == 0xfa) && (udata[3] == 0xce)) + if ((m->ar_object_attr = AR_OBJECT_ATTR_MACHO)) + return AR_MEMBER_ATTR_OBJECT; + + /* big endian 64-bit macho object? [quick and dirty] */ + if (m->ar_file_header.ar_file_size >= 4) + if ((udata[0] == 0xfe) && (udata[1] == 0xed)) + if ((udata[2] == 0xfa) && (udata[3] == 0xcf)) + if ((m->ar_object_attr = AR_OBJECT_ATTR_MACHO)) + return AR_MEMBER_ATTR_OBJECT; + + /* little endian 32-bit macho object? [quick and dirty] */ + if (m->ar_file_header.ar_file_size >= 4) + if ((udata[3] == 0xfe) && (udata[2] == 0xed)) + if ((udata[1] == 0xfa) && (udata[0] == 0xce)) + if ((m->ar_object_attr = AR_OBJECT_ATTR_MACHO)) + return AR_MEMBER_ATTR_OBJECT; + + /* little endian 64-bit macho object? [quick and dirty] */ + if (m->ar_file_header.ar_file_size >= 4) + if ((udata[3] == 0xfe) && (udata[2] == 0xed)) + if ((udata[1] == 0xfa) && (udata[0] == 0xcf)) + if ((m->ar_object_attr = AR_OBJECT_ATTR_MACHO)) + return AR_MEMBER_ATTR_OBJECT; + + /* all other */ + return AR_MEMBER_ATTR_DEFAULT; +} + +static int slbt_ar_parse_primary_armap_bsd_32( + const struct slbt_driver_ctx * dctx, + struct slbt_archive_meta_impl * m) + +{ + struct ar_raw_armap_bsd_32 * armap; + struct ar_meta_member_info * memberp; + struct ar_meta_armap_common_32 *armapref; + uint32_t nsyms; + uint32_t sizeofrefs; + uint32_t sizeofstrs; + unsigned char * uch; + unsigned char (*mark)[0x04]; + + armap = &m->armaps.armap_bsd_32; + memberp = m->memberv[0]; + + mark = memberp->ar_object_data; + + armap->ar_size_of_refs = mark; + uch = *mark++; + + armap->ar_first_name_offset = mark; + + sizeofrefs = (uch[3] << 24) + (uch[2] << 16) + (uch[1] << 8) + uch[0]; + nsyms = sizeofrefs / sizeof(struct ar_raw_armap_ref_32); + mark += (sizeofrefs / sizeof(*mark)); + + armap->ar_size_of_strs = mark; + uch = *mark++; + + sizeofstrs = (uch[3] << 24) + (uch[2] << 16) + (uch[1] << 8) + uch[0]; + + m->symstrs = (const char *)mark; + + if (!(m->symstrv = calloc(nsyms + 1,sizeof(const char *)))) + return SLBT_SYSTEM_ERROR(dctx,0); + + armap->ar_string_table = m->symstrv; + + armapref = &m->armaps.armap_common_32; + armapref->ar_member = memberp; + armapref->ar_armap_bsd = armap; + armapref->ar_armap_attr = AR_ARMAP_ATTR_BSD | AR_ARMAP_ATTR_LE_32; + armapref->ar_num_of_symbols = nsyms; + armapref->ar_size_of_refs = sizeofrefs; + armapref->ar_size_of_strs = sizeofstrs; + armapref->ar_string_table = m->symstrs; + + m->armaps.armap_nsyms = nsyms; + + m->armeta.a_armap_primary.ar_armap_common_32 = armapref; + + return 0; +} + +static int slbt_ar_parse_primary_armap_bsd_64( + const struct slbt_driver_ctx * dctx, + struct slbt_archive_meta_impl * m) +{ + struct ar_raw_armap_bsd_64 * armap; + struct ar_meta_member_info * memberp; + struct ar_meta_armap_common_64 *armapref; + uint64_t u64_lo; + uint64_t u64_hi; + uint64_t nsyms; + uint64_t sizeofrefs; + uint64_t sizeofstrs; + unsigned char * uch; + unsigned char (*mark)[0x08]; + + armap = &m->armaps.armap_bsd_64; + memberp = m->memberv[0]; + + mark = memberp->ar_object_data; + + armap->ar_size_of_refs = mark; + uch = *mark++; + + armap->ar_first_name_offset = mark; + + u64_lo = (uch[3] << 24) + (uch[2] << 16) + (uch[1] << 8) + uch[0]; + u64_hi = (uch[7] << 24) + (uch[6] << 16) + (uch[5] << 8) + uch[4]; + + sizeofrefs = u64_lo + (u64_hi << 32); + nsyms = sizeofrefs / sizeof(struct ar_raw_armap_ref_64); + mark += (sizeofrefs / sizeof(*mark)); + + armap->ar_size_of_strs = mark; + uch = *mark++; + + u64_lo = (uch[3] << 24) + (uch[2] << 16) + (uch[1] << 8) + uch[0]; + u64_hi = (uch[7] << 24) + (uch[6] << 16) + (uch[5] << 8) + uch[4]; + + sizeofstrs = u64_lo + (u64_hi << 32); + m->symstrs = (const char *)mark; + + if (!(m->symstrv = calloc(nsyms + 1,sizeof(const char *)))) + return SLBT_SYSTEM_ERROR(dctx,0); + + armap->ar_string_table = m->symstrv; + + armapref = &m->armaps.armap_common_64; + armapref->ar_member = memberp; + armapref->ar_armap_bsd = armap; + armapref->ar_armap_attr = AR_ARMAP_ATTR_BSD | AR_ARMAP_ATTR_LE_64; + armapref->ar_num_of_symbols = nsyms; + armapref->ar_size_of_refs = sizeofrefs; + armapref->ar_size_of_strs = sizeofstrs; + armapref->ar_string_table = m->symstrs; + + m->armaps.armap_nsyms = nsyms; + + m->armeta.a_armap_primary.ar_armap_common_64 = armapref; + + return 0; +} + +static int slbt_ar_parse_primary_armap_sysv_32( + const struct slbt_driver_ctx * dctx, + struct slbt_archive_meta_impl * m) +{ + struct ar_raw_armap_sysv_32 * armap; + struct ar_meta_member_info * memberp; + struct ar_meta_armap_common_32 *armapref; + uint32_t nsyms; + unsigned char * uch; + unsigned char (*mark)[0x04]; + + armap = &m->armaps.armap_sysv_32; + memberp = m->memberv[0]; + + mark = memberp->ar_object_data; + + armap->ar_num_of_syms = mark; + uch = *mark++; + + armap->ar_first_ref_offset = mark; + + nsyms = (uch[0] << 24) + (uch[1] << 16) + (uch[2] << 8) + uch[3]; + mark += nsyms; + + m->symstrs = (const char *)mark; + + if (!(m->symstrv = calloc(nsyms + 1,sizeof(const char *)))) + return SLBT_SYSTEM_ERROR(dctx,0); + + armap->ar_string_table = m->symstrv; + + armapref = &m->armaps.armap_common_32; + armapref->ar_member = memberp; + armapref->ar_armap_sysv = armap; + armapref->ar_armap_attr = AR_ARMAP_ATTR_SYSV | AR_ARMAP_ATTR_BE_32; + armapref->ar_num_of_symbols = nsyms; + armapref->ar_string_table = m->symstrs; + + m->armaps.armap_nsyms = nsyms; + + m->armeta.a_armap_primary.ar_armap_common_32 = armapref; + + return 0; +} + +static int slbt_ar_parse_primary_armap_sysv_64( + const struct slbt_driver_ctx * dctx, + struct slbt_archive_meta_impl * m) +{ + struct ar_raw_armap_sysv_64 * armap; + struct ar_meta_member_info * memberp; + struct ar_meta_armap_common_64 *armapref; + uint64_t nsyms_hi; + uint64_t nsyms_lo; + uint64_t nsyms; + unsigned char * uch; + unsigned char (*mark)[0x08]; + + armap = &m->armaps.armap_sysv_64; + memberp = m->memberv[0]; + + mark = memberp->ar_object_data; + + armap->ar_num_of_syms = mark; + uch = *mark++; + + armap->ar_first_ref_offset = mark; + + nsyms_hi = (uch[0] << 24) + (uch[1] << 16) + (uch[2] << 8) + uch[3]; + nsyms_lo = (uch[4] << 24) + (uch[5] << 16) + (uch[6] << 8) + uch[7]; + + nsyms = (nsyms_hi << 32) + nsyms_lo; + mark += nsyms; + + m->symstrs = (const char *)mark; + + if (!(m->symstrv = calloc(nsyms + 1,sizeof(const char *)))) + return SLBT_SYSTEM_ERROR(dctx,0); + + armap->ar_string_table = m->symstrv; + + armapref = &m->armaps.armap_common_64; + armapref->ar_member = memberp; + armapref->ar_armap_sysv = armap; + armapref->ar_armap_attr = AR_ARMAP_ATTR_SYSV | AR_ARMAP_ATTR_BE_64; + armapref->ar_num_of_symbols = nsyms; + armapref->ar_string_table = m->symstrs; + + m->armaps.armap_nsyms = nsyms; + + m->armeta.a_armap_primary.ar_armap_common_64 = armapref; + + return 0; +} + +static int slbt_ar_parse_primary_armap( + const struct slbt_driver_ctx * dctx, + struct slbt_archive_meta_impl * m) + +{ + struct ar_meta_member_info * memberp; + const char * hdrname; + uint32_t hdrattr; + + memberp = m->memberv[0]; + hdrname = memberp->ar_file_header.ar_member_name; + hdrattr = memberp->ar_file_header.ar_header_attr; + + if (!(memberp->ar_member_attr & AR_MEMBER_ATTR_ARMAP)) + return 0; + + if (hdrattr & AR_HEADER_ATTR_SYSV) { + /* mips 64-bit armap member? */ + if (!strncmp(hdrname,"/SYM64/",7)) + return slbt_ar_parse_primary_armap_sysv_64( + dctx,m); + + /* sysv 32-bit armap member */ + return slbt_ar_parse_primary_armap_sysv_32( + dctx,m); + + } else if (hdrattr & AR_HEADER_ATTR_BSD) { + if (!strcmp(hdrname,"__.SYMDEF")) + return slbt_ar_parse_primary_armap_bsd_32( + dctx,m); + + else if (!strcmp(hdrname,"__.SYMDEF SORTED")) + return slbt_ar_parse_primary_armap_bsd_32( + dctx,m); + + else if (!strcmp(hdrname,"__.SYMDEF_64")) + return slbt_ar_parse_primary_armap_bsd_64( + dctx,m); + + else if (!strcmp(hdrname,"__.SYMDEF_64 SORTED")) + return slbt_ar_parse_primary_armap_bsd_64( + dctx,m); + } + + return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_FLOW_ERROR); +} + +int slbt_get_archive_meta( + const struct slbt_driver_ctx * dctx, + const struct slbt_raw_archive * archive, + struct slbt_archive_meta ** meta) +{ + const char * mark; + const char * cap; + struct slbt_archive_meta_impl * m; + const char * slash; + const char * ch; + const char * fldcap; + size_t nelements; + uint64_t nentries; + uint64_t stblsize; + uint64_t filesize; + uint64_t namelen; + uint64_t nameoff; + uint32_t attr; + struct ar_raw_file_header * arhdr; + struct ar_raw_file_header * arlongnames; + struct ar_meta_member_info * memberp; + char * longnamep; + size_t idx; + struct ar_header_info * hdrinfov; + struct ar_header_info * hdrinfov_cap; + struct ar_header_info * hdrinfov_next; + struct ar_header_info hdrinfobuf[AR_STACK_VECTOR_ELEMENTS]; + + /* init */ + hdrinfov = hdrinfobuf; + hdrinfov_cap = &hdrinfobuf[AR_STACK_VECTOR_ELEMENTS]; + nelements = AR_STACK_VECTOR_ELEMENTS; + + memset(hdrinfobuf,0,sizeof(hdrinfobuf)); + + mark = archive->map_addr; + cap = &mark[archive->map_size]; + + /* preliminary validation */ + if (archive->map_size < sizeof(struct ar_raw_signature)) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_SIGNATURE); + + else if (strncmp(mark,ar_signature,sizeof(struct ar_raw_signature))) + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_SIGNATURE); + + /* alloc */ + if (!(m = calloc(1,sizeof(*m)))) + return SLBT_SYSTEM_ERROR(dctx,0); + + /* archive map info */ + m->armeta.r_archive.map_addr = archive->map_addr; + m->armeta.r_archive.map_size = archive->map_size; + + /* archive signature */ + m->armeta.r_signature = (struct ar_raw_signature *)mark; + m->armeta.m_signature = (struct ar_meta_signature *)ar_signature; + + /* signature only? */ + if (archive->map_size == sizeof(struct ar_raw_signature)) { + *meta = &m->armeta; + return 0; + } + + mark += sizeof(struct ar_raw_signature); + + /* only trailing null characters past the signature? */ + if (cap < &mark[sizeof(*arhdr)]) + for (ch=mark; char_file_size, + sizeof(arhdr->ar_file_size), + &filesize)) < 0) + return slbt_free_archive_meta_impl( + m,SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_HEADER)); + + mark += sizeof(struct ar_raw_file_header); + + /* stblsize, member name type */ + fldcap = &arhdr->ar_file_id[sizeof(arhdr->ar_file_id)]; + + /* sysv long names table? */ + if ((arhdr->ar_file_id[0] == '/') && (arhdr->ar_file_id[1] == '/')) { + for (ch=&arhdr->ar_file_id[2]; char_file_size, + sizeof(arhdr->ar_file_size), + &namelen) < 0) + return slbt_free_archive_meta_impl( + m,SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_HEADER)); + + + /* duplicate long names member? */ + if (arlongnames) + return slbt_free_archive_meta_impl( + m,SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_DUPLICATE_LONG_NAMES)); + + attr = AR_HEADER_ATTR_FILE_ID | AR_HEADER_ATTR_SYSV; + + stblsize++; + stblsize++; + stblsize++; + + stblsize += namelen; + + arlongnames = arhdr; + + /* sysv armap member or sysv long name reference? */ + } else if (arhdr->ar_file_id[0] == '/') { + if (slbt_ar_read_decimal_64( + &arhdr->ar_file_id[1], + sizeof(arhdr->ar_file_id)-1, + &nameoff) < 0) + return slbt_free_archive_meta_impl( + m,SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_HEADER)); + + if (arhdr->ar_file_id[1] == AR_DEC_PADDING) { + attr = AR_HEADER_ATTR_FILE_ID | AR_HEADER_ATTR_SYSV; + stblsize++; + stblsize++; + } else { + attr = AR_HEADER_ATTR_NAME_REF | AR_HEADER_ATTR_SYSV; + } + + /* bsd long name reference? */ + } else if ((arhdr->ar_file_id[0] == '#') + && (arhdr->ar_file_id[1] == '1') + && (arhdr->ar_file_id[2] == '/')) { + if (slbt_ar_read_decimal_64( + &arhdr->ar_file_id[3], + sizeof(arhdr->ar_file_id)-3, + &namelen) < 0) + return slbt_free_archive_meta_impl( + m,SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_INVALID_HEADER)); + + attr = AR_HEADER_ATTR_NAME_REF | AR_HEADER_ATTR_BSD; + + stblsize += namelen + 1; + + /* must be either a sysv short member name, or a (legacy) bsd short name */ + } else { + for (ch=arhdr->ar_file_id,slash=0; (char_file_id) + 1; + } else { + attr = AR_HEADER_ATTR_FILE_ID | AR_HEADER_ATTR_BSD; + stblsize += sizeof(arhdr->ar_file_id) + 1; + } + + for (; chhdrinfov = hdrinfov; + } + + hdrinfov[nentries].phdr = arhdr; + hdrinfov[nentries].attr = attr; + } + + /* allocate name strings, member vector */ + if (!(m->namestrs = calloc(1,stblsize))) + return slbt_free_archive_meta_impl( + m,SLBT_SYSTEM_ERROR(dctx,0)); + + if (!(m->memberv = calloc(nentries+1,sizeof(*m->memberv)))) + return slbt_free_archive_meta_impl( + m,SLBT_SYSTEM_ERROR(dctx,0)); + + if (!(m->members = calloc(nentries,sizeof(*m->members)))) + return slbt_free_archive_meta_impl( + m,SLBT_SYSTEM_ERROR(dctx,0)); + + /* iterate, store meta data in library-friendly form */ + for (idx=0,longnamep=m->namestrs; idxmembers[idx]; + m->memberv[idx] = memberp; + + memberp->ar_file_header.ar_header_attr = attr; + + slbt_ar_read_decimal_64( + arhdr->ar_time_date_stamp, + sizeof(arhdr->ar_time_date_stamp), + &memberp->ar_file_header.ar_time_date_stamp); + + slbt_ar_read_decimal_32( + arhdr->ar_uid, + sizeof(arhdr->ar_uid), + &memberp->ar_file_header.ar_uid); + + slbt_ar_read_decimal_32( + arhdr->ar_gid, + sizeof(arhdr->ar_gid), + &memberp->ar_file_header.ar_gid); + + slbt_ar_read_octal( + arhdr->ar_file_mode, + sizeof(arhdr->ar_file_mode), + &memberp->ar_file_header.ar_file_mode); + + slbt_ar_read_decimal_64( + arhdr->ar_file_size, + sizeof(arhdr->ar_file_size), + &memberp->ar_file_header.ar_file_size); + + memberp->ar_file_header.ar_member_name = longnamep; + + if (attr == (AR_HEADER_ATTR_FILE_ID | AR_HEADER_ATTR_SYSV)) { + if ((arhdr->ar_file_id[0] == '/') && (arhdr->ar_file_id[1] == '/')) { + *longnamep++ = '/'; + *longnamep++ = '/'; + longnamep++; + + } else if (arhdr->ar_file_id[0] == '/') { + *longnamep++ = '/'; + longnamep++; + + } else { + ch = arhdr->ar_file_id; + + for (; (*ch != '/'); ) + *longnamep++ = *ch++; + + longnamep++; + } + + } else if (attr == (AR_HEADER_ATTR_FILE_ID | AR_HEADER_ATTR_BSD)) { + ch = arhdr->ar_file_id; + fldcap = &ch[sizeof(arhdr->ar_file_id)]; + + for (; (char_file_id[1], + sizeof(arhdr->ar_file_id) - 1, + &nameoff); + + ch = arlongnames->ar_file_id; + ch += sizeof(*arlongnames); + ch += nameoff; + + for (; *ch && (*ch != '/') && (*ch != AR_OBJ_PADDING); ) + *longnamep++ = *ch++; + + longnamep++; + + } else if (attr == (AR_HEADER_ATTR_NAME_REF | AR_HEADER_ATTR_BSD)) { + slbt_ar_read_decimal_64( + &arhdr->ar_file_id[3], + sizeof(arhdr->ar_file_id) - 3, + &namelen); + + mark = arhdr->ar_file_id; + mark += sizeof(*arhdr); + + memcpy(longnamep,mark,namelen); + + longnamep += namelen; + longnamep++; + } + + /* object size, object data */ + mark = arhdr->ar_file_id; + mark += sizeof(*arhdr); + namelen = 0; + + if (attr == (AR_HEADER_ATTR_NAME_REF | AR_HEADER_ATTR_BSD)) { + slbt_ar_read_decimal_64( + &arhdr->ar_file_id[3], + sizeof(arhdr->ar_file_id)-3, + &namelen); + + namelen += 1; + namelen |= 1; + namelen ^= 1; + + mark += namelen; + }; + + memberp->ar_object_data = (void *)mark; + memberp->ar_object_size = memberp->ar_file_header.ar_file_size - namelen; + + /* member attribute */ + memberp->ar_member_attr = slbt_ar_get_member_attr(memberp); + + /* pe/coff second linker member? */ + if ((idx == 1) && (memberp->ar_member_attr == AR_MEMBER_ATTR_ARMAP)) + if (hdrinfov[0].attr & AR_HEADER_ATTR_SYSV) + if (m->members[0].ar_member_attr == AR_MEMBER_ATTR_ARMAP) + if (attr & AR_HEADER_ATTR_SYSV) + memberp->ar_member_attr = AR_MEMBER_ATTR_LINKINFO; + + /* armap member must be the first */ + if ((memberp->ar_member_attr == AR_MEMBER_ATTR_ARMAP) && (idx > 0)) { + if (m->members[0].ar_member_attr == AR_MEMBER_ATTR_ARMAP) + return slbt_free_archive_meta_impl( + m,SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_DUPLICATE_ARMAP_MEMBER)); + + return slbt_free_archive_meta_impl( + m,SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_MISPLACED_ARMAP_MEMBER)); + } + } + + /* primary armap (first linker member) */ + if (slbt_ar_parse_primary_armap(dctx,m) < 0) + return slbt_free_archive_meta_impl( + m,SLBT_NESTED_ERROR(dctx)); + + for (idx=0,ch=m->symstrs; idxarmaps.armap_nsyms; idx++) { + m->symstrv[idx] = ch; + ch += strlen(ch); + ch++; + } + + /* pe/coff armap attributes (second linker member) */ + (void)m->armeta.a_armap_pecoff; + + /* all done */ + if (m->hdrinfov) { + free(m->hdrinfov); + m->hdrinfov = 0; + } + + *meta = &m->armeta; + + return 0; +} + +void slbt_free_archive_meta(struct slbt_archive_meta * meta) +{ + struct slbt_archive_meta_impl * m; + + if (meta) { + m = slbt_archive_meta_ictx(meta); + slbt_free_archive_meta_impl(m,0); + } +} diff --git a/src/internal/slibtool_ar_impl.h b/src/internal/slibtool_ar_impl.h index 3dfabe7..13cd6ef 100644 --- a/src/internal/slibtool_ar_impl.h +++ b/src/internal/slibtool_ar_impl.h @@ -2,6 +2,8 @@ #define SLIBTOOL_AR_IMPL_H #include "argv/argv.h" +#include +#include extern const struct argv_option slbt_ar_options[]; @@ -9,4 +11,37 @@ enum ar_tags { TAG_AR_HELP, }; +struct ar_armaps_impl { + struct ar_raw_armap_bsd_32 armap_bsd_32; + struct ar_raw_armap_bsd_64 armap_bsd_64; + struct ar_raw_armap_sysv_32 armap_sysv_32; + struct ar_raw_armap_sysv_64 armap_sysv_64; + struct ar_meta_armap_common_32 armap_common_32; + struct ar_meta_armap_common_64 armap_common_64; + uint64_t armap_nsyms; +}; + +struct slbt_archive_meta_impl { + void * hdrinfov; + char * namestrs; + const char * symstrs; + const char ** symstrv; + struct ar_meta_member_info ** memberv; + struct ar_meta_member_info * members; + struct ar_armaps_impl armaps; + struct slbt_archive_meta armeta; +}; + +static inline struct slbt_archive_meta_impl * slbt_archive_meta_ictx(const struct slbt_archive_meta * meta) +{ + uintptr_t addr; + + if (meta) { + addr = (uintptr_t)meta - offsetof(struct slbt_archive_meta_impl,armeta); + return (struct slbt_archive_meta_impl *)addr; + } + + return 0; +} + #endif diff --git a/src/logic/slbt_exec_ar.c b/src/logic/slbt_exec_ar.c index 7c15d8b..a68ff03 100644 --- a/src/logic/slbt_exec_ar.c +++ b/src/logic/slbt_exec_ar.c @@ -12,8 +12,6 @@ #include "slibtool_errinfo_impl.h" #include "argv/argv.h" -struct slbt_archive_ctx; - static int slbt_ar_usage( int fdout, const char * program,