/** * Inject a section from ET_REL object into ET_EXEC * @param file * @param sect * @param mod * @return */ static int elfsh_inject_etrel_section(elfshobj_t *file, elfshsect_t *sect, u_int mod) { elfsh_Shdr hdr; elfshsect_t *enew; char *newname; char writable; int mode; char *data; u_int modulo; elfshsect_t *plt; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); if (elfsh_dynamic_file(file) && NULL == (plt = elfsh_get_plt(file, NULL))) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to get PLT", -1); /* else create a new section */ hdr = elfsh_create_shdr(0, sect->shdr->sh_type, sect->shdr->sh_flags, 0, 0, sect->shdr->sh_size, 0, 0, 0, 0); XALLOC(__FILE__, __FUNCTION__, __LINE__,newname, strlen(sect->parent->name) + strlen(sect->name) + 2, -1); sprintf(newname, "%s%s", sect->parent->name, sect->name); enew = elfsh_create_section(newname); /* Copy the data */ XALLOC(__FILE__, __FUNCTION__, __LINE__,data, sect->shdr->sh_size, -1); memcpy(data, sect->data, sect->shdr->sh_size); /* Inject new section by top or after bss depending on its type */ writable = elfsh_get_section_writableflag(sect->shdr); /* FreeBSD is incompatible with pre-interp injection */ ELFSH_SELECT_INJECTION(file,writable,mode); if (mode == ELFSH_DATA_INJECTION) modulo = sizeof(eresi_Addr); else { /* modulo = mod; (to be uncommented one day) */ //modulo = elfsh_get_pagesize(file); modulo = sizeof(eresi_Addr); } #if __DEBUG_RELADD__ printf("[DEBUG_RELADD] Mapping new section %s with data = %p \n", enew->name, data); #endif if (elfsh_insert_mapped_section(file, enew, hdr, data, mode, modulo) < 0) goto bad; enew = elfsh_get_section_by_name(file, newname, NULL, NULL, NULL); if (enew == NULL) goto bad; PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); bad: XFREE(__FILE__, __FUNCTION__, __LINE__,newname); PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to inject ET_REL section", -1); }
/** * @brief Copy the PLT of an ET_EXEC object for the ALTPLT technique. * and the GOT of an ET_EXEC object for the ALTGOT technique. * @param file Host file. * @param mod Always inject sections with size being a multiple of mod. * @return Success (0) or Error (-1). */ int elfsh_relink_plt(elfshobj_t *file, u_int mod) { elfshsect_t *got; elfshsect_t *plt; elfshsect_t *symtab; elfshsect_t *dynsym; elfshsect_t *prolog; elfshsect_t *extplt = NULL; elfshsect_t *altgot = NULL; /* shut the nice talkative */ elfshsect_t *enew = NULL; /* compiler also know as gcc */ elfsh_Shdr hdr; elfsh_Sym *sym; elfsh_Sym newsym; char buf[BUFSIZ]; u_int off; u_int entsz; int mode; eresi_Addr addr; char *prologdata; u_int sz; char *name; u_char ostype; eresi_Addr diff; u_int extplt_size; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); /* Get PLT */ if (file->secthash[ELFSH_SECTION_ALTPLT] != NULL) PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); plt = elfsh_get_plt(file, NULL); if (NULL == plt) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "PLT section not found", -1); entsz = elfsh_get_pltentsz(file); if (entsz < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Failed to get PLT entry size", -1); /* Get GOT (recent ld call it .got.plt) */ got = elfsh_get_gotsct(file); if (NULL == got) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "GOT section not found", -1); /* Get symtabs */ if (NULL == elfsh_get_dynsymtab(file, NULL)) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "DYNSYM not found", -1); if (NULL == elfsh_get_symtab(file, NULL)) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "SYMTAB not found", -1); /* Some fingerprint */ ostype = elfsh_get_ostype(file); if (ostype == ELFSH_OS_ERROR) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid OS target", -1); /* Insert alternative .plt */ dynsym = file->secthash[ELFSH_SECTION_DYNSYM]; symtab = file->secthash[ELFSH_SECTION_SYMTAB]; /* FreeBSD and BeoS is incompatible with pre-interp injection */ /* Solaris needs self-mutating code for ALTPLT technique */ /* %gp offsets on ALPHA/MIPS requires data injection */ ELFSH_SELECT_INJECTION(file,NULL,mode); /* Map .alt.plt.prolog on ALPHA, or .alt.got.prolog on MIPS */ if (FILE_IS_MIPS(file) || FILE_IS_ALPHA64(file)) { if (FILE_IS_MIPS(file)) { name = ELFSH_SECTION_NAME_ALTGOTPROLOG; sz = 28; } else { name = ELFSH_SECTION_NAME_ALTPLTPROLOG; sz = 48; } prolog = elfsh_create_section(name); hdr = elfsh_create_shdr(0, SHT_PROGBITS, SHF_EXECINSTR | SHF_ALLOC, 0, 0, sz, 0, 0, 0, 0); XALLOC(__FILE__, __FUNCTION__, __LINE__, prologdata, sz, -1); if (elfsh_insert_mapped_section(file, prolog, hdr, prologdata, mode, mod) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, ".alt.{plt,got}.prolog insertion failed", -1); enew = elfsh_get_section_by_name(file, name, NULL, NULL, NULL); if (enew == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, ".alt.{plt,got}.prolog insertion failed", -1); file->secthash[ELFSH_SECTION_ALTPLTPROLOG] = enew; } /* Map .alt.plt (or .pad.got on MIPS) On MIPS we use .pad.got in order to align .alt.got on a 0x1000 bound boundary. On ALPHA and SPARC, .alt.plt will be relocated instead of .plt */ sz = plt->shdr->sh_size; if (FILE_IS_MIPS(file)) { addr = enew->shdr->sh_addr + enew->shdr->sh_size; if ((addr - (got->shdr->sh_addr)) % 1024) sz = 1024 - ((addr - (got->shdr->sh_addr)) % 1024); XALLOC(__FILE__, __FUNCTION__, __LINE__, prologdata, sz, -1); memset(prologdata, 0x00, sz); name = ELFSH_SECTION_NAME_PADGOT; } else { XALLOC(__FILE__, __FUNCTION__, __LINE__, prologdata, sz, -1); memcpy(prologdata, elfsh_readmem(plt), sz); name = ELFSH_SECTION_NAME_ALTPLT; } enew = elfsh_create_section(name); hdr = elfsh_create_shdr(0, SHT_PROGBITS, SHF_EXECINSTR | SHF_ALLOC, 0, 0, sz, 0, 0, 0, 0); if (elfsh_insert_mapped_section(file, enew, hdr, prologdata, mode, mod) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, ".alt.plt|.pad.got insertion failed", -1); enew = elfsh_get_section_by_name(file, name, NULL, NULL, NULL); if (enew == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, ".alt.plt|.pad.got insertion failed", -1); file->secthash[ELFSH_SECTION_ALTPLT] = enew; /* Map .alt.got (all architectures except SPARC) */ /* On IA32, remap GOT with a doubled size for non-present symbol resolving */ if (FILE_IS_MIPS(file) || FILE_IS_ALPHA64(file) || FILE_IS_IA32(file)) { sz = (FILE_IS_MIPS(file) ? got->shdr->sh_size : FILE_IS_IA32(file) ? got->shdr->sh_size * 4 : plt->shdr->sh_size / elfsh_get_pltentsz(file) * sizeof(eresi_Addr)); altgot = elfsh_create_section(ELFSH_SECTION_NAME_ALTGOT); hdr = elfsh_create_shdr(0, SHT_PROGBITS, SHF_ALLOC | SHF_WRITE, 0, 0, sz, 0, 0, 0, sizeof(eresi_Addr)); XALLOC(__FILE__, __FUNCTION__, __LINE__, prologdata, sz, -1); memcpy(prologdata, elfsh_readmem(got), got->shdr->sh_size); if (elfsh_insert_mapped_section(file, altgot, hdr, prologdata, ELFSH_DATA_INJECTION, mod) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, ".alt.got insertion failed", -1); altgot = elfsh_get_section_by_name(file, ELFSH_SECTION_NAME_ALTGOT, NULL, NULL, NULL); if (altgot == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, ".alt.got insertion failed", -1); file->secthash[ELFSH_SECTION_ALTGOT] = altgot; altgot->curend = got->shdr->sh_size; memset(elfsh_readmem(altgot) + got->shdr->sh_size, 0x00, got->shdr->sh_size); altgot->shdr->sh_entsize = sizeof(eresi_Addr); } /* Insert EXTPLT in order to be able to resolve non present symbols */ if (FILE_IS_IA32(file)) { extplt_size = plt->shdr->sh_size * 2; extplt = elfsh_create_section(ELFSH_SECTION_NAME_EXTPLT); hdr = elfsh_create_shdr(0, SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, 0, 0, extplt_size, 0, 0, 0, 0); XALLOC(__FILE__, __FUNCTION__, __LINE__, prologdata, plt->shdr->sh_size, -1); memcpy(prologdata, elfsh_readmem(plt), plt->shdr->sh_size); if (elfsh_insert_mapped_section(file, extplt, hdr, prologdata, mode, mod) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, ".ext.plt insertion failed", -1); extplt = elfsh_get_section_by_name(file, ELFSH_SECTION_NAME_EXTPLT, NULL, NULL, NULL); if (extplt == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, ".ext.plt insertion failed", -1); file->secthash[ELFSH_SECTION_EXTPLT] = extplt; extplt->curend = elfsh_get_first_pltentsz(file); } /* Loop on .plt and inject 'old_symnam' symbols */ for (off = 0; off < plt->shdr->sh_size; off += entsz) { /* SPARC does not have ALTGOT */ if (FILE_IS_MIPS(file) || FILE_IS_ALPHA64(file) || FILE_IS_IA32(file)) diff = (uint32_t) altgot->shdr->sh_addr - got->shdr->sh_addr; else diff = 0; /* Special case for the first plt entry */ if (off == 0 && elfsh_altplt_firstent(enew, &off, symtab, file, extplt, plt, diff) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "ALTPLT on first entry failed", -1); else if (off == 0) continue; /* Get the existing symbol name for this plt entry ... */ sym = elfsh_get_sym_by_value(elfsh_readmem(dynsym), dynsym->shdr->sh_size / sizeof(elfsh_Sym), plt->shdr->sh_addr + off, NULL, ELFSH_EXACTSYM); /* New versions of ld do not fill the vaddr of dynamic symbols, do it ourself. Do not insert old symbol in emergency cases */ if (sym == NULL) { if ((sym = elfsh_restore_dynsym(file, plt, off, dynsym)) == NULL) continue; name = elfsh_get_dynsymbol_name(file, sym); /* __gmon_start__ should not be resolved if it was not already done by gcc */ if (name && !strcmp(name, "__gmon_start__")) sym->st_value = 0x0; } /* ... and we inject the 'old' occurence symbol pointing in .alt.plt (.plt on MIPS) */ if (!FILE_IS_MIPS(file)) addr = enew->shdr->sh_addr + off; else addr = plt->shdr->sh_addr + off; #if __BYTE_ORDER == __BIG_ENDIAN if (file->hdr->e_ident[EI_DATA] == ELFDATA2LSB) #elif __BYTE_ORDER == __LITTLE_ENDIAN if (file->hdr->e_ident[EI_DATA] == ELFDATA2MSB) #else #error Unexpected __BYTE_ORDER ! #endif addr = swaplong(addr); /* Injection */ name = elfsh_get_dynsymbol_name(file, sym); newsym = elfsh_create_symbol(addr, entsz, STT_FUNC, 0, 0, 0); snprintf(buf, BUFSIZ, "old_%s", name); if (elfsh_insert_symbol(symtab, &newsym, buf) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "old_* symbol injection failed", -1); #if __DEBUG_COPYPLT__ printf("[DEBUG_COPYPLT] Symbol at .plt + %u injected" " succesfully (%s) \n", off, buf); #endif /* On ALPHA, shift the relocation offset from .got to .alt.got to avoid hooks removing when calling back the original function. */ if (FILE_IS_ALPHA64(file) && elfsh_shift_alpha_relocs(file, name, altgot, off) < 0) continue; /* Reencode the PLT entry to use the alternative GOT */ /* This condition is for compatibility with other archs where EXTPLT is not yet supported. For those we do not enter the hook */ if (FILE_IS_IA32(file)) { diff = (eresi_Addr) altgot->shdr->sh_addr - got->shdr->sh_addr; elfsh_encodeplt(file, plt, diff, off); if (file->hdr->e_type == ET_DYN) elfsh_encodeplt(file, file->secthash[ELFSH_SECTION_ALTPLT], diff, off); diff = (eresi_Addr) altgot->shdr->sh_addr - got->shdr->sh_addr + got->shdr->sh_size; elfsh_encodeplt(file, extplt, diff, off); } } /* Activate ALTGOT */ if (elfsh_redirect_pltgot(file, altgot, got, plt, enew) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "PLTGOT redirection failed", -1); /* Activate EXTPLT */ if (elfsh_extplt_mirror_sections(file) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Section mirroring failed", -1); #if __DEBUG_COPYPLT__ printf("[DEBUG_COPYPLT] Section Mirrored Successfully ! \n"); #endif /* Everything is 0k4y */ if (elfsh_sync_sorted_symtab(symtab) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "symtab synchronisation failed", -1); if (elfsh_sync_sorted_symtab(dynsym) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "dynsym synchronisation failed", -1); elfsh_sync_sectnames(file); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); }
/** * Relocate the just injected section * @param enew * @param reltab * @param stage * @return */ static int elfsh_relocate_etrel_section(elfshsect_t *enew, elfshsect_t *reltab, u_char stage) { elfsh_Rel *cur; volatile u_int index; elfsh_Sym *sym; volatile u_int size; eresi_Addr *dword; eresi_Addr addr; char *name; char tmpname[BUFSIZ]; elfshsect_t *sect; u_int entsz; elfshsect_t *plt; void *data; elfsh_Half symtype; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); /* ET_REL object is not mapped we use unconditionaly the ondisk relocation tables for such operation */ data = reltab->data; #if __DEBUG_RELADD__ fprintf(stderr, "[DEBUG_RELADD] Using reloc table from %s [%s] data at %p \n", reltab->parent->name, reltab->name, data); #endif /* Loop on the relocation table entries */ size = (reltab->shdr->sh_type == SHT_RELA ? sizeof(elfsh_Rela) : sizeof(elfsh_Rel)); size = reltab->shdr->sh_size / size; plt = elfsh_get_plt(enew->parent, NULL); if (NULL == plt && elfsh_dynamic_file(enew->parent)) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to get plt", -1); entsz = elfsh_get_pltentsz(enew->parent); if (entsz < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to get pltentsz", -1); for (index = 0; index < size; index++) { #if __DEBUG_RELADD__ fprintf(stderr, "[DEBUG_RELADD] relocation loop stage %u for section %s index %u \n", stage, enew->name, index); #endif /* We try a enew relocation now that the ET_REL dependence is mapped */ retry: /* Get symbol value in ET_REL */ cur = (reltab->shdr->sh_type == SHT_RELA ? (void *) (((elfsh_Rela *) data) + index) : (void *) (((elfsh_Rel *) data) + index)); sym = elfsh_get_symbol_from_reloc(reltab->parent, cur); name = elfsh_get_symname_from_reloc(reltab->parent, cur); if (sym == NULL || name == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to find symbol in ET_REL", -1); /* Grab a pointer on the dword that need to be relocated */ dword = (eresi_Addr *) ((char *) elfsh_readmem(enew) + cur->r_offset); /* ** If symbol type is NOTYPE, we use ET_EXEC symtab, else if ** symbol link is COMMON, we use ET_REL symbol inserted in ET_EXEC ** during BSS sizescan in bss.c:elfsh_find_bsslen() */ symtype = elfsh_get_symbol_type(sym); if (elfsh_get_symbol_bind(sym) != STB_LOCAL && /* patch BEOS */ (symtype == STT_NOTYPE || elfsh_get_symbol_link(sym) == SHN_COMMON)) { if (stage == ELFSH_RELOC_STAGE2 && !strstr(name, "old_")) continue; /* If the symbol is not found and we are still in the first stage relocation, just pass it */ sym = elfsh_get_metasym_by_name(enew->parent, name); if (!sym) { switch (elfsh_find_relocsym(enew, reltab, &sym, name, stage, symtype)) { case 2: #if __DEBUG_STATIC__ fprintf(stderr, "[DEBUG_STATIC] RETRY\n"); #endif goto retry; break; case 0: continue; case 1: break; case -1: default: PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to satisfy symbol in ET_REL", -1); } } addr = sym->st_value; #if __DEBUG_RELADD__ fprintf(stderr, "[DEBUG_RELADD] Relocate using existing symbol %-20s " AFMT "]\n", name, (eresi_Addr) addr); #endif } /* Compute addr giving the injected section's vaddr in ET_EXEC */ else { /* All the following relocs are computed in stage 1 */ if (stage == ELFSH_RELOC_STAGE2) continue; /* Find target section in ET_REL */ sect = elfsh_get_section_by_index(reltab->parent, sym->st_shndx, NULL, NULL); if (sect == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Cant find extracted section in ET_REL", -1); #if __DEBUG_RELADD__ fprintf(stderr, "[DEBUG_RELADD] Found -%s- section (idx = %u), now looking at " "injected base address\n", sect->name, sect->index); #endif /* Find corresponding inserted section in ET_EXEC */ snprintf(tmpname, sizeof(tmpname), "%s%s", reltab->parent->name, sect->name); sect = elfsh_get_section_by_name(enew->parent, tmpname, NULL, NULL, NULL); if (sect == NULL) { #if __DEBUG_RELADD__ elfsh_print_sectlist(reltab->parent, "HEH"); fprintf(stderr, "[DEBUG_RELADD] Did not found %s section (sym = %s) \n", tmpname, name); #endif PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Cant find inserted section in ET_EXEC", -1); } /* Compute pointer value */ addr = sect->shdr->sh_addr; addr += ((elfsh_get_symbol_type(sym) == STT_SECTION && !FILE_IS_SPARC(sect->parent) && !FILE_IS_ALPHA64(sect->parent) && !FILE_IS_MIPS(sect->parent)) ? *dword : sym->st_value); #if __DEBUG_RELADD__ fprintf(stderr, "[DEBUG_RELADD] Relocate using section %-20s base [-> " AFMT "] \n", sect->name, (eresi_Addr) addr); #endif } /* Perform relocation */ if (elfsh_relocate_entry(enew, cur, dword, addr, reltab) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to relocate entry", -1); } PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); }
/** * Load all the part of the binary. * This function should not be used by e2dbg * @param file * @return */ int elfsh_read_obj(elfshobj_t *file) { elfshsect_t *actual; int index; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); if (file->read) PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); if (file->sht == NULL && NULL == elfsh_get_sht(file, NULL)) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to grab SHT", -1); if (NULL == elfsh_get_pht(file, NULL) && file->hdr->e_type != ET_REL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to grab PHT", -1); #if __DEBUG_MAP__ puts("[DEBUG:read_obj] Loading all known typed sections\n"); #endif /* Fill multiple relocation sections */ for (index = 0; NULL != (actual = elfsh_get_reloc(file, index, NULL)); index++); /* ** Load sections placed after symtab ** Added for Solaris */ elfsh_get_comments(file); elfsh_get_dwarf(file); elfsh_get_stab(file, NULL); if (file->hdr->e_type == ET_CORE) { elfsh_get_core_notes(file); goto out; } /* ** We cannot use simply elfsh_get_anonymous_section() here ** because the object's section hash ptrs would not be filled. */ elfsh_get_symtab(file, NULL); /* Fixup stuffs in the SHT */ elfsh_fixup(file); elfsh_get_dynsymtab(file, NULL); elfsh_get_stab(file, NULL); elfsh_get_dynamic(file, NULL); elfsh_get_ctors(file, NULL); elfsh_get_dtors(file, NULL); elfsh_get_got(file, NULL); elfsh_get_interp(file); elfsh_get_versymtab(file, NULL); elfsh_get_verneedtab(file, NULL); elfsh_get_verdeftab(file, NULL); elfsh_get_hashtable(file, NULL); //elfsh_get_comments(file); elfsh_get_plt(file, NULL); /* Fill the multiple notes sections */ for (index = 0; NULL != elfsh_get_notes(file, index); index++); /* Loop on the section header table and load all unknown-typed sections */ for (actual = file->sectlist; actual; actual = actual->next) { /* Fix first section size */ if (actual->shdr->sh_size == 0 && actual->next && actual->next->shdr->sh_offset != actual->shdr->sh_offset && actual->next->shdr->sh_addr != actual->shdr->sh_addr) actual->shdr->sh_size = actual->next->shdr->sh_offset - actual->shdr->sh_offset; /* If the section data has to be loaded, load it */ /* In case of bss, only load if BSS data is inserted in the file */ if (actual->data == NULL && actual->shdr->sh_size) { if ((actual->shdr->sh_type == SHT_NOBITS && actual->shdr->sh_offset == actual->next->shdr->sh_offset) || (actual->next != NULL && actual->next->shdr->sh_offset == actual->shdr->sh_offset)) continue; #if __DEBUG_MAP__ printf("[LIBELFSH] Loading anonymous section %15s \n", elfsh_get_section_name(file, actual)); #endif elfsh_get_anonymous_section(file, actual); } } /* Fixup various symbols like dynamic ones that are NULL */ /* Non fatal error */ if (file->secthash[ELFSH_SECTION_DYNSYM]) elfsh_fixup_dynsymtab(file->secthash[ELFSH_SECTION_DYNSYM]); out: /* We close the file descriptor after file mapping so we can open more files */ if (file->fd >= 0) { #if __DEBUG_MAP__ printf("[LIBELFSH] Closing descriptor %d \n", file->fd); #endif XCLOSE(file->fd, -1); /* neutralize file descriptor */ file->fd = -1; } PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); }