|
|
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 |
}
|