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 }