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>
2f4c03
#include <sys/mman.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,
a6209c
	const int *			stype,
9c013b
	struct mdso_object *		vobj)
9c013b
{
9c013b
	int					ret;
9c013b
	const char **				psym;
9c013b
	int					nsym;
9c013b
	int					nobj;
a6209c
	int					ndata;
9c013b
	uint32_t				objlen;
9c013b
	uint32_t				hdrlen;
9c013b
	uint32_t				mapstrsnum;
9c013b
	uint32_t				mapstrslen;
9c013b
	uint32_t				symidx;
2f4c03
	void *					addr;
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 */
9695ec
	memset(sobj,0,sizeof(sobj));
9c013b
a6209c
	for (nsym=0,ndata=0,psym=symv; *psym; psym++,nsym++)
a6209c
		ndata += (stype[psym-symv] == MDSO_SYMBOL_TYPE_DATA);
9c013b
a6209c
	if ((nobj = 1 + (2*nsym) - ndata) < 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 */
a3e2cf
	ret = mdso_objgen_dsometa(dctx,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
9695ec
	/* objlen: symfn, symentry */
9c013b
	for (psym=symv,pobj=&aobj[1]; *psym && !ret; psym++) {
a6209c
		if (stype[psym-symv] == MDSO_SYMBOL_TYPE_CODE) {
a3e2cf
			ret  = mdso_objgen_symfn(dctx,*psym,pobj);
9c013b
a6209c
			pobj->size += 1;
a6209c
			pobj->size |= 1;
a6209c
			pobj->size ^= 1;
9c013b
a6209c
			objlen += pobj->size;
a6209c
			objlen += sizeof(struct pe_raw_archive_common_hdr);
9c013b
a6209c
			mapstrslen += pobj->mapstrslen;
a6209c
			mapstrsnum += pobj->mapstrsnum;
a6209c
			pobj++;
a6209c
		}
9c013b
a3e2cf
		ret |= mdso_objgen_symentry(dctx,*psym,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
9695ec
	/* verify logic */
9695ec
	if (ret && (aobj == sobj))
9695ec
		return MDSO_NESTED_ERROR(dctx);
9c013b
9695ec
	if (ret) {
9695ec
		free(aobj);
9695ec
		return MDSO_NESTED_ERROR(dctx);
9695ec
	}
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
9695ec
	/* archive meta info, in-memory mapping */
2f4c03
	if (vobj->addr && (vobj->size < objlen))
9c013b
		return MDSO_BUFFER_ERROR(dctx);
9c013b
2f4c03
	if ((addr = vobj->addr)) {
2f4c03
		(void)0;
2f4c03
2f4c03
	} else {
2f4c03
		vobj->size       = objlen;
9c013b
		vobj->mapstrslen = mapstrslen;
9c013b
		vobj->mapstrsnum = mapstrsnum;
9c013b
2f4c03
		if (!vobj->name)
2f4c03
			return 0;
9c013b
2f4c03
		else if (mdso_create_archive(dctx,vobj) < 0)
2f4c03
			return MDSO_NESTED_ERROR(dctx);
9c013b
	}
9c013b
2f4c03
	ar = (unsigned char *)vobj->addr;
2f4c03
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
a3e2cf
	ret = mdso_objgen_dsometa(dctx,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 */
a6209c
		if (stype[psym-symv] == MDSO_SYMBOL_TYPE_CODE) {
a6209c
			pobj->mapstrs  = mapstrs;
a6209c
			pobj->arhdrpos = (uint32_t)(mark - ar);
a6209c
			pobj->arhdrlen = sizeof(struct pe_raw_archive_common_hdr);
a6209c
			pobj->addr     = &mark[pobj->arhdrlen];
a6209c
a6209c
			for (symidx=0; symidx<pobj->mapstrsnum; symidx++) {
a6209c
				mdso_write_big_endian_long(idx,pobj->arhdrpos);
a6209c
				idx += sizeof(uint32_t);
a6209c
			}
a6209c
a3e2cf
			ret = mdso_objgen_symfn(dctx,*psym,pobj);
a6209c
a6209c
			sprintf(
a6209c
				objname,"f%06zu.o",
a6209c
				psym - symv);
a6209c
a6209c
			mdso_argen_common_hdr(
a6209c
				(struct pe_raw_archive_common_hdr *)mark,
a6209c
				objname,pobj->size);
a6209c
a6209c
			mark    += pobj->arhdrlen + pobj->size;
a6209c
			mapstrs += pobj->mapstrslen;
a6209c
			pobj++;
9c013b
		}
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
a3e2cf
		ret = mdso_objgen_symentry(dctx,*psym,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
2f4c03
	/* aobj */
9c013b
	if (aobj != sobj)
9c013b
		free(aobj);
9c013b
2f4c03
	/* fs object unmap */
2f4c03
	if (!addr)
2f4c03
		munmap(vobj->addr,vobj->size);
2f4c03
9695ec
	/* verify */
9695ec
	if (ret)
9695ec
		return MDSO_NESTED_ERROR(dctx);
9695ec
2f4c03
	/* tada */
2f4c03
	return 0;
9c013b
9c013b
}