int findelfsecidx(Elf *elf, const char *file, const char *tofind) { Elf_Scn *scn = NULL; GElf_Ehdr ehdr; GElf_Shdr shdr; if (gelf_getehdr(elf, &ehdr) == NULL) elfterminate(file, "Couldn't read ehdr"); while ((scn = elf_nextscn(elf, scn)) != NULL) { char *name; if (gelf_getshdr(scn, &shdr) == NULL) { elfterminate(file, "Couldn't read header for section %d", elf_ndxscn(scn)); } if ((name = elf_strptr(elf, ehdr.e_shstrndx, (size_t)shdr.sh_name)) == NULL) { elfterminate(file, "Couldn't get name for section %d", elf_ndxscn(scn)); } if (strcmp(name, tofind) == 0) return (elf_ndxscn(scn)); } return (-1); }
int ElfWriter::newSection(LIBDWARF_CALLBACK_NAME_TYPE name, uint64_t size, uint32_t type, uint64_t flags, uint64_t addr/* = 0*/) { Elf_Scn *scn = elf_newscn(m_elf); if (!scn) { logError("Unable to create new section"); return -1; } Elf64_Shdr *sectionHdr = elf64_getshdr(scn); if (!sectionHdr) { logError("Unable to create section header"); return -1; } int nameOffset = addSectionString(name); sectionHdr->sh_name = nameOffset; sectionHdr->sh_type = type; sectionHdr->sh_flags = flags; sectionHdr->sh_size = size; sectionHdr->sh_addr = addr; sectionHdr->sh_offset = 0; sectionHdr->sh_link = 0; sectionHdr->sh_info = 0; sectionHdr->sh_addralign = 1; sectionHdr->sh_entsize = 0; return elf_ndxscn(scn); }
int internal_function __libdwfl_find_build_id (Dwfl_Module *mod, bool set, Elf *elf) { size_t shstrndx = SHN_UNDEF; int result = 0; Elf_Scn *scn = elf_nextscn (elf, NULL); if (scn == NULL) { /* No sections, have to look for phdrs. */ GElf_Ehdr ehdr_mem; GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem); size_t phnum; if (unlikely (ehdr == NULL) || unlikely (elf_getphdrnum (elf, &phnum) != 0)) { __libdwfl_seterrno (DWFL_E_LIBELF); return -1; } for (size_t i = 0; result == 0 && i < phnum; ++i) { GElf_Phdr phdr_mem; GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem); if (likely (phdr != NULL) && phdr->p_type == PT_NOTE) result = check_notes (mod, set, elf_getdata_rawchunk (elf, phdr->p_offset, phdr->p_filesz, ELF_T_NHDR), phdr->p_vaddr + mod->main.bias); } } else do { GElf_Shdr shdr_mem; GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); if (likely (shdr != NULL) && shdr->sh_type == SHT_NOTE) { /* Determine the right sh_addr in this module. */ GElf_Addr vaddr = 0; if (!(shdr->sh_flags & SHF_ALLOC)) vaddr = NO_VADDR; else if (mod->e_type != ET_REL) vaddr = shdr->sh_addr + mod->main.bias; else if (__libdwfl_relocate_value (mod, elf, &shstrndx, elf_ndxscn (scn), &vaddr)) vaddr = NO_VADDR; result = check_notes (mod, set, elf_getdata (scn, NULL), vaddr); } } while (result == 0 && (scn = elf_nextscn (elf, scn)) != NULL); return result; }
//--------------------------------------------------------------------- static int convElfHdr(Melf_Scn* mscn, Elf_Scn* escn) { Elf32_Shdr *shdr; if ((shdr = elf32_getshdr(escn)) == NULL){ fprintf(stderr, "Error reading section header.\n"); return -1; } mscn->m_shdr.sh_id = (Melf_Half)elf_ndxscn(escn); mscn->m_shdr.sh_type = shdr->sh_type; mscn->m_shdr.sh_link = shdr->sh_link; mscn->m_shdr.sh_info = shdr->sh_info; return 0; }
void * drsym_obj_mod_init_pre(byte *map_base, size_t file_size) { elf_info_t *mod; Elf_Scn *symtab_scn; Elf_Scn *strtab_scn; Elf_Shdr *symtab_shdr; mod = dr_global_alloc(sizeof(*mod)); memset(mod, 0, sizeof(*mod)); mod->map_base = map_base; mod->elf = elf_memory((char *)map_base, file_size); symtab_scn = find_elf_section_by_name(mod->elf, ".symtab"); strtab_scn = find_elf_section_by_name(mod->elf, ".strtab"); if (symtab_scn != NULL) { mod->debug_kind |= DRSYM_SYMBOLS | DRSYM_ELF_SYMTAB; if (strtab_scn != NULL) { symtab_shdr = elf_getshdr(symtab_scn); mod->strtab_idx = elf_ndxscn(strtab_scn); mod->num_syms = symtab_shdr->sh_size / symtab_shdr->sh_entsize; /* This assumes that the ELF file uses the same representation conventions * as the current machine, which is reasonable considering this module is * probably loaded in the current process. */ mod->syms = (Elf_Sym*)(((char*) mod->map_base) + symtab_shdr->sh_offset); } } else { /* XXX i#672: there may still be dwarf2 or stabs sections even if the * symtable is stripped and we could do symbol lookup via dwarf2 */ } if (find_elf_section_by_name(mod->elf, ".debug_line") != NULL) { mod->debug_kind |= DRSYM_LINE_NUMS | DRSYM_DWARF_LINE; } return (void *) mod; }
const char * dwfl_module_relocation_info (Dwfl_Module *mod, unsigned int idx, Elf32_Word *shndxp) { if (mod == NULL) return NULL; switch (mod->e_type) { case ET_REL: break; case ET_DYN: if (idx != 0) return NULL; if (shndxp) *shndxp = SHN_ABS; return ""; default: return NULL; } if (unlikely (mod->reloc_info == NULL) && cache_sections (mod) < 0) return NULL; struct dwfl_relocation *sections = mod->reloc_info; if (idx >= sections->count) return NULL; if (shndxp) *shndxp = elf_ndxscn (sections->refs[idx].scn); return sections->refs[idx].name; }
/** * parse initial ELF file and collect essential section header information */ int ElfInject::collectSHInfo() { Elf_Scn *scn = NULL; GElf_Shdr shdr; GElf_Shdr tmpShdr; char *symName = NULL; info("collect section header information"); /* initialize important sections */ elf_getshdrstrndx(bin.elf, &bin.shStrtabIndex); debug("° section .shstrtab: %d", bin.shStrtabIndex); while((scn = elf_nextscn(bin.elf, scn)) != NULL) { /* get section header */ gelf_getshdr(scn, &shdr); switch(shdr.sh_type) { case SHT_SYMTAB: bin.shSymtabIndex = elf_ndxscn(scn); debug("° section .symtab: %d", bin.shSymtabIndex); break; case SHT_DYNAMIC: bin.shDynamicIndex = elf_ndxscn(scn); debug("° section .dyntab: %d", bin.shDynamicIndex); break; case SHT_STRTAB: gelf_getshdr(scn, &tmpShdr); symName = elf_strptr(bin.elf, bin.shStrtabIndex, tmpShdr.sh_name); if (!strcmp(symName, SH_NAME_DYNSTR)) { bin.shDynstrIndex = elf_ndxscn(scn); debug("° section .dynstr: %d", bin.shDynstrIndex); } else if (!strcmp(symName, SH_NAME_STRTAB)) { bin.shStrtabIndex = elf_ndxscn(scn); debug("° section .strtab: %d", bin.shStrtabIndex); } break; case SHT_DYNSYM: bin.shDynsymIndex = elf_ndxscn(scn); debug("° section .dynsym: %d", bin.shDynsymIndex); break; case SHT_PROGBITS: gelf_getshdr(scn, &tmpShdr); symName = elf_strptr(bin.elf, bin.shStrtabIndex, tmpShdr.sh_name); if (!strcmp(symName, SH_NAME_PLT)) { bin.shPltIndex = elf_ndxscn(scn); debug("° section .plt: %d", bin.shPltIndex); } else if (!strcmp(symName, SH_NAME_GOTPLT)) { bin.shGotPltIndex = elf_ndxscn(scn); bin.sizeGotPlt = tmpShdr.sh_size; debug("° section .got.plt: %d (size: %d)", bin.shGotPltIndex, bin.sizeGotPlt); } else if (!strcmp(symName, SH_NAME_GOT)) { bin.shGotIndex = elf_ndxscn(scn); bin.sizeGot = tmpShdr.sh_size; debug("° section .got: %d (size: %d)", bin.shGotIndex, bin.sizeGot); } break; case SHT_REL: gelf_getshdr(scn, &tmpShdr); symName = elf_strptr(bin.elf, bin.shStrtabIndex, tmpShdr.sh_name); if (!strcmp(symName, SH_NAME_RELPLT)) { bin.shRelPltIndex = elf_ndxscn(scn); debug("° section .rel.plt: %d", bin.shRelPltIndex); } else if (!strcmp(symName, SH_NAME_RELDYN)) { bin.shRelDynIndex = elf_ndxscn(scn); debug("° section .rel.dyn: %d", bin.shRelDynIndex); } break; default: /* do nothing */ break; } } if(!bin.shSymtabIndex) { error("cannot find section .symtab"); return -1; } return 0; }
/* * Print the symbol table according to the flags that were * set, if any. Input is an opened ELF file, the section name, * the section header, the section descriptor, and the filename. * First get the symbol table with a call to elf_getdata. * Then translate the symbol table data in memory by calling * readsyms(). This avoids duplication of function calls * and improves sorting efficiency. qsort is used when sorting * is requested. */ static void print_symtab(Elf *elf_file, unsigned int shstrndx, Elf_Scn *p_sd, GElf_Shdr *shdr, char *filename) { Elf_Data * sd; SYM *sym_data; SYM *s; GElf_Sxword count = 0; const int ndigits_arr[] = { 10, /* FMT_T_DEC */ 8, /* FMT_T_HEX */ 11, /* FMT_T_OCT */ }; int ndigits; /* * Determine # of digits to use for each numeric value. */ ndigits = ndigits_arr[fmt_flag]; if (gelf_getclass(elf_file) == ELFCLASS64) ndigits *= 2; /* * print header */ print_header(ndigits); /* * get symbol table data */ if (((sd = elf_getdata(p_sd, NULL)) == NULL) || (sd->d_size == 0)) { (void) fprintf(stderr, gettext("%s: %s: no symbol table data\n"), prog_name, filename); return; } count = shdr->sh_size / shdr->sh_entsize; /* * translate symbol table data */ sym_data = readsyms(sd, count, elf_file, shdr->sh_link, (unsigned int)elf_ndxscn(p_sd)); if (sym_data == NULL) { (void) fprintf(stderr, gettext( "%s: %s: problem reading symbol data\n"), prog_name, filename); return; } qsort((char *)sym_data, count-1, sizeof (SYM), (int (*)(const void *, const void *))compare); s = sym_data; while (count > 1) { #ifndef XPG4 if (u_flag) { /* * U_flag specified */ print_with_uflag(sym_data, filename); } else if (p_flag) #else if (p_flag) #endif print_with_pflag(ndigits, elf_file, shstrndx, sym_data, filename); else if (P_flag) print_with_Pflag(ndigits, elf_file, shstrndx, sym_data); else print_with_otherflags(ndigits, elf_file, shstrndx, sym_data, filename); sym_data++; count--; } free(s); /* allocated in readsym() */ }
dt_module_update(dtrace_hdl_t *dtp, struct kld_file_stat *k_stat) #endif { char fname[MAXPATHLEN]; struct stat64 st; int fd, err, bits; dt_module_t *dmp; const char *s; size_t shstrs; GElf_Shdr sh; Elf_Data *dp; Elf_Scn *sp; #if defined(sun) (void) snprintf(fname, sizeof (fname), "%s/%s/object", OBJFS_ROOT, name); #else GElf_Ehdr ehdr; GElf_Phdr ph; char name[MAXPATHLEN]; uintptr_t mapbase, alignmask; int i = 0; int is_elf_obj; (void) strlcpy(name, k_stat->name, sizeof(name)); (void) strlcpy(fname, k_stat->pathname, sizeof(fname)); #endif if ((fd = open(fname, O_RDONLY)) == -1 || fstat64(fd, &st) == -1 || (dmp = dt_module_create(dtp, name)) == NULL) { dt_dprintf("failed to open %s: %s\n", fname, strerror(errno)); (void) close(fd); return; } /* * Since the module can unload out from under us (and /system/object * will return ENOENT), tell libelf to cook the entire file now and * then close the underlying file descriptor immediately. If this * succeeds, we know that we can continue safely using dmp->dm_elf. */ dmp->dm_elf = elf_begin(fd, ELF_C_READ, NULL); err = elf_cntl(dmp->dm_elf, ELF_C_FDREAD); (void) close(fd); if (dmp->dm_elf == NULL || err == -1 || elf_getshdrstrndx(dmp->dm_elf, &shstrs) == -1) { dt_dprintf("failed to load %s: %s\n", fname, elf_errmsg(elf_errno())); dt_module_destroy(dtp, dmp); return; } switch (gelf_getclass(dmp->dm_elf)) { case ELFCLASS32: dmp->dm_ops = &dt_modops_32; bits = 32; break; case ELFCLASS64: dmp->dm_ops = &dt_modops_64; bits = 64; break; default: dt_dprintf("failed to load %s: unknown ELF class\n", fname); dt_module_destroy(dtp, dmp); return; } #if defined(__FreeBSD__) mapbase = (uintptr_t)k_stat->address; gelf_getehdr(dmp->dm_elf, &ehdr); is_elf_obj = (ehdr.e_type == ET_REL); if (is_elf_obj) { dmp->dm_sec_offsets = malloc(ehdr.e_shnum * sizeof(*dmp->dm_sec_offsets)); if (dmp->dm_sec_offsets == NULL) { dt_dprintf("failed to allocate memory\n"); dt_module_destroy(dtp, dmp); return; } } #endif /* * Iterate over the section headers locating various sections of * interest and use their attributes to flesh out the dt_module_t. */ for (sp = NULL; (sp = elf_nextscn(dmp->dm_elf, sp)) != NULL; ) { if (gelf_getshdr(sp, &sh) == NULL || sh.sh_type == SHT_NULL || (s = elf_strptr(dmp->dm_elf, shstrs, sh.sh_name)) == NULL) continue; /* skip any malformed sections */ #if defined(__FreeBSD__) if (sh.sh_size == 0) continue; if (sh.sh_type == SHT_PROGBITS || sh.sh_type == SHT_NOBITS) { alignmask = sh.sh_addralign - 1; mapbase += alignmask; mapbase &= ~alignmask; sh.sh_addr = mapbase; if (is_elf_obj) dmp->dm_sec_offsets[elf_ndxscn(sp)] = sh.sh_addr; mapbase += sh.sh_size; } #endif if (strcmp(s, ".text") == 0) { dmp->dm_text_size = sh.sh_size; dmp->dm_text_va = sh.sh_addr; } else if (strcmp(s, ".data") == 0) { dmp->dm_data_size = sh.sh_size; dmp->dm_data_va = sh.sh_addr; } else if (strcmp(s, ".bss") == 0) { dmp->dm_bss_size = sh.sh_size; dmp->dm_bss_va = sh.sh_addr; } else if (strcmp(s, ".info") == 0 && (dp = elf_getdata(sp, NULL)) != NULL) { bcopy(dp->d_buf, &dmp->dm_info, MIN(sh.sh_size, sizeof (dmp->dm_info))); } else if (strcmp(s, ".filename") == 0 && (dp = elf_getdata(sp, NULL)) != NULL) { (void) strlcpy(dmp->dm_file, dp->d_buf, sizeof (dmp->dm_file)); } } dmp->dm_flags |= DT_DM_KERNEL; #if defined(sun) dmp->dm_modid = (int)OBJFS_MODID(st.st_ino); #else /* * Include .rodata and special sections into .text. * This depends on default section layout produced by GNU ld * for ELF objects and libraries: * [Text][R/O data][R/W data][Dynamic][BSS][Non loadable] */ dmp->dm_text_size = dmp->dm_data_va - dmp->dm_text_va; #if defined(__i386__) /* * Find the first load section and figure out the relocation * offset for the symbols. The kernel module will not need * relocation, but the kernel linker modules will. */ for (i = 0; gelf_getphdr(dmp->dm_elf, i, &ph) != NULL; i++) { if (ph.p_type == PT_LOAD) { dmp->dm_reloc_offset = k_stat->address - ph.p_vaddr; break; } } #endif #endif if (dmp->dm_info.objfs_info_primary) dmp->dm_flags |= DT_DM_PRIMARY; dt_dprintf("opened %d-bit module %s (%s) [%d]\n", bits, dmp->dm_name, dmp->dm_file, dmp->dm_modid); }
// Extract the strings associated with the provided `DynamicTag` // from the DYNAMIC section of the ELF binary. Try<std::vector<std::string>> GetDynamicStrings(DynamicTag tag) const { if (sections.count(SectionType::DYNAMIC) == 0) { return Error("No DYNAMIC sections found in ELF"); } if (sections.count(SectionType::DYNAMIC) != 1) { return Error("Multiple DYNAMIC sections found in ELF"); } Elf_Scn* dynamic_section = sections.at(SectionType::DYNAMIC)[0]; // Walk through the entries in the dynamic section and look for // entries with the provided tag. These entries contain offsets to // strings in the dynamic section's string table. Consequently, we // also have to look for an entry containing a pointer to the // dynamic section's string table so we can resolve the strings // associated with the provided tag later on. Elf_Data* dynamic_data = elf_getdata(dynamic_section, NULL); if (dynamic_data == NULL) { return Error("elf_getdata() failed: " + stringify(elf_errmsg(-1))); } Option<uintptr_t> strtab_pointer = None(); std::vector<uintptr_t> strtab_offsets; for (size_t i = 0; i < dynamic_data->d_size / sizeof(GElf_Dyn); i++) { GElf_Dyn entry; if (gelf_getdyn(dynamic_data, i, &entry) == NULL) { return Error("gelf_getdyn() failed: " + stringify(elf_errmsg(-1))); } if ((DynamicTag)entry.d_tag == DynamicTag::STRTAB) { strtab_pointer = entry.d_un.d_ptr; } if ((DynamicTag)entry.d_tag == tag) { strtab_offsets.push_back(entry.d_un.d_ptr); } } if (strtab_offsets.empty()) { return std::vector<std::string>(); } if (strtab_pointer.isNone()) { return Error("Failed to find string table"); } // Get a reference to the actual string table so we can index into it. Elf_Scn* string_table_section = gelf_offscn(elf, strtab_pointer.get()); if (string_table_section == NULL) { return Error("gelf_offscn() failed: " + stringify(elf_errmsg(-1))); } size_t strtab_index = elf_ndxscn(string_table_section); if (strtab_index == SHN_UNDEF) { return Error("elf_ndxscn() failed: " + stringify(elf_errmsg(-1))); } // Find the strings in the string table from their offsets and return them. std::vector<std::string> strings; foreach (uintptr_t offset, strtab_offsets) { char* string = elf_strptr(elf, strtab_index, offset); if (string == NULL) { return Error("elf_strptr() failed: " + stringify(elf_errmsg(-1))); } strings.push_back(string); }
int main (int argc, char *argv[]) { int result = 0; int cnt; elf_version (EV_CURRENT); for (cnt = 1; cnt < argc; ++cnt) { int fd = open (argv[cnt], O_RDONLY); Elf *elf = elf_begin (fd, ELF_C_READ, NULL); if (elf == NULL) { printf ("%s not usable %s\n", argv[cnt], elf_errmsg (-1)); result = 1; close (fd); continue; } size_t shdrstrndx; if (elf_getshdrstrndx (elf, &shdrstrndx) == -1) { printf ("elf_getshdrstrnd failed %s\n", elf_errmsg (-1)); result = 1; close (fd); continue; } Elf_Scn *scn = NULL; while ((scn = elf_nextscn (elf, scn)) != NULL) { int idx = elf_ndxscn (scn); GElf_Shdr shdr; if (gelf_getshdr (scn, &shdr) == NULL) { printf ("gelf_getshdr failed: %s\n", elf_errmsg (-1)); result = 1; break; } if ((shdr.sh_flags & SHF_COMPRESSED) != 0) { GElf_Chdr chdr; if (gelf_getchdr (scn, &chdr) == NULL) { printf ("gelf_getchdr failed: %s\n", elf_errmsg (-1)); result = 1; break; } printf ("section %d: ELF Compressed ch_type: %" PRId32 ", ch_size: %" PRIx64 ", ch_addralign: %" PRIx64 "\n", idx, chdr.ch_type, chdr.ch_size, chdr.ch_addralign); } else { const char *sname = elf_strptr (elf, shdrstrndx, shdr.sh_name); if (sname == NULL) { printf ("couldn't get section name: %s\n", elf_errmsg (-1)); result = 1; break; } /* This duplicates what the dwelfgnucompressed testcase does. */ if (strncmp(".zdebug", sname, strlen (".zdebug")) == 0) { ssize_t size; if ((size = dwelf_scn_gnu_compressed_size (scn)) == -1) { printf ("dwelf_scn_gnu_compressed_size failed: %s\n", elf_errmsg (-1)); result = 1; break; } printf ("section %d: GNU Compressed size: %zx\n", idx, size); } else printf ("section %d: NOT Compressed\n", idx); } } elf_end (elf); close (fd); } return result; }
//-------------------------------------------------------------------------------- static int convElfToMiniFile(char* elffilename, char* melffilename) { int fdelf, fdmelf, modhdrsymndx; Elf* elf; Elf32_Ehdr *ehdr; Elf_Scn *relatextscn, *textscn, *symtabscn, *strtabscn; Melf_Scn *m_relatextscn, *m_textscn, *m_symtabscn; Melf* melf; symbol_map_t* symmap; Melf_Data *relatextdata, *symtabdata, *textdata; symbol_map_t symmap_storage; printf("ELF File: %s\n", elffilename); printf("Mini-ELF File: %s\n", melffilename); symmap = &symmap_storage; // Open ELF file for reading if ((fdelf = open(elffilename, O_RDONLY)) < 0){ fprintf(stderr, "%s: ", elffilename); perror("convElfToMini -> fopen: "); exit(EXIT_FAILURE); } // Open Mini-ELF file for writing if ((fdmelf = open(melffilename, (O_RDWR | O_CREAT | O_EXCL), (S_IRWXU | S_IRWXG | S_IRWXO))) < 0){ fprintf(stderr, "%s: ", melffilename); perror("convElfToMini -> fopen: "); exit(EXIT_FAILURE); } // Check version of ELF Library if (elf_version(EV_CURRENT) == EV_NONE){ fprintf(stderr, "Library version is out of date.\n"); exit(EXIT_FAILURE); } // Get the ELF descriptor elf = elf_begin(fdelf, ELF_C_READ, NULL); if (NULL == elf){ fprintf(stderr, "elf_begin: Error getting elf descriptor\n"); exit(EXIT_FAILURE); } // Ensure that it is an ELF format file if (elf_kind(elf) != ELF_K_ELF){ fprintf(stderr, "This program can only read ELF format files.\n"); exit(EXIT_FAILURE); } // Get the ELF Header ehdr = elf32_getehdr(elf); if (NULL == ehdr){ fprintf(stderr, "Error reading ELF header\n"); exit(EXIT_FAILURE); } // Verify if the ELF is AVR specific if (ehdr->e_machine != EM_AVR && ehdr->e_machine != EM_MSP430){ fprintf(stderr, "This ELF binary is not supported.\n"); exit(EXIT_FAILURE); } e_machine = ehdr->e_machine; // Create a new Mini-ELF (MELF) descriptor if ((melf = melf_new(fdmelf)) == NULL){ fprintf(stderr, "Error creating a new MELF descriptor\n"); exit(EXIT_FAILURE); } // Get the pointer to .symtab section if ((symtabscn = getELFSectionByName(elf, ".symtab")) == NULL){ fprintf(stderr, "Error getting .symtab section.\n"); exit(EXIT_FAILURE); } // Get the pointer to .rela.text section /* if ((relatextscn = getELFSectionByName(elf, ".rela.text")) == NULL){ fprintf(stderr, "Error getting .rela.text section.\n"); exit(EXIT_FAILURE); } */ relatextscn = getELFSectionByName(elf, ".rela.text"); // Get the pointer to .text section if ((textscn = getELFSectionByName(elf, ".text")) == NULL){ fprintf(stderr, "Error getting .text section.\n"); exit(EXIT_FAILURE); } if ((strtabscn = getELFSectionByName(elf, ".strtab")) == NULL ) { fprintf(stderr, "Error getting .strtab section. \n"); exit(EXIT_FAILURE); } // DEBUG info. to verify we have the correct sections DEBUG("Section Number (.text): %d\n", (int)elf_ndxscn(textscn)); if( relatextscn != NULL ) { DEBUG("Section Number (.rela.text): %d\n", (int)elf_ndxscn(relatextscn)); } DEBUG("Section Number (.symtab): %d\n", (int)elf_ndxscn(symtabscn)); // Initialize Symbol Map if (initSymbolMap(symmap, symtabscn) < 0){ fprintf(stderr, "Error initializing symbol map.\n"); exit(EXIT_FAILURE); } // // Set string table to symbol map // addStrTabToSymbolMap( symmap, strtabscn ); addTxtScnToSymbolMap( symmap, textscn ); // Convert Relocation Table // Simon: convert relocation before text section // because some symbols will be patched in .text section if( relatextscn != NULL ) { if ((relatextdata = convRelaScn(relatextscn, symmap)) == NULL){ fprintf(stderr, "Error converting Rela table.\n"); exit(EXIT_FAILURE); } } // Convert Text Section if ((textdata = convProgbitsScn(textscn)) == NULL){ fprintf(stderr, "Error converting text section.\n"); exit(EXIT_FAILURE); } // Add mod_header symbol if ((modhdrsymndx = getELFSymbolTableNdx(elf, "mod_header")) == -1){ fprintf(stderr, "Could not locate symbol: mod_header. Not a valid SOS module\n"); exit(EXIT_FAILURE); } addMelfSymbol(symmap, modhdrsymndx); melf_setModHdrSymNdx(melf, symmap->etommap[modhdrsymndx]); // Convert Symbol Table if ((symtabdata = convSymScn(symmap)) == NULL){ fprintf(stderr, "Error convering symbol table.\n"); exit(EXIT_FAILURE); } // Create a new MELF Symbol table section if ((m_symtabscn = melf_new_scn(melf)) == NULL){ fprintf(stderr, "Error creating symbol table MELF section.\n"); exit(EXIT_FAILURE); } convElfHdr(m_symtabscn, symtabscn); melf_add_data_to_scn(m_symtabscn, symtabdata); // Create a new MELF Relocation table section if( relatextscn != NULL ) { if ((m_relatextscn = melf_new_scn(melf)) == NULL){ fprintf(stderr, "Error creating relocation table MELF section.\n"); exit(EXIT_FAILURE); } convElfHdr(m_relatextscn, relatextscn); melf_add_data_to_scn(m_relatextscn, relatextdata); } // Create a new MELF Symbol table section if ((m_textscn = melf_new_scn(melf)) == NULL){ fprintf(stderr, "Error creating .text MELF section.\n"); exit(EXIT_FAILURE); } convElfHdr(m_textscn, textscn); melf_add_data_to_scn(m_textscn, textdata); // Sort the MELF Sections (Enable single pass writing on the nodes) melf_sortScn(melf); // Set the section offsets melf_setScnOffsets(melf); // Write the MELF File melf_write(melf); #ifdef DBGMODE prettyPrintMELF(melf); #endif // Close ELF Descriptor elf_end(elf); // Close ELF File close(fdelf); // Close MELF File close(fdmelf); return 0; }
int _dwarf_elf_init(Dwarf_Debug dbg, Elf *elf, Dwarf_Error *error) { Dwarf_Obj_Access_Interface *iface; Dwarf_Elf_Object *e; const char *name; GElf_Shdr sh; Elf_Scn *scn; Elf_Data *symtab_data; size_t symtab_ndx; int elferr, i, j, n, ret; ret = DW_DLE_NONE; if ((iface = calloc(1, sizeof(*iface))) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); return (DW_DLE_MEMORY); } if ((e = calloc(1, sizeof(*e))) == NULL) { free(iface); DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); return (DW_DLE_MEMORY); } e->eo_elf = elf; e->eo_methods.get_section_info = _dwarf_elf_get_section_info; e->eo_methods.get_byte_order = _dwarf_elf_get_byte_order; e->eo_methods.get_length_size = _dwarf_elf_get_length_size; e->eo_methods.get_pointer_size = _dwarf_elf_get_pointer_size; e->eo_methods.get_section_count = _dwarf_elf_get_section_count; e->eo_methods.load_section = _dwarf_elf_load_section; iface->object = e; iface->methods = &e->eo_methods; dbg->dbg_iface = iface; if (gelf_getehdr(elf, &e->eo_ehdr) == NULL) { DWARF_SET_ELF_ERROR(dbg, error); ret = DW_DLE_ELF; goto fail_cleanup; } dbg->dbg_machine = e->eo_ehdr.e_machine; if (!elf_getshstrndx(elf, &e->eo_strndx)) { DWARF_SET_ELF_ERROR(dbg, error); ret = DW_DLE_ELF; goto fail_cleanup; } n = 0; symtab_ndx = 0; symtab_data = NULL; scn = NULL; (void) elf_errno(); while ((scn = elf_nextscn(elf, scn)) != NULL) { if (gelf_getshdr(scn, &sh) == NULL) { DWARF_SET_ELF_ERROR(dbg, error); ret = DW_DLE_ELF; goto fail_cleanup; } if ((name = elf_strptr(elf, e->eo_strndx, sh.sh_name)) == NULL) { DWARF_SET_ELF_ERROR(dbg, error); ret = DW_DLE_ELF; goto fail_cleanup; } if (!strcmp(name, ".symtab")) { symtab_ndx = elf_ndxscn(scn); if ((symtab_data = elf_getdata(scn, NULL)) == NULL) { elferr = elf_errno(); if (elferr != 0) { _DWARF_SET_ERROR(NULL, error, DW_DLE_ELF, elferr); ret = DW_DLE_ELF; goto fail_cleanup; } } continue; } for (i = 0; debug_name[i] != NULL; i++) { if (!strcmp(name, debug_name[i])) n++; } } elferr = elf_errno(); if (elferr != 0) { DWARF_SET_ELF_ERROR(dbg, error); return (DW_DLE_ELF); } e->eo_seccnt = n; if (n == 0) return (DW_DLE_NONE); if ((e->eo_data = calloc(n, sizeof(Dwarf_Elf_Data))) == NULL || (e->eo_shdr = calloc(n, sizeof(GElf_Shdr))) == NULL) { DWARF_SET_ERROR(NULL, error, DW_DLE_MEMORY); ret = DW_DLE_MEMORY; goto fail_cleanup; } scn = NULL; j = 0; while ((scn = elf_nextscn(elf, scn)) != NULL && j < n) { if (gelf_getshdr(scn, &sh) == NULL) { DWARF_SET_ELF_ERROR(dbg, error); ret = DW_DLE_ELF; goto fail_cleanup; } memcpy(&e->eo_shdr[j], &sh, sizeof(sh)); if ((name = elf_strptr(elf, e->eo_strndx, sh.sh_name)) == NULL) { DWARF_SET_ELF_ERROR(dbg, error); ret = DW_DLE_ELF; goto fail_cleanup; } for (i = 0; debug_name[i] != NULL; i++) { if (strcmp(name, debug_name[i])) continue; (void) elf_errno(); if ((e->eo_data[j].ed_data = elf_getdata(scn, NULL)) == NULL) { elferr = elf_errno(); if (elferr != 0) { _DWARF_SET_ERROR(dbg, error, DW_DLE_ELF, elferr); ret = DW_DLE_ELF; goto fail_cleanup; } } if (_libdwarf.applyrela) { if (_dwarf_elf_relocate(dbg, elf, &e->eo_data[j], elf_ndxscn(scn), symtab_ndx, symtab_data, error) != DW_DLE_NONE) goto fail_cleanup; } j++; } } assert(j == n); return (DW_DLE_NONE); fail_cleanup: _dwarf_elf_deinit(dbg); return (ret); }
static void print_symtab(Elf *elf, const char *file) { Elf_Scn *scn = NULL; GElf_Shdr shdr; GElf_Ehdr ehdr; size_t shstrndx; if (gelf_getehdr(elf, &ehdr) == NULL) { (void) fprintf(stderr, "%s: elf_getehdr() failed: %s\n", file, elf_errmsg(0)); return; } if (elf_getshdrstrndx(elf, &shstrndx) == -1) { (void) fprintf(stderr, "%s: elf_getshdrstrndx() failed: %s\n", file, elf_errmsg(0)); return; } while ((scn = elf_nextscn(elf, scn)) != NULL) { uint_t symcnt, ndx, nosymshndx; Elf_Data *symdata, *shndxdata; if (gelf_getshdr(scn, &shdr) == NULL) { (void) fprintf(stderr, "%s: elf_getshdr() failed: %s\n", file, elf_errmsg(0)); return; } if ((shdr.sh_type != SHT_SYMTAB) && (shdr.sh_type != SHT_DYNSYM) && (shdr.sh_type != SHT_SUNW_LDYNSYM)) continue; /* * Get the data associated with the Symbol * section. */ if ((symdata = elf_getdata(scn, NULL)) == NULL) { (void) fprintf(stderr, "%s: elf_getdata() failed: %s\n", file, elf_errmsg(0)); return; } /* * Print symbol table title and header for symbol display */ (void) printf("\nSymTab: %s:%s\n", file, elf_strptr(elf, shstrndx, shdr.sh_name)); (void) printf(" index value size type " "bind oth shndx name\n"); /* * We now iterate over the full symbol table printing * the symbols as we go. */ shndxdata = 0; nosymshndx = 0; symcnt = shdr.sh_size / shdr.sh_entsize; for (ndx = 0; ndx < symcnt; ndx++) { GElf_Sym sym; Elf32_Word shndx; uint_t type, bind, specshndx; char bindbuf[INTSTRLEN]; char typebuf[INTSTRLEN]; char shndxbuf[INTSTRLEN]; const char *bindstr, *typestr, *shndxstr; /* * Get a symbol entry */ if (gelf_getsymshndx(symdata, shndxdata, ndx, &sym, &shndx) == NULL) { (void) fprintf(stderr, "%s: gelf_getsymshndx() failed: %s\n", file, elf_errmsg(0)); return; } /* * Check to see if this symbol's st_shndx is using * the 'Extended SHNDX table' for a SYMTAB. * * If it is - and we haven't searched before, go * find the associated SHT_SYMTAB_SHNDX section. */ if ((sym.st_shndx == SHN_XINDEX) && (shndxdata == 0) && (nosymshndx == 0)) { Elf_Scn *_scn = NULL; GElf_Shdr _shdr; GElf_Word symscnndx; specshndx = 0; symscnndx = elf_ndxscn(scn); while ((_scn = elf_nextscn(elf, _scn)) != NULL) { if (gelf_getshdr(_scn, &_shdr) == NULL) break; /* * We've found the Symtab SHNDX table * if it's of type SHT_SYMTAB_SHNDX * and it's shdr.sh_link points to the * section index for the current symbol * table. */ if ((_shdr.sh_type == SHT_SYMTAB_SHNDX) && (_shdr.sh_link == symscnndx) && ((shndxdata = elf_getdata(_scn, NULL)) != NULL)) break; } /* * Get a symbol entry */ if (shndxdata && (gelf_getsymshndx(symdata, shndxdata, ndx, &sym, &shndx) == NULL)) { (void) fprintf(stderr, "%s: gelf_getsymshndx() " "failed: %s\n", file, elf_errmsg(0)); return; } /* * No Symtab SHNDX table was found. We could * give a fatal error here - instead we'll * just mark that fact and display as much of * the symbol table as we can. Any symbol * displayed with a XINDX section index has * a bogus value. */ if (shndxdata == 0) nosymshndx = 1; } /* * Decode the type & binding information */ type = GELF_ST_TYPE(sym.st_info); bind = GELF_ST_BIND(sym.st_info); if (type < STT_NUM) typestr = symtype[type]; else { (void) snprintf(typebuf, INTSTRLEN, "%d", type); typestr = typebuf; } if (bind < STB_NUM) bindstr = symbind[bind]; else { (void) snprintf(bindbuf, INTSTRLEN, "%d", bind); bindstr = bindbuf; } specshndx = 0; if (sym.st_shndx < SHN_LORESERVE) shndx = sym.st_shndx; else if ((sym.st_shndx != SHN_XINDEX) || (shndxdata == NULL)) { shndx = sym.st_shndx; specshndx = 1; } if (shndx == SHN_UNDEF) { shndxstr = (const char *)"UNDEF"; } else if (specshndx) { if (shndx == SHN_ABS) shndxstr = (const char *)"ABS"; else if (shndx == SHN_COMMON) shndxstr = (const char *)"COMM"; else if (shndx == SHN_XINDEX) shndxstr = (const char *)"XIND"; else { (void) snprintf(shndxbuf, INTSTRLEN, "%ld", shndx); shndxstr = shndxbuf; } } else { (void) snprintf(shndxbuf, INTSTRLEN, "%ld", shndx); shndxstr = shndxbuf; } /* * Display the symbol entry. */ (void) printf("[%3d] 0x%08llx 0x%08llx %-4s " "%-6s %2d %5s %s\n", ndx, sym.st_value, sym.st_size, typestr, bindstr, sym.st_other, shndxstr, elf_strptr(elf, shdr.sh_link, sym.st_name)); } } }
Elf_Scn *symtab_write_elf(Elf *e, struct sect * sects, struct buffer *strtab_buf, struct buffer *shstrtab_buf) { unsigned i, k; struct sym_info *sym; Elf32_Sym esym; Elf_Scn *scn, *relscn, *tmpscn; Elf_Data *data, *reldata; Elf32_Shdr *shdr, *relshdr; struct buffer buf; struct buffer *relbuf; struct sect *s; buffer_init(&buf); esym.st_name = 0; esym.st_value = 0; esym.st_size = 0; esym.st_info = 0; esym.st_other = 0; esym.st_shndx = 0; buffer_writemem(&buf, &esym, sizeof(esym)); relbuf = malloc(0); for (s = sects, k = 0; s != NULL; s = s->next, k++) { relbuf = realloc(relbuf, (k+1)*sizeof(struct buffer)); buffer_init(&relbuf[k]); } for (i = 0; i < SYMTAB_SIZE; i++) { for (sym = symtab[i]; sym != NULL; sym = sym->next) { if (sym->symbol[0] != '.' || sym->relocs != NULL) { struct reloc_info size; int type = STT_NOTYPE; int bind = STB_LOCAL; if (!sym->defined || sym->bind == SYM_BIND_GLOBAL) { bind = STB_GLOBAL; } esym.st_name = strtab_buf->pos; buffer_writestr(strtab_buf, sym->symbol); esym.st_value = sym->addr; size = expr_evaluate(sym->size); if (size.symbol != NULL) { eprintf("Cannot relocate symbol size"); exit(EXIT_FAILURE); } esym.st_size = size.intval; if (strcmp(sym->type, "@function") == 0) type = STT_FUNC; if (strcmp(sym->type, "@object") == 0) type = STT_OBJECT; esym.st_info = ELF32_ST_INFO(bind, type); esym.st_other = ELF32_ST_VISIBILITY(STV_DEFAULT); tmpscn = section_find(e, sym->section, shstrtab_buf); if (tmpscn == NULL && sym->section != NULL) tmpscn = section_find(e, pile_name(pile_match(sym->section)), shstrtab_buf); esym.st_shndx = tmpscn != NULL ? elf_ndxscn(tmpscn) : 0; if (sym->relocs != NULL) { struct sym_reloc_info *r; for (r = sym->relocs; r != NULL; r = r->next) { Elf32_Rela rel; rel.r_offset = r->addr; rel.r_info = ELF32_R_INFO(buf.pos/sizeof(esym), r->type); rel.r_addend = r->addend; for (s = sects, k = 0; s != NULL; s = s->next, k++) { if (strcmp(s->name, r->sect) == 0) { buffer_writemem(&relbuf[k], &rel, sizeof(rel)); } } } } buffer_writemem(&buf, &esym, sizeof(esym)); } } } scn = xelf_newscn(e); shdr = xelf32_getshdr(scn); shdr->sh_name = shstrtab_buf->pos; buffer_writestr(shstrtab_buf, ".symtab"); shdr->sh_type = SHT_SYMTAB; shdr->sh_flags = 0; data = xelf_newdata(scn); data->d_align = 4; data->d_off = 0; data->d_type = ELF_T_SYM; data->d_version = EV_CURRENT; data->d_buf = buf.data; data->d_size = buf.pos; for (s = sects, k = 0; s != NULL; s = s->next, k++) { if (relbuf[k].pos > 0) { char *relname; relscn = xelf_newscn(e); relshdr = xelf32_getshdr(relscn); relshdr->sh_name = shstrtab_buf->pos; relname = malloc(strlen(s->name)+6); strcpy(relname, ".rela"); strcat(relname, s->name); buffer_writestr(shstrtab_buf, relname); relshdr->sh_type = SHT_RELA; shdr->sh_flags = 0; reldata = xelf_newdata(relscn); reldata->d_align = 4; reldata->d_off = 0; reldata->d_type = ELF_T_RELA; reldata->d_version = EV_CURRENT; reldata->d_buf = relbuf[k].data; reldata->d_size = relbuf[k].pos; relshdr->sh_link = elf_ndxscn(scn); tmpscn = section_find(e, s->name, shstrtab_buf); relshdr->sh_info = tmpscn != NULL ? elf_ndxscn(tmpscn) : 0; } } return scn; }
int main() { Dwarf_Error error = 0; Dwarf_P_Debug dw = dwarf_producer_init_c(DW_DLC_WRITE | DW_DLC_SIZE_64, createSectionCallback, /* error handler */0, /* error arg */0, /* user data */0, &error); if (error != 0) die("dwarf_producer_init_c failed"); Dwarf_Unsigned cie = dwarf_add_frame_cie(dw, "", /* code alignment factor */QT_POINTER_SIZE, /* data alignment factor */-QT_POINTER_SIZE, /* return address reg*/InstructionPointerRegister, cie_init_instructions, sizeof(cie_init_instructions), &error); if (error != 0) die("dwarf_add_frame_cie failed"); Dwarf_P_Fde fde = dwarf_new_fde(dw, &error); if (error != 0) die("dwarf_new_fde failed"); /* New entry in state machine for code offset 1 after push rbp instruction */ dwarf_add_fde_inst(fde, DW_CFA_advance_loc, /*offset in code alignment units*/ 1, /* unused*/ 0, &error); /* After "push rbp" the offset to the CFA is now 2 instead of 1 */ dwarf_add_fde_inst(fde, DW_CFA_def_cfa_offset_sf, /*offset in code alignment units*/ -2, /* unused*/ 0, &error); /* After "push rbp" the value of rbp is now stored at offset 1 from CFA */ dwarf_add_fde_inst(fde, DW_CFA_offset, StackFrameRegister, 2, &error); /* New entry in state machine for code offset 3 for mov rbp, rsp instruction */ dwarf_add_fde_inst(fde, DW_CFA_advance_loc, /*offset in code alignment units*/ 3, /* unused */ 0, &error); /* After "mov rbp, rsp" the cfa is reachable via rbp */ dwarf_add_fde_inst(fde, DW_CFA_def_cfa_register, StackFrameRegister, /* unused */0, &error); /* Callee saved registers */ for (int i = 0; i < calleeSavedRegisterCount; ++i) { dwarf_add_fde_inst(fde, DW_CFA_offset, calleeSavedRegisters[i], i + 3, &error); } dwarf_add_frame_fde(dw, fde, /* die */0, cie, /*virt addr */0, /* length of code */0, /* symbol index */0, &error); if (error != 0) die("dwarf_add_frame_fde failed"); dwarf_transform_to_disk_form(dw, &error); if (error != 0) die("dwarf_transform_to_disk_form failed"); Dwarf_Unsigned len = 0; Dwarf_Signed elfIdx = 0; unsigned char *bytes = (unsigned char *)dwarf_get_section_bytes(dw, /* section */1, &elfIdx, &len, &error); if (error != 0) die("dwarf_get_section_bytes failed"); // libdwarf doesn't add a terminating FDE with zero length, so let's add one // ourselves. unsigned char *newBytes = (unsigned char *)alloca(len + 4); memcpy(newBytes, bytes, len); newBytes[len] = 0; newBytes[len + 1] = 0; newBytes[len + 2] = 0; newBytes[len + 3] = 0; newBytes[len + 4] = 0; bytes = newBytes; len += 4; // Reset CIE-ID back to 0 as expected for .eh_frames bytes[4] = 0; bytes[5] = 0; bytes[6] = 0; bytes[7] = 0; unsigned fde_offset = bytes[0] + 4; bytes[fde_offset + 4] = fde_offset + 4; printf("static const unsigned char cie_fde_data[] = {\n"); int i = 0; while (i < len) { printf(" "); for (int j = 0; i < len && j < 8; ++j, ++i) printf("0x%x, ", bytes[i]); printf("\n"); } printf("};\n"); printf("static const int fde_offset = %d;\n", fde_offset); printf("static const int initial_location_offset = %d;\n", fde_offset + 8); printf("static const int address_range_offset = %d;\n", fde_offset + 8 + QT_POINTER_SIZE); #ifdef DEBUG { if (elf_version(EV_CURRENT) == EV_NONE) die("wrong elf version"); int fd = open("debug.o", O_WRONLY | O_CREAT, 0777); if (fd < 0) die("cannot create debug.o"); Elf *e = elf_begin(fd, ELF_C_WRITE, 0); if (!e) die("elf_begin failed"); Elf_Ehdr *ehdr = elf_newehdr(e); if (!ehdr) die(elf_errmsg(-1)); ehdr->e_ident[EI_DATA] = ELFDATA2LSB; #if defined(Q_PROCESSOR_X86_64) ehdr->e_machine = EM_X86_64; #elif defined(Q_PROCESSOR_X86) ehdr->e_machine = EM_386; #else #error port me :) #endif ehdr->e_type = ET_EXEC; ehdr->e_version = EV_CURRENT; Elf_Scn *section = elf_newscn(e); if (!section) die("elf_newscn failed"); Elf_Data *data = elf_newdata(section); if (!data) die(elf_errmsg(-1)); data->d_align = 4; data->d_off = 0; data->d_buf = bytes; data->d_size = len; data->d_type = ELF_T_BYTE; data->d_version = EV_CURRENT; Elf_Shdr *shdr = elf_getshdr(section); if (!shdr) die(elf_errmsg(-1)); shdr->sh_name = 1; shdr->sh_type = SHT_PROGBITS; shdr->sh_entsize = 0; char stringTable[] = { 0, '.', 'e', 'h', '_', 'f', 'r', 'a', 'm', 'e', 0, '.', 's', 'h', 's', 't', 'r', 't', 'a', 'b', 0 }; section = elf_newscn(e); if (!section) die("elf_newscn failed"); data = elf_newdata(section); if (!data) die(elf_errmsg(-1)); data->d_align = 1; data->d_off = 0; data->d_buf = stringTable; data->d_size = sizeof(stringTable); data->d_type = ELF_T_BYTE; data->d_version = EV_CURRENT; shdr = elf_getshdr(section); if (!shdr) die(elf_errmsg(-1)); shdr->sh_name = 11; shdr->sh_type = SHT_STRTAB; shdr->sh_flags = SHF_STRINGS | SHF_ALLOC; shdr->sh_entsize = 0; ehdr->e_shstrndx = elf_ndxscn(section); if (elf_update(e, ELF_C_WRITE) < 0) die(elf_errmsg(-1)); elf_end(e); close(fd); } #endif dwarf_producer_finish(dw, &error); if (error != 0) die("dwarf_producer_finish failed"); return 0; }
int rewrite_code_section(elf_data_t *elf, inject_data_t *inject, char **err) { Elf_Scn *scn; GElf_Shdr shdr; char *s; size_t shstrndx; if(elf_getshdrstrndx(elf->e, &shstrndx) < 0) { (*err) = "failed to get string table section index"; return -1; } printf("shstrndx : %d\n",shstrndx); scn = NULL; while((scn = elf_nextscn(elf->e, scn))) { if(!gelf_getshdr(scn, &shdr)) { (*err) = "failed to get section header"; return -1; } s = elf_strptr(elf->e, shstrndx, shdr.sh_name); if(!s) { (*err) = "failed to get section name"; return -1; } printf("section : %s\n",s); if(!strcmp(s, ABITAG_NAME)) { shdr.sh_name = shdr.sh_name; /* offset into string table */ shdr.sh_type = SHT_PROGBITS; /* type */ shdr.sh_flags = SHF_ALLOC | SHF_EXECINSTR; /* flags */ shdr.sh_addr = inject->secaddr; /* address to load section at */ shdr.sh_offset = inject->off; /* file offset to start of section */ shdr.sh_size = inject->len; /* size in bytes */ shdr.sh_link = 0; /* not used for code section */ shdr.sh_info = 0; /* not used for code section */ shdr.sh_addralign = 16; /* memory alignment */ shdr.sh_entsize = 0; /* not used for code section */ verbose("rewriting section header %lu:", elf_ndxscn(scn)); verbose(" sh_name = %u", shdr.sh_name); verbose(" sh_type = SHT_PROGBITS"); verbose(" sh_flags = SHF_ALLOC | SHF_EXECINSTR"); verbose(" sh_addr = 0x%x", shdr.sh_addr); verbose(" sh_offset = %lu", shdr.sh_offset); verbose(" sh_size = %lu", shdr.sh_size); verbose(" sh_link = 0"); verbose(" sh_info = 0"); verbose(" sh_addralign = 0x%x", shdr.sh_addralign); verbose(" sh_entsize = 0"); inject->sidx = elf_ndxscn(scn); inject->scn = scn; memcpy(&inject->shdr, &shdr, sizeof(shdr)); verbose("writing section header to file"); if(write_shdr(elf, scn, &shdr, elf_ndxscn(scn), err) < 0) { return -1; } if(reorder_shdrs(elf, inject, err) < 0) { return -1; } break; } } if(!scn) { (*err) = "cannot find section to rewrite"; return -1; } return 0; }
int reorder_shdrs(elf_data_t *elf, inject_data_t *inject, char **err) { int direction, skip; size_t i; Elf_Scn *scn; GElf_Shdr shdr; direction = 0; scn = elf_getscn(elf->e, inject->sidx - 1); if(scn && !gelf_getshdr(scn, &shdr)) { (*err) = "failed to get section header"; return -1; } if(scn && shdr.sh_addr > inject->shdr.sh_addr) { /* Injected section header must be moved left */ direction = -1; } scn = elf_getscn(elf->e, inject->sidx + 1); if(scn && !gelf_getshdr(scn, &shdr)) { (*err) = "failed to get section header"; return -1; } if(scn && shdr.sh_addr < inject->shdr.sh_addr) { /* Injected section header must be moved right */ direction = 1; } if(direction == 0) { /* Section headers are already in order */ return 0; } i = inject->sidx; /* Order section headers by increasing address */ skip = 0; for(scn = elf_getscn(elf->e, inject->sidx + direction); scn != NULL; scn = elf_getscn(elf->e, inject->sidx + direction + skip)) { if(!gelf_getshdr(scn, &shdr)) { (*err) = "failed to get section header"; return -1; } if((direction < 0 && shdr.sh_addr <= inject->shdr.sh_addr) || (direction > 0 && shdr.sh_addr >= inject->shdr.sh_addr)) { /* The order is okay from this point on */ break; } /* Only reorder code section headers */ if(shdr.sh_type != SHT_PROGBITS) { skip += direction; continue; } /* Swap the injected shdr with its neighbor progbits header */ if(write_shdr(elf, scn, &inject->shdr, elf_ndxscn(scn), err) < 0) { return -1; } if(write_shdr(elf, inject->scn, &shdr, inject->sidx, err) < 0) { return -1; } inject->sidx += direction + skip; inject->scn = elf_getscn(elf->e, inject->sidx); skip = 0; } verbose("reordered sections %lu - %lu", i, inject->sidx); return 0; }
static int cache_sections (Dwfl_Module *mod) { struct secref *refs = NULL; size_t nrefs = 0; size_t shstrndx; if (unlikely (elf_getshdrstrndx (mod->main.elf, &shstrndx) < 0)) { elf_error: __libdwfl_seterrno (DWFL_E_LIBELF); return -1; } bool check_reloc_sections = false; Elf_Scn *scn = NULL; while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL) { GElf_Shdr shdr_mem; GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); if (shdr == NULL) goto elf_error; if ((shdr->sh_flags & SHF_ALLOC) && shdr->sh_addr == 0 && mod->e_type == ET_REL) { /* This section might not yet have been looked at. */ if (__libdwfl_relocate_value (mod, mod->main.elf, &shstrndx, elf_ndxscn (scn), &shdr->sh_addr) != DWFL_E_NOERROR) continue; shdr = gelf_getshdr (scn, &shdr_mem); if (unlikely (shdr == NULL)) goto elf_error; } if (shdr->sh_flags & SHF_ALLOC) { const char *name = elf_strptr (mod->main.elf, shstrndx, shdr->sh_name); if (unlikely (name == NULL)) goto elf_error; struct secref *newref = alloca (sizeof *newref); newref->scn = scn; newref->relocs = NULL; newref->name = name; newref->start = dwfl_adjusted_address (mod, shdr->sh_addr); newref->end = newref->start + shdr->sh_size; newref->next = refs; refs = newref; ++nrefs; } if (mod->e_type == ET_REL && shdr->sh_size != 0 && (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA) && mod->dwfl->callbacks->section_address != NULL) { if (shdr->sh_info < elf_ndxscn (scn)) { /* We've already looked at the section these relocs apply to. */ Elf_Scn *tscn = elf_getscn (mod->main.elf, shdr->sh_info); if (likely (tscn != NULL)) for (struct secref *sec = refs; sec != NULL; sec = sec->next) if (sec->scn == tscn) { sec->relocs = scn; break; } } else /* We'll have to do a second pass. */ check_reloc_sections = true; } } mod->reloc_info = malloc (offsetof (struct dwfl_relocation, refs[nrefs])); if (mod->reloc_info == NULL) { __libdwfl_seterrno (DWFL_E_NOMEM); return -1; } struct secref **sortrefs = alloca (nrefs * sizeof sortrefs[0]); for (size_t i = nrefs; i-- > 0; refs = refs->next) sortrefs[i] = refs; assert (refs == NULL); qsort (sortrefs, nrefs, sizeof sortrefs[0], &compare_secrefs); mod->reloc_info->count = nrefs; for (size_t i = 0; i < nrefs; ++i) { mod->reloc_info->refs[i].name = sortrefs[i]->name; mod->reloc_info->refs[i].scn = sortrefs[i]->scn; mod->reloc_info->refs[i].relocs = sortrefs[i]->relocs; mod->reloc_info->refs[i].start = sortrefs[i]->start; mod->reloc_info->refs[i].end = sortrefs[i]->end; } if (unlikely (check_reloc_sections)) { /* There was a reloc section that preceded its target section. So we have to scan again now that we have cached all the possible target sections we care about. */ scn = NULL; while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL) { GElf_Shdr shdr_mem; GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); if (shdr == NULL) goto elf_error; if (shdr->sh_size != 0 && (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)) { Elf_Scn *tscn = elf_getscn (mod->main.elf, shdr->sh_info); if (likely (tscn != NULL)) for (size_t i = 0; i < nrefs; ++i) if (mod->reloc_info->refs[i].scn == tscn) { mod->reloc_info->refs[i].relocs = scn; break; } } } } return nrefs; }
int main(int argc, const char *argv[]) { ssize_t bytes_written; // only used to silence compiler warnings if (argc < 2) errx(EX_USAGE, "Usage: PatchEntry <binary>"); if (elf_version(EV_CURRENT) == EV_NONE) errx(EX_SOFTWARE, "Invalid ELF version: %s", elf_errmsg(-1)); int fd = open(argv[1], O_RDWR); if (fd == -1) err(EX_NOINPUT, "open() failed"); Elf *e; e = elf_begin(fd, ELF_C_RDWR, NULL); if (e == nullptr) errx(EX_SOFTWARE, "Failed to read from ELF file: %s", elf_errmsg(-1)); if (elf_kind(e) != ELF_K_ELF) errx(EX_SOFTWARE, "File is not an ELF object"); // Read the ELF header to find the entry point // FIXME: check the class/architecture, make sure it's the same as ours GElf_Ehdr elf_hdr; if (gelf_getehdr(e, &elf_hdr) == NULL) errx(EX_SOFTWARE, "Failed to read ELF header: %s", elf_errmsg(-1)); auto dt_init = FindDynamicInit(e); auto dt_init_ofs = 0; if (dt_init) { dt_init_ofs = dt_init->info.second.sh_offset + dt_init->data->d_off + dt_init->index * sizeof(Elf_Dyn) + offsetof(Elf_Dyn, d_un); } auto pit_sym = FindSymbol(e, kProgramInfoTableName); auto pit_info = FindSectionDataByAddr(e, pit_sym.st_value); auto pit_ofs = std::get<0>(pit_info).second.sh_offset + // Section file offset std::get<1>(pit_info)->d_off + // Elf_Data offset std::get<2>(pit_info); // Offset relative to Elf_Data #if 1 if (dt_init) printf("Old ELF entry:%p DT_INIT:%p@%x PIT:%p@%lx\n", (void*) elf_hdr.e_entry, (void*) dt_init->dyn_section.d_un.d_ptr, dt_init_ofs, (void*) pit_sym.st_value, pit_ofs); else printf("Old ELF entry:%p DT_INIT:NULL PIT:%p@%lx\n", (void*) elf_hdr.e_entry, (void*) pit_sym.st_value, pit_ofs); #endif // Replace the ProgramInfoTable values auto pit_data = std::get<1>(pit_info); auto orig_pit = reinterpret_cast<TrapProgramInfoTable*>( reinterpret_cast<uint8_t*>(pit_data->d_buf) + std::get<2>(pit_info)); TrapProgramInfoTable pit = *orig_pit; // Need to copy it here, since elf_end releases it if (pit.num_sections != 0) errx(EX_USAGE, "Binary already contains full ProgramInfoTable structure"); if (dt_init) pit.orig_dt_init = dt_init->dyn_section.d_un.d_ptr; else pit.orig_dt_init = 0; pit.orig_entry = elf_hdr.e_entry; // Find executable sections in the binary (.text/.plt/others) // then copy them over to the PIT pit.num_sections = TRAP_NUM_SECTIONS; for (size_t i = 0; i < TRAP_NUM_SECTIONS; i++) { auto sec_info = FindSectionByName(e, kExecSections[i][0]); if (sec_info.first != nullptr) { pit.sections[i].start = sec_info.second.sh_addr; pit.sections[i].size = sec_info.second.sh_size; } auto trap_sec_info = FindSectionByName(e, kExecSections[i][1]); if (trap_sec_info.first != nullptr) { pit.sections[i].trap = trap_sec_info.second.sh_addr; pit.sections[i].trap_size = trap_sec_info.second.sh_size; } } // Set the new entry point addresses auto entry_trampoline_sym = FindSymbol(e, kEntryTrampolineName); auto init_trampoline_sym = FindSymbol(e, kInitTrampolineName); elf_hdr.e_entry = entry_trampoline_sym.st_value; auto new_dt_init = static_cast<ArchPointer>(init_trampoline_sym.st_value); // Find export trampolines auto xptramp_info = FindSectionByName(e, ".xptramp"); DynamicSymbolMap dyn_sym_map; ExportTrampolineVector xptramp_vec; size_t xptramp_shndx = 0; if (xptramp_info.first != nullptr) { pit.xptramp_start = xptramp_info.second.sh_addr; pit.xptramp_size = xptramp_info.second.sh_size; dyn_sym_map = FindDynamicSymbols(e); xptramp_vec = FindExportTrampolines(e, xptramp_info); xptramp_shndx = elf_ndxscn(xptramp_info.first); } // Update the ELF header, then write it out // There's some pretty ugly behavior from libelf here: // if we let it handle the layout, it mis-aligns the data sections // It also doesn't seem to update the contents correctly, // so we do that manually elf_flagelf(e, ELF_C_SET, ELF_F_LAYOUT); gelf_update_ehdr(e, &elf_hdr); if (elf_update(e, ELF_C_WRITE) <= 0) errx(EX_SOFTWARE, "Couldn't update ELF file: %s", elf_errmsg(-1)); elf_end(e); // FIXME: libelf shenanigans force us to // write data out to the file manually // 1) DT_INIT inside .dynamic if (dt_init) { printf("writing new DT_INIT: 0x%lu\n", new_dt_init); lseek(fd, dt_init_ofs, SEEK_SET); bytes_written = write(fd, &new_dt_init, sizeof(new_dt_init)); } // 2) The ProgramInfoTable lseek(fd, pit_ofs, SEEK_SET); bytes_written = write(fd, &pit, sizeof(pit)); // 3) Exported symbols WriteExportSymbols(fd, xptramp_info, xptramp_vec, xptramp_shndx, dyn_sym_map); close(fd); return 0; }
const char * dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr addr, GElf_Sym *closest_sym, GElf_Word *shndxp) { int syments = INTUSE(dwfl_module_getsymtab) (mod); if (syments < 0) return NULL; /* Return true iff we consider ADDR to lie in the same section as SYM. */ GElf_Word addr_shndx = SHN_UNDEF; inline bool same_section (const GElf_Sym *sym, GElf_Word shndx) { /* For absolute symbols and the like, only match exactly. */ if (shndx >= SHN_LORESERVE) return sym->st_value == addr; /* Figure out what section ADDR lies in. */ if (addr_shndx == SHN_UNDEF) { GElf_Addr mod_addr = dwfl_deadjust_st_value (mod, addr); Elf_Scn *scn = NULL; addr_shndx = SHN_ABS; while ((scn = elf_nextscn (mod->symfile->elf, scn)) != NULL) { GElf_Shdr shdr_mem; GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); if (likely (shdr != NULL) && mod_addr >= shdr->sh_addr && mod_addr < shdr->sh_addr + shdr->sh_size) { addr_shndx = elf_ndxscn (scn); break; } } } return shndx == addr_shndx; } /* Keep track of the closest symbol we have seen so far. Here we store only symbols with nonzero st_size. */ const char *closest_name = NULL; GElf_Word closest_shndx = SHN_UNDEF; /* Keep track of an eligible symbol with st_size == 0 as a fallback. */ const char *sizeless_name = NULL; GElf_Sym sizeless_sym = { 0, 0, 0, 0, 0, SHN_UNDEF }; GElf_Word sizeless_shndx = SHN_UNDEF; /* Keep track of the lowest address a relevant sizeless symbol could have. */ GElf_Addr min_label = 0; /* Look through the symbol table for a matching symbol. */ inline void search_table (int start, int end) { for (int i = start; i < end; ++i) { GElf_Sym sym; GElf_Word shndx; const char *name = INTUSE(dwfl_module_getsym) (mod, i, &sym, &shndx); if (name != NULL && name[0] != '\0' && sym.st_shndx != SHN_UNDEF && sym.st_value <= addr && GELF_ST_TYPE (sym.st_info) != STT_SECTION && GELF_ST_TYPE (sym.st_info) != STT_FILE && GELF_ST_TYPE (sym.st_info) != STT_TLS) { /* Even if we don't choose this symbol, its existence excludes any sizeless symbol (assembly label) that is below its upper bound. */ if (sym.st_value + sym.st_size > min_label) min_label = sym.st_value + sym.st_size; if (sym.st_size == 0 || addr - sym.st_value < sym.st_size) { /* This symbol is a better candidate than the current one if it's closer to ADDR or is global when it was local. */ if (closest_name == NULL || closest_sym->st_value < sym.st_value || (GELF_ST_BIND (closest_sym->st_info) < GELF_ST_BIND (sym.st_info))) { if (sym.st_size != 0) { *closest_sym = sym; closest_shndx = shndx; closest_name = name; } else if (closest_name == NULL && sym.st_value >= min_label && same_section (&sym, shndx)) { /* Handwritten assembly symbols sometimes have no st_size. If no symbol with proper size includes the address, we'll use the closest one that is in the same section as ADDR. */ sizeless_sym = sym; sizeless_shndx = shndx; sizeless_name = name; } } /* When the beginning of its range is no closer, the end of its range might be. But do not replace a global symbol with a local! */ else if (sym.st_size != 0 && closest_sym->st_value == sym.st_value && closest_sym->st_size > sym.st_size && (GELF_ST_BIND (closest_sym->st_info) <= GELF_ST_BIND (sym.st_info))) { *closest_sym = sym; closest_shndx = shndx; closest_name = name; } } } } } /* First go through global symbols. mod->first_global is setup by dwfl_module_getsymtab to the index of the first global symbol in the module's symbol table, or -1 when unknown. All symbols with local binding come first in the symbol table, then all globals. */ search_table (mod->first_global < 0 ? 1 : mod->first_global, syments); /* If we found nothing searching the global symbols, then try the locals. Unless we have a global sizeless symbol that matches exactly. */ if (closest_name == NULL && mod->first_global > 1 && (sizeless_name == NULL || sizeless_sym.st_value != addr)) search_table (1, mod->first_global); /* If we found no proper sized symbol to use, fall back to the best candidate sizeless symbol we found, if any. */ if (closest_name == NULL && sizeless_name != NULL && sizeless_sym.st_value >= min_label) { *closest_sym = sizeless_sym; closest_shndx = sizeless_shndx; closest_name = sizeless_name; } if (shndxp != NULL) *shndxp = closest_shndx; return closest_name; }
int main (int argc, char *argv[]) { int result = 0; int cnt; elf_version (EV_CURRENT); for (cnt = 1; cnt < argc; ++cnt) { int fd = open (argv[cnt], O_RDONLY); Elf *elf = elf_begin (fd, ELF_C_READ, NULL); if (elf == NULL) { printf ("%s not usable %s\n", argv[cnt], elf_errmsg (-1)); result = 1; close (fd); continue; } size_t shdrstrndx; if (elf_getshdrstrndx (elf, &shdrstrndx) == -1) { printf ("elf_getshdrstrnd failed %s\n", elf_errmsg (-1)); result = 1; close (fd); continue; } Elf_Scn *scn = NULL; while ((scn = elf_nextscn (elf, scn)) != NULL) { int idx = elf_ndxscn (scn); GElf_Shdr shdr; if (gelf_getshdr (scn, &shdr) == NULL) { printf ("gelf_getshdr failed: %s\n", elf_errmsg (-1)); result = 1; break; } const char *sname = elf_strptr (elf, shdrstrndx, shdr.sh_name); if (sname == NULL) { printf ("couldn't get section name: %s\n", elf_errmsg (-1)); result = 1; break; } if (strncmp(".zdebug", sname, strlen (".zdebug")) == 0) { ssize_t size; if ((size = dwelf_scn_gnu_compressed_size (scn)) == -1) { printf ("dwelf_scn_gnu_compressed_size failed: %s\n", elf_errmsg (-1)); result = 1; break; } printf ("section %d: GNU Compressed size: %zx\n", idx, size); } } elf_end (elf); close (fd); } return result; }
void clone_elf(Elf *elf, Elf *newelf, const char *elf_name, const char *newelf_name, bool *sym_filter, int num_symbols, int shady #ifdef SUPPORT_ANDROID_PRELINK_TAGS , int *prelinked, int *elf_little, long *prelink_addr #endif , bool rebuild_shstrtab, bool strip_debug, bool dry_run) { GElf_Ehdr ehdr_mem, *ehdr; /* store ELF header of original library */ size_t shstrndx; /* section-strings-section index */ size_t shnum; /* number of sections in the original file */ /* string table for section headers in new file */ struct Ebl_Strtab *shst = NULL; int dynamic_idx = -1; /* index in shdr_info[] of .dynamic section */ int dynsym_idx = -1; /* index in shdr_info[] of dynamic symbol table section */ unsigned int cnt; /* general-purpose counter */ /* This flag is true when at least one section is dropped or when the relative order of sections has changed, so that section indices in the resulting file will be different from those in the original. */ bool sections_dropped_or_rearranged; Elf_Scn *scn; /* general-purpose section */ size_t idx; /* general-purporse section index */ shdr_info_t *shdr_info = NULL; unsigned int shdr_info_len = 0; GElf_Phdr *phdr_info = NULL; /* Get the information from the old file. */ ehdr = gelf_getehdr (elf, &ehdr_mem); FAILIF_LIBELF(NULL == ehdr, gelf_getehdr); /* Create new program header for the elf file */ FAILIF(gelf_newehdr (newelf, gelf_getclass (elf)) == 0 || (ehdr->e_type != ET_REL && gelf_newphdr (newelf, ehdr->e_phnum) == 0), "Cannot create new file: %s", elf_errmsg (-1)); #ifdef SUPPORT_ANDROID_PRELINK_TAGS ASSERT(prelinked); ASSERT(prelink_addr); ASSERT(elf_little); *elf_little = (ehdr->e_ident[EI_DATA] == ELFDATA2LSB); *prelinked = check_prelinked(elf_name, *elf_little, prelink_addr); #endif INFO("\n\nCALCULATING MODIFICATIONS\n\n"); /* Copy out the old program header: notice that if the ELF file does not have a program header, this loop won't execute. */ INFO("Copying ELF program header...\n"); phdr_info = (GElf_Phdr *)CALLOC(ehdr->e_phnum, sizeof(GElf_Phdr)); for (cnt = 0; cnt < ehdr->e_phnum; ++cnt) { INFO("\tRetrieving entry %d\n", cnt); FAILIF_LIBELF(NULL == gelf_getphdr(elf, cnt, phdr_info + cnt), gelf_getphdr); /* -- we update the header at the end FAILIF_LIBELF(gelf_update_phdr (newelf, cnt, phdr_info + cnt) == 0, gelf_update_phdr); */ } /* Get the section-header strings section. This section contains the strings used to name the other sections. */ FAILIF_LIBELF(elf_getshstrndx(elf, &shstrndx) < 0, elf_getshstrndx); /* Get the number of sections. */ FAILIF_LIBELF(elf_getshnum (elf, &shnum) < 0, elf_getshnum); INFO("Original ELF file has %zd sections.\n", shnum); /* Allocate the section-header-info buffer. We allocate one more entry for the section-strings section because we regenerate that one and place it at the very end of the file. Note that just because we create an extra entry in the shdr_info array, it does not mean that we create one more section the header. We just mark the old section for removal and create one as the last section. */ INFO("Allocating section-header info structure (%zd) bytes...\n", shnum*sizeof (shdr_info_t)); shdr_info_len = rebuild_shstrtab ? shnum + 1 : shnum; shdr_info = (shdr_info_t *)CALLOC(shdr_info_len, sizeof (shdr_info_t)); /* Iterate over all the sections and initialize the internal section-info array... */ INFO("Initializing section-header info structure...\n"); /* Gather information about the sections in this file. */ scn = NULL; cnt = 1; while ((scn = elf_nextscn (elf, scn)) != NULL) { ASSERT(elf_ndxscn(scn) == cnt); shdr_info[cnt].scn = scn; FAILIF_LIBELF(NULL == gelf_getshdr(scn, &shdr_info[cnt].shdr), gelf_getshdr); /* Get the name of the section. */ shdr_info[cnt].name = elf_strptr (elf, shstrndx, shdr_info[cnt].shdr.sh_name); INFO("\tname: %s\n", shdr_info[cnt].name); FAILIF(shdr_info[cnt].name == NULL, "Malformed file: section %d name is null\n", cnt); /* Mark them as present but not yet investigated. By "investigating" sections, we mean that we check to see if by stripping other sections, the sections under investigation will be compromised. For example, if we are removing a section of code, then we want to make sure that the symbol table does not contain symbols that refer to this code, so we investigate the symbol table. If we do find such symbols, we will not strip the code section. */ shdr_info[cnt].idx = 1; /* Remember the shdr.sh_link value. We need to remember this value for those sections that refer to other sections. For example, we need to remember it for relocation-entry sections, because if we modify the symbol table that a relocation-entry section is relative to, then we need to patch the relocation section. By the time we get to deciding whether we need to patch the relocation section, we will have overwritten its header's sh_link field with a new value. */ shdr_info[cnt].old_shdr = shdr_info[cnt].shdr; INFO("\t\toriginal sh_link: %08d\n", shdr_info[cnt].old_shdr.sh_link); INFO("\t\toriginal sh_addr: %lld\n", shdr_info[cnt].old_shdr.sh_addr); INFO("\t\toriginal sh_offset: %lld\n", shdr_info[cnt].old_shdr.sh_offset); INFO("\t\toriginal sh_size: %lld\n", shdr_info[cnt].old_shdr.sh_size); if (shdr_info[cnt].shdr.sh_type == SHT_DYNAMIC) { INFO("\t\tthis is the SHT_DYNAMIC section [%s] at index %d\n", shdr_info[cnt].name, cnt); dynamic_idx = cnt; } else if (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM) { INFO("\t\tthis is the SHT_DYNSYM section [%s] at index %d\n", shdr_info[cnt].name, cnt); dynsym_idx = cnt; } FAILIF(shdr_info[cnt].shdr.sh_type == SHT_SYMTAB_SHNDX, "Cannot handle sh_type SHT_SYMTAB_SHNDX!\n"); FAILIF(shdr_info[cnt].shdr.sh_type == SHT_GROUP, "Cannot handle sh_type SHT_GROUP!\n"); FAILIF(shdr_info[cnt].shdr.sh_type == SHT_GNU_versym, "Cannot handle sh_type SHT_GNU_versym!\n"); /* Increment the counter. */ ++cnt; } /* while */ /* Get the EBL handling. */ Ebl *ebl = ebl_openbackend (elf); FAILIF_LIBELF(NULL == ebl, ebl_openbackend); FAILIF_LIBELF(0 != arm_init(elf, ehdr->e_machine, ebl, sizeof(Ebl)), arm_init); if (strip_debug) { /* This will actually strip more than just sections. It will strip anything not essential to running the image. */ INFO("Finding debug sections to strip.\n"); /* Now determine which sections can go away. The general rule is that all sections which are not used at runtime are stripped out. But there are a few exceptions: - special sections named ".comment" and ".note" are kept - OS or architecture specific sections are kept since we might not know how to handle them - if a section is referred to from a section which is not removed in the sh_link or sh_info element it cannot be removed either */ for (cnt = 1; cnt < shnum; ++cnt) { /* Check whether the section can be removed. */ if (SECTION_STRIP_P (ebl, elf, ehdr, &shdr_info[cnt].shdr, shdr_info[cnt].name, 1, /* remove .comment sections */ 1 /* remove all debug sections */) || /* The macro above is broken--check for .comment explicitly */ !strcmp(".comment", shdr_info[cnt].name) #ifdef ARM_SPECIFIC_HACKS || /* We ignore this section, that's why we can remove it. */ !strcmp(".stack", shdr_info[cnt].name) #endif ) { /* For now assume this section will be removed. */ INFO("Section [%s] will be stripped from image.\n", shdr_info[cnt].name); shdr_info[cnt].idx = 0; } #ifdef STRIP_STATIC_SYMBOLS else if (shdr_info[cnt].shdr.sh_type == SHT_SYMTAB) { /* Mark the static symbol table for removal */ INFO("Section [%s] (static symbol table) will be stripped from image.\n", shdr_info[cnt].name); shdr_info[cnt].idx = 0; if (shdr_info[shdr_info[cnt].shdr.sh_link].shdr.sh_type == SHT_STRTAB) { /* Mark the symbol table's string table for removal. */ INFO("Section [%s] (static symbol-string table) will be stripped from image.\n", shdr_info[shdr_info[cnt].shdr.sh_link].name); shdr_info[shdr_info[cnt].shdr.sh_link].idx = 0; } else { ERROR("Expecting the sh_link field of a symbol table to point to" " associated symbol-strings table! This is not mandated by" " the standard, but is a common practice and the only way " " to know for sure which strings table corresponds to which" " symbol table!\n"); } } #endif } /* Mark the SHT_NULL section as handled. */ shdr_info[0].idx = 2; /* Handle exceptions: section groups and cross-references. We might have to repeat this a few times since the resetting of the flag might propagate. */ int exceptions_pass = 0; bool changes; do { changes = false; INFO("\nHandling exceptions, pass %d\n\n", exceptions_pass++); for (cnt = 1; cnt < shnum; ++cnt) { if (shdr_info[cnt].idx == 0) { /* If a relocation section is marked as being removed but the section it is relocating is not, then do not remove the relocation section. */ if ((shdr_info[cnt].shdr.sh_type == SHT_REL || shdr_info[cnt].shdr.sh_type == SHT_RELA) && shdr_info[shdr_info[cnt].shdr.sh_info].idx != 0) { PRINT("\tSection [%s] will not be removed because the " "section it is relocating (%s) stays.\n", shdr_info[cnt].name, shdr_info[shdr_info[cnt].shdr.sh_info].name); } } if (shdr_info[cnt].idx == 1) { INFO("Processing section [%s]...\n", shdr_info[cnt].name); /* The content of symbol tables we don't remove must not reference any section which we do remove. Otherwise we cannot remove the referred section. */ if (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM || shdr_info[cnt].shdr.sh_type == SHT_SYMTAB) { Elf_Data *symdata; size_t elsize; INFO("\tSection [%s] is a symbol table that's not being" " removed.\n\tChecking to make sure that no symbols" " refer to sections that are being removed.\n", shdr_info[cnt].name); /* Make sure the data is loaded. */ symdata = elf_getdata (shdr_info[cnt].scn, NULL); FAILIF_LIBELF(NULL == symdata, elf_getdata); /* Go through all symbols and make sure the section they reference is not removed. */ elsize = gelf_fsize (elf, ELF_T_SYM, 1, ehdr->e_version); /* Check the length of the dynamic-symbol filter. */ FAILIF(sym_filter != NULL && (size_t)num_symbols != symdata->d_size / elsize, "Length of dynsym filter (%d) must equal the number" " of dynamic symbols (%zd)!\n", num_symbols, symdata->d_size / elsize); size_t inner; for (inner = 0; inner < symdata->d_size / elsize; ++inner) { GElf_Sym sym_mem; GElf_Sym *sym; size_t scnidx; sym = gelf_getsymshndx (symdata, NULL, inner, &sym_mem, NULL); FAILIF_LIBELF(sym == NULL, gelf_getsymshndx); scnidx = sym->st_shndx; FAILIF(scnidx == SHN_XINDEX, "Can't handle SHN_XINDEX!\n"); if (scnidx == SHN_UNDEF || scnidx >= shnum || (scnidx >= SHN_LORESERVE && scnidx <= SHN_HIRESERVE) || GELF_ST_TYPE (sym->st_info) == STT_SECTION) { continue; } /* If the symbol is going to be thrown and it is a global or weak symbol that is defined (not imported), then continue. Since the symbol is going away, we do not care whether it refers to a section that is also going away. */ if (sym_filter && !sym_filter[inner]) { bool global_or_weak = ELF32_ST_BIND(sym->st_info) == STB_GLOBAL || ELF32_ST_BIND(sym->st_info) == STB_WEAK; if (!global_or_weak && sym->st_shndx != SHN_UNDEF) continue; } /* -- far too much output INFO("\t\t\tSymbol [%s] (%d)\n", elf_strptr(elf, shdr_info[cnt].shdr.sh_link, sym->st_name), shdr_info[cnt].shdr.sh_info); */ if (shdr_info[scnidx].idx == 0) { PRINT("\t\t\tSymbol [%s] refers to section [%s], " "which is being removed. Will keep that " "section.\n", elf_strptr(elf, shdr_info[cnt].shdr.sh_link, sym->st_name), shdr_info[scnidx].name); /* Mark this section as used. */ shdr_info[scnidx].idx = 1; changes |= scnidx < cnt; } } /* for each symbol */ } /* section type is SHT_DYNSYM or SHT_SYMTAB */ /* Cross referencing happens: - for the cases the ELF specification says. That are + SHT_DYNAMIC in sh_link to string table + SHT_HASH in sh_link to symbol table + SHT_REL and SHT_RELA in sh_link to symbol table + SHT_SYMTAB and SHT_DYNSYM in sh_link to string table + SHT_GROUP in sh_link to symbol table + SHT_SYMTAB_SHNDX in sh_link to symbol table Other (OS or architecture-specific) sections might as well use this field so we process it unconditionally. - references inside section groups - specially marked references in sh_info if the SHF_INFO_LINK flag is set */ if (shdr_info[shdr_info[cnt].shdr.sh_link].idx == 0) { shdr_info[shdr_info[cnt].shdr.sh_link].idx = 1; changes |= shdr_info[cnt].shdr.sh_link < cnt; } /* Handle references through sh_info. */ if (SH_INFO_LINK_P (&shdr_info[cnt].shdr) && shdr_info[shdr_info[cnt].shdr.sh_info].idx == 0) { PRINT("\tSection [%s] links to section [%s], which was " "marked for removal--it will not be removed.\n", shdr_info[cnt].name, shdr_info[shdr_info[cnt].shdr.sh_info].name); shdr_info[shdr_info[cnt].shdr.sh_info].idx = 1; changes |= shdr_info[cnt].shdr.sh_info < cnt; } /* Mark the section as investigated. */ shdr_info[cnt].idx = 2; } /* if (shdr_info[cnt].idx == 1) */ } /* for (cnt = 1; cnt < shnum; ++cnt) */ } while (changes); } else { INFO("Not stripping sections.\n"); /* Mark the SHT_NULL section as handled. */ shdr_info[0].idx = 2; } /* Mark the section header string table as unused, we will create a new one as the very last section in the new ELF file. */ shdr_info[shstrndx].idx = rebuild_shstrtab ? 0 : 2; /* We need a string table for the section headers. */ FAILIF_LIBELF((shst = ebl_strtabinit (1 /* null-terminated */)) == NULL, ebl_strtabinit); /* Assign new section numbers. */ INFO("Creating new sections...\n"); //shdr_info[0].idx = 0; for (cnt = idx = 1; cnt < shnum; ++cnt) { if (shdr_info[cnt].idx > 0) { shdr_info[cnt].idx = idx++; /* Create a new section. */ FAILIF_LIBELF((shdr_info[cnt].newscn = elf_newscn(newelf)) == NULL, elf_newscn); ASSERT(elf_ndxscn (shdr_info[cnt].newscn) == shdr_info[cnt].idx); /* Add this name to the section header string table. */ shdr_info[cnt].se = ebl_strtabadd (shst, shdr_info[cnt].name, 0); INFO("\tsection [%s] (old offset %lld, old size %lld) will have index %d " "(was %zd).\n", shdr_info[cnt].name, shdr_info[cnt].old_shdr.sh_offset, shdr_info[cnt].old_shdr.sh_size, shdr_info[cnt].idx, elf_ndxscn(shdr_info[cnt].scn)); } else { INFO("\tIgnoring section [%s] (offset %lld, size %lld, index %zd), " "it will be discarded.\n", shdr_info[cnt].name, shdr_info[cnt].shdr.sh_offset, shdr_info[cnt].shdr.sh_size, elf_ndxscn(shdr_info[cnt].scn)); } } /* for */ sections_dropped_or_rearranged = idx != cnt; Elf_Data *shstrtab_data = NULL; #if 0 /* Fail if sections are being dropped or rearranged (except for moving shstrtab) or the symbol filter is not empty, AND the file is an executable. */ FAILIF(((idx != cnt && !(cnt - idx == 1 && rebuild_shstrtab)) || sym_filter != NULL) && ehdr->e_type != ET_DYN, "You may not rearrange sections or strip symbols on an executable file!\n"); #endif INFO("\n\nADJUSTING ELF FILE\n\n"); adjust_elf(elf, elf_name, newelf, newelf_name, ebl, ehdr, /* store ELF header of original library */ sym_filter, num_symbols, shdr_info, shdr_info_len, phdr_info, idx, /* highest_scn_num */ shnum, shstrndx, shst, sections_dropped_or_rearranged, dynamic_idx, /* index in shdr_info[] of .dynamic section */ dynsym_idx, /* index in shdr_info[] of dynamic symbol table */ shady, &shstrtab_data, ehdr->e_type == ET_DYN, /* adjust section ofsets only when the file is a shared library */ rebuild_shstrtab); /* We have everything from the old file. */ FAILIF_LIBELF(elf_cntl(elf, ELF_C_FDDONE) != 0, elf_cntl); /* The ELF library better follows our layout when this is not a relocatable object file. */ elf_flagelf (newelf, ELF_C_SET, (ehdr->e_type != ET_REL ? ELF_F_LAYOUT : 0)); /* Finally write the file. */ FAILIF_LIBELF(!dry_run && elf_update(newelf, ELF_C_WRITE) == -1, elf_update); if (shdr_info != NULL) { /* For some sections we might have created an table to map symbol table indices. */ for (cnt = 1; cnt < shdr_info_len; ++cnt) { FREEIF(shdr_info[cnt].newsymidx); FREEIF(shdr_info[cnt].symse); if(shdr_info[cnt].dynsymst != NULL) ebl_strtabfree (shdr_info[cnt].dynsymst); } /* Free the memory. */ FREE (shdr_info); } FREEIF(phdr_info); ebl_closebackend(ebl); /* Free other resources. */ if (shst != NULL) ebl_strtabfree (shst); if (shstrtab_data != NULL) FREEIF(shstrtab_data->d_buf); }
static int replaceAMDILSection(Elf* e, int nStream, MWCALtargetEnum target) { Elf_Scn* scn = NULL; size_t shstrndx = 0; static const int verbose = 0; static const int verboseDebug = 0; /* Get section index of section containing the string table of section names */ if (elf_getshdrstrndx(e, &shstrndx) != 0) { mw_printf("elf_getshdrstrndx failed: %s\n", elf_errmsg(-1)); return 1; } /* Iterate through all the sections */ while ((scn = elf_nextscn(e, scn))) { Elf32_Shdr* shdr; const char* name; /* Get the header for this section */ shdr = elf32_getshdr(scn); if (!shdr) { mw_printf("elf32_getshdr() failed: %s\n", elf_errmsg(-1)); return 1; } /* Look up the name of the section in the string table */ name = elf_strptr(e, shstrndx, shdr->sh_name); if (!name) { mw_printf("elf_strptr() failed: %s\n", elf_errmsg(-1)); return 1; } /* if (strstr(name, ".rodata") != NULL) { Elf_Data* data = elf_getdata(scn, NULL); FILE* f = fopen("rodata_section.bin", "wb"); if (f) { fwrite(data->d_buf, 1, data->d_size, f); fclose(f); } else { perror("Failed to open file"); } size_t roSize; char* r770RO = mwReadFileWithSize("rodata_section_RV770.bin", &roSize); assert(r770RO); data->d_buf = r770RO; data->d_size = roSize; if (!elf_flagdata(data, ELF_C_SET, ELF_F_DIRTY)) { mw_printf("elf_flagdata() failed: %s\n", elf_errmsg(-1)); return 1; } if (!elf_flagscn(scn, ELF_C_SET, ELF_F_DIRTY)) { mw_printf("elf_flagscn() failed: %s\n", elf_errmsg(-1)); return 1; } if (elf_update(e, ELF_C_NULL) < 0) { mw_printf("elf_update(NULL) failed: %s\n", elf_errmsg(-1)); return 1; } } */ if (strstr(name, ".amdil") != NULL) { int uavId; const char* uavComment; Elf_Data* data; data = elf_getdata(scn, NULL); if (!data) { mw_printf("Failed to get data for .amdil section: %s\n", elf_errmsg(-1)); return 1; } if (verbose) { mw_printf("Replacing section data of type %d, off %d align "ZU"\n", data->d_type, (int) data->d_off, data->d_align); } /* Before we overwrite it, there is information we would like to extract */ uavComment = strstr((const char*) data->d_buf, ";uavid:"); if (!uavComment || (sscanf(uavComment, ";uavid:%d\n", &uavId) != 1)) { mw_printf("Error reading uavid from IL comment\n"); uavId = -1; } ilSrc = getILSrc(nStream, target, uavId, &ilSrcLen); if (!ilSrc || (ilSrcLen == 0)) { mw_printf("Failed to get IL source\n"); return 1; } data->d_buf = (void*) ilSrc; data->d_size = ilSrcLen; if (!elf_flagdata(data, ELF_C_SET, ELF_F_DIRTY)) { mw_printf("elf_flagdata() failed: %s\n", elf_errmsg(-1)); return 1; } if (!elf_flagscn(scn, ELF_C_SET, ELF_F_DIRTY)) { mw_printf("elf_flagscn() failed: %s\n", elf_errmsg(-1)); return 1; } /* Don't let libelf rearrange the sections when writing. clBuildProgram() crashes on Windows if you don't do this with some(?) Catalyst versions */ if (!elf_flagelf(e, ELF_C_SET, ELF_F_LAYOUT)) { mw_printf("elf_flagelf() failed: %s\n", elf_errmsg(-1)); return 1; } if (elf_update(e, ELF_C_NULL) < 0) { mw_printf("elf_update(NULL) failed: %s\n", elf_errmsg(-1)); return 1; } } if (verboseDebug) { printf("Section %u %s\n", (unsigned int) elf_ndxscn(scn), name); } } if (elf_update(e, ELF_C_WRITE) < 0) { mw_printf("elf_update(ELF_C_WRITE) failed: %s\n", elf_errmsg(-1)); return 1; } return 0; }