/* * Format an input section descriptor name for output, in the format * [ndx]name * If possible, a user supplied fixed size buffer is used. Failing that, * dynamic memory is allocated, which must be freed by the caller. * * entry: * [dbg_fmt_isec_name2]: name, scnndx - Name and section index * [dbg_fmt_isec_name]: isp - Input section descriptor giving name * and index. * * buf - Caller supplied buffer * alloc_mem - Address of pointer to be set to address of allocated * memory, or NULL if no memory is allocated. * * exit: * A pointer to the formatted string is returned. If the supplied buffer * was sufficient, *alloc_mem is set to NULL. If memory was allocated, * *alloc_mem references it. The caller must free this memory after use. */ const char * dbg_fmt_isec_name2(const char *name, Word scnndx, dbg_isec_name_buf_t buf, char **alloc_mem) { int cnt; /* * If the section index is 0, it's not a real section. * Just use the name as is. */ if (scnndx == 0) { *alloc_mem = NULL; return (name); } /* Format into the fixed buffer */ cnt = snprintf(buf, sizeof (dbg_isec_name_buf_t), MSG_ORIG(MSG_FMT_ISEC_NAME), EC_WORD(scnndx), name); /* * If the name was too long, try to allocate a dynamic buffer. * Failing that, fall through and use the clipped one already * formatted into buf, as that's better than nothing. */ if ((cnt >= sizeof (dbg_isec_name_buf_t)) && ((*alloc_mem = malloc(cnt + 1)) != NULL)) { (void) snprintf(*alloc_mem, cnt + 1, MSG_ORIG(MSG_FMT_ISEC_NAME), EC_WORD(scnndx), name); return (*alloc_mem); } /* Return the caller supplied buffer */ *alloc_mem = NULL; return (buf); }
/* * Common processing for capabilities value setting. * * entry: * argstate - Argument state block * cap - capabilities data pointer * ndx - capabilities data index * cap_ndx - capabilities section index * cap_name - capabilities section name * cap_tag - capabilities tag * const_type - data conversion type */ static elfedit_cmdret_t cap_set(ARGSTATE *argstate, Cap *cap, Word ndx, Word cap_ndx, const char *cap_name, Xword cap_tag, elfedit_const_t const_type) { Conv_cap_val_buf_t buf1, buf2; Half mach = argstate->obj_state->os_ehdr->e_machine; Xword ncap, ocap; ncap = flag_bitop(argstate, cap[ndx].c_un.c_val, elfedit_const_to_atoui(const_type)); /* Set the value */ if ((ocap = cap[ndx].c_un.c_val) == ncap) { elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_BSB_OK), cap_ndx, cap_name, EC_WORD(ndx), conv_cap_val(cap_tag, ocap, mach, CONV_FMT_NOBKT, &buf1)); return (ELFEDIT_CMDRET_NONE); } else { elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_BSB_CHG), cap_ndx, cap_name, EC_WORD(ndx), conv_cap_val(cap_tag, ocap, mach, CONV_FMT_NOBKT, &buf1), conv_cap_val(cap_tag, ncap, mach, CONV_FMT_NOBKT, &buf2)); cap[ndx].c_un.c_val = ncap; return (ELFEDIT_CMDRET_MOD); } }
/* * Convenience wrapper on elfedit_atoui() to read a section index * that understands the special SHN_ names. * * entry: * str - String to process * shnum - Number of sections in the ELF file * * exit: * If it is possible to convert str to a number, that value * is returned. If the value is out of range for the file, * a warning message to that effect is issued. On failure, * an error is issued and this routine does not return to * the caller. */ elfedit_atoui_t elfedit_atoshndx(const char *str, size_t shnum) { elfedit_atoui_t ndx; ndx = elfedit_atoconst(str, ELFEDIT_CONST_SHN); if ((ndx >= shnum) && ((ndx < SHN_LORESERVE) || (ndx > SHN_HIRESERVE))) elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_SHNDX_RANGE), EC_WORD(ndx), EC_WORD(shnum-1)); return (ndx); }
/* * Given an index into the capabilities array, issue a group title for * the capabilities group that contains it. */ static void group_title(ARGSTATE *argstate, Word ndx) { ARGSTATE loc_argstate; loc_argstate = *argstate; cap_group_extents(argstate, ndx, &loc_argstate.cap.grp_start_ndx, &loc_argstate.cap.grp_end_ndx); elfedit_printf(MSG_INTL(MSG_FMT_CAPGRP), EC_WORD(loc_argstate.cap.grp_start_ndx), EC_WORD(loc_argstate.cap.grp_end_ndx), cap_group_id(&loc_argstate)); }
/* * Given an index into the capabilities array, set the argstate cap.grp_* * fields to reflect the capabilities group containing the index. * * The group concept is used to limit operations to a related group * of capabilities, and prevent insert/delete/move operations from * spilling across groups. */ static void argstate_cap_group(ARGSTATE *argstate, Word ndx) { if (argstate->cap.grp_set == TRUE) return; cap_group_extents(argstate, ndx, &argstate->cap.grp_start_ndx, &argstate->cap.grp_end_ndx); argstate->cap.grp_set = TRUE; elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_CAPGRP), EC_WORD(argstate->cap.sec->sec_shndx), argstate->cap.sec->sec_name, EC_WORD(argstate->cap.grp_start_ndx), EC_WORD(argstate->cap.grp_end_ndx), cap_group_id(argstate)); }
static void disp_reg_line(struct ps_prochandle *ph, pstatus_t *prst, char *r1, int ind1, char *r2, int ind2) { char str1[MAXPATHLEN], str2[MAXPATHLEN]; (void) strcpy(str1, print_address_ps(ph, prst->pr_lwp.pr_reg[ind1], FLG_PAP_NOHEXNAME)); (void) strcpy(str2, print_address_ps(ph, prst->pr_lwp.pr_reg[ind2], FLG_PAP_NOHEXNAME)); (void) printf("%8s: 0x%08x %-16s %8s: 0x%08x %-16s\n", r1, EC_WORD(prst->pr_lwp.pr_reg[ind1]), str1, r2, EC_WORD(prst->pr_lwp.pr_reg[ind2]), str2); }
Group_desc * ld_get_group(Ofl_desc *ofl, Is_desc *isp) { Ifl_desc *ifl = isp->is_file; uint_t scnndx = isp->is_scnndx; Group_desc *gdp; Aliste idx; /* * Scan the GROUP sections associated with this file to find the * matching group section. */ for (ALIST_TRAVERSE(ifl->ifl_groups, idx, gdp)) { size_t ndx; Word *data; if (isp->is_shdr->sh_type == SHT_GROUP) { if (isp->is_scnndx == gdp->gd_isc->is_scnndx) return (gdp); continue; } data = gdp->gd_data; for (ndx = 1; ndx < gdp->gd_cnt; ndx++) { if (data[ndx] == scnndx) return (gdp); } } ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_ELF_NOGROUPSECT), ifl->ifl_name, EC_WORD(isp->is_scnndx), isp->is_name); return (NULL); }
/* * Generate a statistics line for the auxiliary relocation descriptor cache. * * entry: * ofl - output file descriptor */ static void rel_aux_cache_statistics(Ofl_desc *ofl) { Rel_aux_cachebuf *racp; Lm_list *lml = ofl->ofl_lml; size_t desc_cnt = 0, desc_used = 0, bytes; Aliste idx; char unit_buf[CONV_INV_BUFSIZE + 10]; /* Sum the total memory allocated across all the buffers */ for (APLIST_TRAVERSE(ofl->ofl_relaux, idx, racp)) { desc_cnt += racp->rac_end - racp->rac_arr; desc_used += racp->rac_free - racp->rac_arr; } bytes = desc_cnt * sizeof (Rel_desc); dbg_print(lml, MSG_INTL(MSG_STATS_REL_ACACHE), EC_WORD(aplist_nitems(ofl->ofl_relaux)), EC_XWORD(desc_used), EC_XWORD(desc_cnt), (desc_cnt == 0) ? 100 : EC_WORD((desc_used * 100) / desc_cnt), EC_XWORD(bytes), fmt_human_units(bytes, unit_buf, sizeof (unit_buf))); }
/* * Lookup the string table associated with the capabilities * section. * * entry: * argstate - Argument state block * required - If TRUE, failure to obtain a string table should be * considered to be an error. * * exit: * If a string table is found, argstate->str is updated to reference it. * If no string table is found, and required is TRUE, an error is issued * and this routine does not return to the caller. Otherwise, this * routine returns quietly without modifying argstate->str. */ static void argstate_add_str(ARGSTATE *argstate, Boolean required) { /* String table already loaded? */ if (argstate->str.sec != NULL) return; /* * We can't proceed if the capabilities section does not have * an associated string table. */ if (argstate->cap.sec->sec_shdr->sh_info == 0) { /* Error if the operation requires a string table */ if (required) elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSTRTAB), EC_WORD(argstate->cap.sec->sec_shndx), argstate->cap.sec->sec_name); return; } argstate->str.sec = elfedit_sec_getstr(argstate->obj_state, argstate->cap.sec->sec_shdr->sh_info, 0); }
/* * move the location of items in an array by shifting the surround * items into the vacated hole and them putting the values into * the new location. * * entry: * name_str - Array identification prefix to use for debug message * data_start - Address of 1st byte in array * entsize - sizeof a single element of the array * num_ent - # of elements in array * start_ndx - Index of first item to be moved * dst_ndx - Index to receive the moved block * cnt - # of items to move * scr_item - Space allocated by the caller sufficient to hold * one item from the array. Used to swap elements. * * exit: * Any errors are issued and control does not return to the * caller. On success, the items have been moved, and debug * messages issued. */ void elfedit_array_elts_move(const char *name_str, void *data_start, size_t entsize, size_t num_ent, size_t srcndx, size_t dstndx, size_t cnt, void *scr_item) { char *data = data_start; /* The specified source and destination ranges must be in bounds */ if (((srcndx + cnt) > num_ent) || ((dstndx + cnt) > num_ent)) elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_ARRBNDS), name_str, EC_WORD(num_ent), EC_WORD(num_ent - 1)); /* If source and destination are same, there's nothing to do */ if (srcndx == dstndx) return; /* * It is meaningless to do a move where the source and destination * are overlapping, because this "move" amounts to shifting * the existing items around into a new position. If there is * more than one element, then overlap is possible and we need * to test for it. */ if (cnt > 1) { size_t low, hi; if (srcndx > dstndx) { low = dstndx; hi = srcndx; } else { low = srcndx; hi = dstndx; } /* Ensure that the src and dst don't overlap */ if ((low + cnt) > hi) elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_ARRMVOVERLAP), name_str, EC_WORD(srcndx), EC_WORD(srcndx + cnt - 1), EC_WORD(dstndx), EC_WORD(dstndx + cnt - 1)); } if (cnt == 1) elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_ARRMOVE_1), name_str, EC_WORD(srcndx), EC_WORD(dstndx)); else elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_ARRMOVE_N), name_str, EC_WORD(cnt), EC_WORD(srcndx), EC_WORD(srcndx + cnt - 1), EC_WORD(dstndx), EC_WORD(dstndx + cnt - 1)); if (srcndx < dstndx) { srcndx += cnt - 1; dstndx += cnt - 1; for (; cnt-- > 0; srcndx--, dstndx--) { /* * Copy item at srcndx to scratch location * * save = dyn[srcndx]; */ bcopy(data + (srcndx * entsize), scr_item, entsize); /* * Shift items after source up through destination * to source. bcopy() handles overlapped copies. * * for (i = srcndx; i < dstndx; i++) * dyn[i] = dyn[i + 1]; */ bcopy(data + ((srcndx + 1) * entsize), data + (srcndx * entsize), (dstndx - srcndx) * entsize); /* * Copy saved item into destination slot * * dyn[dstndx] = save; */ bcopy(scr_item, data + (dstndx * entsize), entsize); } } else { for (; cnt-- > 0; srcndx++, dstndx++) { /* * Copy item at srcndx to scratch location * * save = dyn[srcndx]; */ bcopy(data + (srcndx * entsize), scr_item, entsize); /* * Shift items from destination through item below * source up one. bcopy() handles overlapped copies. * * for (i = srcndx; i > dstndx; i--) * dyn[i] = dyn[i - 1]; */ bcopy(data + (dstndx * entsize), data + ((dstndx + 1) * entsize), (srcndx - dstndx) * entsize); /* * Copy saved item into destination slot * * dyn[dstndx] = save; */ bcopy(scr_item, data + (dstndx * entsize), entsize); } } }
uintptr_t ld_group_process(Is_desc *gisc, Ofl_desc *ofl) { Ifl_desc *gifl = gisc->is_file; Shdr *sshdr, *gshdr = gisc->is_shdr; Is_desc *isc; Sym *sym; const char *str; Group_desc gd; size_t ndx; int gnu_stt_section; /* * Confirm that the sh_link points to a valid section. */ if ((gshdr->sh_link == SHN_UNDEF) || (gshdr->sh_link >= gifl->ifl_shnum) || ((isc = gifl->ifl_isdesc[gshdr->sh_link]) == NULL)) { ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_FIL_INVSHLINK), gifl->ifl_name, EC_WORD(gisc->is_scnndx), gisc->is_name, EC_XWORD(gshdr->sh_link)); return (0); } if (gshdr->sh_entsize == 0) { ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_FIL_INVSHENTSIZE), gifl->ifl_name, EC_WORD(gisc->is_scnndx), gisc->is_name, EC_XWORD(gshdr->sh_entsize)); return (0); } /* * Get the associated symbol table. Sanity check the sh_info field * (which points to the signature symbol table entry) against the size * of the symbol table. */ sshdr = isc->is_shdr; sym = (Sym *)isc->is_indata->d_buf; if ((sshdr->sh_info == SHN_UNDEF) || (gshdr->sh_info >= (Word)(sshdr->sh_size / sshdr->sh_entsize)) || ((isc = gifl->ifl_isdesc[sshdr->sh_link]) == NULL)) { ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_FIL_INVSHINFO), gifl->ifl_name, EC_WORD(gisc->is_scnndx), gisc->is_name, EC_XWORD(gshdr->sh_info)); return (0); } sym += gshdr->sh_info; /* * Get the symbol name from the associated string table. */ str = (char *)isc->is_indata->d_buf; str += sym->st_name; /* * The GNU assembler can use section symbols as the signature symbol * as described by this comment in the gold linker (found via google): * * It seems that some versions of gas will create a section group * associated with a section symbol, and then fail to give a name * to the section symbol. In such a case, use the name of the * section. * * In order to support such objects, we do the same. */ gnu_stt_section = ((sym->st_name == 0) || (*str == '\0')) && (ELF_ST_TYPE(sym->st_info) == STT_SECTION); if (gnu_stt_section) str = gisc->is_name; /* * Generate a group descriptor. */ gd.gd_isc = gisc; gd.gd_oisc = NULL; gd.gd_name = str; gd.gd_data = gisc->is_indata->d_buf; gd.gd_cnt = gisc->is_indata->d_size / sizeof (Word); /* * If this group is a COMDAT group, validate the signature symbol. */ if ((gd.gd_data[0] & GRP_COMDAT) && !gnu_stt_section && ((ELF_ST_BIND(sym->st_info) == STB_LOCAL) || (sym->st_shndx == SHN_UNDEF))) { /* If section symbol, construct a printable name for it */ if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) { if (gisc->is_sym_name == NULL) (void) ld_stt_section_sym_name(gisc); if (gisc->is_sym_name != NULL) str = gisc->is_sym_name; } ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_GRP_INVALSYM), gifl->ifl_name, EC_WORD(gisc->is_scnndx), gisc->is_name, str); return (0); } /* * If the signature symbol is a name generated by the GNU compiler to * refer to a header, we need sloppy relocation. */ if (is_header_gensym(str)) { if ((ofl->ofl_flags1 & FLG_OF1_NRLXREL) == 0) ofl->ofl_flags1 |= FLG_OF1_RLXREL; DBG_CALL(Dbg_sec_gnu_comdat(ofl->ofl_lml, gisc, TRUE, (ofl->ofl_flags1 & FLG_OF1_RLXREL) != 0)); } /* * Validate the section indices within the group. If this is a COMDAT * group, mark each section as COMDAT. */ for (ndx = 1; ndx < gd.gd_cnt; ndx++) { Word gndx; if ((gndx = gd.gd_data[ndx]) >= gifl->ifl_shnum) { ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_GRP_INVALNDX), gifl->ifl_name, EC_WORD(gisc->is_scnndx), gisc->is_name, ndx, gndx); return (0); } if (gd.gd_data[0] & GRP_COMDAT) gifl->ifl_isdesc[gndx]->is_flags |= FLG_IS_COMDAT; } /* * If this is a COMDAT group, determine whether this group has already * been encountered, or whether this is the first instance of the group. */ if ((gd.gd_data[0] & GRP_COMDAT) && (gpavl_loaded(ofl, &gd) == S_ERROR)) return (S_ERROR); /* * Associate the group descriptor with this input file. */ if (alist_append(&(gifl->ifl_groups), &gd, sizeof (Group_desc), AL_CNT_IFL_GROUPS) == NULL) return (S_ERROR); return (1); }
/* * Standard argument processing for cap module * * entry * obj_state, argc, argv - Standard command arguments * argstate - Address of ARGSTATE block to be initialized * * exit: * On success, *argstate is initialized. On error, * an error is issued and this routine does not return. */ static void process_args(elfedit_obj_state_t *obj_state, int argc, const char *argv[], ARGSTATE *argstate) { elfedit_getopt_state_t getopt_state; elfedit_getopt_ret_t *getopt_ret; const char *capid = NULL; bzero(argstate, sizeof (*argstate)); argstate->obj_state = obj_state; elfedit_getopt_init(&getopt_state, &argc, &argv); /* Add each new option to the options mask */ while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL) { argstate->optmask |= getopt_ret->gor_idmask; if (getopt_ret->gor_idmask == CAP_OPT_F_CAPID) capid = getopt_ret->gor_value; } /* If there may be an arbitrary amount of output, use a pager */ if (argc == 0) elfedit_pager_init(); /* Return the updated values of argc/argv */ argstate->argc = argc; argstate->argv = argv; /* Locate the capabilities section */ argstate->cap.sec = elfedit_sec_getcap(obj_state, &argstate->cap.data, &argstate->cap.num); /* * If -capid was specified, locate the specified capabilities group, * and narrow the section data to use only that group. Otherwise, * use the whole array. */ if (capid != NULL) { Word i; Cap *cap = argstate->cap.data; /* * -capid requires the capability section to have an * associated string table. */ argstate_add_str(argstate, TRUE); for (i = 0; i < argstate->cap.num; i++, cap++) if ((cap->c_tag == CA_SUNW_ID) && (strcmp(capid, elfedit_offset_to_str( argstate->str.sec, cap->c_un.c_val, ELFEDIT_MSG_ERR, 0)) == 0)) break; if (i == argstate->cap.num) elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_BADCAPID), EC_WORD(argstate->cap.sec->sec_shndx), argstate->cap.sec->sec_name, capid); argstate_cap_group(argstate, i); } else { argstate->cap.grp_start_ndx = 0; argstate->cap.grp_end_ndx = argstate->cap.num - 1; } }
/* * "delete" items in an array by copying the following items up * over the "deleted" items and then zero filling the vacated * slots at the bottom. * * entry: * name_str - Array identification prefix to use for debug message * data_start - Address of 1st byte in array * entsize - sizeof a single element of the array * num_ent - # of elements in array * start_ndx - Index of first item to be deleted * cnt - # of items to delete * * exit: * Any errors are issued and control does not return to the * caller. On success, the items have been removed, zero filling * has been done, and debug messages issued. */ void elfedit_array_elts_delete(const char *name_str, void *data_start, size_t entsize, size_t num_ent, size_t start_ndx, size_t cnt) { char *data = data_start; /* The specified index and range must be in bounds */ if ((start_ndx + cnt) > num_ent) elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_ARRBNDS), name_str, EC_WORD(num_ent), EC_WORD(num_ent - 1)); /* * Everything below the deleted items moves up. * Note that bcopy() is documented to handle overlapping * src/dst correctly, so we make no effort to handle this * element by element, but issue a single operation. * * If we're doing the last element, there is nothing to * move up, and we skip this step, moving on to the zeroing below. */ if (start_ndx < (num_ent - 1)) { size_t ncpy = num_ent - (start_ndx + cnt); bcopy(data + ((start_ndx + cnt) * entsize), data + (start_ndx * entsize), ncpy * entsize); if (ncpy == 1) { elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_ARRCPY_1), name_str, EC_WORD(start_ndx + cnt), EC_WORD(start_ndx)); } else { elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_ARRCPY_N), name_str, EC_WORD(start_ndx + cnt), EC_WORD(start_ndx + cnt + ncpy - 1), EC_WORD(start_ndx), EC_WORD(start_ndx + ncpy - 1)); } } /* Zero out the vacated elements at the end */ bzero(data + ((num_ent - cnt) * entsize), entsize * cnt); if (cnt == 1) { elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_ARRZERO_1), name_str, EC_WORD(num_ent - 1)); } else { elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_ARRZERO_N), name_str, EC_WORD(num_ent - cnt), EC_WORD(num_ent - 1), EC_WORD(cnt)); } }
void Dbg_got_display(Ofl_desc *ofl, Off goff, int stage, Word m_got_xnumber, size_t m_got_entsize) { Lm_list *lml = ofl->ofl_lml; Gottable *gtp = ofl->ofl_gottable; Word gotndx; Xword *gptr; if (DBG_NOTCLASS(DBG_C_GOT)) return; if (ofl->ofl_gotcnt == m_got_xnumber) return; Dbg_util_nl(lml, DBG_NL_STD); dbg_print(lml, MSG_INTL(MSG_GOT_INFO), EC_WORD(ofl->ofl_gotcnt)); if (DBG_NOTDETAIL()) return; qsort((char *)gtp, ofl->ofl_gotcnt, sizeof (Gottable), (int(*)(const void *, const void *))Dbg_got_compare); if (stage == 0) dbg_print(lml, MSG_INTL(MSG_GOT_COLUMNS1)); else dbg_print(lml, MSG_INTL(MSG_GOT_COLUMNS2)); gptr = (Xword *)ofl->ofl_osgot->os_outdata->d_buf; for (gotndx = 0; gotndx < ofl->ofl_gotcnt; gotndx++, gtp++, gptr++) { Sym_desc *sdp = gtp->gt_sym; const char *refstr, *name; Gotndx *gnp = >p->gt_gndx; Lword gotaddval; Off off = goff + (gotndx * m_got_entsize); char index[INDEX_STR_SIZE]; (void) snprintf(index, INDEX_STR_SIZE, MSG_ORIG(MSG_GOT_INDEX), EC_SWORD(gnp->gn_gotndx)); if (sdp == 0) refstr = MSG_ORIG(MSG_STR_EMPTY); else if (sdp->sd_flags & FLG_SY_SMGOT) refstr = MSG_ORIG(MSG_GOT_SMALL_PIC); else refstr = MSG_ORIG(MSG_GOT_BIG_PIC); if (sdp == 0) name = MSG_ORIG(MSG_STR_EMPTY); else if (sdp->sd_name) name = Dbg_demangle_name(sdp->sd_name); else name = MSG_INTL(MSG_STR_UNKNOWN); if (stage == 0) gotaddval = gnp->gn_addend; else gotaddval = *gptr; if ((sdp == 0) || (sdp->sd_sym->st_shndx == SHN_UNDEF) || (sdp->sd_file == 0)) { dbg_print(lml, MSG_INTL(MSG_GOT_FORMAT1), index, refstr, EC_OFF(off), EC_XWORD(gotaddval), name); } else { dbg_print(lml, MSG_INTL(MSG_GOT_FORMAT2), index, refstr, EC_OFF(off), EC_XWORD(gotaddval), sdp->sd_file->ifl_name, name); } } }
/* * Read the archive symbol table. For each symbol in the table, determine * whether that symbol satisfies an unresolved reference, tentative reference, * or a reference that expects hidden or protected visibility. If so, the * corresponding object from the archive is processed. The archive symbol * table is searched until we go through a complete pass without satisfying any * unresolved symbols * * entry: * name - Name of archive * fd - Open file descriptor for archive * adp - Archive descriptor * ofl - output descriptor * found - Address of variable to set to TRUE if any objects are extracted * rej - Rejection descriptor to pass to ld_process_ifl(). * * exit: * Returns FALSE on fatal error. On success, *found will be TRUE * if any object was extracted, rej will be set if any object * was rejected, and TRUE is returned. */ static Boolean ar_extract_bysym(const char *name, int fd, Ar_desc *adp, Ofl_desc *ofl, Boolean *found, Rej_desc *rej) { Elf_Arsym * arsym; Elf * arelf; Ar_aux * aup; Sym_desc * sdp; const char *arname, *arpath; Boolean again = FALSE; uintptr_t err; /* * An archive without a symbol table should not reach this function, * because it can only get past ld_ar_setup() in the case where * the archive is first seen under the influence of '-z allextract'. * That will cause the entire archive to be extracted, and any * subsequent reference to the archive will be ignored by * ld_process_archive(). */ if (adp->ad_start == NULL) { assert(adp->ad_start != NULL); return (TRUE); } /* * Loop through archive symbol table until we make a complete pass * without satisfying an unresolved reference. For each archive * symbol, see if there is a symbol with the same name in ld's * symbol table. If so, and if that symbol is still unresolved or * tentative, process the corresponding archive member. */ do { DBG_CALL(Dbg_file_ar(ofl->ofl_lml, name, again)); DBG_CALL(Dbg_syms_ar_title(ofl->ofl_lml, name, again)); again = FALSE; for (arsym = adp->ad_start, aup = adp->ad_aux; arsym->as_name; ++arsym, ++aup) { Ar_mem *amp; Sym *sym; Boolean visible = TRUE; Boolean vers; Ifl_desc *ifl; /* * If the auxiliary members value indicates that this * member has been processed then this symbol will have * been added to the output file image already or the * object was rejected in which case we don't want to * process it again. */ if (aup->au_mem == FLG_ARMEM_PROC) continue; /* * If the auxiliary symbol element is non-zero lookup * the symbol from the internal symbol table. */ if ((sdp = aup->au_syms) == NULL) { if ((sdp = ld_sym_find(arsym->as_name, /* LINTED */ (Word)arsym->as_hash, NULL, ofl)) == NULL) { DBG_CALL(Dbg_syms_ar_skip(ofl->ofl_lml, name, arsym)); continue; } aup->au_syms = sdp; } /* * With '-z allextract', all members will be extracted. * * This archive member is a candidate for extraction if * the internal symbol originates from an explicit file, * and represents an undefined or tentative symbol. * * By default, weak references do not cause archive * extraction, however the -zweakextract flag overrides * this default. * * If this symbol has already been bound to a versioned * shared object, but the shared objects version is not * available, then a definition of this symbol from * within the archive is a better candidate. Similarly, * if this symbol has been bound to a shared object, but * the original reference expected hidden or protected * visibility, then a definition of this symbol from * within the archive is a better candidate. */ vers = TRUE; ifl = sdp->sd_file; sym = sdp->sd_sym; if (sdp->sd_ref == REF_DYN_NEED) { uchar_t vis; if (ifl->ifl_vercnt) { Word vndx; Ver_index *vip; vndx = sdp->sd_aux->sa_dverndx; vip = &ifl->ifl_verndx[vndx]; if (!(vip->vi_flags & FLG_VER_AVAIL)) vers = FALSE; } vis = ELF_ST_VISIBILITY(sym->st_other); visible = sym_vis[vis]; } if (((ifl->ifl_flags & FLG_IF_NEEDED) == 0) || (visible && vers && (sym->st_shndx != SHN_UNDEF) && (sym->st_shndx != SHN_COMMON)) || ((ELF_ST_BIND(sym->st_info) == STB_WEAK) && (!(ofl->ofl_flags1 & FLG_OF1_WEAKEXT)))) { DBG_CALL(Dbg_syms_ar_skip(ofl->ofl_lml, name, arsym)); continue; } /* * Determine if we have already extracted this member, * and if so reuse the Ar_mem information. */ if ((amp = aup->au_mem) != 0) { arelf = amp->am_elf; arname = amp->am_name; arpath = amp->am_path; } else { /* * Set up a new elf descriptor for this member. */ if (elf_rand(adp->ad_elf, arsym->as_off) != arsym->as_off) { ld_eprintf(ofl, ERR_ELF, MSG_INTL(MSG_ELF_ARMEM), name, EC_WORD(arsym->as_off), demangle(arsym->as_name)); return (FALSE); } if ((arelf = elf_begin(fd, ELF_C_READ, adp->ad_elf)) == NULL) { ld_eprintf(ofl, ERR_ELF, MSG_INTL(MSG_ELF_BEGIN), name); return (FALSE); } /* Get member filename */ if ((arname = ar_member_name(name, arelf, ofl)) == NULL) return (FALSE); /* Construct the member's full pathname */ if ((arpath = ar_member_path(name, arname)) == NULL) return (S_ERROR); /* * Determine whether the support libraries wish * to process this open. See comments in * ld_process_open(). */ ld_sup_open(ofl, &arpath, &arname, &fd, (FLG_IF_EXTRACT | FLG_IF_NEEDED), &arelf, adp->ad_elf, arsym->as_off, elf_kind(arelf)); if (arelf == NULL) { /* Ignore this archive member */ aup->au_mem = FLG_ARMEM_PROC; continue; } } /* * The symbol for which this archive member is being * processed may provide a better alternative to the * symbol that is presently known. Two cases are * covered: * * i. The present symbol represents tentative data. * The archive member may provide a data * definition symbol. * ii. The present symbol represents a reference that * has seen a definition within a shared object * dependency, but the reference expects to be * reduced to hidden or protected visibility. */ if ((sym->st_shndx == SHN_COMMON) || (visible == FALSE)) { /* * If we don't already have a member structure * allocate one. */ if (!amp) { if ((amp = libld_calloc(sizeof (Ar_mem), 1)) == NULL) return (FALSE); amp->am_elf = arelf; amp->am_name = arname; amp->am_path = arpath; } DBG_CALL(Dbg_syms_ar_checking(ofl->ofl_lml, name, arname, arsym)); if ((err = process_member(amp, arsym->as_name, sdp, ofl)) == S_ERROR) return (FALSE); /* * If it turns out that we don't need this * member simply initialize all other auxiliary * entries that match this offset with this * members address. In this way we can resuse * this information if we recurse back to this * symbol. */ if (err == 0) { if (aup->au_mem == NULL) ld_ar_member(adp, arsym, aup, amp); continue; } } /* * Process the archive member. Retain any error for * return to the caller. */ DBG_CALL(Dbg_syms_ar_resolve(ofl->ofl_lml, name, arname, arsym)); switch (ar_input(fd, adp, ofl, arelf, arpath, rej)) { case S_ERROR: return (FALSE); case 0: /* * Mark the member as extracted so that we * don't try and process it again on a rescan. */ ld_ar_member(adp, arsym, aup, FLG_ARMEM_PROC); continue; } /* * Note that this archive has contributed something * during this specific operation, and also signal * the need to rescan the archive. */ *found = again = TRUE; ld_ar_member(adp, arsym, aup, FLG_ARMEM_PROC); } } while (again); return (TRUE); }
/* * Validate a SHT_SUNW_move section. These are only processed from input * relocatable objects. The move section entries are validated and any data * structures required for later processing are created. */ uintptr_t ld_process_move(Ofl_desc *ofl) { size_t idx; Is_desc *isp; int errcnt = 0; for (APLIST_TRAVERSE(ofl->ofl_ismove, idx, isp)) { Ifl_desc *ifile = isp->is_file; Elf64_Move *mvp; Elf64_Xword i, num; mvp = (Elf64_Move *)isp->is_indata->d_buf; if (isp->is_shdr->sh_entsize == 0) { ld_eprintf(ofl, ERR_FATAL, MSG_FIL_INVSHENTSIZE, isp->is_file->ifl_name, EC_WORD(isp->is_scnndx), isp->is_name, EC_XWORD(0)); return (S_ERROR); } num = isp->is_shdr->sh_size / isp->is_shdr->sh_entsize; for (i = 0; i < num; i++) { Elf64_Xword ndx = ELF_M_SYM(mvp->m_info); Sym_desc *sdp; Elf64_Sym *sym; if ((ndx >= (Elf64_Xword) isp->is_file->ifl_symscnt) || (ndx == 0)) { ld_eprintf(ofl, ERR_FATAL, MSG_PSYM_INVMINFO1, isp->is_file->ifl_name, EC_WORD(isp->is_scnndx), isp->is_name, i, EC_XWORD(mvp->m_info)); return (S_ERROR); } if (mvp->m_repeat == 0) { ld_eprintf(ofl, ERR_FATAL, MSG_PSYM_INVMREPEAT, isp->is_file->ifl_name, EC_WORD(isp->is_scnndx), isp->is_name, i, EC_XWORD(mvp->m_repeat)); return (S_ERROR); } sdp = isp->is_file->ifl_oldndx[ndx]; /* * Validate that this entry has a valid size. */ /* LINTED */ switch (ELF_M_SIZE(mvp->m_info)) { case 1: case 2: case 4: case 8: break; default: ld_eprintf(ofl, ERR_FATAL, MSG_PSYM_INVMINFO2, isp->is_file->ifl_name, EC_WORD(isp->is_scnndx), isp->is_name, i, EC_XWORD(mvp->m_info)); return (S_ERROR); } /* * If this is a global symbol, adjust the visibility. */ if (sdp->sd_aux && ((sdp->sd_flags & FLG_SY_VISIBLE) == 0)) ld_sym_adjust_vis(sdp, ofl); sym = sdp->sd_sym; if (sdp->sd_move == NULL) { /* * If this is the first move entry associated * with this symbol, save the symbol on the * partial symbol list, and initialize various * state regarding this symbol. */ if (aplist_append(&ofl->ofl_parsyms, sdp, AL_CNT_OFL_PARSYMS) == NULL) return (S_ERROR); /* * Even if -zredlocsym is in effect, the local * symbol used for partial initialization is * kept. */ if ((ofl->ofl_flags & FLG_OF_REDLSYM) && (ELF_ST_BIND(sym->st_info) == STB_LOCAL) && (ELF_ST_TYPE(sym->st_info) == STT_OBJECT)) { ofl->ofl_locscnt++; if (st_insert(ofl->ofl_strtab, sdp->sd_name) == -1) return (S_ERROR); } /* * Mark the input section associated with this * partially initialized symbol. * This is needed when the symbol * the relocation entry uses symbol information * not from the symbol entry. * * For executable, the following is * needed only for expanded symbol. However, * for shared object any partially non * expanded symbols are moved from * .bss/COMMON to .sunwbss. So the following are * needed. */ if ((sym->st_shndx != SHN_UNDEF) && (sym->st_shndx < SHN_LOPROC)) { Is_desc *isc; isc = ifile->ifl_isdesc[ sym->st_shndx]; isc->is_flags |= FLG_IS_RELUPD; if (sdp->sd_osym == NULL) { if ((sdp->sd_osym = libld_calloc(sizeof(Elf64_Sym), 1)) == NULL) return (S_ERROR); *(sdp->sd_osym) = *(sdp->sd_sym); } } } if (append_move_desc(ofl, sdp, mvp, isp) == S_ERROR) return (S_ERROR); if (sdp->sd_flags & FLG_SY_OVERLAP) errcnt++; /* * If this symbol is marked to be expanded, go to the * next move entry. */ if (sdp->sd_flags & FLG_SY_PAREXPN) { mvp++; continue; } /* * Decide whether this partial symbol is to be expanded * or not. * * The symbol will be expanded if: * a) '-z nopartial' is specified * b) move entries covered entire symbol * * To expand an move entry, size of the symbol to be * expanded need to be known to generate a file space. * (see make_movesections().) * * Therefore the move entry can not be expanded * if the partial symbol is a section symbol. * (The size of the symbol may be unknown.) * This may happen, for example, when a local symbol is * reduced by the -zredlocsym. * * The following two if statements checks the * if the move entry can be expanded or not. */ if (OFL_IS_STATIC_EXEC(ofl)) { if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) { errcnt++; ld_eprintf(ofl, ERR_FATAL, MSG_PSYM_CANNOTEXPND, sdp->sd_file->ifl_name, EC_WORD(isp->is_scnndx), isp->is_name, i, MSG_PSYM_NOSTATIC); } else { sdp->sd_flags |= FLG_SY_PAREXPN; } } else if ((ofl->ofl_flags1 & FLG_OF1_NOPARTI) != 0) { if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) { ld_eprintf(ofl, ERR_WARNING, MSG_PSYM_CANNOTEXPND, sdp->sd_file->ifl_name, EC_WORD(isp->is_scnndx), isp->is_name, i, MSG_STR_EMPTY); } else { sdp->sd_flags |= FLG_SY_PAREXPN; } } else if (((Elf64_Xword)((sizeof (Elf64_Move)) * alist_nitems(sdp->sd_move)) > sym->st_size) && (ELF_ST_TYPE(sym->st_info) == STT_OBJECT)) { sdp->sd_flags |= FLG_SY_PAREXPN; } /* * If a move entry exists that references a local * symbol, and this symbol reference will eventually * be assigned to the associated section, make sure the * section symbol is available for relocating against * at runtime. */ if ((ELF_ST_BIND(sym->st_info) == STB_LOCAL) && (((ofl->ofl_flags & FLG_OF_RELOBJ) == 0) || (ofl->ofl_flags & FLG_OF_REDLSYM))) { Os_desc *osp = sdp->sd_isc->is_osdesc; if (osp && ((osp->os_flags & FLG_OS_OUTREL) == 0)) { ofl->ofl_dynshdrcnt++; osp->os_flags |= FLG_OS_OUTREL; } else if ((sdp->sd_flags & FLG_SY_PAREXPN) == 0) ofl->ofl_flags1 |= FLG_OF1_BSSOREL; } mvp++; } } if (errcnt != 0) return (S_ERROR); if (make_mvsections(ofl) == S_ERROR) return (S_ERROR); return (1); }
/* * Assign move descriptors with the associated target symbol. */ static uintptr_t append_move_desc(Ofl_desc *ofl, Sym_desc *sdp, Elf64_Move *mvp, Is_desc *isp) { int i, cnt = mvp->m_repeat; for (i = 0; i < cnt; i++) { size_t idx; Mv_desc *omdp, nmd; /* LINTED */ nmd.md_len = ELF_M_SIZE(mvp->m_info); nmd.md_start = mvp->m_poffset + i * ((mvp->m_stride + 1) * nmd.md_len); nmd.md_move = mvp; /* * Verify that this move descriptor doesn't overlap any existing * move descriptors. */ for (ALIST_TRAVERSE(sdp->sd_move, idx, omdp)) { Mv_desc *smdp, *lmdp; if (nmd.md_start > omdp->md_start) { smdp = omdp; lmdp = &nmd; } else { smdp = &nmd; lmdp = omdp; } /* * If this move entry is exactly the same as that of * a symbol that has overridden this symbol (for example * should two identical COMMON definitions be associated * with the same move data), simply ignore this move * element. */ if ((nmd.md_start == omdp->md_start) && ((nmd.md_len == smdp->md_len) && sdp->sd_file != isp->is_file)) continue; if ((nmd.md_start != omdp->md_start) && ((smdp->md_start + smdp->md_len) <= lmdp->md_start)) continue; ld_eprintf(ofl, ERR_FATAL, MSG_MOVE_OVERLAP, sdp->sd_file->ifl_name, EC_WORD(isp->is_scnndx), isp->is_name, demangle(sdp->sd_name), EC_XWORD(nmd.md_start), EC_XWORD(nmd.md_len), EC_XWORD(omdp->md_start), EC_XWORD(omdp->md_len)); /* * Indicate that an error has occurred, so that * processing can be terminated once all move errors * are flushed out. */ sdp->sd_flags |= FLG_SY_OVERLAP; return (1); } if (alist_append(&sdp->sd_move, &nmd, sizeof (Mv_desc), AL_CNT_SDP_MOVE) == NULL) return (S_ERROR); } return (1); }
/* * Finish the initialization of a new segment descriptor allocated by * ld_map_seg_alloc(), and enter it into the segment list. * * entry: * mf - Mapfile descriptor * seg_type - One of DBG_SEG_NEW or DBG_SEG_NEW_IMPLICIT * ins_head - If true, the new segment goes at the front of * others of its type. If false, it goes at the end. * sgp - Segment descriptor to enter. * where - Insertion point, initialized by a previous (failed) call to * ld_seg_lookup(). Ignored if the segment has a NULL sg_name. * * exit: * On success, returns SEG_INS_OK. A non-fatal error is indicated with * a return value of SEG_INS_SKIP, in which case the descriptor is * not entered, but the user is expected to discard it and continue * running. On failure, returns SEG_INS_FAIL. * * note: * This routine will modify the contents of the descriptor referenced * by sgp_tmpl before allocating the new descriptor. The caller must * not expect it to be unmodified. */ ld_map_seg_ins_t ld_map_seg_insert(Mapfile *mf, dbg_state_t dbg_state, Sg_desc *sgp, avl_index_t where) { Ofl_desc *ofl = mf->mf_ofl; size_t idx; Sg_desc *sgp2; /* temp segment descriptor pointer */ int ins_head; Elf64_Xword sg_ndx; /* * If specific fields have not been supplied via * map_equal(), make sure defaults are supplied. */ if (((sgp->sg_flags & FLG_SG_P_TYPE) == 0) && (sgp->sg_phdr.p_type == PT_NULL)) { /* * Default to a loadable segment. */ sgp->sg_phdr.p_type = PT_LOAD; sgp->sg_flags |= FLG_SG_P_TYPE; } if (sgp->sg_phdr.p_type == PT_LOAD) { if ((sgp->sg_flags & FLG_SG_P_FLAGS) == 0) { /* * Default to read/write and execute. */ sgp->sg_phdr.p_flags = PF_R + PF_W + PF_X; sgp->sg_flags |= FLG_SG_P_FLAGS; } if ((sgp->sg_flags & FLG_SG_P_ALIGN) == 0) { /* * Default to segment alignment */ sgp->sg_phdr.p_align = ld_targ.t_m.m_segm_align; sgp->sg_flags |= FLG_SG_P_ALIGN; } } /* * Determine where the new item should be inserted in * the segment descriptor list. */ switch (sgp->sg_phdr.p_type) { case PT_LOAD: if (sgp->sg_flags & FLG_SG_EMPTY) sgp->sg_id = SGID_TEXT_EMPTY; else sgp->sg_id = SGID_TEXT; break; case PT_NULL: if (sgp->sg_flags & FLG_SG_EMPTY) sgp->sg_id = SGID_NULL_EMPTY; else sgp->sg_id = SGID_NULL; break; case PT_NOTE: sgp->sg_id = SGID_NOTE; break; default: mf_fatal(mf, (MSG_MAP_UNKSEGTYP), EC_WORD(sgp->sg_phdr.p_type)); return (SEG_INS_FAIL); } /* * Add the descriptor to the segment list. In the v1 syntax, * new sections are added at the head of their type, while in * the newer syntax, they go at the end of their type. */ sg_ndx = 0; ins_head = (mf->mf_version == MFV_SYSV); for (APLIST_TRAVERSE(ofl->ofl_segs, idx, sgp2)) { if (ins_head) { /* Insert before the others of its type */ if (sgp->sg_id > sgp2->sg_id) { sg_ndx++; continue; } } else { /* Insert after the others of its type */ if (sgp->sg_id >= sgp2->sg_id) { sg_ndx++; continue; } } break; } if (aplist_insert(&ofl->ofl_segs, sgp, AL_CNT_SEGMENTS, idx) == NULL) return (SEG_INS_FAIL); if (sgp->sg_name != NULL) avl_insert(&ofl->ofl_segs_avl, sgp, where); //DBG_CALL(Dbg_map_seg(ofl, dbg_state, sg_ndx, sgp, mf->mf_lineno)); return (SEG_INS_OK); }
void Dbg_sec_order_list(Ofl_desc *ofl, int flag) { Os_desc *osp; Is_desc *isp1; Listnode *lnp1, *lnp2; Lm_list *lml = ofl->ofl_lml; const char *str; if (DBG_NOTCLASS(DBG_C_SECTIONS)) return; if (DBG_NOTDETAIL()) return; Dbg_util_nl(lml, DBG_NL_STD); /* * If the flag == 0, then the routine is called before sorting. */ if (flag == 0) str = MSG_INTL(MSG_ORD_SORT_BEFORE); else str = MSG_INTL(MSG_ORD_SORT_AFTER); for (LIST_TRAVERSE(&ofl->ofl_ordered, lnp1, osp)) { Sort_desc *sort = osp->os_sort; dbg_print(lml, str, osp->os_name); dbg_print(lml, MSG_INTL(MSG_ORD_HDR_1), EC_WORD(sort->st_beforecnt), EC_WORD(sort->st_aftercnt), EC_WORD(sort->st_ordercnt)); for (LIST_TRAVERSE(&osp->os_isdescs, lnp2, isp1)) { Word link; Ifl_desc *ifl = isp1->is_file; Is_desc *isp2; const char *msg; if ((isp1->is_flags & FLG_IS_ORDERED) == 0) { dbg_print(lml, MSG_INTL(MSG_ORD_TITLE_0), isp1->is_name, isp1->is_file->ifl_name); continue; } if (isp1->is_shdr->sh_flags & SHF_ORDERED) { link = isp1->is_shdr->sh_info; msg = MSG_ORIG(MSG_SH_INFO); } else { /* SHF_LINK_ORDER */ link = isp1->is_shdr->sh_link; msg = MSG_ORIG(MSG_SH_LINK); } if (link == SHN_BEFORE) { dbg_print(lml, MSG_INTL(MSG_ORD_TITLE_1), isp1->is_name, isp1->is_file->ifl_name, msg); continue; } if (link == SHN_AFTER) { dbg_print(lml, MSG_INTL(MSG_ORD_TITLE_2), isp1->is_name, isp1->is_file->ifl_name, msg); continue; } isp2 = ifl->ifl_isdesc[link]; dbg_print(lml, MSG_INTL(MSG_ORD_TITLE_3), isp1->is_name, ifl->ifl_name, msg, isp2->is_name, isp2->is_key); } } Dbg_util_nl(lml, DBG_NL_STD); }
static void print_cap(CAP_CMD_T cmd, int autoprint, ARGSTATE *argstate, PRINT_CAP_T print_type, Word arg) { elfedit_outstyle_t outstyle; Word cnt, ndx, printed = 0; Cap *cap; Boolean header_done = FALSE, null_seen = FALSE; const char *str; size_t str_size; if (autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0)) return; /* * Pick an output style. cap:dump is required to use the default * style. The other commands use the current output style. */ outstyle = (cmd == CAP_CMD_T_DUMP) ? ELFEDIT_OUTSTYLE_DEFAULT : elfedit_outstyle(); /* How many elements do we examine? */ if (print_type == PRINT_CAP_T_NDX) { if (arg >= argstate->cap.num) return; /* Out of range */ ndx = arg; cnt = 1; } else { ndx = argstate->cap.grp_start_ndx; cnt = argstate->cap.grp_end_ndx - ndx + 1; } /* Load string table if there is one */ argstate_add_str(argstate, FALSE); if (argstate->str.sec == NULL) { str = NULL; str_size = 0; } else { str = (const char *)argstate->str.sec->sec_data->d_buf; str_size = argstate->str.sec->sec_data->d_size; } cap = &argstate->cap.data[ndx]; for (; cnt--; cap++, ndx++) { /* * If we are only displaying certain tag types and * this isn't one of those, move on to next element. */ if ((print_type == PRINT_CAP_T_TAG) && (cap->c_tag != arg)) { if (cap->c_tag == CA_SUNW_NULL) null_seen = TRUE; continue; } /* * If capability type requires a string table, and we don't * have one, force an error. */ switch (cap->c_tag) { case CA_SUNW_PLAT: case CA_SUNW_MACH: case CA_SUNW_ID: if (argstate->str.sec == NULL) argstate_add_str(argstate, TRUE); break; } if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) { if (null_seen && (cap->c_tag != CA_SUNW_NULL)) { null_seen = FALSE; if (header_done) { elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), MSG_ORIG(MSG_STR_EMPTY)); header_done = FALSE; } } if (header_done == FALSE) { header_done = TRUE; group_title(argstate, ndx); Elf_cap_title(0); } Elf_cap_entry(NULL, cap, ndx, str, str_size, argstate->obj_state->os_ehdr->e_machine); } else { /* * If CAP_CMD_T_TAG, and not in default output * style, display the tag rather than the value. */ if (cmd == CAP_CMD_T_TAG) { if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) { Conv_inv_buf_t inv_buf; elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), conv_cap_tag(cap->c_tag, 0, &inv_buf)); } else { elfedit_printf( MSG_ORIG(MSG_FMT_WORDVALNL), EC_WORD(cap->c_tag)); } printed = 1; continue; } /* Displaying the value in simple or numeric mode */ if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) { Conv_cap_val_buf_t cap_val_buf; if (print_type == PRINT_CAP_T_TAG) { elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), conv_cap_val_hw1(cap->c_un.c_val, argstate->obj_state->os_ehdr-> e_machine, CONV_FMT_NOBKT, &cap_val_buf.cap_val_hw1_buf)); printed = 1; continue; } switch (cap->c_tag) { case CA_SUNW_HW_1: elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), conv_cap_val_hw1(cap->c_un.c_val, argstate->obj_state->os_ehdr-> e_machine, CONV_FMT_NOBKT, &cap_val_buf.cap_val_hw1_buf)); printed = 1; continue; case CA_SUNW_SF_1: elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), conv_cap_val_sf1(cap->c_un.c_val, argstate->obj_state->os_ehdr-> e_machine, CONV_FMT_NOBKT, &cap_val_buf.cap_val_sf1_buf)); printed = 1; continue; case CA_SUNW_HW_2: elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), conv_cap_val_hw2(cap->c_un.c_val, argstate->obj_state->os_ehdr-> e_machine, CONV_FMT_NOBKT, &cap_val_buf.cap_val_hw2_buf)); printed = 1; continue; case CA_SUNW_PLAT: case CA_SUNW_MACH: case CA_SUNW_ID: elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), elfedit_offset_to_str( argstate->str.sec, cap->c_un.c_val, ELFEDIT_MSG_ERR, 0)); printed = 1; continue; } } elfedit_printf(MSG_ORIG(MSG_FMT_HEXXWORDNL), EC_XWORD(cap->c_un.c_val)); } printed = 1; if (cap->c_tag == CA_SUNW_NULL) null_seen = TRUE; } /* * If nothing was output under the print types that are * based on tag type, issue an error saying it doesn't exist. */ if (!printed && (print_type == PRINT_CAP_T_TAG)) { Conv_inv_buf_t inv_buf; elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOCAELT), EC_WORD(argstate->cap.sec->sec_shndx), argstate->cap.sec->sec_name, argstate->cap.grp_start_ndx, argstate->cap.grp_end_ndx, cap_group_id(argstate), conv_cap_tag(arg, 0, &inv_buf)); } }
/* * Process the elt argument: This will be a tag type if -capndx is * not present and this is a print request. It will be an index otherwise. * * entry: * argstate - Argument state block * arg - Argument string to be converted into an index * argname - String giving the name by which the argument is * referred in the online help for the command. * print_request - True if the command is to print the current * value(s) and return without changing anything. * print_type - Address of variable containing PRINT_CAP_T_ * code specifying how the elements will be displayed. * * exit: * If print_request is False: arg is converted into an integer value. * If -capndx was used, we convert it into an integer. If it was not * used, then arg is a tag name --- we find the first capabilities entry * that matches. If no entry matches, and there is an extra CA_NULL, * it is added. Otherwise an error is issued. *print_type is set * to PRINT_CAP_T_NDX. * * If print_request is True: If -capndx was used, arg is converted into * an integer value, *print_type is set to PRINT_CAP_T_NDX, and * the value is returned. If -capndx was not used, *print_type is set to * PRINT_CAP_T_TAG, and the tag value is returned. */ static Word arg_to_index(ARGSTATE *argstate, const char *arg, const char *argname, int print_request, PRINT_CAP_T *print_type) { Word ndx, ca_value; /* Assume we are returning an index, alter as needed below */ *print_type = PRINT_CAP_T_NDX; /* * If -capndx was used, this is a simple numeric index. * Determine its capability group because some operations * (move, delete) are limited to operate within it. */ if ((argstate->optmask & CAP_OPT_F_CAPNDX) != 0) { ndx = (Word) elfedit_atoui_range(arg, argname, 0, argstate->cap.num - 1, NULL); argstate_cap_group(argstate, ndx); return (ndx); } /* The argument is a CA_ tag type, not a numeric index */ ca_value = (Word) elfedit_atoconst(arg, ELFEDIT_CONST_CA); /* * If this is a printing request, then we let print_cap() show * all the items with this tag type. */ if (print_request) { *print_type = PRINT_CAP_T_TAG; return (ca_value); } /* * If we haven't determined a capability group yet, either via * -capid, or -capndx, then make it the initial group, which * represent the object capabilities. */ if (!argstate->cap.grp_set) argstate_cap_group(argstate, 0); /* * Locate the first entry with the given tag type within the * capabilities group. */ for (ndx = argstate->cap.grp_start_ndx; ndx <= argstate->cap.grp_end_ndx; ndx++) { if (argstate->cap.data[ndx].c_tag == ca_value) { elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_CA2NDX), EC_WORD(argstate->cap.sec->sec_shndx), argstate->cap.sec->sec_name, EC_WORD(ndx), arg); return (ndx); } /* * If we hit a NULL, then only more NULLs can follow it and * there's no need to look further. If there is more than * one NULL, we can grab the first one and turn it into * an element of the desired type. */ if (argstate->cap.data[ndx].c_tag == CA_SUNW_NULL) { if (ndx < argstate->cap.grp_end_ndx) { Conv_inv_buf_t inv_buf; elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_CONVNULL), EC_WORD(argstate->cap.sec->sec_shndx), argstate->cap.sec->sec_name, EC_WORD(ndx), conv_cap_tag(ca_value, 0, &inv_buf)); argstate->cap.data[ndx].c_tag = ca_value; bzero(&argstate->cap.data[ndx].c_un, sizeof (argstate->cap.data[ndx].c_un)); return (ndx); } break; } } /* No room to create one, so we're out of options and must fail */ elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOCAELT), EC_WORD(argstate->cap.sec->sec_shndx), argstate->cap.sec->sec_name, argstate->cap.grp_start_ndx, argstate->cap.grp_end_ndx, cap_group_id(argstate), arg); /*NOTREACHED*/ return (0); /* For lint */ }
/* * Output a block of raw data as hex bytes. Each row is given * the index of the first byte in the row. * * entry: * data - Pointer to first byte of data to be displayed * n - # of bytes of data * prefix - String to be output before each line. Useful * for indenting output. * bytes_per_col - # of space separated bytes to output * in each column. * col_per_row - # of columns to output per row * * exit: * The formatted data has been sent to stdout. Each row of output * shows (bytes_per_col * col_per_row) bytes of data. */ void dump_hex_bytes(const void *data, size_t n, int indent, int bytes_per_col, int col_per_row) { const uchar_t *ldata = data; int bytes_per_row = bytes_per_col * col_per_row; int ndx, byte, word; char string[128], *str = string; char index[MAXNDXSIZE]; int index_width; int sp_prefix = 0; /* * Determine the width to use for the index string. We follow * 8-byte tab rules, but don't use an actual \t character so * that the output can be arbitrarily shifted without odd * tab effects, and so that all the columns line up no matter * how many lines of output are produced. */ ndx = n / bytes_per_row; (void) snprintf(index, sizeof (index), MSG_ORIG(MSG_FMT_INDEX2), EC_WORD(ndx)); index_width = strlen(index); index_width = S_ROUND(index_width, 8); for (ndx = byte = word = 0; n > 0; n--, ldata++) { while (sp_prefix-- > 0) *str++ = ' '; (void) snprintf(str, sizeof (string), MSG_ORIG(MSG_HEXDUMP_TOK), (int)*ldata); str += 2; sp_prefix = 1; if (++byte == bytes_per_col) { sp_prefix += 2; word++; byte = 0; } if (word == col_per_row) { *str = '\0'; (void) snprintf(index, sizeof (index), MSG_ORIG(MSG_FMT_INDEX2), EC_WORD(ndx)); dbg_print(0, MSG_ORIG(MSG_HEXDUMP_ROW), indent, MSG_ORIG(MSG_STR_EMPTY), index_width, index, string); sp_prefix = 0; word = 0; ndx += bytes_per_row; str = string; } } if (byte || word) { *str = '\0'; /* */ (void) snprintf(index, sizeof (index), MSG_ORIG(MSG_FMT_INDEX2), EC_WORD(ndx)); dbg_print(0, MSG_ORIG(MSG_HEXDUMP_ROW), indent, MSG_ORIG(MSG_STR_EMPTY), index_width, index, string); } }
/* * Common body for the cap: module commands. These commands * share a large amount of common behavior, so it is convenient * to centralize things and use the cmd argument to handle the * small differences. * * entry: * cmd - One of the CAP_CMD_T_* constants listed above, specifying * which command to implement. * obj_state, argc, argv - Standard command arguments */ static elfedit_cmdret_t cmd_body(CAP_CMD_T cmd, elfedit_obj_state_t *obj_state, int argc, const char *argv[]) { ARGSTATE argstate; Cap *cap; const char *cap_name; Word cap_ndx; elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE; PRINT_CAP_T print_type = PRINT_CAP_T_ALL; Word ndx; int print_only = 0; int do_autoprint = 1; /* Process the optional arguments */ process_args(obj_state, argc, argv, &argstate); cap = argstate.cap.data; cap_name = argstate.cap.sec->sec_name; cap_ndx = argstate.cap.sec->sec_shndx; /* Check number of arguments, gather information */ switch (cmd) { case CAP_CMD_T_DUMP: /* cap:dump can accept an optional index argument */ if (argstate.argc > 1) elfedit_command_usage(); print_only = 1; if (argstate.argc == 1) ndx = arg_to_index(&argstate, argstate.argv[0], MSG_ORIG(MSG_STR_ELT), print_only, &print_type); break; case CAP_CMD_T_TAG: case CAP_CMD_T_VALUE: print_only = (argstate.argc != 2); if (argstate.argc > 0) { if (argstate.argc > 2) elfedit_command_usage(); ndx = arg_to_index(&argstate, argstate.argv[0], MSG_ORIG(MSG_STR_ELT), print_only, &print_type); } break; case CAP_CMD_T_DELETE: if ((argstate.argc < 1) || (argstate.argc > 2)) elfedit_command_usage(); ndx = arg_to_index(&argstate, argstate.argv[0], MSG_ORIG(MSG_STR_ELT), 0, &print_type); do_autoprint = 0; break; case CAP_CMD_T_MOVE: if ((argstate.argc < 2) || (argstate.argc > 3)) elfedit_command_usage(); ndx = arg_to_index(&argstate, argstate.argv[0], MSG_ORIG(MSG_STR_ELT), 0, &print_type); do_autoprint = 0; break; case CAP_CMD_T_HW1: print_only = (argstate.argc == 0); ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str( ELFEDIT_CONST_CA, CA_SUNW_HW_1, 1), MSG_ORIG(MSG_STR_VALUE), print_only, &print_type); break; case CAP_CMD_T_SF1: print_only = (argstate.argc == 0); ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str( ELFEDIT_CONST_CA, CA_SUNW_SF_1, 1), MSG_ORIG(MSG_STR_VALUE), print_only, &print_type); break; case CAP_CMD_T_HW2: print_only = (argstate.argc == 0); ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str( ELFEDIT_CONST_CA, CA_SUNW_HW_2, 1), MSG_ORIG(MSG_STR_VALUE), print_only, &print_type); break; default: /* Note expected: All commands should have been caught above */ elfedit_command_usage(); break; } /* If this is a request to print current values, do it and return */ if (print_only) { print_cap(cmd, 0, &argstate, print_type, ndx); return (ELFEDIT_CMDRET_NONE); } switch (cmd) { /* * CAP_CMD_T_DUMP can't get here: It is a print-only * command. */ case CAP_CMD_T_TAG: { Conv_inv_buf_t inv_buf1, inv_buf2; Word c_tag = (Word) elfedit_atoconst(argstate.argv[1], ELFEDIT_CONST_CA); if (cap[ndx].c_tag == c_tag) { elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_OK), cap_ndx, cap_name, EC_WORD(ndx), conv_cap_tag(c_tag, 0, &inv_buf1)); } else { elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_CHG), cap_ndx, cap_name, EC_WORD(ndx), conv_cap_tag(cap[ndx].c_tag, 0, &inv_buf1), conv_cap_tag(c_tag, 0, &inv_buf2)); cap[ndx].c_tag = c_tag; ret = ELFEDIT_CMDRET_MOD; } } break; case CAP_CMD_T_VALUE: { Xword c_val; if (argstate.optmask & CAP_OPT_F_STRVAL) { argstate_add_str(&argstate, TRUE); c_val = elfedit_strtab_insert(obj_state, argstate.str.sec, NULL, argstate.argv[1]); } else { c_val = (Xword) elfedit_atoui(argstate.argv[1], NULL); } if (cap[ndx].c_un.c_val == c_val) { elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_X_OK), argstate.cap.sec->sec_shndx, argstate.cap.sec->sec_name, EC_WORD(ndx), EC_XWORD(c_val)); } else { elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_X_CHG), argstate.cap.sec->sec_shndx, argstate.cap.sec->sec_name, EC_WORD(ndx), EC_XWORD(cap[ndx].c_un.c_val), EC_XWORD(c_val)); cap[ndx].c_un.c_val = c_val; ret = ELFEDIT_CMDRET_MOD; } } break; case CAP_CMD_T_DELETE: { Word cnt = (argstate.argc == 1) ? 1 : (Word) elfedit_atoui_range(argstate.argv[1], MSG_ORIG(MSG_STR_COUNT), 1, argstate.cap.grp_end_ndx - ndx + 1, NULL); const char *msg_prefix = elfedit_sec_msgprefix(argstate.cap.sec); /* * We want to limit the deleted elements to be * in the range of the current capabilities group, * and for the resulting NULL elements to be inserted * at the end of the group, rather than at the end * of the section. To do this, we set the array length * in the call to the delete function so that it thinks * the array ends with the current group. * * The delete function will catch attempts to delete * past this virtual end, but the error message will * not make sense to the user. In order to prevent that, * we check for the condition here and provide a more * useful error. */ if ((ndx + cnt - 1) > argstate.cap.grp_end_ndx) elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_GRPARRBNDS), msg_prefix, argstate.cap.grp_start_ndx, argstate.cap.grp_end_ndx, cap_group_id(&argstate)); elfedit_array_elts_delete(msg_prefix, cap, sizeof (Cap), argstate.cap.grp_end_ndx + 1, ndx, cnt); ret = ELFEDIT_CMDRET_MOD; } break; case CAP_CMD_T_MOVE: { Cap save; Word cnt; Word dstndx; const char *msg_prefix = elfedit_sec_msgprefix(argstate.cap.sec); dstndx = (Word) elfedit_atoui_range(argstate.argv[1], MSG_ORIG(MSG_STR_DST_INDEX), argstate.cap.grp_start_ndx, argstate.cap.grp_end_ndx, NULL); if (argstate.argc == 2) { cnt = 1; } else { Word max; max = argstate.cap.grp_end_ndx - ((ndx > dstndx) ? ndx : dstndx) + 1; cnt = (Word) elfedit_atoui_range( argstate.argv[2], MSG_ORIG(MSG_STR_COUNT), 1, max, NULL); } /* * Moves are required to be self contained within * the bounds of the selected capability group. * The move utility function contains bounds checking, * but is not sub-array aware. Hence, we bounds check * check it here, and then hand of the validated * operation to the move utility function to execute. */ if ((ndx < argstate.cap.grp_start_ndx) || ((ndx + cnt) > argstate.cap.grp_end_ndx) || (dstndx < argstate.cap.grp_start_ndx) || ((dstndx + cnt) > argstate.cap.grp_end_ndx)) elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_GRPARRBNDS), msg_prefix, argstate.cap.grp_start_ndx, argstate.cap.grp_end_ndx, cap_group_id(&argstate)); elfedit_array_elts_move(msg_prefix, cap, sizeof (save), argstate.cap.grp_end_ndx + 1, ndx, dstndx, cnt, &save); ret = ELFEDIT_CMDRET_MOD; } break; case CAP_CMD_T_HW1: { ret = cap_set(&argstate, cap, ndx, cap_ndx, cap_name, CA_SUNW_HW_1, ELFEDIT_CONST_HW1_SUNW); } break; case CAP_CMD_T_SF1: { ret = cap_set(&argstate, cap, ndx, cap_ndx, cap_name, CA_SUNW_SF_1, ELFEDIT_CONST_SF1_SUNW); } break; case CAP_CMD_T_HW2: { ret = cap_set(&argstate, cap, ndx, cap_ndx, cap_name, CA_SUNW_HW_2, ELFEDIT_CONST_HW2_SUNW); } break; } /* * If we modified the capabilities section header, tell libelf. */ if (ret == ELFEDIT_CMDRET_MOD) elfedit_modified_data(argstate.cap.sec); /* Do autoprint */ if (do_autoprint) print_cap(cmd, 1, &argstate, print_type, ndx); return (ret); }
void Dbg_sec_order_list(Ofl_desc *ofl, int flag) { Os_desc *osp; Is_desc *isp1; Aliste idx1; Lm_list *lml = ofl->ofl_lml; const char *str; if (DBG_NOTCLASS(DBG_C_SECTIONS)) return; if (DBG_NOTDETAIL()) return; Dbg_util_nl(lml, DBG_NL_STD); /* * If the flag == 0, then the routine is called before sorting. */ if (flag == 0) str = MSG_INTL(MSG_ORD_SORT_BEFORE); else str = MSG_INTL(MSG_ORD_SORT_AFTER); for (APLIST_TRAVERSE(ofl->ofl_ordered, idx1, osp)) { int os_isdescs_idx; Aliste idx2; Dbg_util_nl(lml, DBG_NL_STD); dbg_print(lml, str, osp->os_name); dbg_print(lml, MSG_INTL(MSG_ORD_HDR_1), EC_WORD(aplist_nitems(osp->os_isdescs[OS_ISD_BEFORE])), EC_WORD(aplist_nitems(osp->os_isdescs[OS_ISD_ORDERED])), EC_WORD(aplist_nitems(osp->os_isdescs[OS_ISD_DEFAULT])), EC_WORD(aplist_nitems(osp->os_isdescs[OS_ISD_AFTER]))); OS_ISDESCS_TRAVERSE(os_isdescs_idx, osp, idx2, isp1) { dbg_isec_name_buf_t buf; char *alloc_mem; const char *isp1_str; Word link; Ifl_desc *ifl = isp1->is_file; Is_desc *isp2; const char *msg; /* * An output segment that requires ordering might have * as little as two sorted input sections. For example, * the crt's can provide a SHN_BEGIN and SHN_AFTER, and * only these two sections must be processed. Thus, if * a input section is unordered, move on. Diagnosing * any unsorted section can produce way too much noise. */ if ((isp1->is_flags & FLG_IS_ORDERED) == 0) continue; if (isp1->is_shdr->sh_flags & SHF_ORDERED) { link = isp1->is_shdr->sh_info; msg = MSG_ORIG(MSG_SH_INFO); } else { /* SHF_LINK_ORDER */ link = isp1->is_shdr->sh_link; msg = MSG_ORIG(MSG_SH_LINK); } isp1_str = dbg_fmt_isec_name(isp1, buf, &alloc_mem); if (link == SHN_BEFORE) { dbg_print(lml, MSG_INTL(MSG_ORD_TITLE_1), msg, isp1_str, isp1->is_file->ifl_name); } else if (link == SHN_AFTER) { dbg_print(lml, MSG_INTL(MSG_ORD_TITLE_2), msg, isp1_str, isp1->is_file->ifl_name); } else { isp2 = ifl->ifl_isdesc[link]; dbg_print(lml, MSG_INTL(MSG_ORD_TITLE_3), EC_WORD(isp2->is_keyident), isp1_str, ifl->ifl_name, msg, isp2->is_name); } if (alloc_mem != NULL) free(alloc_mem); } }