Blame src/archive/mdso_argen_common.c

9c013b
/****************************************************************/
9c013b
/*  mdso: midipix dso scavenger                                 */
9c013b
/*  Copyright (C) 2015--2017  Z. Gilboa                         */
9c013b
/*  Released under GPLv2 and GPLv3; see COPYING.MDSO.           */
9c013b
/****************************************************************/
9c013b
9c013b
#include <stdint.h>
9c013b
#include <stdio.h>
9c013b
#include <stdlib.h>
9c013b
#include <string.h>
9c013b
9c013b
#include <mdso/mdso.h>
9c013b
#include "mdso_errinfo_impl.h"
9c013b
#include "perk_structs.h"
9c013b
9c013b
static void mdso_argen_common_hdr(
9c013b
	struct pe_raw_archive_common_hdr *	arhdr,
9c013b
	char *					file_id,
9c013b
	size_t					size)
9c013b
{
9c013b
	size_t	slen;
9c013b
	char	sbuf[10];
9c013b
9c013b
	memset(arhdr,0x20,sizeof(*arhdr));
9c013b
9c013b
	slen = strlen(file_id);
9c013b
	memcpy(arhdr->ar_file_id,file_id,slen);
9c013b
	arhdr->ar_file_id[slen] = '/';
9c013b
9c013b
	arhdr->ar_uid[0] = '0';
9c013b
	arhdr->ar_gid[0] = '0';
9c013b
	arhdr->ar_file_mode[0] = '0';
9c013b
9c013b
	slen = sprintf(sbuf,"%zu",size);
9c013b
	memcpy(arhdr->ar_file_size,sbuf,slen);
9c013b
9c013b
	arhdr->ar_end_tag[0] = 0x60;
9c013b
	arhdr->ar_end_tag[1] = 0x0a;
9c013b
}
9c013b
9c013b
static void mdso_write_big_endian_long(unsigned char * ch, uint32_t val)
9c013b
{
9c013b
	ch[3] = val;
9c013b
	ch[2] = val >> 8;
9c013b
	ch[1] = val >> 16;
9c013b
	ch[0] = val >> 24;
9c013b
}
9c013b
9c013b
int  mdso_argen_common(
9c013b
	const struct mdso_driver_ctx *	dctx,
9c013b
	const char **			symv,
9c013b
	FILE *				fout,
9c013b
	struct mdso_object *		vobj)
