|
|
d4473b |
/*******************************************************************/
|
|
|
d4473b |
/* slibtool: a skinny libtool implementation, written in C */
|
|
|
d4473b |
/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
|
|
|
d4473b |
/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
|
|
|
d4473b |
/*******************************************************************/
|
|
|
d4473b |
|
|
|
d4473b |
#include <stdint.h>
|
|
|
d4473b |
#include <stddef.h>
|
|
|
d4473b |
#include <stdlib.h>
|
|
|
d4473b |
#include <string.h>
|
|
|
d4473b |
#include <sys/mman.h>
|
|
|
d4473b |
|
|
|
d4473b |
#include <slibtool/slibtool.h>
|
|
|
d4473b |
#include <slibtool/slibtool_arbits.h>
|
|
|
d4473b |
#include "slibtool_ar_impl.h"
|
|
|
d4473b |
#include "slibtool_driver_impl.h"
|
|
|
d4473b |
#include "slibtool_errinfo_impl.h"
|
|
|
d4473b |
|
|
|
d4473b |
/* decimal values in archive header are right padded with ascii spaces */
|
|
|
d4473b |
#define AR_DEC_PADDING (0x20)
|
|
|
d4473b |
|
|
|
d4473b |
/* archive file members are right padded as needed with ascii newline */
|
|
|
d4473b |
#define AR_OBJ_PADDING (0x0A)
|
|
|
d4473b |
|
|
|
d4473b |
/* initial number of elements in the transient, on-stack vector */
|
|
|
1b515c |
# define AR_STACK_VECTOR_ELEMENTS (0x200)
|
|
|
d4473b |
|
|
|
d4473b |
/* transient header info vector */
|
|
|
d4473b |
struct ar_header_info {
|
|
|
d4473b |
struct ar_raw_file_header * phdr;
|
|
|
d4473b |
uint32_t attr;
|
|
|
d4473b |
};
|
|
|
d4473b |
|
|
|
d4473b |
static const char ar_signature[] = AR_SIGNATURE;
|
|
|
d4473b |
|
|
|
d4473b |
static int slbt_free_archive_meta_impl(struct slbt_archive_meta_impl * meta, int ret)
|
|
|
d4473b |
{
|
|
|
d4473b |
if (meta) {
|
|
|
d4473b |
if (meta->hdrinfov)
|
|
|
d4473b |
free(meta->hdrinfov);
|
|
|
d4473b |
|
|
|
d4473b |
if (meta->namestrs)
|
|
|
d4473b |
free(meta->namestrs);
|
|
|
d4473b |
|
|
|
d4473b |
if (meta->memberv)
|
|
|
d4473b |
free(meta->memberv);
|
|
|
d4473b |
|
|
|
d4473b |
if (meta->members)
|
|
|
d4473b |
free(meta->members);
|
|
|
d4473b |
|
|
|
d4473b |
if (meta->symstrv)
|
|
|
d4473b |
free(meta->symstrv);
|
|
|
d4473b |
|
|
|
d4473b |
free(meta);
|
|
|
d4473b |
}
|
|
|
d4473b |
|
|
|
d4473b |
return ret;
|
|
|
d4473b |
}
|
|
|
d4473b |
|
|
|
d4473b |
|
|
|
d4473b |
static int slbt_ar_read_octal(const char * mark, int len, uint32_t * dec)
|
|
|
d4473b |
{
|
|
|
d4473b |
int i;
|
|
|
d4473b |
uint64_t res;
|
|
|
d4473b |
|
|
|
d4473b |
for (; len && (mark[len-1]==AR_DEC_PADDING); )
|
|
|
d4473b |
len--;
|
|
|
d4473b |
|
|
|
d4473b |
for (i=0,res=0; i
|
|
|
d4473b |
if ((mark[i] >= '0') && (mark[i] <= '7')) {
|
|
|
d4473b |
res *= 8;
|
|
|
d4473b |
res += (mark[i] - '0');
|
|
|
d4473b |
} else {
|
|
|
d4473b |
return -1;
|
|
|
d4473b |
}
|
|
|
d4473b |
}
|
|
|
d4473b |
|
|
|
d4473b |
*dec = res;
|
|
|
d4473b |
|
|
|
d4473b |
return 0;
|
|
|
d4473b |
}
|
|
|
d4473b |
|
|
|
d4473b |
static int slbt_ar_read_decimal_64(const char * mark, int len, uint64_t * dec)
|
|
|
d4473b |
{
|
|
|
d4473b |
int i;
|
|
|
d4473b |
uint64_t res;
|
|
|
d4473b |
|
|
|
d4473b |
for (; len && (mark[len-1]==AR_DEC_PADDING); )
|
|
|
d4473b |
len--;
|
|
|
d4473b |
|
|
|
d4473b |
for (i=0,res=0; i
|
|
|
d4473b |
if ((mark[i] >= '0') && (mark[i] <= '9')) {
|
|
|
d4473b |
res *= 10;
|
|
|
d4473b |
res += (mark[i] - '0');
|
|
|
d4473b |
} else {
|
|
|
d4473b |
return -1;
|
|
|
d4473b |
}
|
|
|
d4473b |
}
|
|
|
d4473b |
|
|
|
d4473b |
*dec = res;
|
|
|
d4473b |
|
|
|
d4473b |
return 0;
|
|
|
d4473b |
}
|
|
|
d4473b |
|
|
|
d4473b |
static int slbt_ar_read_decimal_32(const char * mark, int len, uint32_t * dec)
|
|
|
d4473b |
{
|
|
|
d4473b |
uint64_t res;
|
|
|
d4473b |
|
|
|
d4473b |
if (slbt_ar_read_decimal_64(mark,len,&res) < 0)
|
|
|
d4473b |
return -1;
|
|
|
d4473b |
|
|
|
d4473b |
*dec = res;
|
|
|
d4473b |
|
|
|
d4473b |
return 0;
|
|
|
d4473b |
}
|
|
|
d4473b |
|
|
|
d4473b |
static uint32_t slbt_ar_get_member_attr(struct ar_meta_member_info * m)
|
|
|
d4473b |
{
|
|
|
d4473b |
const char * hdrname;
|
|
|
d4473b |
uint32_t hdrattr;
|
|
|
d4473b |
const char * data;
|
|
|
d4473b |
const char * data_cap;
|
|
|
d4473b |
const unsigned char * udata;
|
|
|
d4473b |
unsigned char uch;
|
|
|
d4473b |
const size_t siglen = sizeof(struct ar_raw_signature);
|
|
|
d4473b |
|
|
|
d4473b |
hdrname = m->ar_file_header.ar_member_name;
|
|
|
d4473b |
hdrattr = m->ar_file_header.ar_header_attr;
|
|
|
d4473b |
|
|
|
d4473b |
data = m->ar_object_data;
|
|
|
d4473b |
data_cap = &data[m->ar_file_header.ar_file_size];
|
|
|
d4473b |
|
|
|
d4473b |
if (hdrattr & AR_HEADER_ATTR_SYSV) {
|
|
|
d4473b |
/* long names member? */
|
|
|
d4473b |
if ((hdrname[0] == '/') && (hdrname[1] == '/'))
|
|
|
d4473b |
return AR_MEMBER_ATTR_NAMESTRS;
|
|
|
d4473b |
|
|
|
d4473b |
/* mips 64-bit armap member? */
|
|
|
d4473b |
else if (!strncmp(hdrname,"/SYM64/",7))
|
|
|
d4473b |
return AR_MEMBER_ATTR_ARMAP;
|
|
|
d4473b |
|
|
|
d4473b |
/* armap member? */
|
|
|
d4473b |
else if (hdrname[0] == '/' && (hdrname[1] == '\0'))
|
|
|
d4473b |
return AR_MEMBER_ATTR_ARMAP;
|
|
|
d4473b |
|
|
|
d4473b |
/* nested archive? */
|
|
|
d4473b |
else if (m->ar_file_header.ar_file_size >= siglen)
|
|
|
d4473b |
if (!strncmp(data,ar_signature,siglen))
|
|
|
d4473b |
return AR_MEMBER_ATTR_ARCHIVE;
|
|
|
d4473b |
|
|
|
d4473b |
} else if (hdrattr & AR_HEADER_ATTR_BSD) {
|
|
|
d4473b |
if (!strcmp(hdrname,"__.SYMDEF"))
|
|
|
d4473b |
return AR_MEMBER_ATTR_ARMAP;
|
|
|
d4473b |
|
|
|
d4473b |
else if (!strcmp(hdrname,"__.SYMDEF SORTED"))
|
|
|
d4473b |
return AR_MEMBER_ATTR_ARMAP;
|
|
|
d4473b |
|
|
|
d4473b |
else if (!strcmp(hdrname,"__.SYMDEF_64"))
|
|
|
d4473b |
return AR_MEMBER_ATTR_ARMAP;
|
|
|
d4473b |
|
|
|
d4473b |
else if (!strcmp(hdrname,"__.SYMDEF_64 SORTED"))
|
|
|
d4473b |
return AR_MEMBER_ATTR_ARMAP;
|
|
|
d4473b |
}
|
|
|
d4473b |
|
|
|
d4473b |
/* ascii only data? */
|
|
|
d4473b |
for (; data
|
|
|
d4473b |
if ((uch = *data) >= 0x80)
|
|
|
d4473b |
break;
|
|
|
d4473b |
|
|
|
d4473b |
data++;
|
|
|
d4473b |
}
|
|
|
d4473b |
|
|
|
d4473b |
if (data == data_cap)
|
|
|
d4473b |
return AR_MEMBER_ATTR_ASCII;
|
|
|
d4473b |
|
|
|
d4473b |
data = m->ar_object_data;
|
|
|
d4473b |
udata = (unsigned char *)data;
|
|
|
d4473b |
|
|
|
d4473b |
/* elf object? [quick and dirty] */
|
|
|
d4473b |
if (m->ar_file_header.ar_file_size >= 5)
|
|
|
d4473b |
if ((udata[0] == 0x7f)
|
|
|
d4473b |
&& (udata[1] == 'E')
|
|
|
d4473b |
&& (udata[2] == 'L')
|
|
|
d4473b |
&& (udata[3] == 'F'))
|
|
|
d4473b |
if ((m->ar_object_attr = AR_OBJECT_ATTR_ELF))
|
|
|
d4473b |
return AR_MEMBER_ATTR_OBJECT;
|
|
|
d4473b |
|
|
|
d4473b |
/* coff i386 object? [quick and dirty] */
|
|
|
d4473b |
if (m->ar_file_header.ar_file_size >= 2)
|
|
|
d4473b |
if ((udata[0] == 0x4c) && (udata[1] == 0x01))
|
|
|
d4473b |
if ((m->ar_object_attr = AR_OBJECT_ATTR_COFF))
|
|
|
d4473b |
return AR_MEMBER_ATTR_OBJECT;
|
|
|
d4473b |
|
|
|
d4473b |
/* coff x86_64 object? [quick and dirty] */
|
|
|
d4473b |
if (m->ar_file_header.ar_file_size >= 2)
|
|
|
d4473b |
if ((udata[0] == 0x64) && (udata[1] == 0x86))
|
|
|
d4473b |
if ((m->ar_object_attr = AR_OBJECT_ATTR_COFF))
|
|
|
d4473b |
return AR_MEMBER_ATTR_OBJECT;
|
|
|
d4473b |
|
|
|
d4473b |
/* big endian 32-bit macho object? [quick and dirty] */
|
|
|
d4473b |
if (m->ar_file_header.ar_file_size >= 4)
|
|
|
d4473b |
if ((udata[0] == 0xfe) && (udata[1] == 0xed))
|
|
|
d4473b |
if ((udata[2] == 0xfa) && (udata[3] == 0xce))
|
|
|
d4473b |
if ((m->ar_object_attr = AR_OBJECT_ATTR_MACHO))
|
|
|
d4473b |
return AR_MEMBER_ATTR_OBJECT;
|
|
|
d4473b |
|
|
|
d4473b |
/* big endian 64-bit macho object? [quick and dirty] */
|
|
|
d4473b |
if (m->ar_file_header.ar_file_size >= 4)
|
|
|
d4473b |
if ((udata[0] == 0xfe) && (udata[1] == 0xed))
|
|
|
d4473b |
if ((udata[2] == 0xfa) && (udata[3] == 0xcf))
|
|
|
d4473b |
if ((m->ar_object_attr = AR_OBJECT_ATTR_MACHO))
|
|
|
d4473b |
return AR_MEMBER_ATTR_OBJECT;
|
|
|
d4473b |
|
|
|
d4473b |
/* little endian 32-bit macho object? [quick and dirty] */
|
|
|
d4473b |
if (m->ar_file_header.ar_file_size >= 4)
|
|
|
d4473b |
if ((udata[3] == 0xfe) && (udata[2] == 0xed))
|
|
|
d4473b |
if ((udata[1] == 0xfa) && (udata[0] == 0xce))
|
|
|
d4473b |
if ((m->ar_object_attr = AR_OBJECT_ATTR_MACHO))
|
|
|
d4473b |
return AR_MEMBER_ATTR_OBJECT;
|
|
|
d4473b |
|
|
|
d4473b |
/* little endian 64-bit macho object? [quick and dirty] */
|
|
|
d4473b |
if (m->ar_file_header.ar_file_size >= 4)
|
|
|
d4473b |
if ((udata[3] == 0xfe) && (udata[2] == 0xed))
|
|
|
d4473b |
if ((udata[1] == 0xfa) && (udata[0] == 0xcf))
|
|
|
d4473b |
if ((m->ar_object_attr = AR_OBJECT_ATTR_MACHO))
|
|
|
d4473b |
return AR_MEMBER_ATTR_OBJECT;
|
|
|
d4473b |
|
|
|
d4473b |
/* all other */
|
|
|
d4473b |
return AR_MEMBER_ATTR_DEFAULT;
|
|
|
d4473b |
}
|
|
|
d4473b |
|
|
|
d4473b |
static int slbt_ar_parse_primary_armap_bsd_32(
|
|
|
d4473b |
const struct slbt_driver_ctx * dctx,
|
|
|
d4473b |
struct slbt_archive_meta_impl * m)
|
|
|
d4473b |
|
|
|
d4473b |
{
|
|
|
d4473b |
struct ar_raw_armap_bsd_32 * armap;
|
|
|
d4473b |
struct ar_meta_member_info * memberp;
|
|
|
d4473b |
struct ar_meta_armap_common_32 *armapref;
|
|
|
c37698 |
uint32_t attr;
|
|
|
d4473b |
uint32_t nsyms;
|
|
|
c37698 |
uint32_t nstrs;
|
|
|
c37698 |
uint32_t sizeofrefs_le;
|
|
|
c37698 |
uint32_t sizeofrefs_be;
|
|
|
d4473b |
uint32_t sizeofrefs;
|
|
|
d4473b |
uint32_t sizeofstrs;
|
|
|
c37698 |
const char * ch;
|
|
|
380c44 |
const char * cap;
|
|
|
d4473b |
unsigned char * uch;
|
|
|
d4473b |
unsigned char (*mark)[0x04];
|
|
|
d4473b |
|
|
|
d4473b |
armap = &m->armaps.armap_bsd_32;
|
|
|
d4473b |
memberp = m->memberv[0];
|
|
|
d4473b |
|
|
|
d4473b |
mark = memberp->ar_object_data;
|
|
|
d4473b |
|
|
|
d4473b |
armap->ar_size_of_refs = mark;
|
|
|
d4473b |
uch = *mark++;
|
|
|
d4473b |
|
|
|
d4473b |
armap->ar_first_name_offset = mark;
|
|
|
d4473b |
|
|
|
c37698 |
sizeofrefs_le = (uch[3] << 24) + (uch[2] << 16) + (uch[1] << 8) + uch[0];
|
|
|
c37698 |
sizeofrefs_be = (uch[0] << 24) + (uch[1] << 16) + (uch[2] << 8) + uch[3];
|
|
|
c37698 |
|
|
|
c37698 |
if (sizeofrefs_le < memberp->ar_object_size - sizeof(*mark)) {
|
|
|
c37698 |
sizeofrefs = sizeofrefs_le;
|
|
|
c37698 |
attr = AR_ARMAP_ATTR_LE_32;
|
|
|
c37698 |
|
|
|
c37698 |
} else if (sizeofrefs_be < memberp->ar_object_size - sizeof(*mark)) {
|
|
|
c37698 |
sizeofrefs = sizeofrefs_be;
|
|
|
c37698 |
attr = AR_ARMAP_ATTR_BE_32;
|
|
|
c37698 |
} else {
|
|
|
c37698 |
return SLBT_CUSTOM_ERROR(
|
|
|
c37698 |
dctx,
|
|
|
c37698 |
SLBT_ERR_AR_INVALID_ARMAP_SIZE_OF_REFS);
|
|
|
c37698 |
}
|
|
|
c37698 |
|
|
|
c37698 |
nsyms = sizeofrefs / sizeof(struct ar_raw_armap_ref_32);
|
|
|
c37698 |
mark += (sizeofrefs / sizeof(*mark));
|
|
|
d4473b |
|
|
|
d4473b |
armap->ar_size_of_strs = mark;
|
|
|
d4473b |
uch = *mark++;
|
|
|
d4473b |
|
|
|
c37698 |
sizeofstrs = (attr == AR_ARMAP_ATTR_LE_32)
|
|
|
c37698 |
? (uch[3] << 24) + (uch[2] << 16) + (uch[1] << 8) + uch[0]
|
|
|
c37698 |
: (uch[0] << 24) + (uch[1] << 16) + (uch[2] << 8) + uch[3];
|
|
|
c37698 |
|
|
|
c37698 |
if (sizeofstrs > memberp->ar_object_size - 2*sizeof(*mark) - sizeofrefs)
|
|
|
c37698 |
return SLBT_CUSTOM_ERROR(
|
|
|
c37698 |
dctx,
|
|
|
c37698 |
SLBT_ERR_AR_INVALID_ARMAP_SIZE_OF_STRS);
|
|
|
d4473b |
|
|
|
d4473b |
m->symstrs = (const char *)mark;
|
|
|
d4473b |
|
|
|
380c44 |
cap = memberp->ar_object_data;
|
|
|
380c44 |
cap += memberp->ar_object_size;
|
|
|
380c44 |
|
|
|
380c44 |
if ((cap == m->symstrs) && nsyms)
|
|
|
380c44 |
return SLBT_CUSTOM_ERROR(
|
|
|
380c44 |
dctx,
|
|
|
380c44 |
SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
|
|
|
380c44 |
|
|
|
c37698 |
if (nsyms && !m->symstrs[0])
|
|
|
c37698 |
return SLBT_CUSTOM_ERROR(
|
|
|
c37698 |
dctx,
|
|
|
c37698 |
SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
|
|
|
c37698 |
|
|
|
380c44 |
for (ch=&m->symstrs[1],nstrs=0; ch
|
|
|
380c44 |
if (!ch[0] && !ch[-1] && (nstrs < nsyms))
|
|
|
380c44 |
return SLBT_CUSTOM_ERROR(
|
|
|
380c44 |
dctx,
|
|
|
380c44 |
SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
|
|
|
380c44 |
|
|
|
c37698 |
if (!ch[0] && ch[-1])
|
|
|
c37698 |
nstrs++;
|
|
|
380c44 |
}
|
|
|
c37698 |
|
|
|
c37698 |
if (nstrs != nsyms)
|
|
|
c37698 |
return SLBT_CUSTOM_ERROR(
|
|
|
c37698 |
dctx,
|
|
|
380c44 |
SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
|
|
|
380c44 |
|
|
|
380c44 |
if (cap[-1])
|
|
|
380c44 |
return SLBT_CUSTOM_ERROR(
|
|
|
380c44 |
dctx,
|
|
|
c37698 |
SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
|
|
|
c37698 |
|
|
|
d4473b |
if (!(m->symstrv = calloc(nsyms + 1,sizeof(const char *))))
|
|
|
d4473b |
return SLBT_SYSTEM_ERROR(dctx,0);
|
|
|
d4473b |
|
|
|
d4473b |
armap->ar_string_table = m->symstrv;
|
|
|
d4473b |
|
|
|
d4473b |
armapref = &m->armaps.armap_common_32;
|
|
|
d4473b |
armapref->ar_member = memberp;
|
|
|
d4473b |
armapref->ar_armap_bsd = armap;
|
|
|
c37698 |
armapref->ar_armap_attr = AR_ARMAP_ATTR_BSD | attr;
|
|
|
d4473b |
armapref->ar_num_of_symbols = nsyms;
|
|
|
d4473b |
armapref->ar_size_of_refs = sizeofrefs;
|
|
|
d4473b |
armapref->ar_size_of_strs = sizeofstrs;
|
|
|
d4473b |
armapref->ar_string_table = m->symstrs;
|
|
|
d4473b |
|
|
|
d4473b |
m->armaps.armap_nsyms = nsyms;
|
|
|
d4473b |
|
|
|
d4473b |
m->armeta.a_armap_primary.ar_armap_common_32 = armapref;
|
|
|
d4473b |
|
|
|
d4473b |
return 0;
|
|
|
d4473b |
}
|
|
|
d4473b |
|
|
|
d4473b |
static int slbt_ar_parse_primary_armap_bsd_64(
|
|
|
d4473b |
const struct slbt_driver_ctx * dctx,
|
|
|
d4473b |
struct slbt_archive_meta_impl * m)
|
|
|
d4473b |
{
|
|
|
d4473b |
struct ar_raw_armap_bsd_64 * armap;
|
|
|
d4473b |
struct ar_meta_member_info * memberp;
|
|
|
d4473b |
struct ar_meta_armap_common_64 *armapref;
|
|
|
1c4fed |
uint32_t attr;
|
|
|
d4473b |
uint64_t u64_lo;
|
|
|
d4473b |
uint64_t u64_hi;
|
|
|
d4473b |
uint64_t nsyms;
|
|
|
1c4fed |
uint64_t nstrs;
|
|
|
1c4fed |
uint64_t sizeofrefs_le;
|
|
|
1c4fed |
uint64_t sizeofrefs_be;
|
|
|
d4473b |
uint64_t sizeofrefs;
|
|
|
d4473b |
uint64_t sizeofstrs;
|
|
|
1c4fed |
const char * ch;
|
|
|
3fcae4 |
const char * cap;
|
|
|
d4473b |
unsigned char * uch;
|
|
|
d4473b |
unsigned char (*mark)[0x08];
|
|
|
d4473b |
|
|
|
d4473b |
armap = &m->armaps.armap_bsd_64;
|
|
|
d4473b |
memberp = m->memberv[0];
|
|
|
d4473b |
|
|
|
d4473b |
mark = memberp->ar_object_data;
|
|
|
d4473b |
|
|
|
d4473b |
armap->ar_size_of_refs = mark;
|
|
|
d4473b |
uch = *mark++;
|
|
|
d4473b |
|
|
|
d4473b |
armap->ar_first_name_offset = mark;
|
|
|
d4473b |
|
|
|
d4473b |
u64_lo = (uch[3] << 24) + (uch[2] << 16) + (uch[1] << 8) + uch[0];
|
|
|
d4473b |
u64_hi = (uch[7] << 24) + (uch[6] << 16) + (uch[5] << 8) + uch[4];
|
|
|
d4473b |
|
|
|
1c4fed |
sizeofrefs_le = u64_lo + (u64_hi << 32);
|
|
|
1c4fed |
|
|
|
1c4fed |
u64_hi = (uch[0] << 24) + (uch[1] << 16) + (uch[2] << 8) + uch[3];
|
|
|
1c4fed |
u64_lo = (uch[4] << 24) + (uch[5] << 16) + (uch[6] << 8) + uch[7];
|
|
|
1c4fed |
|
|
|
1c4fed |
sizeofrefs_be = (u64_hi << 32) + u64_lo;
|
|
|
1c4fed |
|
|
|
1c4fed |
if (sizeofrefs_le < memberp->ar_object_size - sizeof(*mark)) {
|
|
|
1c4fed |
sizeofrefs = sizeofrefs_le;
|
|
|
1c4fed |
attr = AR_ARMAP_ATTR_LE_64;
|
|
|
1c4fed |
|
|
|
1c4fed |
} else if (sizeofrefs_be < memberp->ar_object_size - sizeof(*mark)) {
|
|
|
1c4fed |
sizeofrefs = sizeofrefs_be;
|
|
|
1c4fed |
attr = AR_ARMAP_ATTR_BE_64;
|
|
|
1c4fed |
} else {
|
|
|
1c4fed |
return SLBT_CUSTOM_ERROR(
|
|
|
1c4fed |
dctx,
|
|
|
1c4fed |
SLBT_ERR_AR_INVALID_ARMAP_SIZE_OF_REFS);
|
|
|
1c4fed |
}
|
|
|
1c4fed |
|
|
|
1c4fed |
nsyms = sizeofrefs / sizeof(struct ar_raw_armap_ref_64);
|
|
|
1c4fed |
mark += (sizeofrefs / sizeof(*mark));
|
|
|
d4473b |
|
|
|
d4473b |
armap->ar_size_of_strs = mark;
|
|
|
d4473b |
uch = *mark++;
|
|
|
d4473b |
|
|
|
1c4fed |
if (attr == AR_ARMAP_ATTR_LE_64) {
|
|
|
1c4fed |
u64_lo = (uch[3] << 24) + (uch[2] << 16) + (uch[1] << 8) + uch[0];
|
|
|
1c4fed |
u64_hi = (uch[7] << 24) + (uch[6] << 16) + (uch[5] << 8) + uch[4];
|
|
|
1c4fed |
} else {
|
|
|
1c4fed |
u64_hi = (uch[0] << 24) + (uch[1] << 16) + (uch[2] << 8) + uch[3];
|
|
|
1c4fed |
u64_lo = (uch[4] << 24) + (uch[5] << 16) + (uch[6] << 8) + uch[7];
|
|
|
1c4fed |
}
|
|
|
d4473b |
|
|
|
d4473b |
sizeofstrs = u64_lo + (u64_hi << 32);
|
|
|
d4473b |
m->symstrs = (const char *)mark;
|
|
|
d4473b |
|
|
|
3fcae4 |
cap = memberp->ar_object_data;
|
|
|
3fcae4 |
cap += memberp->ar_object_size;
|
|
|
3fcae4 |
|
|
|
3fcae4 |
if ((cap == m->symstrs) && nsyms)
|
|
|
3fcae4 |
return SLBT_CUSTOM_ERROR(
|
|
|
3fcae4 |
dctx,
|
|
|
3fcae4 |
SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
|
|
|
3fcae4 |
|
|
|
1c4fed |
if (nsyms && !m->symstrs[0])
|
|
|
1c4fed |
return SLBT_CUSTOM_ERROR(
|
|
|
1c4fed |
dctx,
|
|
|
1c4fed |
SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
|
|
|
1c4fed |
|
|
|
3fcae4 |
for (ch=&m->symstrs[1],nstrs=0; ch
|
|
|
3fcae4 |
if (!ch[0] && !ch[-1] && (nstrs < nsyms))
|
|
|
3fcae4 |
return SLBT_CUSTOM_ERROR(
|
|
|
3fcae4 |
dctx,
|
|
|
3fcae4 |
SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
|
|
|
3fcae4 |
|
|
|
1c4fed |
if (!ch[0] && ch[-1])
|
|
|
1c4fed |
nstrs++;
|
|
|
3fcae4 |
}
|
|
|
1c4fed |
|
|
|
1c4fed |
if (nstrs != nsyms)
|
|
|
1c4fed |
return SLBT_CUSTOM_ERROR(
|
|
|
1c4fed |
dctx,
|
|
|
1c4fed |
SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
|
|
|
1c4fed |
|
|
|
3fcae4 |
if (cap[-1])
|
|
|
3fcae4 |
return SLBT_CUSTOM_ERROR(
|
|
|
3fcae4 |
dctx,
|
|
|
3fcae4 |
SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
|
|
|
3fcae4 |
|
|
|
d4473b |
if (!(m->symstrv = calloc(nsyms + 1,sizeof(const char *))))
|
|
|
d4473b |
return SLBT_SYSTEM_ERROR(dctx,0);
|
|
|
d4473b |
|
|
|
d4473b |
armap->ar_string_table = m->symstrv;
|
|
|
d4473b |
|
|
|
d4473b |
armapref = &m->armaps.armap_common_64;
|
|
|
d4473b |
armapref->ar_member = memberp;
|
|
|
d4473b |
armapref->ar_armap_bsd = armap;
|
|
|
1c4fed |
armapref->ar_armap_attr = AR_ARMAP_ATTR_BSD | attr;
|
|
|
d4473b |
armapref->ar_num_of_symbols = nsyms;
|
|
|
d4473b |
armapref->ar_size_of_refs = sizeofrefs;
|
|
|
d4473b |
armapref->ar_size_of_strs = sizeofstrs;
|
|
|
d4473b |
armapref->ar_string_table = m->symstrs;
|
|
|
d4473b |
|
|
|
d4473b |
m->armaps.armap_nsyms = nsyms;
|
|
|
d4473b |
|
|
|
d4473b |
m->armeta.a_armap_primary.ar_armap_common_64 = armapref;
|
|
|
d4473b |
|
|
|
d4473b |
return 0;
|
|
|
d4473b |
}
|
|
|
d4473b |
|
|
|
d4473b |
static int slbt_ar_parse_primary_armap_sysv_32(
|
|
|
d4473b |
const struct slbt_driver_ctx * dctx,
|
|
|
d4473b |
struct slbt_archive_meta_impl * m)
|
|
|
d4473b |
{
|
|
|
d4473b |
struct ar_raw_armap_sysv_32 * armap;
|
|
|
d4473b |
struct ar_meta_member_info * memberp;
|
|
|
d4473b |
struct ar_meta_armap_common_32 *armapref;
|
|
|
d4473b |
uint32_t nsyms;
|
|
|
80052a |
uint32_t nstrs;
|
|
|
80052a |
const char * ch;
|
|
|
80052a |
const char * cap;
|
|
|
d4473b |
unsigned char * uch;
|
|
|
d4473b |
unsigned char (*mark)[0x04];
|
|
|
d4473b |
|
|
|
d4473b |
armap = &m->armaps.armap_sysv_32;
|
|
|
d4473b |
memberp = m->memberv[0];
|
|
|
d4473b |
|
|
|
d4473b |
mark = memberp->ar_object_data;
|
|
|
d4473b |
|
|
|
d4473b |
armap->ar_num_of_syms = mark;
|
|
|
d4473b |
uch = *mark++;
|
|
|
d4473b |
|
|
|
d4473b |
armap->ar_first_ref_offset = mark;
|
|
|
d4473b |
|
|
|
d4473b |
nsyms = (uch[0] << 24) + (uch[1] << 16) + (uch[2] << 8) + uch[3];
|
|
|
d4473b |
mark += nsyms;
|
|
|
d4473b |
|
|
|
80052a |
if (memberp->ar_object_size < (sizeof(*mark) + (nsyms * sizeof(*mark))))
|
|
|
80052a |
return SLBT_CUSTOM_ERROR(
|
|
|
80052a |
dctx,
|
|
|
80052a |
SLBT_ERR_AR_INVALID_ARMAP_NUMBER_OF_SYMS);
|
|
|
80052a |
|
|
|
d4473b |
m->symstrs = (const char *)mark;
|
|
|
d4473b |
|
|
|
80052a |
cap = memberp->ar_object_data;
|
|
|
80052a |
cap += memberp->ar_object_size;
|
|
|
80052a |
|
|
|
8a0804 |
if ((cap == m->symstrs) && nsyms)
|
|
|
80052a |
return SLBT_CUSTOM_ERROR(
|
|
|
80052a |
dctx,
|
|
|
80052a |
SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
|
|
|
80052a |
|
|
|
80052a |
if (nsyms && !m->symstrs[0])
|
|
|
80052a |
return SLBT_CUSTOM_ERROR(
|
|
|
80052a |
dctx,
|
|
|
80052a |
SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
|
|
|
80052a |
|
|
|
80052a |
for (ch=&m->symstrs[1],nstrs=0; ch
|
|
|
80052a |
if (!ch[0] && !ch[-1] && (nstrs < nsyms))
|
|
|
80052a |
return SLBT_CUSTOM_ERROR(
|
|
|
80052a |
dctx,
|
|
|
80052a |
SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
|
|
|
80052a |
|
|
|
80052a |
if (!ch[0] && ch[-1])
|
|
|
80052a |
nstrs++;
|
|
|
80052a |
}
|
|
|
80052a |
|
|
|
80052a |
if (nstrs != nsyms)
|
|
|
80052a |
return SLBT_CUSTOM_ERROR(
|
|
|
80052a |
dctx,
|
|
|
80052a |
SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
|
|
|
80052a |
|
|
|
80052a |
if (cap[-1])
|
|
|
80052a |
return SLBT_CUSTOM_ERROR(
|
|
|
80052a |
dctx,
|
|
|
80052a |
SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
|
|
|
80052a |
|
|
|
d4473b |
if (!(m->symstrv = calloc(nsyms + 1,sizeof(const char *))))
|
|
|
d4473b |
return SLBT_SYSTEM_ERROR(dctx,0);
|
|
|
d4473b |
|
|
|
d4473b |
armap->ar_string_table = m->symstrv;
|
|
|
d4473b |
|
|
|
d4473b |
armapref = &m->armaps.armap_common_32;
|
|
|
d4473b |
armapref->ar_member = memberp;
|
|
|
d4473b |
armapref->ar_armap_sysv = armap;
|
|
|
d4473b |
armapref->ar_armap_attr = AR_ARMAP_ATTR_SYSV | AR_ARMAP_ATTR_BE_32;
|
|
|
d4473b |
armapref->ar_num_of_symbols = nsyms;
|
|
|
d4473b |
armapref->ar_string_table = m->symstrs;
|
|
|
d4473b |
|
|
|
d4473b |
m->armaps.armap_nsyms = nsyms;
|
|
|
d4473b |
|
|
|
d4473b |
m->armeta.a_armap_primary.ar_armap_common_32 = armapref;
|
|
|
d4473b |
|
|
|
d4473b |
return 0;
|
|
|
d4473b |
}
|
|
|
d4473b |
|
|
|
d4473b |
static int slbt_ar_parse_primary_armap_sysv_64(
|
|
|
d4473b |
const struct slbt_driver_ctx * dctx,
|
|
|
d4473b |
struct slbt_archive_meta_impl * m)
|
|
|
d4473b |
{
|
|
|
d4473b |
struct ar_raw_armap_sysv_64 * armap;
|
|
|
d4473b |
struct ar_meta_member_info * memberp;
|
|
|
d4473b |
struct ar_meta_armap_common_64 *armapref;
|
|
|
d4473b |
uint64_t nsyms_hi;
|
|
|
d4473b |
uint64_t nsyms_lo;
|
|
|
d4473b |
uint64_t nsyms;
|
|
|
5152c7 |
uint64_t nstrs;
|
|
|
5152c7 |
const char * ch;
|
|
|
5152c7 |
const char * cap;
|
|
|
d4473b |
unsigned char * uch;
|
|
|
d4473b |
unsigned char (*mark)[0x08];
|
|
|
d4473b |
|
|
|
d4473b |
armap = &m->armaps.armap_sysv_64;
|
|
|
d4473b |
memberp = m->memberv[0];
|
|
|
d4473b |
|
|
|
d4473b |
mark = memberp->ar_object_data;
|
|
|
d4473b |
|
|
|
d4473b |
armap->ar_num_of_syms = mark;
|
|
|
d4473b |
uch = *mark++;
|
|
|
d4473b |
|
|
|
d4473b |
armap->ar_first_ref_offset = mark;
|
|
|
d4473b |
|
|
|
d4473b |
nsyms_hi = (uch[0] << 24) + (uch[1] << 16) + (uch[2] << 8) + uch[3];
|
|
|
d4473b |
nsyms_lo = (uch[4] << 24) + (uch[5] << 16) + (uch[6] << 8) + uch[7];
|
|
|
d4473b |
|
|
|
d4473b |
nsyms = (nsyms_hi << 32) + nsyms_lo;
|
|
|
d4473b |
mark += nsyms;
|
|
|
d4473b |
|
|
|
5152c7 |
if (memberp->ar_object_size < (sizeof(*mark) + (nsyms * sizeof(*mark))))
|
|
|
5152c7 |
return SLBT_CUSTOM_ERROR(
|
|
|
5152c7 |
dctx,
|
|
|
5152c7 |
SLBT_ERR_AR_INVALID_ARMAP_NUMBER_OF_SYMS);
|
|
|
5152c7 |
|
|
|
d4473b |
m->symstrs = (const char *)mark;
|
|
|
d4473b |
|
|
|
5152c7 |
cap = memberp->ar_object_data;
|
|
|
5152c7 |
cap += memberp->ar_object_size;
|
|
|
5152c7 |
|
|
|
e5f056 |
if ((cap == m->symstrs) && nsyms)
|
|
|
5152c7 |
return SLBT_CUSTOM_ERROR(
|
|
|
5152c7 |
dctx,
|
|
|
5152c7 |
SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
|
|
|
5152c7 |
|
|
|
5152c7 |
if (nsyms && !m->symstrs[0])
|
|
|
5152c7 |
return SLBT_CUSTOM_ERROR(
|
|
|
5152c7 |
dctx,
|
|
|
5152c7 |
SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
|
|
|
5152c7 |
|
|
|
5152c7 |
for (ch=&m->symstrs[1],nstrs=0; ch
|
|
|
5152c7 |
if (!ch[0] && !ch[-1] && (nstrs < nsyms))
|
|
|
5152c7 |
return SLBT_CUSTOM_ERROR(
|
|
|
5152c7 |
dctx,
|
|
|
5152c7 |
SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
|
|
|
5152c7 |
|
|
|
5152c7 |
if (!ch[0] && ch[-1])
|
|
|
5152c7 |
nstrs++;
|
|
|
5152c7 |
}
|
|
|
5152c7 |
|
|
|
5152c7 |
if (nstrs != nsyms)
|
|
|
5152c7 |
return SLBT_CUSTOM_ERROR(
|
|
|
5152c7 |
dctx,
|
|
|
5152c7 |
SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
|
|
|
5152c7 |
|
|
|
5152c7 |
if (cap[-1])
|
|
|
5152c7 |
return SLBT_CUSTOM_ERROR(
|
|
|
5152c7 |
dctx,
|
|
|
5152c7 |
SLBT_ERR_AR_INVALID_ARMAP_STRING_TABLE);
|
|
|
5152c7 |
|
|
|
d4473b |
if (!(m->symstrv = calloc(nsyms + 1,sizeof(const char *))))
|
|
|
d4473b |
return SLBT_SYSTEM_ERROR(dctx,0);
|
|
|
d4473b |
|
|
|
d4473b |
armap->ar_string_table = m->symstrv;
|
|
|
d4473b |
|
|
|
d4473b |
armapref = &m->armaps.armap_common_64;
|
|
|
d4473b |
armapref->ar_member = memberp;
|
|
|
d4473b |
armapref->ar_armap_sysv = armap;
|
|
|
d4473b |
armapref->ar_armap_attr = AR_ARMAP_ATTR_SYSV | AR_ARMAP_ATTR_BE_64;
|
|
|
d4473b |
armapref->ar_num_of_symbols = nsyms;
|
|
|
d4473b |
armapref->ar_string_table = m->symstrs;
|
|
|
d4473b |
|
|
|
d4473b |
m->armaps.armap_nsyms = nsyms;
|
|
|
d4473b |
|
|
|
d4473b |
m->armeta.a_armap_primary.ar_armap_common_64 = armapref;
|
|
|
d4473b |
|
|
|
d4473b |
return 0;
|
|
|
d4473b |
}
|
|
|
d4473b |
|
|
|
d4473b |
static int slbt_ar_parse_primary_armap(
|
|
|
d4473b |
const struct slbt_driver_ctx * dctx,
|
|
|
d4473b |
struct slbt_archive_meta_impl * m)
|
|
|
d4473b |
|
|
|
d4473b |
{
|
|
|
d4473b |
struct ar_meta_member_info * memberp;
|
|
|
d4473b |
const char * hdrname;
|
|
|
d4473b |
uint32_t hdrattr;
|
|
|
d4473b |
|
|
|
d4473b |
memberp = m->memberv[0];
|
|
|
d4473b |
hdrname = memberp->ar_file_header.ar_member_name;
|
|
|
d4473b |
hdrattr = memberp->ar_file_header.ar_header_attr;
|
|
|
d4473b |
|
|
|
d4473b |
if (!(memberp->ar_member_attr & AR_MEMBER_ATTR_ARMAP))
|
|
|
d4473b |
return 0;
|
|
|
d4473b |
|
|
|
d4473b |
if (hdrattr & AR_HEADER_ATTR_SYSV) {
|
|
|
d4473b |
/* mips 64-bit armap member? */
|
|
|
d4473b |
if (!strncmp(hdrname,"/SYM64/",7))
|
|
|
d4473b |
return slbt_ar_parse_primary_armap_sysv_64(
|
|
|
d4473b |
dctx,m);
|
|
|
d4473b |
|
|
|
d4473b |
/* sysv 32-bit armap member */
|
|
|
d4473b |
return slbt_ar_parse_primary_armap_sysv_32(
|
|
|
d4473b |
dctx,m);
|
|
|
d4473b |
|
|
|
d4473b |
} else if (hdrattr & AR_HEADER_ATTR_BSD) {
|
|
|
d4473b |
if (!strcmp(hdrname,"__.SYMDEF"))
|
|
|
d4473b |
return slbt_ar_parse_primary_armap_bsd_32(
|
|
|
d4473b |
dctx,m);
|
|
|
d4473b |
|
|
|
d4473b |
else if (!strcmp(hdrname,"__.SYMDEF SORTED"))
|
|
|
d4473b |
return slbt_ar_parse_primary_armap_bsd_32(
|
|
|
d4473b |
dctx,m);
|
|
|
d4473b |
|
|
|
d4473b |
else if (!strcmp(hdrname,"__.SYMDEF_64"))
|
|
|
d4473b |
return slbt_ar_parse_primary_armap_bsd_64(
|
|
|
d4473b |
dctx,m);
|
|
|
d4473b |
|
|
|
d4473b |
else if (!strcmp(hdrname,"__.SYMDEF_64 SORTED"))
|
|
|
d4473b |
return slbt_ar_parse_primary_armap_bsd_64(
|
|
|
d4473b |
dctx,m);
|
|
|
d4473b |
}
|
|
|
d4473b |
|
|
|
d4473b |
return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_FLOW_ERROR);
|
|
|
d4473b |
}
|
|
|
d4473b |
|
|
|
d4473b |
int slbt_get_archive_meta(
|
|
|
d4473b |
const struct slbt_driver_ctx * dctx,
|
|
|
d4473b |
const struct slbt_raw_archive * archive,
|
|
|
d4473b |
struct slbt_archive_meta ** meta)
|
|
|
d4473b |
{
|
|
|
d4473b |
const char * mark;
|
|
|
d4473b |
const char * cap;
|
|
|
d4473b |
struct slbt_archive_meta_impl * m;
|
|
|
d4473b |
const char * slash;
|
|
|
d4473b |
const char * ch;
|
|
|
d4473b |
const char * fldcap;
|
|
|
d4473b |
size_t nelements;
|
|
|
d4473b |
uint64_t nentries;
|
|
|
d4473b |
uint64_t stblsize;
|
|
|
d4473b |
uint64_t filesize;
|
|
|
d4473b |
uint64_t namelen;
|
|
|
d4473b |
uint64_t nameoff;
|
|
|
d4473b |
uint32_t attr;
|
|
|
d4473b |
struct ar_raw_file_header * arhdr;
|
|
|
d4473b |
struct ar_raw_file_header * arlongnames;
|
|
|
d4473b |
struct ar_meta_member_info * memberp;
|
|
|
d4473b |
char * longnamep;
|
|
|
d4473b |
size_t idx;
|
|
|
d4473b |
struct ar_header_info * hdrinfov;
|
|
|
d4473b |
struct ar_header_info * hdrinfov_cap;
|
|
|
d4473b |
struct ar_header_info * hdrinfov_next;
|
|
|
d4473b |
struct ar_header_info hdrinfobuf[AR_STACK_VECTOR_ELEMENTS];
|
|
|
d4473b |
|
|
|
d4473b |
/* init */
|
|
|
d4473b |
hdrinfov = hdrinfobuf;
|
|
|
d4473b |
hdrinfov_cap = &hdrinfobuf[AR_STACK_VECTOR_ELEMENTS];
|
|
|
d4473b |
nelements = AR_STACK_VECTOR_ELEMENTS;
|
|
|
d4473b |
|
|
|
d4473b |
memset(hdrinfobuf,0,sizeof(hdrinfobuf));
|
|
|
d4473b |
|
|
|
d4473b |
mark = archive->map_addr;
|
|
|
d4473b |
cap = &mark[archive->map_size];
|
|
|
d4473b |
|
|
|
d4473b |
/* preliminary validation */
|
|
|
d4473b |
if (archive->map_size < sizeof(struct ar_raw_signature))
|
|
|
d4473b |
return SLBT_CUSTOM_ERROR(
|
|
|
d4473b |
dctx,
|
|
|
d4473b |
SLBT_ERR_AR_INVALID_SIGNATURE);
|
|
|
d4473b |
|
|
|
d4473b |
else if (strncmp(mark,ar_signature,sizeof(struct ar_raw_signature)))
|
|
|
d4473b |
return SLBT_CUSTOM_ERROR(
|
|
|
d4473b |
dctx,
|
|
|
d4473b |
SLBT_ERR_AR_INVALID_SIGNATURE);
|
|
|
d4473b |
|
|
|
d4473b |
/* alloc */
|
|
|
d4473b |
if (!(m = calloc(1,sizeof(*m))))
|
|
|
d4473b |
return SLBT_SYSTEM_ERROR(dctx,0);
|
|
|
d4473b |
|
|
|
d4473b |
/* archive map info */
|
|
|
d4473b |
m->armeta.r_archive.map_addr = archive->map_addr;
|
|
|
d4473b |
m->armeta.r_archive.map_size = archive->map_size;
|
|
|
d4473b |
|
|
|
d4473b |
/* archive signature */
|
|
|
d4473b |
m->armeta.r_signature = (struct ar_raw_signature *)mark;
|
|
|
d4473b |
m->armeta.m_signature = (struct ar_meta_signature *)ar_signature;
|
|
|
d4473b |
|
|
|
d4473b |
/* signature only? */
|
|
|
d4473b |
if (archive->map_size == sizeof(struct ar_raw_signature)) {
|
|
|
d4473b |
*meta = &m->armeta;
|
|
|
d4473b |
return 0;
|
|
|
d4473b |
}
|
|
|
d4473b |
|
|
|
d4473b |
mark += sizeof(struct ar_raw_signature);
|
|
|
d4473b |
|
|
|
d4473b |
/* only trailing null characters past the signature? */
|
|
|
d4473b |
if (cap < &mark[sizeof(*arhdr)])
|
|
|
d4473b |
for (ch=mark; ch
|
|
|
d4473b |
if (*ch)
|
|
|
d4473b |
return slbt_free_archive_meta_impl(
|
|
|
d4473b |
m,SLBT_CUSTOM_ERROR(
|
|
|
d4473b |
dctx,
|
|
|
d4473b |
SLBT_ERR_AR_INVALID_HEADER));
|
|
|
d4473b |
|
|
|
d4473b |
/* count entries, calculate string table size */
|
|
|
d4473b |
for (nentries=0,stblsize=0,arlongnames=0; mark
|
|
|
d4473b |
arhdr = (struct ar_raw_file_header *)mark;
|
|
|
d4473b |
|
|
|
d4473b |
/* file size */
|
|
|
d4473b |
if ((slbt_ar_read_decimal_64(
|
|
|
d4473b |
arhdr->ar_file_size,
|
|
|
d4473b |
sizeof(arhdr->ar_file_size),
|
|
|
d4473b |
&filesize)) < 0)
|
|
|
d4473b |
return slbt_free_archive_meta_impl(
|
|
|
d4473b |
m,SLBT_CUSTOM_ERROR(
|
|
|
d4473b |
dctx,
|
|
|
d4473b |
SLBT_ERR_AR_INVALID_HEADER));
|
|
|
d4473b |
|
|
|
d4473b |
mark += sizeof(struct ar_raw_file_header);
|
|
|
d4473b |
|
|
|
d4473b |
/* stblsize, member name type */
|
|
|
d4473b |
fldcap = &arhdr->ar_file_id[sizeof(arhdr->ar_file_id)];
|
|
|
d4473b |
|
|
|
d4473b |
/* sysv long names table? */
|
|
|
d4473b |
if ((arhdr->ar_file_id[0] == '/') && (arhdr->ar_file_id[1] == '/')) {
|
|
|
d4473b |
for (ch=&arhdr->ar_file_id[2]; ch
|
|
|
d4473b |
if (*ch != AR_DEC_PADDING)
|
|
|
d4473b |
return slbt_free_archive_meta_impl(
|
|
|
d4473b |
m,SLBT_CUSTOM_ERROR(
|
|
|
d4473b |
dctx,
|
|
|
d4473b |
SLBT_ERR_AR_INVALID_HEADER));
|
|
|
d4473b |
|
|
|
d4473b |
if (slbt_ar_read_decimal_64(
|
|
|
d4473b |
arhdr->ar_file_size,
|
|
|
d4473b |
sizeof(arhdr->ar_file_size),
|
|
|
d4473b |
&namelen) < 0)
|
|
|
d4473b |
return slbt_free_archive_meta_impl(
|
|
|
d4473b |
m,SLBT_CUSTOM_ERROR(
|
|
|
d4473b |
dctx,
|
|
|
d4473b |
SLBT_ERR_AR_INVALID_HEADER));
|
|
|
d4473b |
|
|
|
d4473b |
|
|
|
d4473b |
/* duplicate long names member? */
|
|
|
d4473b |
if (arlongnames)
|
|
|
d4473b |
return slbt_free_archive_meta_impl(
|
|
|
d4473b |
m,SLBT_CUSTOM_ERROR(
|
|
|
d4473b |
dctx,
|
|
|
d4473b |
SLBT_ERR_AR_DUPLICATE_LONG_NAMES));
|
|
|
d4473b |
|
|
|
d4473b |
attr = AR_HEADER_ATTR_FILE_ID | AR_HEADER_ATTR_SYSV;
|
|
|
d4473b |
|
|
|
d4473b |
stblsize++;
|
|
|
d4473b |
stblsize++;
|
|
|
d4473b |
stblsize++;
|
|
|
d4473b |
|
|
|
d4473b |
stblsize += namelen;
|
|
|
d4473b |
|
|
|
d4473b |
arlongnames = arhdr;
|
|
|
d4473b |
|
|
|
1af4bb |
/* the /SYM64/ string must be special cased, also below when it gets copied */
|
|
|
1af4bb |
} else if (!strncmp(arhdr->ar_file_id,"/SYM64/",7)) {
|
|
|
1af4bb |
for (ch=&arhdr->ar_file_id[7]; ch
|
|
|
1af4bb |
if (*ch != AR_DEC_PADDING)
|
|
|
1af4bb |
return slbt_free_archive_meta_impl(
|
|
|
1af4bb |
m,SLBT_CUSTOM_ERROR(
|
|
|
1af4bb |
dctx,
|
|
|
1af4bb |
SLBT_ERR_AR_INVALID_HEADER));
|
|
|
1af4bb |
|
|
|
1af4bb |
attr = AR_HEADER_ATTR_FILE_ID | AR_HEADER_ATTR_SYSV;
|
|
|
1af4bb |
stblsize += 8;
|
|
|
1af4bb |
|
|
|
d4473b |
/* sysv armap member or sysv long name reference? */
|
|
|
d4473b |
} else if (arhdr->ar_file_id[0] == '/') {
|
|
|
d4473b |
if (slbt_ar_read_decimal_64(
|
|
|
d4473b |
&arhdr->ar_file_id[1],
|
|
|
d4473b |
sizeof(arhdr->ar_file_id)-1,
|
|
|
d4473b |
&nameoff) < 0)
|
|
|
d4473b |
return slbt_free_archive_meta_impl(
|
|
|
d4473b |
m,SLBT_CUSTOM_ERROR(
|
|
|
d4473b |
dctx,
|
|
|
d4473b |
SLBT_ERR_AR_INVALID_HEADER));
|
|
|
d4473b |
|
|
|
d4473b |
if (arhdr->ar_file_id[1] == AR_DEC_PADDING) {
|
|
|
d4473b |
attr = AR_HEADER_ATTR_FILE_ID | AR_HEADER_ATTR_SYSV;
|
|
|
d4473b |
stblsize++;
|
|
|
d4473b |
stblsize++;
|
|
|
d4473b |
} else {
|
|
|
d4473b |
attr = AR_HEADER_ATTR_NAME_REF | AR_HEADER_ATTR_SYSV;
|
|
|
d4473b |
}
|
|
|
d4473b |
|
|
|
d4473b |
/* bsd long name reference? */
|
|
|
d4473b |
} else if ((arhdr->ar_file_id[0] == '#')
|
|
|
d4473b |
&& (arhdr->ar_file_id[1] == '1')
|
|
|
d4473b |
&& (arhdr->ar_file_id[2] == '/')) {
|
|
|
d4473b |
if (slbt_ar_read_decimal_64(
|
|
|
d4473b |
&arhdr->ar_file_id[3],
|
|
|
d4473b |
sizeof(arhdr->ar_file_id)-3,
|
|
|
d4473b |
&namelen) < 0)
|
|
|
d4473b |
return slbt_free_archive_meta_impl(
|
|
|
d4473b |
m,SLBT_CUSTOM_ERROR(
|
|
|
d4473b |
dctx,
|
|
|
d4473b |
SLBT_ERR_AR_INVALID_HEADER));
|
|
|
d4473b |
|
|
|
d4473b |
attr = AR_HEADER_ATTR_NAME_REF | AR_HEADER_ATTR_BSD;
|
|
|
d4473b |
|
|
|
d4473b |
stblsize += namelen + 1;
|
|
|
d4473b |
|
|
|
d4473b |
/* must be either a sysv short member name, or a (legacy) bsd short name */
|
|
|
d4473b |
} else {
|
|
|
d4473b |
for (ch=arhdr->ar_file_id,slash=0; (ch
|
|
|
d4473b |
if (*ch == '/')
|
|
|
d4473b |
slash = ch;
|
|
|
d4473b |
|
|
|
d4473b |
if (slash) {
|
|
|
d4473b |
attr = AR_HEADER_ATTR_FILE_ID | AR_HEADER_ATTR_SYSV;
|
|
|
d4473b |
stblsize += (slash - arhdr->ar_file_id) + 1;
|
|
|
d4473b |
} else {
|
|
|
d4473b |
attr = AR_HEADER_ATTR_FILE_ID | AR_HEADER_ATTR_BSD;
|
|
|
d4473b |
stblsize += sizeof(arhdr->ar_file_id) + 1;
|
|
|
d4473b |
}
|
|
|
d4473b |
|
|
|
d4473b |
for (; ch
|
|
|
d4473b |
if (*ch++ != AR_DEC_PADDING)
|
|
|
d4473b |
return slbt_free_archive_meta_impl(
|
|
|
d4473b |
m,SLBT_CUSTOM_ERROR(
|
|
|
d4473b |
dctx,
|
|
|
d4473b |
SLBT_ERR_AR_INVALID_HEADER));
|
|
|
d4473b |
|
|
|
d4473b |
}
|
|
|
d4473b |
|
|
|
d4473b |
/* truncated data? */
|
|
|
d4473b |
if (cap < &mark[filesize])
|
|
|
d4473b |
return slbt_free_archive_meta_impl(
|
|
|
d4473b |
m,SLBT_CUSTOM_ERROR(
|
|
|
d4473b |
dctx,
|
|
|
d4473b |
SLBT_ERR_AR_TRUNCATED_DATA));
|
|
|
d4473b |
|
|
|
d4473b |
/* ar member alignment */
|
|
|
d4473b |
filesize += 1;
|
|
|
d4473b |
filesize |= 1;
|
|
|
d4473b |
filesize ^= 1;
|
|
|
d4473b |
|
|
|
d4473b |
mark += filesize;
|
|
|
d4473b |
|
|
|
d4473b |
/* only trailing null characters past the signature? */
|
|
|
d4473b |
if (cap < &mark[sizeof(*arhdr)])
|
|
|
d4473b |
for (; mark
|
|
|
d4473b |
if (*mark++)
|
|
|
d4473b |
return slbt_free_archive_meta_impl(
|
|
|
d4473b |
m,SLBT_CUSTOM_ERROR(
|
|
|
d4473b |
dctx,
|
|
|
d4473b |
SLBT_ERR_AR_INVALID_HEADER));
|
|
|
d4473b |
|
|
|
d4473b |
/* transient header info vector */
|
|
|
d4473b |
if (&hdrinfov[nentries] == hdrinfov_cap) {
|
|
|
d4473b |
nelements = (nelements == AR_STACK_VECTOR_ELEMENTS)
|
|
|
1b515c |
? (nelements << 4) : (nelements << 1);
|
|
|
d4473b |
|
|
|
d4473b |
if (!(hdrinfov_next = calloc(nelements,sizeof(*hdrinfov))))
|
|
|
d4473b |
return slbt_free_archive_meta_impl(
|
|
|
d4473b |
m,SLBT_CUSTOM_ERROR(
|
|
|
d4473b |
dctx,
|
|
|
d4473b |
SLBT_ERR_AR_TRUNCATED_DATA));
|
|
|
d4473b |
|
|
|
d4473b |
for (idx=0; idx
|
|
|
d4473b |
hdrinfov_next[idx].phdr = hdrinfov[idx].phdr;
|
|
|
d4473b |
hdrinfov_next[idx].attr = hdrinfov[idx].attr;
|
|
|
d4473b |
};
|
|
|
d4473b |
|
|
|
d4473b |
if (hdrinfov != hdrinfobuf)
|
|
|
d4473b |
free(hdrinfov);
|
|
|
d4473b |
|
|
|
d4473b |
hdrinfov = hdrinfov_next;
|
|
|
d4473b |
hdrinfov_cap = &hdrinfov_next[nelements];
|
|
|
d4473b |
m->hdrinfov = hdrinfov;
|
|
|
d4473b |
}
|
|
|
d4473b |
|
|
|
d4473b |
hdrinfov[nentries].phdr = arhdr;
|
|
|
d4473b |
hdrinfov[nentries].attr = attr;
|
|
|
d4473b |
}
|
|
|
d4473b |
|
|
|
d4473b |
/* allocate name strings, member vector */
|
|
|
d4473b |
if (!(m->namestrs = calloc(1,stblsize)))
|
|
|
d4473b |
return slbt_free_archive_meta_impl(
|
|
|
d4473b |
m,SLBT_SYSTEM_ERROR(dctx,0));
|
|
|
d4473b |
|
|
|
d4473b |
if (!(m->memberv = calloc(nentries+1,sizeof(*m->memberv))))
|
|
|
d4473b |
return slbt_free_archive_meta_impl(
|
|
|
d4473b |
m,SLBT_SYSTEM_ERROR(dctx,0));
|
|
|
d4473b |
|
|
|
d4473b |
if (!(m->members = calloc(nentries,sizeof(*m->members))))
|
|
|
d4473b |
return slbt_free_archive_meta_impl(
|
|
|
d4473b |
m,SLBT_SYSTEM_ERROR(dctx,0));
|
|
|
d4473b |
|
|
|
d4473b |
/* iterate, store meta data in library-friendly form */
|
|
|
d4473b |
for (idx=0,longnamep=m->namestrs; idx
|
|
|
d4473b |
arhdr = hdrinfov[idx].phdr;
|
|
|
d4473b |
attr = hdrinfov[idx].attr;
|
|
|
d4473b |
|
|
|
d4473b |
memberp = &m->members[idx];
|
|
|
d4473b |
m->memberv[idx] = memberp;
|
|
|
d4473b |
|
|
|
d4473b |
memberp->ar_file_header.ar_header_attr = attr;
|
|
|
d4473b |
|
|
|
d4473b |
slbt_ar_read_decimal_64(
|
|
|
d4473b |
arhdr->ar_time_date_stamp,
|
|
|
d4473b |
sizeof(arhdr->ar_time_date_stamp),
|
|
|
d4473b |
&memberp->ar_file_header.ar_time_date_stamp);
|
|
|
d4473b |
|
|
|
d4473b |
slbt_ar_read_decimal_32(
|
|
|
d4473b |
arhdr->ar_uid,
|
|
|
d4473b |
sizeof(arhdr->ar_uid),
|
|
|
d4473b |
&memberp->ar_file_header.ar_uid);
|
|
|
d4473b |
|
|
|
d4473b |
slbt_ar_read_decimal_32(
|
|
|
d4473b |
arhdr->ar_gid,
|
|
|
d4473b |
sizeof(arhdr->ar_gid),
|
|
|
d4473b |
&memberp->ar_file_header.ar_gid);
|
|
|
d4473b |
|
|
|
d4473b |
slbt_ar_read_octal(
|
|
|
d4473b |
arhdr->ar_file_mode,
|
|
|
d4473b |
sizeof(arhdr->ar_file_mode),
|
|
|
d4473b |
&memberp->ar_file_header.ar_file_mode);
|
|
|
d4473b |
|
|
|
d4473b |
slbt_ar_read_decimal_64(
|
|
|
d4473b |
arhdr->ar_file_size,
|
|
|
d4473b |
sizeof(arhdr->ar_file_size),
|
|
|
d4473b |
&memberp->ar_file_header.ar_file_size);
|
|
|
d4473b |
|
|
|
d4473b |
memberp->ar_file_header.ar_member_name = longnamep;
|
|
|
d4473b |
|
|
|
d4473b |
if (attr == (AR_HEADER_ATTR_FILE_ID | AR_HEADER_ATTR_SYSV)) {
|
|
|
d4473b |
if ((arhdr->ar_file_id[0] == '/') && (arhdr->ar_file_id[1] == '/')) {
|
|
|
d4473b |
*longnamep++ = '/';
|
|
|
d4473b |
*longnamep++ = '/';
|
|
|
d4473b |
longnamep++;
|
|
|
d4473b |
|
|
|
1af4bb |
} else if ((arhdr->ar_file_id[0] == '/') && (arhdr->ar_file_id[1] == 'S')) {
|
|
|
1af4bb |
*longnamep++ = '/';
|
|
|
1af4bb |
*longnamep++ = 'S';
|
|
|
1af4bb |
*longnamep++ = 'Y';
|
|
|
1af4bb |
*longnamep++ = 'M';
|
|
|
1af4bb |
*longnamep++ = '6';
|
|
|
1af4bb |
*longnamep++ = '4';
|
|
|
1af4bb |
*longnamep++ = '/';
|
|
|
1af4bb |
longnamep++;
|
|
|
1af4bb |
|
|
|
d4473b |
} else if (arhdr->ar_file_id[0] == '/') {
|
|
|
d4473b |
*longnamep++ = '/';
|
|
|
d4473b |
longnamep++;
|
|
|
d4473b |
|
|
|
d4473b |
} else {
|
|
|
d4473b |
ch = arhdr->ar_file_id;
|
|
|
d4473b |
|
|
|
d4473b |
for (; (*ch != '/'); )
|
|
|
d4473b |
*longnamep++ = *ch++;
|
|
|
d4473b |
|
|
|
d4473b |
longnamep++;
|
|
|
d4473b |
}
|
|
|
d4473b |
|
|
|
d4473b |
} else if (attr == (AR_HEADER_ATTR_FILE_ID | AR_HEADER_ATTR_BSD)) {
|
|
|
d4473b |
ch = arhdr->ar_file_id;
|
|
|
d4473b |
fldcap = &ch[sizeof(arhdr->ar_file_id)];
|
|
|
d4473b |
|
|
|
d4473b |
for (; (ch
|
|
|
d4473b |
*longnamep++ = *ch++;
|
|
|
d4473b |
|
|
|
d4473b |
longnamep++;
|
|
|
d4473b |
|
|
|
d4473b |
} else if (attr == (AR_HEADER_ATTR_NAME_REF | AR_HEADER_ATTR_SYSV)) {
|
|
|
d4473b |
slbt_ar_read_decimal_64(
|
|
|
d4473b |
&arhdr->ar_file_id[1],
|
|
|
d4473b |
sizeof(arhdr->ar_file_id) - 1,
|
|
|
d4473b |
&nameoff);
|
|
|
d4473b |
|
|
|
d4473b |
ch = arlongnames->ar_file_id;
|
|
|
d4473b |
ch += sizeof(*arlongnames);
|
|
|
d4473b |
ch += nameoff;
|
|
|
d4473b |
|
|
|
d4473b |
for (; *ch && (*ch != '/') && (*ch != AR_OBJ_PADDING); )
|
|
|
d4473b |
*longnamep++ = *ch++;
|
|
|
d4473b |
|
|
|
d4473b |
longnamep++;
|
|
|
d4473b |
|
|
|
d4473b |
} else if (attr == (AR_HEADER_ATTR_NAME_REF | AR_HEADER_ATTR_BSD)) {
|
|
|
d4473b |
slbt_ar_read_decimal_64(
|
|
|
d4473b |
&arhdr->ar_file_id[3],
|
|
|
d4473b |
sizeof(arhdr->ar_file_id) - 3,
|
|
|
d4473b |
&namelen);
|
|
|
d4473b |
|
|
|
d4473b |
mark = arhdr->ar_file_id;
|
|
|
d4473b |
mark += sizeof(*arhdr);
|
|
|
d4473b |
|
|
|
d4473b |
memcpy(longnamep,mark,namelen);
|
|
|
d4473b |
|
|
|
d4473b |
longnamep += namelen;
|
|
|
d4473b |
longnamep++;
|
|
|
d4473b |
}
|
|
|
d4473b |
|
|
|
d4473b |
/* object size, object data */
|
|
|
d4473b |
mark = arhdr->ar_file_id;
|
|
|
d4473b |
mark += sizeof(*arhdr);
|
|
|
d4473b |
namelen = 0;
|
|
|
d4473b |
|
|
|
d4473b |
if (attr == (AR_HEADER_ATTR_NAME_REF | AR_HEADER_ATTR_BSD)) {
|
|
|
d4473b |
slbt_ar_read_decimal_64(
|
|
|
d4473b |
&arhdr->ar_file_id[3],
|
|
|
d4473b |
sizeof(arhdr->ar_file_id)-3,
|
|
|
d4473b |
&namelen);
|
|
|
d4473b |
|
|
|
d4473b |
namelen += 1;
|
|
|
d4473b |
namelen |= 1;
|
|
|
d4473b |
namelen ^= 1;
|
|
|
d4473b |
|
|
|
d4473b |
mark += namelen;
|
|
|
d4473b |
};
|
|
|
d4473b |
|
|
|
d4473b |
memberp->ar_object_data = (void *)mark;
|
|
|
d4473b |
memberp->ar_object_size = memberp->ar_file_header.ar_file_size - namelen;
|
|
|
d4473b |
|
|
|
d4473b |
/* member attribute */
|
|
|
d4473b |
memberp->ar_member_attr = slbt_ar_get_member_attr(memberp);
|
|
|
d4473b |
|
|
|
d4473b |
/* pe/coff second linker member? */
|
|
|
d4473b |
if ((idx == 1) && (memberp->ar_member_attr == AR_MEMBER_ATTR_ARMAP))
|
|
|
d4473b |
if (hdrinfov[0].attr & AR_HEADER_ATTR_SYSV)
|
|
|
d4473b |
if (m->members[0].ar_member_attr == AR_MEMBER_ATTR_ARMAP)
|
|
|
d4473b |
if (attr & AR_HEADER_ATTR_SYSV)
|
|
|
d4473b |
memberp->ar_member_attr = AR_MEMBER_ATTR_LINKINFO;
|
|
|
d4473b |
|
|
|
d4473b |
/* armap member must be the first */
|
|
|
d4473b |
if ((memberp->ar_member_attr == AR_MEMBER_ATTR_ARMAP) && (idx > 0)) {
|
|
|
d4473b |
if (m->members[0].ar_member_attr == AR_MEMBER_ATTR_ARMAP)
|
|
|
d4473b |
return slbt_free_archive_meta_impl(
|
|
|
d4473b |
m,SLBT_CUSTOM_ERROR(
|
|
|
d4473b |
dctx,
|
|
|
d4473b |
SLBT_ERR_AR_DUPLICATE_ARMAP_MEMBER));
|
|
|
d4473b |
|
|
|
d4473b |
return slbt_free_archive_meta_impl(
|
|
|
d4473b |
m,SLBT_CUSTOM_ERROR(
|
|
|
d4473b |
dctx,
|
|
|
d4473b |
SLBT_ERR_AR_MISPLACED_ARMAP_MEMBER));
|
|
|
d4473b |
}
|
|
|
d4473b |
}
|
|
|
d4473b |
|
|
|
d4473b |
/* primary armap (first linker member) */
|
|
|
d4473b |
if (slbt_ar_parse_primary_armap(dctx,m) < 0)
|
|
|
d4473b |
return slbt_free_archive_meta_impl(
|
|
|
d4473b |
m,SLBT_NESTED_ERROR(dctx));
|
|
|
d4473b |
|
|
|
d4473b |
for (idx=0,ch=m->symstrs; idx<m->armaps.armap_nsyms; idx++) {
|
|
|
d4473b |
m->symstrv[idx] = ch;
|
|
|
d4473b |
ch += strlen(ch);
|
|
|
d4473b |
ch++;
|
|
|
d4473b |
}
|
|
|
d4473b |
|
|
|
d4473b |
/* pe/coff armap attributes (second linker member) */
|
|
|
d4473b |
(void)m->armeta.a_armap_pecoff;
|
|
|
d4473b |
|
|
|
d4473b |
/* all done */
|
|
|
d4473b |
if (m->hdrinfov) {
|
|
|
d4473b |
free(m->hdrinfov);
|
|
|
d4473b |
m->hdrinfov = 0;
|
|
|
d4473b |
}
|
|
|
d4473b |
|
|
|
d4473b |
*meta = &m->armeta;
|
|
|
d4473b |
|
|
|
d4473b |
return 0;
|
|
|
d4473b |
}
|
|
|
d4473b |
|
|
|
d4473b |
void slbt_free_archive_meta(struct slbt_archive_meta * meta)
|
|
|
d4473b |
{
|
|
|
d4473b |
struct slbt_archive_meta_impl * m;
|
|
|
d4473b |
|
|
|
d4473b |
if (meta) {
|
|
|
d4473b |
m = slbt_archive_meta_ictx(meta);
|
|
|
d4473b |
slbt_free_archive_meta_impl(m,0);
|
|
|
d4473b |
}
|
|
|
d4473b |
}
|