Elf_Scn *elf_utils_new_scn_with_name(Elf *e, const char *scn_name) { Elf_Scn *scn; GElf_Shdr shdr; size_t shstrndx, index, namelen; Elf_Data *shstrdata; void *ptr; ELF_ASSERT(elf_getshdrstrndx(e, &shstrndx) == 0); ELF_ASSERT(scn = elf_getscn(e, shstrndx)); ELF_ASSERT(shstrdata = elf_getdata(scn, NULL)); namelen = strlen(scn_name) + 1; ELF_ASSERT(gelf_getshdr(scn, &shdr)); if (!elf_utils_shift_contents(e, shdr.sh_offset + shdr.sh_size, namelen)) goto failure; ASSERT(ptr = realloc(shstrdata->d_buf, shstrdata->d_size + namelen)); index = shstrdata->d_size; strcpy(ptr+index, scn_name); shstrdata->d_buf = ptr; shstrdata->d_size += namelen; shdr.sh_size += namelen; ELF_ASSERT(gelf_update_shdr(scn, &shdr)); ELF_ASSERT(scn = elf_newscn(e)); ELF_ASSERT(gelf_getshdr(scn, &shdr)); shdr.sh_name = index; ELF_ASSERT(gelf_update_shdr(scn, &shdr)); return scn; failure: return NULL; }
Elf_Scn *elf_utils_new_scn_with_data(Elf *e, const char *scn_name, void *buf, int len) { Elf_Scn *scn; GElf_Ehdr ehdr; GElf_Shdr shdr; Elf_Data *data; int offset; scn = elf_utils_new_scn_with_name(e, scn_name); if (scn == NULL) goto failure; ELF_ASSERT(gelf_getehdr(e, &ehdr)); offset = ehdr.e_shoff; if (!elf_utils_shift_contents(e, offset, len)) goto failure; ELF_ASSERT(gelf_getshdr(scn, &shdr)); shdr.sh_offset = offset; shdr.sh_size = len; shdr.sh_addralign = 1; ELF_ASSERT(gelf_update_shdr(scn, &shdr)); ELF_ASSERT(data = elf_newdata(scn)); data->d_buf = buf; data->d_type = ELF_T_BYTE; data->d_version = EV_CURRENT; data->d_size = len; data->d_off = 0; data->d_align = 1; return scn; failure: return NULL; }
Dwfl_Error internal_function __libdwfl_relocate_value (Dwfl_Module *mod, Elf *elf, size_t *shstrndx, Elf32_Word shndx, GElf_Addr *value) { assert (mod->e_type == ET_REL); Elf_Scn *refscn = elf_getscn (elf, shndx); GElf_Shdr refshdr_mem, *refshdr = gelf_getshdr (refscn, &refshdr_mem); if (refshdr == NULL) return DWFL_E_LIBELF; if (refshdr->sh_addr == 0 && (refshdr->sh_flags & SHF_ALLOC)) { /* This is a loaded section. Find its actual address and update the section header. */ if (*shstrndx == SHN_UNDEF && unlikely (elf_getshdrstrndx (elf, shstrndx) < 0)) return DWFL_E_LIBELF; const char *name = elf_strptr (elf, *shstrndx, refshdr->sh_name); if (unlikely (name == NULL)) return DWFL_E_LIBELF; if ((*mod->dwfl->callbacks->section_address) (MODCB_ARGS (mod), name, shndx, refshdr, &refshdr->sh_addr)) return CBFAIL; if (refshdr->sh_addr == (Dwarf_Addr) -1l) /* The callback indicated this section wasn't really loaded but we don't really care. */ refshdr->sh_addr = 0; /* Make no adjustment below. */ /* Update the in-core file's section header to show the final load address (or unloadedness). This serves as a cache, so we won't get here again for the same section. */ if (likely (refshdr->sh_addr != 0) && unlikely (! gelf_update_shdr (refscn, refshdr))) return DWFL_E_LIBELF; } if (refshdr->sh_flags & SHF_ALLOC) /* Apply the adjustment. */ *value += dwfl_adjusted_address (mod, refshdr->sh_addr); return DWFL_E_NOERROR; }
int elf_utils_shift_contents(Elf *e, int start_offset, int shift_amount) { GElf_Ehdr ehdr; Elf_Scn *scn; GElf_Shdr shdr; size_t segment_count = 0, segndx; GElf_Phdr phdr; int bottom_section_offset = 0; ELF_ASSERT(gelf_getehdr(e, &ehdr)); if (ehdr.e_shoff >= start_offset) { ehdr.e_shoff += shift_amount; ELF_ASSERT(gelf_update_ehdr(e, &ehdr)); } scn = NULL; while ((scn = elf_nextscn(e, scn)) != NULL) { ELF_ASSERT(gelf_getshdr(scn, &shdr)); if (shdr.sh_offset >= start_offset) { shdr.sh_offset += shift_amount; ELF_ASSERT(gelf_update_shdr(scn, &shdr)); } if (shdr.sh_offset + shdr.sh_size > bottom_section_offset) { bottom_section_offset = shdr.sh_offset + shdr.sh_size; } } if (bottom_section_offset > ehdr.e_shoff) { ELF_ASSERT(gelf_getehdr(e, &ehdr)); ehdr.e_shoff = bottom_section_offset; ELF_ASSERT(gelf_update_ehdr(e, &ehdr)); } /* A bug in libelf means that getphdrnum will report failure in a new file. * However, it will still set segment_count, so we'll use it. */ ELF_ASSERT((elf_getphdrnum(e, &segment_count), segment_count > 0)); for (segndx = 0; segndx < segment_count; segndx++) { ELF_ASSERT(gelf_getphdr(e, segndx, &phdr)); if (phdr.p_offset >= start_offset) { phdr.p_offset += shift_amount; ELF_ASSERT(gelf_update_phdr(e, segndx, &phdr)); } } return 1; failure: return 0; }
static void remove_dyn(ElfCreator *ctor, size_t idx) { size_t cnt; for (cnt = idx; cnt < ctor->dynshdr->sh_size/ctor->dynshdr->sh_entsize; cnt++) { GElf_Dyn *dyn, dyn_mem; if (cnt+1 == ctor->dynshdr->sh_size/ctor->dynshdr->sh_entsize) { memset(&dyn_mem, '\0', sizeof(dyn_mem)); gelf_update_dyn(ctor->dyndata, cnt, &dyn_mem); break; } dyn = gelf_getdyn(ctor->dyndata, cnt+1, &dyn_mem); gelf_update_dyn(ctor->dyndata, cnt, dyn); } ctor->dynshdr->sh_size--; gelf_update_shdr(ctor->dynscn, ctor->dynshdr); update_dyn_cache(ctor); }
int elf_utils_copy(Elf *dest, Elf *source) { GElf_Ehdr ehdr; Elf_Scn *dst_scn, *src_scn; GElf_Shdr shdr; Elf_Data *dst_data, *src_data; size_t segment_count, segndx; GElf_Phdr phdr; ELF_ASSERT(elf_flagelf(dest, ELF_C_SET, ELF_F_LAYOUT)); ELF_ASSERT(gelf_getehdr(source, &ehdr)); ELF_ASSERT(gelf_newehdr(dest, gelf_getclass(source))); ELF_ASSERT(gelf_update_ehdr(dest, &ehdr)); src_scn = NULL; while ((src_scn = elf_nextscn(source, src_scn)) != NULL) { ELF_ASSERT(gelf_getshdr(src_scn, &shdr)); ELF_ASSERT(dst_scn = elf_newscn(dest)); ELF_ASSERT(gelf_update_shdr(dst_scn, &shdr)); src_data = NULL; while ((src_data = elf_getdata(src_scn, src_data)) != NULL) { ELF_ASSERT(dst_data = elf_newdata(dst_scn)); memcpy(dst_data, src_data, sizeof(Elf_Data)); } } ELF_ASSERT(elf_getphdrnum(source, &segment_count) == 0); ELF_ASSERT(gelf_newphdr(dest, segment_count)); for (segndx = 0; segndx < segment_count; segndx++) { ELF_ASSERT(gelf_getphdr(source, segndx, &phdr)); ELF_ASSERT(gelf_update_phdr(dest, segndx, &phdr)); } return 1; failure: return 0; }
int write_shdr(elf_data_t *elf, Elf_Scn *scn, GElf_Shdr *shdr, size_t sidx, char **err) { off_t off; size_t n, shdr_size; void *shdr_buf; if(!gelf_update_shdr(scn, shdr)) { (*err) = "failed to update section header"; return -1; } if(elf->bits == 32) { shdr_buf = elf32_getshdr(scn); shdr_size = sizeof(Elf32_Shdr); } else { shdr_buf = elf64_getshdr(scn); shdr_size = sizeof(Elf64_Shdr); } if(!shdr_buf) { (*err) = "failed to get section header"; return -1; } off = lseek(elf->fd, elf->ehdr.e_shoff + sidx*elf->ehdr.e_shentsize, SEEK_SET); if(off < 0) { (*err) = "lseek failed"; return -1; } n = write(elf->fd, shdr_buf, shdr_size); if(n != shdr_size) { (*err) = "write failed"; return -1; } return 0; }
void elfcreator_copy_scn(ElfCreator *ctor, Elf *src, Elf_Scn *scn) { Elf_Scn *newscn; Elf_Data *indata, *outdata; GElf_Shdr *oldshdr, oldshdr_mem; GElf_Shdr *newshdr, newshdr_mem; newscn = elf_newscn(ctor->elf); newshdr = gelf_getshdr(newscn, &newshdr_mem); oldshdr = gelf_getshdr(scn, &oldshdr_mem); memmove(newshdr, oldshdr, sizeof(*newshdr)); gelf_update_shdr(newscn, newshdr); indata = NULL; while ((indata = elf_getdata(scn, indata)) != NULL) { outdata = elf_newdata(newscn); *outdata = *indata; } if (newshdr->sh_type == SHT_DYNAMIC) update_dyn_cache(ctor); }
static int build_file(Elf *src_elf, GElf_Ehdr *src_ehdr, Cmd_Info *cmd_info) { Elf_Scn *src_scn; Elf_Scn *dst_scn; int new_sh_name = 0; /* to hold the offset for the new */ /* section's name */ Elf *dst_elf = 0; Elf_Data *elf_data; Elf_Data *data; int64_t scn_no, x; size_t no_of_symbols = 0; section_info_table *info; unsigned int c = 0; int fdtmp; GElf_Shdr src_shdr; GElf_Shdr dst_shdr; GElf_Ehdr dst_ehdr; GElf_Off new_offset = 0, r; size_t shnum, shstrndx; if (elf_getshnum(src_elf, &shnum) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } if (elf_getshstrndx(src_elf, &shstrndx) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } if ((fdtmp = open(elftmpfile, O_RDWR | O_TRUNC | O_CREAT, (mode_t)0666)) == -1) { error_message(OPEN_TEMP_ERROR, SYSTEM_ERROR, strerror(errno), prog, elftmpfile); return (FAILURE); } if ((dst_elf = elf_begin(fdtmp, ELF_C_WRITE, (Elf *) 0)) == NULL) { error_message(READ_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog, elftmpfile); (void) close(fdtmp); return (FAILURE); } if (gelf_newehdr(dst_elf, gelf_getclass(src_elf)) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } /* initialize dst_ehdr */ (void) gelf_getehdr(dst_elf, &dst_ehdr); dst_ehdr = *src_ehdr; /* * flush the changes to the ehdr so the * ident array is filled in. */ (void) gelf_update_ehdr(dst_elf, &dst_ehdr); if (src_ehdr->e_phnum != 0) { (void) elf_flagelf(dst_elf, ELF_C_SET, ELF_F_LAYOUT); if (gelf_newphdr(dst_elf, src_ehdr->e_phnum) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } for (x = 0; x < src_ehdr->e_phnum; ++x) { GElf_Phdr dst; GElf_Phdr src; /* LINTED */ (void) gelf_getphdr(src_elf, (int)x, &src); /* LINTED */ (void) gelf_getphdr(dst_elf, (int)x, &dst); (void) memcpy(&dst, &src, sizeof (GElf_Phdr)); /* LINTED */ (void) gelf_update_phdr(dst_elf, (int)x, &dst); } x = location(dst_ehdr.e_phoff, 0, src_elf); if (x == AFTER) new_offset = (GElf_Off)src_ehdr->e_ehsize; } scn_no = 1; while ((src_scn = sec_table[scn_no].scn) != (Elf_Scn *) -1) { info = &sec_table[scn_no]; /* If section should be copied to new file NOW */ if ((info->secno != (GElf_Word)DELETED) && info->secno <= scn_no) { if ((dst_scn = elf_newscn(dst_elf)) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } (void) gelf_getshdr(dst_scn, &dst_shdr); (void) gelf_getshdr(info->scn, &src_shdr); (void) memcpy(&dst_shdr, &src_shdr, sizeof (GElf_Shdr)); /* * Update link and info fields * The sh_link field may have special values so * check them first. */ if ((src_shdr.sh_link >= shnum) || (src_shdr.sh_link == 0)) dst_shdr.sh_link = src_shdr.sh_link; else if ((int)sec_table[src_shdr.sh_link].secno < 0) dst_shdr.sh_link = 0; else dst_shdr.sh_link = sec_table[src_shdr.sh_link].secno; if ((src_shdr.sh_type == SHT_REL) || (src_shdr.sh_type == SHT_RELA)) { if ((src_shdr.sh_info >= shnum) || ((int)sec_table[src_shdr. sh_info].secno < 0)) dst_shdr.sh_info = 0; else dst_shdr.sh_info = sec_table[src_shdr.sh_info].secno; } data = sec_table[scn_no].data; if ((elf_data = elf_newdata(dst_scn)) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } *elf_data = *data; /* SHT_{DYNSYM, SYMTAB} might need some change */ if (((src_shdr.sh_type == SHT_SYMTAB) || (src_shdr.sh_type == SHT_DYNSYM)) && src_shdr.sh_entsize != 0 && (cmd_info->no_of_delete != 0 || cmd_info->no_of_nulled != 0)) { char *new_sym; no_of_symbols = src_shdr.sh_size / src_shdr.sh_entsize; new_sym = malloc(no_of_symbols * src_shdr.sh_entsize); if (new_sym == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, (char *)0, prog); mcs_exit(FAILURE); } /* CSTYLED */ elf_data->d_buf = (void *) new_sym; for (c = 0; c < no_of_symbols; c++) { GElf_Sym csym; (void) gelf_getsym(data, c, &csym); if ((csym.st_shndx < SHN_LORESERVE) && (csym.st_shndx != SHN_UNDEF)) { section_info_table *i; i = &sec_table[csym.st_shndx]; if (((int)i->secno != DELETED) && ((int)i->secno != NULLED)) csym.st_shndx = i->secno; else { if (src_shdr.sh_type == SHT_SYMTAB) /* * The section which * this * symbol relates * to is removed. * There is no way to * specify this fact, * just change the shndx * to 1. */ csym.st_shndx = 1; else { /* * If this is in a * .dynsym, NULL it out. */ csym.st_shndx = 0; csym.st_name = 0; csym.st_value = 0; csym.st_size = 0; csym.st_info = 0; csym.st_other = 0; csym.st_shndx = 0; } } } (void) gelf_update_sym(elf_data, c, &csym); } } /* update SHT_SYMTAB_SHNDX */ if ((src_shdr.sh_type == SHT_SYMTAB_SHNDX) && (src_shdr.sh_entsize != 0) && ((cmd_info->no_of_delete != 0) || (cmd_info->no_of_nulled != 0))) { GElf_Word *oldshndx; GElf_Word *newshndx; uint_t entcnt; entcnt = src_shdr.sh_size / src_shdr.sh_entsize; oldshndx = data->d_buf; newshndx = malloc(entcnt * src_shdr.sh_entsize); if (newshndx == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, (char *)0, prog); mcs_exit(FAILURE); } elf_data->d_buf = (void *)newshndx; for (c = 0; c < entcnt; c++) { if (oldshndx[c] != SHN_UNDEF) { section_info_table *i; i = &sec_table[oldshndx[c]]; if (((int)i->secno != DELETED) && ((int)i->secno != NULLED)) newshndx[c] = i->secno; else newshndx[c] = oldshndx[c]; } else newshndx[c] = oldshndx[c]; } } /* * If the section is to be updated, * do so. */ if (ISCANDIDATE(info->flags)) { if ((GET_LOC(info->flags) == PRIOR) && (((int)info->secno == NULLED) || ((int)info->secno == EXPANDED) || ((int)info->secno == SHRUNK))) { /* * The section is updated, * but the position is not too * good. Need to NULL this out. */ dst_shdr.sh_name = 0; dst_shdr.sh_type = SHT_PROGBITS; if ((int)info->secno != NULLED) { (cmd_info->no_of_moved)++; SET_MOVING(info->flags); } } else { /* * The section is positioned AFTER, * or there are no segments. * It is safe to update this section. */ data = sec_table[scn_no].mdata; *elf_data = *data; dst_shdr.sh_size = elf_data->d_size; } } /* add new section name to shstrtab? */ else if (!Sect_exists && (new_sec_string != NULL) && (scn_no == shstrndx) && (dst_shdr.sh_type == SHT_STRTAB) && ((src_ehdr->e_phnum == 0) || ((x = scn_location(dst_scn, dst_elf)) != IN) || (x != PRIOR))) { size_t sect_len; sect_len = strlen(SECT_NAME); if ((elf_data->d_buf = malloc((dst_shdr.sh_size + sect_len + 1))) == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, (char *)0, prog); mcs_exit(FAILURE); } /* put original data plus new data in section */ (void) memcpy(elf_data->d_buf, data->d_buf, data->d_size); (void) memcpy(&((char *)elf_data->d_buf) [data->d_size], SECT_NAME, sect_len + 1); /* LINTED */ new_sh_name = (int)dst_shdr.sh_size; dst_shdr.sh_size += sect_len + 1; elf_data->d_size += sect_len + 1; } /* * Compute offsets. */ if (src_ehdr->e_phnum != 0) { /* * Compute section offset. */ if (off_table[scn_no] == 0) { if (dst_shdr.sh_addralign != 0) { r = new_offset % dst_shdr.sh_addralign; if (r) new_offset += dst_shdr.sh_addralign - r; } dst_shdr.sh_offset = new_offset; elf_data->d_off = 0; } else { if (nobits_table[scn_no] == 0) new_offset = off_table[scn_no]; } if (nobits_table[scn_no] == 0) new_offset += dst_shdr.sh_size; } } (void) gelf_update_shdr(dst_scn, &dst_shdr); /* flush changes */ scn_no++; } /* * This is the real new section. */ if (!Sect_exists && new_sec_string != NULL) { size_t string_size; string_size = strlen(new_sec_string) + 1; if ((dst_scn = elf_newscn(dst_elf)) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } (void) gelf_getshdr(dst_scn, &dst_shdr); dst_shdr.sh_name = new_sh_name; dst_shdr.sh_type = SHT_PROGBITS; dst_shdr.sh_flags = 0; dst_shdr.sh_addr = 0; if (src_ehdr->e_phnum != NULL) dst_shdr.sh_offset = new_offset; else dst_shdr.sh_offset = 0; dst_shdr.sh_size = string_size + 1; dst_shdr.sh_link = 0; dst_shdr.sh_info = 0; dst_shdr.sh_addralign = 1; dst_shdr.sh_entsize = 0; (void) gelf_update_shdr(dst_scn, &dst_shdr); /* flush changes */ if ((elf_data = elf_newdata(dst_scn)) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } elf_data->d_size = string_size + 1; if ((elf_data->d_buf = (char *) calloc(1, string_size + 1)) == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, (char *)0, prog); mcs_exit(FAILURE); } (void) memcpy(&((char *)elf_data->d_buf)[1], new_sec_string, string_size); elf_data->d_align = 1; new_offset += string_size + 1; } /* * If there are sections which needed to be moved, * then do it here. */ if (cmd_info->no_of_moved != 0) { int cnt; info = &sec_table[0]; for (cnt = 0; cnt < shnum; cnt++, info++) { if ((GET_MOVING(info->flags)) == 0) continue; if ((src_scn = elf_getscn(src_elf, info->osecno)) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } if (gelf_getshdr(src_scn, &src_shdr) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } if ((dst_scn = elf_newscn(dst_elf)) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } if (gelf_getshdr(dst_scn, &dst_shdr) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } dst_shdr = src_shdr; data = info->mdata; dst_shdr.sh_offset = new_offset; /* UPDATE fields */ dst_shdr.sh_size = data->d_size; if ((shnum >= src_shdr.sh_link) || (src_shdr.sh_link == 0)) dst_shdr.sh_link = src_shdr.sh_link; else dst_shdr.sh_link = sec_table[src_shdr.sh_link].osecno; if ((shnum >= src_shdr.sh_info) || (src_shdr.sh_info == 0)) dst_shdr.sh_info = src_shdr.sh_info; else dst_shdr.sh_info = sec_table[src_shdr.sh_info].osecno; (void) gelf_update_shdr(dst_scn, &dst_shdr); if ((elf_data = elf_newdata(dst_scn)) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } (void) memcpy(elf_data, data, sizeof (Elf_Data)); new_offset += data->d_size; } } /* * In the event that the position of the sting table has changed, * as a result of deleted sections, update the ehdr->e_shstrndx. */ if ((shstrndx > 0) && (shnum > 0) && (sec_table[shstrndx].secno < shnum)) { if (sec_table[shstrndx].secno < SHN_LORESERVE) { dst_ehdr.e_shstrndx = sec_table[dst_ehdr.e_shstrndx].secno; } else { Elf_Scn *_scn; GElf_Shdr shdr0; /* * If shstrndx requires 'Extended ELF Sections' * then it is stored in shdr[0].sh_link */ dst_ehdr.e_shstrndx = SHN_XINDEX; if ((_scn = elf_getscn(dst_elf, 0)) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } (void) gelf_getshdr(_scn, &shdr0); shdr0.sh_link = sec_table[shstrndx].secno; (void) gelf_update_shdr(_scn, &shdr0); } } if (src_ehdr->e_phnum != 0) { size_t align = gelf_fsize(dst_elf, ELF_T_ADDR, 1, EV_CURRENT); /* UPDATE location of program header table */ if (location(dst_ehdr.e_phoff, 0, dst_elf) == AFTER) { r = new_offset % align; if (r) new_offset += align - r; dst_ehdr.e_phoff = new_offset; new_offset += dst_ehdr.e_phnum * dst_ehdr.e_phentsize; } /* UPDATE location of section header table */ if ((location(dst_ehdr.e_shoff, 0, src_elf) == AFTER) || ((location(dst_ehdr.e_shoff, 0, src_elf) == PRIOR) && (!Sect_exists && new_sec_string != NULL))) { r = new_offset % align; if (r) new_offset += align - r; dst_ehdr.e_shoff = new_offset; } free(b_e_seg_table); /* * The NOTE segment is the one segment whos * sections might get moved by mcs processing. * Make sure that the NOTE segments offset points * to the .note section. */ if ((notesegndx != -1) && (notesctndx != -1) && (sec_table[notesctndx].secno)) { Elf_Scn * notescn; GElf_Shdr nshdr; notescn = elf_getscn(dst_elf, sec_table[notesctndx].secno); (void) gelf_getshdr(notescn, &nshdr); if (gelf_getclass(dst_elf) == ELFCLASS32) { Elf32_Phdr * ph = elf32_getphdr(dst_elf) + notesegndx; /* LINTED */ ph->p_offset = (Elf32_Off)nshdr.sh_offset; } else { Elf64_Phdr * ph = elf64_getphdr(dst_elf) + notesegndx; ph->p_offset = (Elf64_Off)nshdr.sh_offset; } } } /* copy ehdr changes back into real ehdr */ (void) gelf_update_ehdr(dst_elf, &dst_ehdr); if (elf_update(dst_elf, ELF_C_WRITE) < 0) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } (void) elf_end(dst_elf); (void) close(fdtmp); return (SUCCESS); }
static int ctf_write_elf(ctf_file_t *fp, Elf *src, Elf *dst, int flags) { GElf_Ehdr sehdr, dehdr; Elf_Scn *sscn, *dscn; Elf_Data *sdata, *ddata; GElf_Shdr shdr; int symtab_idx = -1; off_t new_offset = 0; off_t ctfnameoff = 0; int compress = (flags & CTF_ELFWRITE_F_COMPRESS); int *secxlate = NULL; int srcidx, dstidx, pad, i; int curnmoff = 0; int changing = 0; int ret; size_t nshdr, nphdr, strndx; void *strdatabuf = NULL, *symdatabuf = NULL; size_t strdatasz = 0, symdatasz = 0; void *cdata = NULL; size_t elfsize, asize; if ((flags & ~(CTF_ELFWRITE_F_COMPRESS)) != 0) { ret = ctf_set_errno(fp, EINVAL); goto out; } if (gelf_newehdr(dst, gelf_getclass(src)) == 0) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } if (gelf_getehdr(src, &sehdr) == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } (void) memcpy(&dehdr, &sehdr, sizeof (GElf_Ehdr)); if (gelf_update_ehdr(dst, &dehdr) == 0) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } /* * Use libelf to get the number of sections and the string section to * deal with ELF files that may have a large number of sections. We just * always use this to make our live easier. */ if (elf_getphdrnum(src, &nphdr) != 0) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } if (elf_getshdrnum(src, &nshdr) != 0) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } if (elf_getshdrstrndx(src, &strndx) != 0) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } /* * Neither the existing debug sections nor the SUNW_ctf sections (new or * existing) are SHF_ALLOC'd, so they won't be in areas referenced by * program headers. As such, we can just blindly copy the program * headers from the existing file to the new file. */ if (nphdr != 0) { (void) elf_flagelf(dst, ELF_C_SET, ELF_F_LAYOUT); if (gelf_newphdr(dst, nphdr) == 0) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } for (i = 0; i < nphdr; i++) { GElf_Phdr phdr; if (gelf_getphdr(src, i, &phdr) == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } if (gelf_update_phdr(dst, i, &phdr) == 0) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } } } secxlate = ctf_alloc(sizeof (int) * nshdr); for (srcidx = dstidx = 0; srcidx < nshdr; srcidx++) { Elf_Scn *scn = elf_getscn(src, srcidx); GElf_Shdr shdr; char *sname; if (gelf_getshdr(scn, &shdr) == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } sname = elf_strptr(src, strndx, shdr.sh_name); if (sname == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } if (strcmp(sname, CTF_ELF_SCN_NAME) == 0) { secxlate[srcidx] = -1; } else { secxlate[srcidx] = dstidx++; curnmoff += strlen(sname) + 1; } new_offset = (off_t)dehdr.e_phoff; } for (srcidx = 1; srcidx < nshdr; srcidx++) { char *sname; sscn = elf_getscn(src, srcidx); if (gelf_getshdr(sscn, &shdr) == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } if (secxlate[srcidx] == -1) { changing = 1; continue; } dscn = elf_newscn(dst); if (dscn == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } /* * If this file has program headers, we need to explicitly lay * out sections. If none of the sections prior to this one have * been removed, then we can just use the existing location. If * one or more sections have been changed, then we need to * adjust this one to avoid holes. */ if (changing && nphdr != 0) { pad = new_offset % shdr.sh_addralign; if (pad != 0) new_offset += shdr.sh_addralign - pad; shdr.sh_offset = new_offset; } shdr.sh_link = secxlate[shdr.sh_link]; if (shdr.sh_type == SHT_REL || shdr.sh_type == SHT_RELA) shdr.sh_info = secxlate[shdr.sh_info]; sname = elf_strptr(src, strndx, shdr.sh_name); if (sname == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } if ((sdata = elf_getdata(sscn, NULL)) == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } if ((ddata = elf_newdata(dscn)) == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } bcopy(sdata, ddata, sizeof (Elf_Data)); if (srcidx == strndx) { char seclen = strlen(CTF_ELF_SCN_NAME); strdatasz = ddata->d_size + shdr.sh_size + seclen + 1; ddata->d_buf = strdatabuf = ctf_alloc(strdatasz); if (ddata->d_buf == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size); (void) strcpy((caddr_t)ddata->d_buf + shdr.sh_size, CTF_ELF_SCN_NAME); ctfnameoff = (off_t)shdr.sh_size; shdr.sh_size += seclen + 1; ddata->d_size += seclen + 1; if (nphdr != 0) changing = 1; } if (shdr.sh_type == SHT_SYMTAB && shdr.sh_entsize != 0) { int nsym = shdr.sh_size / shdr.sh_entsize; symtab_idx = secxlate[srcidx]; symdatasz = shdr.sh_size; ddata->d_buf = symdatabuf = ctf_alloc(symdatasz); if (ddata->d_buf == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } (void) bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size); for (i = 0; i < nsym; i++) { GElf_Sym sym; short newscn; (void) gelf_getsym(ddata, i, &sym); if (sym.st_shndx >= SHN_LORESERVE) continue; if ((newscn = secxlate[sym.st_shndx]) != sym.st_shndx) { sym.st_shndx = (newscn == -1 ? 1 : newscn); if (gelf_update_sym(ddata, i, &sym) == 0) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } } } } if (gelf_update_shdr(dscn, &shdr) == 0) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } new_offset = (off_t)shdr.sh_offset; if (shdr.sh_type != SHT_NOBITS) new_offset += shdr.sh_size; } if (symtab_idx == -1) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } /* Add the ctf section */ if ((dscn = elf_newscn(dst)) == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } if (gelf_getshdr(dscn, &shdr) == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } shdr.sh_name = ctfnameoff; shdr.sh_type = SHT_PROGBITS; shdr.sh_size = fp->ctf_size; shdr.sh_link = symtab_idx; shdr.sh_addralign = 4; if (changing && nphdr != 0) { pad = new_offset % shdr.sh_addralign; if (pad) new_offset += shdr.sh_addralign - pad; shdr.sh_offset = new_offset; new_offset += shdr.sh_size; } if ((ddata = elf_newdata(dscn)) == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } if (compress != 0) { int err; if (ctf_zopen(&err) == NULL) { ret = ctf_set_errno(fp, err); goto out; } if ((err = ctf_compress(fp, &cdata, &asize, &elfsize)) != 0) { ret = ctf_set_errno(fp, err); goto out; } ddata->d_buf = cdata; ddata->d_size = elfsize; } else { ddata->d_buf = (void *)fp->ctf_base; ddata->d_size = fp->ctf_size; } ddata->d_align = shdr.sh_addralign; if (gelf_update_shdr(dscn, &shdr) == 0) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } /* update the section header location */ if (nphdr != 0) { size_t align = gelf_fsize(dst, ELF_T_ADDR, 1, EV_CURRENT); size_t r = new_offset % align; if (r) new_offset += align - r; dehdr.e_shoff = new_offset; } /* commit to disk */ if (sehdr.e_shstrndx == SHN_XINDEX) dehdr.e_shstrndx = SHN_XINDEX; else dehdr.e_shstrndx = secxlate[sehdr.e_shstrndx]; if (gelf_update_ehdr(dst, &dehdr) == 0) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } if (elf_update(dst, ELF_C_WRITE) < 0) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } ret = 0; out: if (strdatabuf != NULL) ctf_free(strdatabuf, strdatasz); if (symdatabuf != NULL) ctf_free(symdatabuf, symdatasz); if (cdata != NULL) ctf_data_free(cdata, fp->ctf_size); if (secxlate != NULL) ctf_free(secxlate, sizeof (int) * nshdr); return (ret); }
int main (int argc, char *argv[]) { if (argc < 3) error (EXIT_FAILURE, 0, "usage: %s FROMNAME TONAME", argv[0]); elf_version (EV_CURRENT); int infd = open (argv[1], O_RDONLY); if (infd == -1) error (EXIT_FAILURE, errno, "cannot open input file '%s'", argv[1]); Elf *inelf = elf_begin (infd, ELF_C_READ, NULL); if (inelf == NULL) error (EXIT_FAILURE, 0, "problems opening '%s' as ELF file: %s", argv[1], elf_errmsg (-1)); int outfd = creat (argv[2], 0666); if (outfd == -1) error (EXIT_FAILURE, errno, "cannot open output file '%s'", argv[2]); Elf *outelf = elf_begin (outfd, ELF_C_WRITE, NULL); if (outelf == NULL) error (EXIT_FAILURE, 0, "problems opening '%s' as ELF file: %s", argv[2], elf_errmsg (-1)); gelf_newehdr (outelf, gelf_getclass (inelf)); GElf_Ehdr ehdr_mem; GElf_Ehdr *ehdr; gelf_update_ehdr (outelf, (ehdr = gelf_getehdr (inelf, &ehdr_mem))); if (ehdr->e_phnum > 0) { int cnt; if (gelf_newphdr (outelf, ehdr->e_phnum) == 0) error (EXIT_FAILURE, 0, "cannot create program header: %s", elf_errmsg (-1)); for (cnt = 0; cnt < ehdr->e_phnum; ++cnt) { GElf_Phdr phdr_mem; gelf_update_phdr (outelf, cnt, gelf_getphdr (inelf, cnt, &phdr_mem)); } } Elf_Scn *scn = NULL; while ((scn = elf_nextscn (inelf, scn)) != NULL) { Elf_Scn *newscn = elf_newscn (outelf); GElf_Shdr shdr_mem; gelf_update_shdr (newscn, gelf_getshdr (scn, &shdr_mem)); *elf_newdata (newscn) = *elf_getdata (scn, NULL); } elf_flagelf (outelf, ELF_C_SET, ELF_F_LAYOUT); if (elf_update (outelf, ELF_C_WRITE) == -1) error (EXIT_FAILURE, 0, "elf_update failed: %s", elf_errmsg (-1)); close (outfd); return 0; }
static Dwfl_Error relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr, size_t shstrndx, struct reloc_symtab_cache *reloc_symtab, Elf_Scn *scn, GElf_Shdr *shdr, Elf_Scn *tscn, bool debugscn, bool partial) { /* First, fetch the name of the section these relocations apply to. */ GElf_Shdr tshdr_mem; GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem); const char *tname = elf_strptr (relocated, shstrndx, tshdr->sh_name); if (tname == NULL) return DWFL_E_LIBELF; if (unlikely (tshdr->sh_type == SHT_NOBITS) || unlikely (tshdr->sh_size == 0)) /* No contents to relocate. */ return DWFL_E_NOERROR; if (debugscn && ! ebl_debugscn_p (mod->ebl, tname)) /* This relocation section is not for a debugging section. Nothing to do here. */ return DWFL_E_NOERROR; /* Fetch the section data that needs the relocations applied. */ Elf_Data *tdata = elf_rawdata (tscn, NULL); if (tdata == NULL) return DWFL_E_LIBELF; /* Apply one relocation. Returns true for any invalid data. */ Dwfl_Error relocate (GElf_Addr offset, const GElf_Sxword *addend, int rtype, int symndx) { /* First see if this is a reloc we can handle. If we are skipping it, don't bother resolving the symbol. */ if (unlikely (rtype == 0)) /* In some odd situations, the linker can leave R_*_NONE relocs behind. This is probably bogus ld -r behavior, but the only cases it's known to appear in are harmless: DWARF data referring to addresses in a section that has been discarded. So we just pretend it's OK without further relocation. */ return DWFL_E_NOERROR; Elf_Type type = ebl_reloc_simple_type (mod->ebl, rtype); if (unlikely (type == ELF_T_NUM)) return DWFL_E_BADRELTYPE; /* First, resolve the symbol to an absolute value. */ GElf_Addr value; if (symndx == STN_UNDEF) /* When strip removes a section symbol referring to a section moved into the debuginfo file, it replaces that symbol index in relocs with STN_UNDEF. We don't actually need the symbol, because those relocs are always references relative to the nonallocated debugging sections, which start at zero. */ value = 0; else { GElf_Sym sym; GElf_Word shndx; Dwfl_Error error = relocate_getsym (mod, relocated, reloc_symtab, symndx, &sym, &shndx); if (unlikely (error != DWFL_E_NOERROR)) return error; if (shndx == SHN_UNDEF || shndx == SHN_COMMON) { /* Maybe we can figure it out anyway. */ error = resolve_symbol (mod, reloc_symtab, &sym, shndx); if (error != DWFL_E_NOERROR && !(error == DWFL_E_RELUNDEF && shndx == SHN_COMMON)) return error; } value = sym.st_value; } /* These are the types we can relocate. */ #define TYPES DO_TYPE (BYTE, Byte); DO_TYPE (HALF, Half); \ DO_TYPE (WORD, Word); DO_TYPE (SWORD, Sword); \ DO_TYPE (XWORD, Xword); DO_TYPE (SXWORD, Sxword) size_t size; switch (type) { #define DO_TYPE(NAME, Name) \ case ELF_T_##NAME: \ size = sizeof (GElf_##Name); \ break TYPES; #undef DO_TYPE default: return DWFL_E_BADRELTYPE; } if (offset + size > tdata->d_size) return DWFL_E_BADRELOFF; #define DO_TYPE(NAME, Name) GElf_##Name Name; union { TYPES; } tmpbuf; #undef DO_TYPE Elf_Data tmpdata = { .d_type = type, .d_buf = &tmpbuf, .d_size = size, .d_version = EV_CURRENT, }; Elf_Data rdata = { .d_type = type, .d_buf = tdata->d_buf + offset, .d_size = size, .d_version = EV_CURRENT, }; /* XXX check for overflow? */ if (addend) { /* For the addend form, we have the value already. */ value += *addend; switch (type) { #define DO_TYPE(NAME, Name) \ case ELF_T_##NAME: \ tmpbuf.Name = value; \ break TYPES; #undef DO_TYPE default: abort (); } } else { /* Extract the original value and apply the reloc. */ Elf_Data *d = gelf_xlatetom (relocated, &tmpdata, &rdata, ehdr->e_ident[EI_DATA]); if (d == NULL) return DWFL_E_LIBELF; assert (d == &tmpdata); switch (type) { #define DO_TYPE(NAME, Name) \ case ELF_T_##NAME: \ tmpbuf.Name += (GElf_##Name) value; \ break TYPES; #undef DO_TYPE default: abort (); } } /* Now convert the relocated datum back to the target format. This will write into rdata.d_buf, which points into the raw section data being relocated. */ Elf_Data *s = gelf_xlatetof (relocated, &rdata, &tmpdata, ehdr->e_ident[EI_DATA]); if (s == NULL) return DWFL_E_LIBELF; assert (s == &rdata); /* We have applied this relocation! */ return DWFL_E_NOERROR; } /* Fetch the relocation section and apply each reloc in it. */ Elf_Data *reldata = elf_getdata (scn, NULL); if (reldata == NULL) return DWFL_E_LIBELF; Dwfl_Error result = DWFL_E_NOERROR; bool first_badreltype = true; inline void check_badreltype (void) { if (first_badreltype) { first_badreltype = false; if (ebl_get_elfmachine (mod->ebl) == EM_NONE) /* This might be because ebl_openbackend failed to find any libebl_CPU.so library. Diagnose that clearly. */ result = DWFL_E_UNKNOWN_MACHINE; } } size_t nrels = shdr->sh_size / shdr->sh_entsize; size_t complete = 0; if (shdr->sh_type == SHT_REL) for (size_t relidx = 0; !result && relidx < nrels; ++relidx) { GElf_Rel rel_mem, *r = gelf_getrel (reldata, relidx, &rel_mem); if (r == NULL) return DWFL_E_LIBELF; result = relocate (r->r_offset, NULL, GELF_R_TYPE (r->r_info), GELF_R_SYM (r->r_info)); check_badreltype (); if (partial) switch (result) { case DWFL_E_NOERROR: /* We applied the relocation. Elide it. */ memset (&rel_mem, 0, sizeof rel_mem); gelf_update_rel (reldata, relidx, &rel_mem); ++complete; break; case DWFL_E_BADRELTYPE: case DWFL_E_RELUNDEF: /* We couldn't handle this relocation. Skip it. */ result = DWFL_E_NOERROR; break; default: break; } } else for (size_t relidx = 0; !result && relidx < nrels; ++relidx) { GElf_Rela rela_mem, *r = gelf_getrela (reldata, relidx, &rela_mem); if (r == NULL) return DWFL_E_LIBELF; result = relocate (r->r_offset, &r->r_addend, GELF_R_TYPE (r->r_info), GELF_R_SYM (r->r_info)); check_badreltype (); if (partial) switch (result) { case DWFL_E_NOERROR: /* We applied the relocation. Elide it. */ memset (&rela_mem, 0, sizeof rela_mem); gelf_update_rela (reldata, relidx, &rela_mem); ++complete; break; case DWFL_E_BADRELTYPE: case DWFL_E_RELUNDEF: /* We couldn't handle this relocation. Skip it. */ result = DWFL_E_NOERROR; break; default: break; } } if (likely (result == DWFL_E_NOERROR)) { if (!partial || complete == nrels) /* Mark this relocation section as being empty now that we have done its work. This affects unstrip -R, so e.g. it emits an empty .rela.debug_info along with a .debug_info that has already been fully relocated. */ nrels = 0; else if (complete != 0) { /* We handled some of the relocations but not all. We've zeroed out the ones we processed. Now remove them from the section. */ size_t next = 0; if (shdr->sh_type == SHT_REL) for (size_t relidx = 0; relidx < nrels; ++relidx) { GElf_Rel rel_mem; GElf_Rel *r = gelf_getrel (reldata, relidx, &rel_mem); if (r->r_info != 0 || r->r_offset != 0) { if (next != relidx) gelf_update_rel (reldata, next, r); ++next; } } else for (size_t relidx = 0; relidx < nrels; ++relidx) { GElf_Rela rela_mem; GElf_Rela *r = gelf_getrela (reldata, relidx, &rela_mem); if (r->r_info != 0 || r->r_offset != 0 || r->r_addend != 0) { if (next != relidx) gelf_update_rela (reldata, next, r); ++next; } } nrels = next; } shdr->sh_size = reldata->d_size = nrels * shdr->sh_entsize; gelf_update_shdr (scn, shdr); } return result; } Dwfl_Error internal_function __libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile, bool debug) { assert (mod->e_type == ET_REL); GElf_Ehdr ehdr_mem; const GElf_Ehdr *ehdr = gelf_getehdr (debugfile, &ehdr_mem); if (ehdr == NULL) return DWFL_E_LIBELF; size_t d_shstrndx; if (elf_getshdrstrndx (debugfile, &d_shstrndx) < 0) return DWFL_E_LIBELF; RELOC_SYMTAB_CACHE (reloc_symtab); /* Look at each section in the debuginfo file, and process the relocation sections for debugging sections. */ Dwfl_Error result = DWFL_E_NOERROR; Elf_Scn *scn = NULL; while (result == DWFL_E_NOERROR && (scn = elf_nextscn (debugfile, scn)) != NULL) { GElf_Shdr shdr_mem; GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); if ((shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA) && shdr->sh_size != 0) { /* It's a relocation section. */ Elf_Scn *tscn = elf_getscn (debugfile, shdr->sh_info); if (unlikely (tscn == NULL)) result = DWFL_E_LIBELF; else result = relocate_section (mod, debugfile, ehdr, d_shstrndx, &reloc_symtab, scn, shdr, tscn, debug, !debug); } } return result; }
int main( int argc, char *argv[]) { int fd, cmd; char *scn_name; Elf *elf; GElf_Ehdr ehdr; Elf_Scn *scn; GElf_Shdr shdr; Elf_Data *data; GElf_Dyn dyn; if(argc != 3) error(EXIT_FAILURE, 0, "Usage: %s <elf> <ld.so>", argv[0]); if(elf_version(EV_CURRENT) == EV_NONE) error(EXIT_FAILURE, 0, "Library out of date."); if((fd = open(argv[1], O_RDWR)) == -1) error(EXIT_FAILURE, 0, "Failed open file."); if((elf = elf_begin(fd, ELF_C_RDWR_MMAP, elf)) != NULL) { if(gelf_getehdr(elf,&ehdr) != NULL) { scn = NULL; while((scn = elf_nextscn(elf, scn)) != NULL) { gelf_getshdr(scn, &shdr); scn_name = elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name); if(strcmp(scn_name, ".interp")) continue; printf("Section name: %s\n", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name)); if((data = elf_getdata(scn, data)) != NULL) { printf("Old ld.so: %s\n", (char *)data->d_buf); printf("Data size: %zu\n", data->d_size); /* printf( "Data:\t\t%s\nType:\t\t%d\nSize:\t\t%lu\n" "Off:\t\t%lu\nAlign:\t\t%lu\nVersion:\t%u\n", (char *)data->d_buf, data->d_type, data->d_size, data->d_off, data->d_align, data->d_version ); */ if(data->d_size >= strlen(argv[2])) { memset(data->d_buf, 0, data->d_size); strncpy(data->d_buf, argv[2], data->d_size); if(!gelf_update_shdr(scn, &shdr)) { elf_end(elf); close(fd); error(EXIT_FAILURE, 0, "\tELF ERROR: gelf_update_shdr(): %s", elf_errmsg(elf_errno())); } } else { elf_end(elf); close(fd); error(EXIT_FAILURE, 0, "\tld.so path too long: max=%zu", data->d_size); } printf( "New ld.so: %s\n", (char *)data->d_buf); /* printf( "Data:\t\t%s\nType:\t\t%d\nSize:\t\t%lu\n" "Off:\t\t%lu\nAlign:\t\t%lu\nVersion:\t%u\n", (char *)data->d_buf, data->d_type, data->d_size, data->d_off, data->d_align, data->d_version ); */ } } } } elf_end(elf); close(fd); }