| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| struct ar_header_info { |
| struct ar_raw_file_header * phdr; |
| uint32_t attr; |
| }; |
| |
| static const char ar_signature[] = AR_SIGNATURE; |
| |
| static int slbt_ar_free_archive_meta_impl(struct slbt_archive_meta_impl * meta, int ret) |
| { |
| if (meta) { |
| if (meta->armaps.armap_symrefs_32) |
| free(meta->armaps.armap_symrefs_32); |
| |
| if (meta->armaps.armap_symrefs_64) |
| free(meta->armaps.armap_symrefs_64); |
| |
| if (meta->hdrinfov) |
| free(meta->hdrinfov); |
| |
| if (meta->namestrs) |
| free(meta->namestrs); |
| |
| if (meta->syminfo) |
| free(meta->syminfo); |
| |
| if (meta->syminfv) |
| free(meta->syminfv); |
| |
| if (meta->memberv) |
| free(meta->memberv); |
| |
| if (meta->offsetv) |
| free(meta->offsetv); |
| |
| if (meta->members) |
| free(meta->members); |
| |
| if (meta->symstrv) |
| free(meta->symstrv); |
| |
| if (meta->mapstrv) |
| free(meta->mapstrv); |
| |
| if (meta->nminfo) |
| slbt_lib_free_txtfile_ctx(meta->nminfo); |
| |
| 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<len; i++) { |
| if ((mark[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<len; i++) { |
| if ((mark[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) { |
| |
| if ((hdrname[0] == '/') && (hdrname[1] == '/')) |
| return AR_MEMBER_ATTR_NAMESTRS; |
| |
| |
| else if (!strncmp(hdrname,"/SYM64/",7)) |
| return AR_MEMBER_ATTR_ARMAP; |
| |
| |
| else if (hdrname[0] == '/' && (hdrname[1] == '\0')) |
| return AR_MEMBER_ATTR_ARMAP; |
| |
| |
| 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; |
| } |
| |
| |
| for (; data<data_cap; ) { |
| if ((uch = *data) >= 0x80) |
| break; |
| |
| data++; |
| } |
| |
| if (data == data_cap) |
| return AR_MEMBER_ATTR_ASCII; |
| |
| data = m->ar_object_data; |
| udata = (unsigned char *)data; |
| |
| |
| 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; |
| |
| |
| 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; |
| |
| |
| 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; |
| |
| |
| 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; |
| |
| |
| 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; |
| |
| |
| 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; |
| |
| |
| 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; |
| |
| |
| return AR_MEMBER_ATTR_DEFAULT; |
| } |
| |
| 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) { |
| |
| if (!strncmp(hdrname,"/SYM64/",7)) |
| return slbt_ar_parse_primary_armap_sysv_64( |
| dctx,m); |
| |
| |
| 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); |
| } |
| |
| slbt_hidden struct ar_meta_member_info * slbt_archive_member_from_offset( |
| struct slbt_archive_meta_impl * meta, |
| off_t offset) |
| { |
| intptr_t l,r,m; |
| off_t * offsetv; |
| |
| l = 0; |
| r = meta->nentries - 1; |
| |
| offsetv = meta->offsetv; |
| |
| while (l != r) { |
| m = (l + r) / 2; |
| m += (l + r) % 2; |
| |
| if (offsetv[m] > offset) { |
| r = --m; |
| } else { |
| l = m; |
| } |
| } |
| |
| return (offsetv[l] == offset) ? meta->memberv[l] : 0; |
| } |
| |
| int slbt_ar_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 nmembers; |
| uint64_t stblsize; |
| uint64_t filesize; |
| uint64_t namelen; |
| uint64_t nameoff; |
| uint32_t attr; |
| void * s_addr; |
| void * m_addr; |
| const char * s_ptr; |
| const char * m_ptr; |
| 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_meta_armap_ref_32 * symrefs_32; |
| struct ar_meta_armap_ref_64 * symrefs_64; |
| 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]; |
| |
| |
| 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]; |
| |
| |
| 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); |
| |
| |
| if (!(m = calloc(1,sizeof(*m)))) |
| return SLBT_SYSTEM_ERROR(dctx,0); |
| |
| |
| m->dctx = dctx; |
| |
| |
| m->armeta.r_archive.map_addr = archive->map_addr; |
| m->armeta.r_archive.map_size = archive->map_size; |
| |
| |
| m->armeta.r_signature = (struct ar_raw_signature *)mark; |
| m->armeta.m_signature = (struct ar_meta_signature *)ar_signature; |
| |
| |
| if (archive->map_size == sizeof(struct ar_raw_signature)) { |
| *meta = &m->armeta; |
| return 0; |
| } |
| |
| mark += sizeof(struct ar_raw_signature); |
| |
| |
| if (cap < &mark[sizeof(*arhdr)]) |
| for (ch=mark; ch<cap; ch++) |
| if (*ch) |
| return slbt_ar_free_archive_meta_impl( |
| m,SLBT_CUSTOM_ERROR( |
| dctx, |
| SLBT_ERR_AR_INVALID_HEADER)); |
| |
| |
| for (nentries=0,stblsize=0,arlongnames=0; mark<cap; nentries++) { |
| arhdr = (struct ar_raw_file_header *)mark; |
| |
| |
| if ((slbt_ar_read_decimal_64( |
| arhdr->ar_file_size, |
| sizeof(arhdr->ar_file_size), |
| &filesize)) < 0) |
| return slbt_ar_free_archive_meta_impl( |
| m,SLBT_CUSTOM_ERROR( |
| dctx, |
| SLBT_ERR_AR_INVALID_HEADER)); |
| |
| mark += sizeof(struct ar_raw_file_header); |
| |
| |
| fldcap = &arhdr->ar_file_id[sizeof(arhdr->ar_file_id)]; |
| |
| |
| if ((arhdr->ar_file_id[0] == '/') && (arhdr->ar_file_id[1] == '/')) { |
| for (ch=&arhdr->ar_file_id[2]; ch<fldcap; ch++) |
| if (*ch != AR_DEC_PADDING) |
| return slbt_ar_free_archive_meta_impl( |
| m,SLBT_CUSTOM_ERROR( |
| dctx, |
| SLBT_ERR_AR_INVALID_HEADER)); |
| |
| if (slbt_ar_read_decimal_64( |
| arhdr->ar_file_size, |
| sizeof(arhdr->ar_file_size), |
| &namelen) < 0) |
| return slbt_ar_free_archive_meta_impl( |
| m,SLBT_CUSTOM_ERROR( |
| dctx, |
| SLBT_ERR_AR_INVALID_HEADER)); |
| |
| |
| |
| if (arlongnames) |
| return slbt_ar_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; |
| |
| |
| } else if (!strncmp(arhdr->ar_file_id,"/SYM64/",7)) { |
| for (ch=&arhdr->ar_file_id[7]; ch<fldcap; ch++) |
| if (*ch != AR_DEC_PADDING) |
| return slbt_ar_free_archive_meta_impl( |
| m,SLBT_CUSTOM_ERROR( |
| dctx, |
| SLBT_ERR_AR_INVALID_HEADER)); |
| |
| attr = AR_HEADER_ATTR_FILE_ID | AR_HEADER_ATTR_SYSV; |
| stblsize += 8; |
| |
| |
| } 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_ar_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; |
| } |
| |
| |
| } 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_ar_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; |
| |
| |
| } else { |
| for (ch=arhdr->ar_file_id,slash=0; (ch<fldcap) && !slash; ch++) |
| if (*ch == '/') |
| slash = ch; |
| |
| if (slash) { |
| attr = AR_HEADER_ATTR_FILE_ID | AR_HEADER_ATTR_SYSV; |
| stblsize += (slash - arhdr->ar_file_id) + 1; |
| } else { |
| attr = AR_HEADER_ATTR_FILE_ID | AR_HEADER_ATTR_BSD; |
| stblsize += sizeof(arhdr->ar_file_id) + 1; |
| } |
| |
| for (; ch<fldcap; ) |
| if (*ch++ != AR_DEC_PADDING) |
| return slbt_ar_free_archive_meta_impl( |
| m,SLBT_CUSTOM_ERROR( |
| dctx, |
| SLBT_ERR_AR_INVALID_HEADER)); |
| |
| } |
| |
| |
| if (cap < &mark[filesize]) |
| return slbt_ar_free_archive_meta_impl( |
| m,SLBT_CUSTOM_ERROR( |
| dctx, |
| SLBT_ERR_AR_TRUNCATED_DATA)); |
| |
| |
| filesize += 1; |
| filesize |= 1; |
| filesize ^= 1; |
| |
| mark += filesize; |
| |
| |
| if (cap < &mark[sizeof(*arhdr)]) |
| for (; mark<cap; ) |
| if (*mark++) |
| return slbt_ar_free_archive_meta_impl( |
| m,SLBT_CUSTOM_ERROR( |
| dctx, |
| SLBT_ERR_AR_INVALID_HEADER)); |
| |
| |
| if (&hdrinfov[nentries] == hdrinfov_cap) { |
| nelements = (nelements == AR_STACK_VECTOR_ELEMENTS) |
| ? (nelements << 4) : (nelements << 1); |
| |
| if (!(hdrinfov_next = calloc(nelements,sizeof(*hdrinfov)))) |
| return slbt_ar_free_archive_meta_impl( |
| m,SLBT_CUSTOM_ERROR( |
| dctx, |
| SLBT_ERR_AR_TRUNCATED_DATA)); |
| |
| for (idx=0; idx<nentries; idx++) { |
| hdrinfov_next[idx].phdr = hdrinfov[idx].phdr; |
| hdrinfov_next[idx].attr = hdrinfov[idx].attr; |
| }; |
| |
| if (hdrinfov != hdrinfobuf) |
| free(hdrinfov); |
| |
| hdrinfov = hdrinfov_next; |
| hdrinfov_cap = &hdrinfov_next[nelements]; |
| m->hdrinfov = hdrinfov; |
| } |
| |
| hdrinfov[nentries].phdr = arhdr; |
| hdrinfov[nentries].attr = attr; |
| } |
| |
| |
| if (!(m->namestrs = calloc(1,stblsize))) |
| return slbt_ar_free_archive_meta_impl( |
| m,SLBT_SYSTEM_ERROR(dctx,0)); |
| |
| if (!(m->offsetv = calloc(nentries+1,sizeof(*m->offsetv)))) |
| return slbt_ar_free_archive_meta_impl( |
| m,SLBT_SYSTEM_ERROR(dctx,0)); |
| |
| if (!(m->memberv = calloc(nentries+1,sizeof(*m->memberv)))) |
| return slbt_ar_free_archive_meta_impl( |
| m,SLBT_SYSTEM_ERROR(dctx,0)); |
| |
| if (!(m->members = calloc(nentries,sizeof(*m->members)))) |
| return slbt_ar_free_archive_meta_impl( |
| m,SLBT_SYSTEM_ERROR(dctx,0)); |
| |
| |
| s_addr = archive->map_addr; |
| s_ptr = s_addr; |
| |
| |
| for (idx=0,longnamep=m->namestrs; idx<nentries; idx++) { |
| arhdr = hdrinfov[idx].phdr; |
| attr = hdrinfov[idx].attr; |
| |
| m_addr = arhdr; |
| m_ptr = m_addr; |
| |
| memberp = &m->members[idx]; |
| m->offsetv[idx] = m_ptr - s_ptr; |
| 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] == '/') && (arhdr->ar_file_id[1] == 'S')) { |
| *longnamep++ = '/'; |
| *longnamep++ = 'S'; |
| *longnamep++ = 'Y'; |
| *longnamep++ = 'M'; |
| *longnamep++ = '6'; |
| *longnamep++ = '4'; |
| *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 (; (ch<fldcap) && (*ch != AR_DEC_PADDING); ) |
| *longnamep++ = *ch++; |
| |
| longnamep++; |
| |
| } else if (attr == (AR_HEADER_ATTR_NAME_REF | AR_HEADER_ATTR_SYSV)) { |
| slbt_ar_read_decimal_64( |
| &arhdr->ar_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++; |
| } |
| |
| |
| 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_member_data = arhdr; |
| memberp->ar_object_data = (void *)mark; |
| memberp->ar_object_size = memberp->ar_file_header.ar_file_size - namelen; |
| |
| |
| memberp->ar_member_attr = slbt_ar_get_member_attr(memberp); |
| |
| |
| 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; |
| |
| |
| if ((memberp->ar_member_attr == AR_MEMBER_ATTR_ARMAP) && (idx > 0)) { |
| if (m->members[0].ar_member_attr == AR_MEMBER_ATTR_ARMAP) |
| return slbt_ar_free_archive_meta_impl( |
| m,SLBT_CUSTOM_ERROR( |
| dctx, |
| SLBT_ERR_AR_DUPLICATE_ARMAP_MEMBER)); |
| |
| return slbt_ar_free_archive_meta_impl( |
| m,SLBT_CUSTOM_ERROR( |
| dctx, |
| SLBT_ERR_AR_MISPLACED_ARMAP_MEMBER)); |
| } |
| } |
| |
| |
| m->nentries = nentries; |
| |
| |
| if (slbt_ar_parse_primary_armap(dctx,m) < 0) |
| return slbt_ar_free_archive_meta_impl( |
| m,SLBT_NESTED_ERROR(dctx)); |
| |
| for (idx=0,ch=m->symstrs; idx<m->armaps.armap_nsyms; idx++) { |
| m->symstrv[idx] = ch; |
| ch += strlen(ch); |
| ch++; |
| } |
| |
| if (m->armaps.armap_common_32.ar_member) { |
| symrefs_32 = m->armaps.armap_symrefs_32; |
| |
| for (idx=0; idx<m->armaps.armap_nsyms; idx++) { |
| if (m->armaps.armap_common_32.ar_armap_attr & AR_ARMAP_ATTR_SYSV) |
| symrefs_32[idx].ar_name_offset = m->symstrv[idx] - m->symstrv[0]; |
| |
| if (!slbt_archive_member_from_offset(m,symrefs_32[idx].ar_member_offset)) |
| return slbt_ar_free_archive_meta_impl( |
| m,SLBT_CUSTOM_ERROR( |
| dctx, |
| SLBT_ERR_AR_INVALID_ARMAP_MEMBER_OFFSET)); |
| |
| if (symrefs_32[idx].ar_name_offset) { |
| ch = &m->symstrs[symrefs_32[idx].ar_name_offset]; |
| |
| if ((ch > m->symstrv[m->armaps.armap_nsyms - 1]) || *--ch) |
| return slbt_ar_free_archive_meta_impl( |
| m,SLBT_CUSTOM_ERROR( |
| dctx, |
| SLBT_ERR_AR_INVALID_ARMAP_NAME_OFFSET)); |
| } |
| |
| } |
| } |
| |
| if (m->armaps.armap_common_64.ar_member) { |
| symrefs_64 = m->armaps.armap_symrefs_64; |
| |
| for (idx=0; idx<m->armaps.armap_nsyms; idx++) { |
| if (m->armaps.armap_common_64.ar_armap_attr & AR_ARMAP_ATTR_SYSV) |
| symrefs_64[idx].ar_name_offset = m->symstrv[idx] - m->symstrv[0]; |
| |
| if (!slbt_archive_member_from_offset(m,symrefs_64[idx].ar_member_offset)) |
| return slbt_ar_free_archive_meta_impl( |
| m,SLBT_CUSTOM_ERROR( |
| dctx, |
| SLBT_ERR_AR_INVALID_ARMAP_MEMBER_OFFSET)); |
| |
| if (symrefs_64[idx].ar_name_offset) { |
| ch = &m->symstrs[symrefs_64[idx].ar_name_offset]; |
| |
| if ((ch > m->symstrv[m->armaps.armap_nsyms - 1]) || *--ch) |
| return slbt_ar_free_archive_meta_impl( |
| m,SLBT_CUSTOM_ERROR( |
| dctx, |
| SLBT_ERR_AR_INVALID_ARMAP_NAME_OFFSET)); |
| } |
| |
| } |
| } |
| |
| |
| for (idx=0,nmembers=0; idx<nentries; idx++) { |
| switch (m->memberv[idx]->ar_member_attr) { |
| case AR_MEMBER_ATTR_ARMAP: |
| case AR_MEMBER_ATTR_LINKINFO: |
| case AR_MEMBER_ATTR_NAMESTRS: |
| break; |
| |
| default: |
| nmembers++; |
| } |
| } |
| |
| if (m->armaps.armap_common_32.ar_member) |
| m->armaps.armap_common_32.ar_num_of_members = nmembers; |
| |
| if (m->armaps.armap_common_64.ar_member) |
| m->armaps.armap_common_64.ar_num_of_members = nmembers; |
| |
| |
| (void)m->armeta.a_armap_pecoff; |
| |
| |
| if (arlongnames) |
| for (idx=0; idx<nentries && !m->armeta.a_arref_longnames; idx++) |
| if (m->memberv[idx]->ar_member_data == arlongnames) |
| m->armeta.a_arref_longnames = m->memberv[idx]; |
| |
| |
| for (idx=0,nmembers=0; idx<nentries; idx++) { |
| if (m->memberv[idx]->ar_member_attr == AR_MEMBER_ATTR_OBJECT) { |
| if (m->ofmtattr && (m->ofmtattr != m->memberv[idx]->ar_object_attr)) { |
| m->ofmtattr = 0; |
| idx = nentries; |
| } else if (!m->ofmtattr) { |
| m->ofmtattr = m->memberv[idx]->ar_object_attr; |
| } |
| } |
| } |
| |
| |
| m->armeta.a_memberv = m->memberv; |
| |
| |
| if (m->hdrinfov) { |
| free(m->hdrinfov); |
| m->hdrinfov = 0; |
| } |
| |
| *meta = &m->armeta; |
| |
| return 0; |
| } |
| |
| void slbt_ar_free_archive_meta(struct slbt_archive_meta * meta) |
| { |
| struct slbt_archive_meta_impl * m; |
| |
| if (meta) { |
| m = slbt_archive_meta_ictx(meta); |
| slbt_ar_free_archive_meta_impl(m,0); |
| } |
| } |