vita-toolchain

git clone https://git.neptards.moe/neptards/vita-toolchain.git
Log | Files | Refs | README | LICENSE

vita-elf.c (19009B)


      1 #include <stdlib.h>
      2 #include <string.h>
      3 
      4 #include <libelf.h>
      5 #include <gelf.h>
      6 /* Note:
      7  * Even though we know the Vita is a 32-bit platform and we specifically check
      8  * that we're operating on a 32-bit ELF only, we still use the GElf family of
      9  * functions.  This is because they have extra sanity checking baked in.
     10  */
     11 
     12 #ifndef MAP_ANONYMOUS
     13 #  define MAP_ANONYMOUS MAP_ANON
     14 #endif
     15 
     16 #ifndef MAP_NORESERVE
     17 #  define MAP_NORESERVE 0
     18 #endif
     19 
     20 #ifndef __MINGW32__
     21 /* This may cause trouble with Windows portability, but there are Windows alternatives
     22  * to mmap() that we can explore later.  It'll probably work under Cygwin.
     23  */
     24 #include <sys/mman.h>
     25 #else
     26 #define mmap(ptr,size,c,d,e,f) malloc(size)
     27 #define munmap(ptr, size) free(ptr)
     28 #endif
     29 
     30 #include "vita-elf.h"
     31 #include "vita-import.h"
     32 #include "elf-defs.h"
     33 #include "fail-utils.h"
     34 #include "endian-utils.h"
     35 
     36 static void free_rela_table(vita_elf_rela_table_t *rtable);
     37 
     38 static int load_stubs(Elf_Scn *scn, int *num_stubs, vita_elf_stub_t **stubs, char *name, int size)
     39 {
     40 	GElf_Shdr shdr;
     41 	Elf_Data *data;
     42 	uint32_t *stub_data;
     43 	int chunk_offset, total_bytes;
     44 	vita_elf_stub_t *curstub;
     45 	int old_num;
     46 
     47 	gelf_getshdr(scn, &shdr);
     48 
     49 	old_num = *num_stubs;
     50 	*num_stubs = old_num + shdr.sh_size / size;
     51 	*stubs = realloc(*stubs, *num_stubs * sizeof(vita_elf_stub_t));
     52 	memset(&(*stubs)[old_num], 0, sizeof(vita_elf_stub_t) * shdr.sh_size / size);
     53 
     54 	name = strrchr(name,'.')+1;
     55 
     56 	curstub = *stubs;
     57 	curstub = &curstub[*num_stubs - (shdr.sh_size / size)];
     58 
     59 	data = NULL; total_bytes = 0;
     60 	while (total_bytes < shdr.sh_size &&
     61 			(data = elf_getdata(scn, data)) != NULL) {
     62 
     63 		for (stub_data = (uint32_t *)data->d_buf, chunk_offset = 0;
     64 				chunk_offset < data->d_size;
     65 				stub_data += size/4, chunk_offset += size) {
     66 			curstub->addr = shdr.sh_addr + data->d_off + chunk_offset;
     67 			curstub->module = vita_imports_module_new(name,false,0,0,0);
     68 			curstub->module->flags = le32toh(stub_data[0]);
     69 			curstub->module_nid = le32toh(stub_data[1]);
     70 			curstub->target_nid = le32toh(stub_data[2]);
     71 			curstub++;
     72 		}
     73 
     74 		total_bytes += data->d_size;
     75 	}
     76 
     77 	return 1;
     78 }
     79 
     80 static int load_symbols(vita_elf_t *ve, Elf_Scn *scn)
     81 {
     82 	GElf_Shdr shdr;
     83 	Elf_Data *data;
     84 	GElf_Sym sym;
     85 	int total_bytes;
     86 	int data_beginsym, symndx;
     87 	vita_elf_symbol_t *cursym;
     88 
     89 	if (elf_ndxscn(scn) == ve->symtab_ndx)
     90 		return 1; /* Already loaded */
     91 
     92 	if (ve->symtab != NULL)
     93 		FAILX("ELF file appears to have multiple symbol tables!");
     94 
     95 	gelf_getshdr(scn, &shdr);
     96 
     97 	ve->num_symbols = shdr.sh_size / shdr.sh_entsize;
     98 	ve->symtab = calloc(ve->num_symbols, sizeof(vita_elf_symbol_t));
     99 	ve->symtab_ndx = elf_ndxscn(scn);
    100 
    101 	data = NULL; total_bytes = 0;
    102 	while (total_bytes < shdr.sh_size &&
    103 			(data = elf_getdata(scn, data)) != NULL) {
    104 
    105 		data_beginsym = data->d_off / shdr.sh_entsize;
    106 		for (symndx = 0; symndx < data->d_size / shdr.sh_entsize; symndx++) {
    107 			if (gelf_getsym(data, symndx, &sym) != &sym)
    108 				FAILE("gelf_getsym() failed");
    109 
    110 			cursym = ve->symtab + symndx + data_beginsym;
    111 
    112 			cursym->name = elf_strptr(ve->elf, shdr.sh_link, sym.st_name);
    113 			cursym->value = sym.st_value;
    114 			cursym->type = GELF_ST_TYPE(sym.st_info);
    115 			cursym->binding = GELF_ST_BIND(sym.st_info);
    116 			cursym->shndx = sym.st_shndx;
    117 		}
    118 
    119 		total_bytes += data->d_size;
    120 	}
    121 
    122 	return 1;
    123 failure:
    124 	return 0;
    125 }
    126 
    127 #define THUMB_SHUFFLE(x) ((((x) & 0xFFFF0000) >> 16) | (((x) & 0xFFFF) << 16))
    128 static uint32_t decode_rel_target(uint32_t data, int type, uint32_t addr)
    129 {
    130 	uint32_t upper, lower, sign, j1, j2, imm10, imm11;
    131 	switch(type) {
    132 		case R_ARM_NONE:
    133 		case R_ARM_V4BX:
    134 			return 0xdeadbeef;
    135 		case R_ARM_ABS32:
    136 		case R_ARM_TARGET1:
    137 			return data;
    138 		case R_ARM_REL32:
    139 		case R_ARM_TARGET2:
    140 			return data + addr;
    141 		case R_ARM_PREL31:
    142 			return data + addr;
    143 		case R_ARM_THM_CALL: // bl (THUMB)
    144 			data = THUMB_SHUFFLE(data);
    145 			upper = data >> 16;
    146 			lower = data & 0xFFFF;
    147 			sign = (upper >> 10) & 1;
    148 			j1 = (lower >> 13) & 1;
    149 			j2 = (lower >> 11) & 1;
    150 			imm10 = upper & 0x3ff;
    151 			imm11 = lower & 0x7ff;
    152 			return addr + (((imm11 | (imm10 << 11) | (!(j2 ^ sign) << 21) | (!(j1 ^ sign) << 22) | (sign << 23)) << 1) | (sign ? 0xff000000 : 0));
    153 		case R_ARM_CALL: // bl/blx
    154 		case R_ARM_JUMP24: // b/bl<cond>
    155 			data = (data & 0x00ffffff) << 2;
    156 			// if we got a negative value, sign extend it
    157 			if (data & (1 << 25))
    158 				data |= 0xfc000000;
    159 			return data + addr;
    160 		case R_ARM_MOVW_ABS_NC: //movw
    161 			return ((data & 0xf0000) >> 4) | (data & 0xfff);
    162 		case R_ARM_MOVT_ABS: //movt
    163 			return (((data & 0xf0000) >> 4) | (data & 0xfff)) << 16;
    164 		case R_ARM_THM_MOVW_ABS_NC: //MOVW (THUMB)
    165 			data = THUMB_SHUFFLE(data);
    166 			return (((data >> 16) & 0xf) << 12)
    167 				| (((data >> 26) & 0x1) << 11)
    168 				| (((data >> 12) & 0x7) << 8)
    169 				| (data & 0xff);
    170 		case R_ARM_THM_MOVT_ABS: //MOVT (THUMB)
    171 			data = THUMB_SHUFFLE(data);
    172 			return (((data >> 16) & 0xf) << 28)
    173 				| (((data >> 26) & 0x1) << 27)
    174 				| (((data >> 12) & 0x7) << 24)
    175 				| ((data & 0xff) << 16);
    176 	}
    177 
    178 	errx(EXIT_FAILURE, "Invalid relocation type: %d", type);
    179 }
    180 
    181 #define REL_HANDLE_NORMAL 0
    182 #define REL_HANDLE_IGNORE -1
    183 #define REL_HANDLE_INVALID -2
    184 static int get_rel_handling(int type)
    185 {
    186 	switch(type) {
    187 		case R_ARM_NONE:
    188 		case R_ARM_V4BX:
    189 			return REL_HANDLE_IGNORE;
    190 		case R_ARM_ABS32:
    191 		case R_ARM_TARGET1:
    192 		case R_ARM_REL32:
    193 		case R_ARM_TARGET2:
    194 		case R_ARM_PREL31:
    195 		case R_ARM_THM_CALL:
    196 		case R_ARM_CALL:
    197 		case R_ARM_JUMP24:
    198 		case R_ARM_MOVW_ABS_NC:
    199 		case R_ARM_MOVT_ABS:
    200 		case R_ARM_THM_MOVW_ABS_NC:
    201 		case R_ARM_THM_MOVT_ABS:
    202 			return REL_HANDLE_NORMAL;
    203 	}
    204 
    205 	return REL_HANDLE_INVALID;
    206 }
    207 
    208 static int load_rel_table(vita_elf_t *ve, Elf_Scn *scn)
    209 {
    210 	Elf_Scn *text_scn;
    211 	GElf_Shdr shdr, text_shdr;
    212 	Elf_Data *data, *text_data;
    213 	GElf_Rel rel;
    214 	int relndx;
    215 
    216 	int rel_sym;
    217 	int handling;
    218 
    219 	vita_elf_rela_table_t *rtable = NULL;
    220 	vita_elf_rela_t *currela = NULL;
    221 	uint32_t insn, target = 0;
    222 
    223 	gelf_getshdr(scn, &shdr);
    224 
    225 	if (!load_symbols(ve, elf_getscn(ve->elf, shdr.sh_link)))
    226 		goto failure;
    227 
    228 	rtable = calloc(1, sizeof(vita_elf_rela_table_t));
    229 	ASSERT(rtable != NULL);
    230 	rtable->num_relas = shdr.sh_size / shdr.sh_entsize;
    231 	rtable->relas = calloc(rtable->num_relas, sizeof(vita_elf_rela_t));
    232 	ASSERT(rtable->relas != NULL);
    233 
    234 	rtable->target_ndx = shdr.sh_info;
    235 	text_scn = elf_getscn(ve->elf, shdr.sh_info);
    236 	gelf_getshdr(text_scn, &text_shdr);
    237 	text_data = elf_getdata(text_scn, NULL);
    238 
    239 	/* We're blatantly assuming here that both of these sections will store
    240 	 * the entirety of their data in one Elf_Data item.  This seems to be true
    241 	 * so far in my testing, and from the libelf source it looks like it's
    242 	 * unlikely to allocate multiple data items on initial file read, but
    243 	 * should be fixed someday. */
    244 	data = elf_getdata(scn, NULL);
    245 	for (relndx = 0; relndx < data->d_size / shdr.sh_entsize; relndx++) {
    246 		if (gelf_getrel(data, relndx, &rel) != &rel)
    247 			FAILX("gelf_getrel() failed");
    248 
    249 		currela = rtable->relas + relndx;
    250 		currela->type = GELF_R_TYPE(rel.r_info);
    251 		/* R_ARM_THM_JUMP24 is functionally the same as R_ARM_THM_CALL, however Vita only supports the second one */
    252 		if (currela->type == R_ARM_THM_JUMP24)
    253 			currela->type = R_ARM_THM_CALL;
    254 		/* This one comes from libstdc++.
    255 		 * Should be safe to ignore because it's pc-relative and already encoded in the file. */
    256 		if (currela->type == R_ARM_THM_PC11)
    257 			continue;
    258 		currela->offset = rel.r_offset;
    259 
    260 		/* Use memcpy for unaligned relocation. */
    261 		memcpy(&insn, text_data->d_buf+(rel.r_offset - text_shdr.sh_addr), sizeof(insn));
    262 		insn = le32toh(insn);
    263 
    264 		handling = get_rel_handling(currela->type);
    265 
    266 		if (handling == REL_HANDLE_IGNORE)
    267 			continue;
    268 		else if (handling == REL_HANDLE_INVALID)
    269 			FAILX("Invalid relocation type %d!", currela->type);
    270 
    271 		rel_sym = GELF_R_SYM(rel.r_info);
    272 		if (rel_sym >= ve->num_symbols)
    273 			FAILX("REL entry tried to access symbol %d, but only %d symbols loaded", rel_sym, ve->num_symbols);
    274 
    275 		currela->symbol = ve->symtab + rel_sym;
    276 
    277 		target = decode_rel_target(insn, currela->type, rel.r_offset);
    278 
    279 		/* From some testing the added for MOVT/MOVW should actually always be 0 */
    280 		if (currela->type == R_ARM_MOVT_ABS || currela->type == R_ARM_THM_MOVT_ABS)
    281 			currela->addend = target - (currela->symbol->value & 0xFFFF0000);
    282 		else if (currela->type == R_ARM_MOVW_ABS_NC || currela->type == R_ARM_THM_MOVW_ABS_NC)
    283 			currela->addend = target - (currela->symbol->value & 0xFFFF);
    284 		/* Symbol value could be OR'ed with 1 if the function is compiled in Thumb mode,
    285 		 * however for the relocation addend we need the actual address. */
    286 		else if (currela->type == R_ARM_THM_CALL)
    287 			currela->addend = target - (currela->symbol->value & 0xFFFFFFFE);
    288 		else
    289 			currela->addend = target - currela->symbol->value;
    290 	}
    291 
    292 	rtable->next = ve->rela_tables;
    293 	ve->rela_tables = rtable;
    294 
    295 	return 1;
    296 failure:
    297 	free_rela_table(rtable);
    298 	return 0;
    299 }
    300 
    301 static int load_rela_table(vita_elf_t *ve, Elf_Scn *scn)
    302 {
    303 	warnx("RELA sections currently unsupported");
    304 	return 0;
    305 }
    306 
    307 static int lookup_stub_symbols(vita_elf_t *ve, int num_stubs, vita_elf_stub_t *stubs, varray *stubs_va, int sym_type)
    308 {
    309 	int symndx;
    310 	vita_elf_symbol_t *cursym;
    311 	int stub, stubs_ndx, i, *cur_ndx;
    312 
    313 	for (symndx = 0; symndx < ve->num_symbols; symndx++) {
    314 		cursym = ve->symtab + symndx;
    315 
    316 		if (cursym->binding != STB_GLOBAL)
    317 			continue;
    318 		if (cursym->type != STT_FUNC && cursym->type != STT_OBJECT)
    319 			continue;
    320 		stubs_ndx = -1;
    321 		
    322 		for(i=0;i<stubs_va->count;i++){
    323 			cur_ndx = VARRAY_ELEMENT(stubs_va,i);
    324 			if (cursym->shndx == *cur_ndx){
    325 				stubs_ndx = cursym->shndx;
    326 				break;
    327 			}
    328 		}
    329 		
    330 		if(stubs_ndx == -1)
    331 			continue;	
    332 			
    333 		if (cursym->type != sym_type)
    334 			FAILX("Global symbol %s in section %d expected to have type %s; instead has type %s",
    335 					cursym->name, stubs_ndx, elf_decode_st_type(sym_type), elf_decode_st_type(cursym->type));
    336 		
    337 		for (stub = 0; stub < num_stubs; stub++) {
    338 			if (stubs[stub].addr != cursym->value)
    339 				continue;
    340 			if (stubs[stub].symbol != NULL)
    341 				FAILX("Stub at %06x in section %d has duplicate symbols: %s, %s",
    342 						cursym->value, stubs_ndx, stubs[stub].symbol->name, cursym->name);
    343 			stubs[stub].symbol = cursym;
    344 			break;
    345 		}
    346 
    347 		if (stub == num_stubs)
    348 			FAILX("Global symbol %s in section %d not pointing to a valid stub",
    349 					cursym->name, cursym->shndx);
    350 	}
    351 
    352 	return 1;
    353 
    354 failure:
    355 	return 0;
    356 }
    357 
    358 static int is_valid_relsection(vita_elf_t *ve, GElf_Shdr *rel) {
    359 	Elf_Scn *info;
    360 	size_t phnum;
    361 	GElf_Shdr shdr;
    362 	GElf_Phdr phdr;
    363 
    364 	ASSERT(rel->sh_type == SHT_REL || rel->sh_type == SHT_RELA);
    365 	ELF_ASSERT(info = elf_getscn(ve->elf, rel->sh_info));
    366 	ELF_ASSERT(gelf_getshdr(info, &shdr));
    367 	ELF_ASSERT(elf_getphdrnum(ve->elf, &phnum) == 0);
    368 
    369 	if (shdr.sh_type == SHT_NOBITS) {
    370 		shdr.sh_size = 0;
    371 	}
    372 
    373 	// Here we assume that every section falls into EXACTLY one segment
    374 	// However, the ELF format allows for weird things like one section that 
    375 	// is partially in one segment and partially in another one (or even 
    376 	// multiple).
    377 	// TODO: For robustness, consider these corner cases
    378 	// Right now, we just assume if you have one of these messed up ELFs, 
    379 	// we don't support it because it's likely to break in other parts of this 
    380 	// code :)
    381 	for (int i = 0; i < phnum; i++) {
    382 		ELF_ASSERT(gelf_getphdr(ve->elf, i, &phdr));
    383 		if (phdr.p_type != PT_LOAD) {
    384 			continue;
    385 		}
    386 		// TODO: Take account of possible integer wrap-arounds
    387 		if (phdr.p_offset <= shdr.sh_offset && shdr.sh_offset + shdr.sh_size <= phdr.p_offset + phdr.p_filesz) {
    388 			return 1;
    389 		}
    390 	}
    391 
    392 failure:
    393 	return 0;
    394 }
    395 
    396 vita_elf_t *vita_elf_load(const char *filename, int check_stub_count)
    397 {
    398 	vita_elf_t *ve = NULL;
    399 	GElf_Ehdr ehdr;
    400 	Elf_Scn *scn;
    401 	GElf_Shdr shdr;
    402 	size_t shstrndx;
    403 	char *name;
    404 	const char **debug_name;
    405 
    406 	GElf_Phdr phdr;
    407 	size_t segment_count, segndx, loaded_segments;
    408 	vita_elf_segment_info_t *curseg;
    409 
    410 
    411 	if (elf_version(EV_CURRENT) == EV_NONE)
    412 		FAILX("ELF library initialization failed: %s", elf_errmsg(-1));
    413 
    414 	ve = calloc(1, sizeof(vita_elf_t));
    415 	ASSERT(ve != NULL);
    416 	
    417 	ASSERT(varray_init(&ve->fstubs_va, sizeof(int), 8));
    418 	ASSERT(varray_init(&ve->vstubs_va, sizeof(int), 4));
    419 
    420 	if ((ve->file = fopen(filename, "rb")) == NULL)
    421 		FAIL("open %s failed", filename);
    422 
    423 	ELF_ASSERT(ve->elf = elf_begin(fileno(ve->file), ELF_C_READ, NULL));
    424 
    425 	if (elf_kind(ve->elf) != ELF_K_ELF)
    426 		FAILX("%s is not an ELF file", filename);
    427 
    428 	ELF_ASSERT(gelf_getehdr(ve->elf, &ehdr));
    429 
    430 	if (ehdr.e_machine != EM_ARM)
    431 		FAILX("%s is not an ARM binary", filename);
    432 
    433 	if (ehdr.e_ident[EI_CLASS] != ELFCLASS32 || ehdr.e_ident[EI_DATA] != ELFDATA2LSB)
    434 		FAILX("%s is not a 32-bit, little-endian binary", filename);
    435 
    436 	ELF_ASSERT(elf_getshdrstrndx(ve->elf, &shstrndx) == 0);
    437 
    438 	scn = NULL;
    439 
    440 	while ((scn = elf_nextscn(ve->elf, scn)) != NULL) {
    441 		ELF_ASSERT(gelf_getshdr(scn, &shdr));
    442 
    443 		ELF_ASSERT(name = elf_strptr(ve->elf, shstrndx, shdr.sh_name));
    444 
    445 		if (shdr.sh_type == SHT_PROGBITS && strncmp(name, ".vitalink.fstubs", strlen(".vitalink.fstubs")) == 0) {
    446 			int ndxscn = elf_ndxscn(scn);
    447 			varray_push(&ve->fstubs_va,&ndxscn);
    448 			if (!load_stubs(scn, &ve->num_fstubs, &ve->fstubs, name, 16))
    449 				goto failure;
    450 		} else if (shdr.sh_type == SHT_PROGBITS && strncmp(name, ".vitalink.vstubs", strlen(".vitalink.vstubs")) == 0) {
    451 			int ndxscn = elf_ndxscn(scn);
    452 			varray_push(&ve->vstubs_va,&ndxscn);
    453 			if (!load_stubs(scn, &ve->num_vstubs, &ve->vstubs, name, 32))
    454 				goto failure;
    455 		}
    456 
    457 		if (shdr.sh_type == SHT_SYMTAB) {
    458 			if (!load_symbols(ve, scn))
    459 				goto failure;
    460 		} else if (shdr.sh_type == SHT_REL) {
    461 			if (!is_valid_relsection(ve, &shdr))
    462 				continue;
    463 			if (!load_rel_table(ve, scn))
    464 				goto failure;
    465 		} else if (shdr.sh_type == SHT_RELA) {
    466 			if (!is_valid_relsection(ve, &shdr))
    467 				continue;
    468 			if (!load_rela_table(ve, scn))
    469 				goto failure;
    470 		}
    471 	}
    472 
    473 	if (ve->fstubs_va.count == 0 && ve->vstubs_va.count == 0 && check_stub_count)
    474 		FAILX("No .vitalink stub sections in binary, probably not a Vita binary. If this is a vita binary, pass '-n' to squash this error.");
    475 
    476 	if (ve->symtab == NULL)
    477 		FAILX("No symbol table in binary, perhaps stripped out");
    478 
    479 	if (ve->rela_tables == NULL)
    480 		FAILX("No relocation sections in binary; use -Wl,-q while compiling");
    481 
    482 	if (ve->fstubs_va.count != 0) {
    483 		if (!lookup_stub_symbols(ve, ve->num_fstubs, ve->fstubs, &ve->fstubs_va, STT_FUNC)) goto failure;
    484 	}
    485 
    486 	if (ve->vstubs_va.count != 0) {
    487 		if (!lookup_stub_symbols(ve, ve->num_vstubs, ve->vstubs, &ve->vstubs_va, STT_FUNC)) goto failure;
    488 	}
    489 
    490 	ELF_ASSERT(elf_getphdrnum(ve->elf, &segment_count) == 0);
    491 
    492 	ve->segments = calloc(segment_count, sizeof(vita_elf_segment_info_t));
    493 	ASSERT(ve->segments != NULL);
    494 	loaded_segments = 0;
    495 
    496 	for (segndx = 0; segndx < segment_count; segndx++) {
    497 		ELF_ASSERT(gelf_getphdr(ve->elf, segndx, &phdr));
    498 
    499 		if (phdr.p_type != PT_LOAD) {
    500 			continue; // skip non-loadable segments
    501 		}
    502 
    503 		curseg = ve->segments + loaded_segments;
    504 		curseg->type = phdr.p_type;
    505 		curseg->vaddr = phdr.p_vaddr;
    506 		curseg->memsz = phdr.p_memsz;
    507 
    508 		if (curseg->memsz) {
    509 			curseg->vaddr_top = mmap(NULL, curseg->memsz, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
    510 			if (curseg->vaddr_top == NULL)
    511 				FAIL("Could not allocate address space for segment %d", (int)segndx);
    512 			curseg->vaddr_bottom = curseg->vaddr_top + curseg->memsz;
    513 		}
    514 		
    515 		loaded_segments++;
    516 	}
    517 	ve->num_segments = loaded_segments;
    518 
    519 	return ve;
    520 
    521 failure:
    522 	if (ve != NULL)
    523 		vita_elf_free(ve);
    524 	return NULL;
    525 }
    526 
    527 static void free_rela_table(vita_elf_rela_table_t *rtable)
    528 {
    529 	if (rtable == NULL) return;
    530 	free(rtable->relas);
    531 	free_rela_table(rtable->next);
    532 	free(rtable);
    533 }
    534 
    535 void vita_elf_free(vita_elf_t *ve)
    536 {
    537 	int i;
    538 
    539 	for (i = 0; i < ve->num_segments; i++) {
    540 		if (ve->segments[i].vaddr_top != NULL)
    541 			munmap((void *)ve->segments[i].vaddr_top, ve->segments[i].memsz);
    542 	}
    543 
    544 	/* free() is safe to call on NULL */
    545 	free(ve->fstubs);
    546 	free(ve->vstubs);
    547 	free(ve->symtab);
    548 	if (ve->elf != NULL)
    549 		elf_end(ve->elf);
    550 	if (ve->file != NULL)
    551 		fclose(ve->file);
    552 	free(ve);
    553 }
    554 
    555 typedef vita_imports_stub_t *(*find_stub_func_ptr)(vita_imports_module_t *, uint32_t);
    556 static int lookup_stubs(vita_elf_stub_t *stubs, int num_stubs, find_stub_func_ptr find_stub, const char *stub_type_name)
    557 {
    558 	int found_all = 1;
    559 	int i, j;
    560 	vita_elf_stub_t *stub;
    561 
    562 	for (i = 0; i < num_stubs; i++) {
    563 		stub = &(stubs[i]);
    564 		stub->target = vita_imports_stub_new(stub->symbol ? stub->symbol->name : "(unreferenced stub)", 0);
    565 	}
    566 
    567 	return found_all;
    568 }
    569 
    570 int vita_elf_lookup_imports(vita_elf_t *ve)
    571 {
    572 	int found_all = 1;
    573 	if (!lookup_stubs(ve->fstubs, ve->num_fstubs, &vita_imports_find_function, "function"))
    574 		found_all = 0;
    575 	if (!lookup_stubs(ve->vstubs, ve->num_vstubs, &vita_imports_find_variable, "variable"))
    576 		found_all = 0;
    577 
    578 	return found_all;
    579 }
    580 
    581 const void *vita_elf_vaddr_to_host(const vita_elf_t *ve, Elf32_Addr vaddr)
    582 {
    583 	vita_elf_segment_info_t *seg;
    584 	int i;
    585 
    586 	for (i = 0, seg = ve->segments; i < ve->num_segments; i++, seg++) {
    587 		if (vaddr >= seg->vaddr && vaddr < seg->vaddr + seg->memsz)
    588 			return seg->vaddr_top + vaddr - seg->vaddr;
    589 	}
    590 
    591 	return NULL;
    592 }
    593 const void *vita_elf_segoffset_to_host(const vita_elf_t *ve, int segndx, uint32_t offset)
    594 {
    595 	vita_elf_segment_info_t *seg = ve->segments + segndx;
    596 
    597 	if (offset < seg->memsz)
    598 		return seg->vaddr_top + offset;
    599 
    600 	return NULL;
    601 }
    602 
    603 Elf32_Addr vita_elf_host_to_vaddr(const vita_elf_t *ve, const void *host_addr)
    604 {
    605 	vita_elf_segment_info_t *seg;
    606 	int i;
    607 
    608 	if (host_addr == NULL)
    609 		return 0;
    610 
    611 	for (i = 0, seg = ve->segments; i < ve->num_segments; i++, seg++) {
    612 		if (host_addr >= seg->vaddr_top && host_addr < seg->vaddr_bottom)
    613 			return seg->vaddr + (uint32_t)(host_addr - seg->vaddr_top);
    614 	}
    615 
    616 	return 0;
    617 }
    618 
    619 int vita_elf_host_to_segndx(const vita_elf_t *ve, const void *host_addr)
    620 {
    621 	vita_elf_segment_info_t *seg;
    622 	int i;
    623 
    624 	for (i = 0, seg = ve->segments; i < ve->num_segments; i++, seg++) {
    625 		if (host_addr >= seg->vaddr_top && host_addr < seg->vaddr_bottom)
    626 			return i;
    627 	}
    628 
    629 	return -1;
    630 }
    631 
    632 int32_t vita_elf_host_to_segoffset(const vita_elf_t *ve, const void *host_addr, int segndx)
    633 {
    634 	vita_elf_segment_info_t *seg = ve->segments + segndx;
    635 
    636 	if (host_addr == NULL)
    637 		return 0;
    638 
    639 	if (host_addr >= seg->vaddr_top && host_addr < seg->vaddr_bottom)
    640 		return (uint32_t)(host_addr - seg->vaddr_top);
    641 
    642 	return -1;
    643 }
    644 
    645 int vita_elf_vaddr_to_segndx(const vita_elf_t *ve, Elf32_Addr vaddr)
    646 {
    647 	vita_elf_segment_info_t *seg;
    648 	int i;
    649 
    650 	for (i = 0, seg = ve->segments; i < ve->num_segments; i++, seg++) {
    651 		/* Segments of type EXIDX will duplicate '.ARM.extab .ARM.exidx' sections already present in the data segment
    652 		 * Since these won't be loaded, we should prefer the actual data segment */
    653 		if (seg->type == SHT_ARM_EXIDX)
    654 			continue;
    655 		if (vaddr >= seg->vaddr && vaddr < seg->vaddr + seg->memsz)
    656 			return i;
    657 	}
    658 
    659 	return -1;
    660 }
    661 
    662 /* vita_elf_vaddr_to_segoffset won't check the validity of the address, it may have been fuzzy-matched */
    663 uint32_t vita_elf_vaddr_to_segoffset(const vita_elf_t *ve, Elf32_Addr vaddr, int segndx)
    664 {
    665 	vita_elf_segment_info_t *seg = ve->segments + segndx;
    666 
    667 	if (vaddr == 0)
    668 		return 0;
    669 
    670 	return vaddr - seg->vaddr;
    671 }