9c013b
{
9c013b
	int					ret;
9c013b
	const char **				psym;
9c013b
	int					nsym;
9c013b
	int					nobj;
9c013b
	uint32_t				objlen;
9c013b
	uint32_t				hdrlen;
9c013b
	uint32_t				mapstrsnum;
9c013b
	uint32_t				mapstrslen;
9c013b
	uint32_t				symidx;
9c013b
	unsigned char *				ar;
9c013b
	unsigned char *				mark;
9c013b
	unsigned char *				idx;
9c013b
	char *					mapstrs;
9c013b
	struct pe_raw_archive_common_hdr *	arhdr;
9c013b
	struct mdso_object *			pobj;
9c013b
	struct mdso_object *			aobj;
9c013b
	struct mdso_object			sobj[256];
9c013b
	char					objname[16];
9c013b
9c013b
	/* init */
9c013b
	memset (sobj,0,sizeof(sobj));
9c013b
9c013b
	for (nsym=0,psym=symv; *psym; psym++)
9c013b
		nsym++;
9c013b
9c013b
	if ((nobj = 2*nsym + 1) < 256)
9c013b
		aobj = sobj;
9c013b
9c013b
	else if (nobj > 1024*1024)
9c013b
		return MDSO_CUSTOM_ERROR(dctx,MDSO_ERR_INVALID_VECTOR);
9c013b
9c013b
	else if (!(aobj = calloc(1,nobj*sizeof(*aobj))))
9c013b
		return MDSO_SYSTEM_ERROR(dctx);
9c013b
68360c
	/* objlen: archive signature, index header */
9c013b
	objlen  = 8;
9c013b
	objlen += sizeof(struct pe_raw_archive_common_hdr);
9c013b
68360c
	/* objlen: member headers */
9c013b
	ret = mdso_objgen_dsometa(dctx,0,aobj);
9c013b
9c013b
	aobj->size += 1;
9c013b
	aobj->size |= 1;
9c013b
	aobj->size ^= 1;
9c013b
9c013b
	objlen += aobj->size;
9c013b
	objlen += sizeof(struct pe_raw_archive_common_hdr);
9c013b
9c013b
	mapstrslen = aobj->mapstrslen;
9c013b
	mapstrsnum = aobj->mapstrsnum;
9c013b
9c013b
	for (psym=symv,pobj=&aobj[1]; *psym && !ret; psym++) {
9c013b
		ret  = mdso_objgen_symfn(dctx,*psym,0,pobj);
9c013b
9c013b
		pobj->size += 1;
9c013b
		pobj->size |= 1;
9c013b
		pobj->size ^= 1;
9c013b
9c013b
		objlen += pobj->size;
9c013b
		objlen += sizeof(struct pe_raw_archive_common_hdr);
9c013b
9c013b
		mapstrslen += pobj->mapstrslen;
9c013b
		mapstrsnum += pobj->mapstrsnum;
9c013b
		pobj++;
9c013b
9c013b
		ret |= mdso_objgen_symentry(dctx,*psym,0,pobj);
9c013b
9c013b
		pobj->size += 1;
9c013b
		pobj->size |= 1;
9c013b
		pobj->size ^= 1;
9c013b
9c013b
		objlen += pobj->size;
9c013b
		objlen += sizeof(struct pe_raw_archive_common_hdr);
9c013b
9c013b
		mapstrslen += pobj->mapstrslen;
9c013b
		mapstrsnum += pobj->mapstrsnum;
9c013b
		pobj++;
9c013b
	}
9c013b
9c013b
	if (ret && (aobj != sobj))
9c013b
		free(aobj);
9c013b
9c013b
	if (ret)
9c013b
		return ret;
9c013b
68360c
	/* index: string block alignment */
9c013b
	mapstrslen += 1;
9c013b
	mapstrslen |= 1;
9c013b
	mapstrslen ^= 1;
9c013b
68360c
	/* objlen: index size, padding */
68360c
	objlen += sizeof(uint32_t) * (1 + mapstrsnum);
68360c
	objlen += mapstrslen;
68360c
9c013b
	objlen += 15;
9c013b
	objlen |= 15;
9c013b
	objlen ^= 15;
9c013b
9c013b
	if (vobj && vobj->addr && (vobj->size < objlen))
9c013b
		return MDSO_BUFFER_ERROR(dctx);
9c013b
9c013b
	if (vobj && !vobj->addr) {
9c013b
		vobj->size = objlen;
9c013b
		vobj->mapstrslen = mapstrslen;
9c013b
		vobj->mapstrsnum = mapstrsnum;
9c013b
		return 0;
9c013b
	}
9c013b
9c013b
	if (vobj)
9c013b
		ar = (unsigned char *)vobj->addr;
9c013b
9c013b
	else if (!(ar = calloc(1,objlen))) {
9c013b
		if (aobj != sobj)
9c013b
			free(aobj);
9c013b
9c013b
		return MDSO_SYSTEM_ERROR(dctx);
9c013b
	}
9c013b
9c013b
	/* archive signature */
9c013b
	memcpy(ar,"!<arch>\n",8);
9c013b
	mark = &ar[8];
9c013b
9c013b
	/* archive header */
9c013b
	arhdr  = (struct pe_raw_archive_common_hdr *)mark;
9c013b
	hdrlen = sizeof(uint32_t) * (1 + mapstrsnum) + mapstrslen;
9c013b
	mdso_argen_common_hdr(arhdr,"",hdrlen);
9c013b
	mark += sizeof(*arhdr);
9c013b
9c013b
	/* archive index initialization */
9c013b
	mdso_write_big_endian_long(mark,mapstrsnum);
9c013b
	mark += sizeof(uint32_t);
9c013b
9c013b
	idx   = mark;
9c013b
	mark += sizeof(uint32_t) * mapstrsnum;
9c013b
9c013b
	mapstrs = (char *)mark;
9c013b
	mark   += mapstrslen;
9c013b
9c013b
	/* .dsometa object */
9c013b
	aobj->mapstrs  = mapstrs;
9c013b
	aobj->arhdrpos = (uint32_t)(mark - ar);
9c013b
	aobj->arhdrlen = sizeof(struct pe_raw_archive_common_hdr);
9c013b
	aobj->addr     = &mark[aobj->arhdrlen];
9c013b
9c013b
	for (symidx=0; symidx<aobj->mapstrsnum; symidx++) {
9c013b
		mdso_write_big_endian_long(idx,aobj->arhdrpos);
9c013b
		idx += sizeof(uint32_t);
9c013b
	}
9c013b
9c013b
	ret = mdso_objgen_dsometa(dctx,0,aobj);
9c013b
9c013b
	mdso_argen_common_hdr(
9c013b
		(struct pe_raw_archive_common_hdr *)mark,
9c013b
		".dsometa.o",aobj->size);
9c013b
9c013b
	mark    += aobj->arhdrlen + aobj->size;
9c013b
	mapstrs += aobj->mapstrslen;
9c013b
9c013b
	/* archive symfn and symentry objects */
9c013b
	for (psym=symv,pobj=&aobj[1]; *psym && !ret; psym++) {
9c013b
		/* symfn object */
9c013b
		pobj->mapstrs  = mapstrs;
9c013b
		pobj->arhdrpos = (uint32_t)(mark - ar);
9c013b
		pobj->arhdrlen = sizeof(struct pe_raw_archive_common_hdr);
9c013b
		pobj->addr     = &mark[pobj->arhdrlen];
9c013b
9c013b
		for (symidx=0; symidx<pobj->mapstrsnum; symidx++) {
9c013b
			mdso_write_big_endian_long(idx,pobj->arhdrpos);
9c013b
			idx += sizeof(uint32_t);
9c013b
		}
9c013b
9c013b
		ret = mdso_objgen_symfn(dctx,*psym,0,pobj);
9c013b
9c013b
		sprintf(
9c013b
			objname,"f%06zu.o",
9c013b
			psym - symv);
9c013b
9c013b
		mdso_argen_common_hdr(
9c013b
			(struct pe_raw_archive_common_hdr *)mark,
9c013b
			objname,pobj->size);
9c013b
9c013b
		mark    += pobj->arhdrlen + pobj->size;
9c013b
		mapstrs += pobj->mapstrslen;
9c013b
		pobj++;
9c013b
9c013b
9c013b
		/* symentry object */
9c013b
		pobj->mapstrs  = mapstrs;
9c013b
		pobj->arhdrpos = (uint32_t)(mark - ar);
9c013b
		pobj->arhdrlen = sizeof(struct pe_raw_archive_common_hdr);
9c013b
		pobj->addr     = &mark[pobj->arhdrlen];
9c013b
9c013b
		for (symidx=0; symidx<pobj->mapstrsnum; symidx++) {
9c013b
			mdso_write_big_endian_long(idx,pobj->arhdrpos);
9c013b
			idx += sizeof(uint32_t);
9c013b
		}
9c013b
9c013b
		sprintf(
9c013b
			objname,"s%06zu.o",
9c013b
			psym - symv);
9c013b
9c013b
		ret = mdso_objgen_symentry(dctx,*psym,0,pobj);
9c013b
9c013b
		mdso_argen_common_hdr(
9c013b
			(struct pe_raw_archive_common_hdr *)mark,
9c013b
			objname,pobj->size);
9c013b
9c013b
		mark    += pobj->arhdrlen + pobj->size;
9c013b
		mapstrs += pobj->mapstrslen;
9c013b
		pobj++;
9c013b
	}
9c013b
9c013b
	if (ret) {
9c013b
		if (aobj != sobj)
9c013b
			free(aobj);
9c013b
9c013b
		if (!vobj)
9c013b
			free(ar);
9c013b
9c013b
		return ret;
9c013b
	}
9c013b
9c013b
	/* tada */
9c013b
	if (fout)
9c013b
		ret = fwrite(ar,objlen,1,fout);
9c013b
9c013b
	if (aobj != sobj)
9c013b
		free(aobj);
9c013b
9c013b
	if (!vobj)
9c013b
		free(ar);
9c013b
9c013b
	return (ret == 0)
9c013b
		? MDSO_FILE_ERROR(dctx)
9c013b
		: 0;
9c013b
}