| |
| |
| |
| |
| |
| |
| #include <stdint.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/mman.h> |
| |
| #include <mdso/mdso.h> |
| #include "mdso_errinfo_impl.h" |
| #include "perk_structs.h" |
| |
| static void mdso_argen_common_hdr( |
| struct pe_raw_archive_common_hdr * arhdr, |
| char * file_id, |
| size_t size) |
| { |
| size_t slen; |
| char sbuf[10]; |
| |
| memset(arhdr,0x20,sizeof(*arhdr)); |
| |
| slen = strlen(file_id); |
| memcpy(arhdr->ar_file_id,file_id,slen); |
| arhdr->ar_file_id[slen] = '/'; |
| |
| arhdr->ar_uid[0] = '0'; |
| arhdr->ar_gid[0] = '0'; |
| arhdr->ar_file_mode[0] = '0'; |
| arhdr->ar_time_date_stamp[0] = '0'; |
| |
| slen = sprintf(sbuf,"%zu",size); |
| memcpy(arhdr->ar_file_size,sbuf,slen); |
| |
| arhdr->ar_end_tag[0] = 0x60; |
| arhdr->ar_end_tag[1] = 0x0a; |
| } |
| |
| static void mdso_write_big_endian_long(unsigned char * ch, uint32_t val) |
| { |
| ch[3] = val; |
| ch[2] = val >> 8; |
| ch[1] = val >> 16; |
| ch[0] = val >> 24; |
| } |
| |
| int mdso_argen_common( |
| const struct mdso_driver_ctx * dctx, |
| const char ** symv, |
| struct mdso_object * vobj) |
| { |
| int ret; |
| const char ** psym; |
| intptr_t nobj; |
| uint32_t objlen; |
| uint32_t hdrlen; |
| uint32_t mapstrsnum; |
| uint32_t mapstrslen; |
| uint32_t symidx; |
| void * addr; |
| unsigned char * ar; |
| unsigned char * mark; |
| unsigned char * idx; |
| char * mapstrs; |
| struct pe_raw_archive_common_hdr * arhdr; |
| struct mdso_object * pobj; |
| struct mdso_object * aobj; |
| struct mdso_object sobj[256]; |
| char objname[16]; |
| |
| |
| memset(sobj,0,sizeof(sobj)); |
| |
| for (psym=symv; *psym; psym++) |
| (void)0; |
| |
| if ((nobj = psym - symv) < 255) |
| aobj = sobj; |
| |
| else if (nobj > 1024*1024) |
| return MDSO_CUSTOM_ERROR(dctx,MDSO_ERR_INVALID_VECTOR); |
| |
| else if (!(aobj = calloc(1,++nobj*sizeof(*aobj)))) |
| return MDSO_SYSTEM_ERROR(dctx); |
| |
| |
| objlen = 8; |
| objlen += sizeof(struct pe_raw_archive_common_hdr); |
| |
| |
| ret = mdso_objgen_dsometa(dctx,aobj); |
| |
| aobj->size += 1; |
| aobj->size |= 1; |
| aobj->size ^= 1; |
| |
| objlen += aobj->size; |
| objlen += sizeof(struct pe_raw_archive_common_hdr); |
| |
| mapstrslen = aobj->mapstrslen; |
| mapstrsnum = aobj->mapstrsnum; |
| |
| |
| for (psym=symv,pobj=&aobj[1]; *psym && !ret; psym++) { |
| ret = mdso_objgen_symentry(dctx,*psym,pobj); |
| |
| pobj->size += 1; |
| pobj->size |= 1; |
| pobj->size ^= 1; |
| |
| objlen += pobj->size; |
| objlen += sizeof(struct pe_raw_archive_common_hdr); |
| |
| mapstrslen += pobj->mapstrslen; |
| mapstrsnum += pobj->mapstrsnum; |
| pobj++; |
| } |
| |
| |
| if (ret && (aobj == sobj)) |
| return MDSO_NESTED_ERROR(dctx); |
| |
| if (ret) { |
| free(aobj); |
| return MDSO_NESTED_ERROR(dctx); |
| } |
| |
| |
| mapstrslen += 1; |
| mapstrslen |= 1; |
| mapstrslen ^= 1; |
| |
| |
| objlen += sizeof(uint32_t) * (1 + mapstrsnum); |
| objlen += mapstrslen; |
| |
| objlen += 15; |
| objlen |= 15; |
| objlen ^= 15; |
| |
| |
| if (vobj->addr && (vobj->size < objlen)) |
| return MDSO_BUFFER_ERROR(dctx); |
| |
| if ((addr = vobj->addr)) { |
| (void)0; |
| |
| } else { |
| vobj->size = objlen; |
| vobj->mapstrslen = mapstrslen; |
| vobj->mapstrsnum = mapstrsnum; |
| |
| if (!vobj->name) |
| return 0; |
| |
| else if (mdso_create_archive(dctx,vobj) < 0) |
| return MDSO_NESTED_ERROR(dctx); |
| } |
| |
| ar = (unsigned char *)vobj->addr; |
| |
| |
| memcpy(ar,"!<arch>\n",8); |
| mark = &ar[8]; |
| |
| |
| arhdr = (struct pe_raw_archive_common_hdr *)mark; |
| hdrlen = sizeof(uint32_t) * (1 + mapstrsnum) + mapstrslen; |
| mdso_argen_common_hdr(arhdr,"",hdrlen); |
| mark += sizeof(*arhdr); |
| |
| |
| mdso_write_big_endian_long(mark,mapstrsnum); |
| mark += sizeof(uint32_t); |
| |
| idx = mark; |
| mark += sizeof(uint32_t) * mapstrsnum; |
| |
| mapstrs = (char *)mark; |
| mark += mapstrslen; |
| |
| |
| aobj->mapstrs = mapstrs; |
| aobj->arhdrpos = (uint32_t)(mark - ar); |
| aobj->arhdrlen = sizeof(struct pe_raw_archive_common_hdr); |
| aobj->addr = &mark[aobj->arhdrlen]; |
| |
| for (symidx=0; symidx<aobj->mapstrsnum; symidx++) { |
| mdso_write_big_endian_long(idx,aobj->arhdrpos); |
| idx += sizeof(uint32_t); |
| } |
| |
| ret = mdso_objgen_dsometa(dctx,aobj); |
| |
| mdso_argen_common_hdr( |
| (struct pe_raw_archive_common_hdr *)mark, |
| ".dsometa.o",aobj->size); |
| |
| mark += aobj->arhdrlen + aobj->size; |
| mapstrs += aobj->mapstrslen; |
| |
| |
| for (psym=symv,pobj=&aobj[1]; *psym && !ret; psym++) { |
| |
| pobj->mapstrs = mapstrs; |
| pobj->arhdrpos = (uint32_t)(mark - ar); |
| pobj->arhdrlen = sizeof(struct pe_raw_archive_common_hdr); |
| pobj->addr = &mark[pobj->arhdrlen]; |
| |
| for (symidx=0; symidx<pobj->mapstrsnum; symidx++) { |
| mdso_write_big_endian_long(idx,pobj->arhdrpos); |
| idx += sizeof(uint32_t); |
| } |
| |
| sprintf( |
| objname,"s%06zu.o", |
| psym - symv); |
| |
| ret = mdso_objgen_symentry(dctx,*psym,pobj); |
| |
| mdso_argen_common_hdr( |
| (struct pe_raw_archive_common_hdr *)mark, |
| objname,pobj->size); |
| |
| mark += pobj->arhdrlen + pobj->size; |
| mapstrs += pobj->mapstrslen; |
| pobj++; |
| } |
| |
| |
| if (aobj != sobj) |
| free(aobj); |
| |
| |
| if (!addr) |
| munmap(vobj->addr,vobj->size); |
| |
| |
| if (ret) |
| return MDSO_NESTED_ERROR(dctx); |
| |
| |
| return 0; |
| |
| } |