Beispiel #1
0
/*
 * 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);
}
Beispiel #2
0
/*
 * 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);
	}
}
Beispiel #3
0
/*
 * 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);
}
Beispiel #4
0
/*
 * 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));
}
Beispiel #5
0
/*
 * 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));
}
Beispiel #6
0
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);
}
Beispiel #7
0
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);
}
Beispiel #8
0
/*
 * 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)));
}
Beispiel #9
0
/*
 * 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);
}
Beispiel #10
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);
		}
	}
}
Beispiel #11
0
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);
}
Beispiel #12
0
/*
 * 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;
	}
}
Beispiel #13
0
/*
 * "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));
	}
}
Beispiel #14
0
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 = &gtp->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);
		}
	}
}
Beispiel #15
0
/*
 * 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);
}
Beispiel #16
0
/*
 * 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);
}
Beispiel #17
0
/*
 * 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);
}
Beispiel #18
0
/*
 * 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);
}
Beispiel #19
0
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);
}
Beispiel #20
0
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));
	}
}
Beispiel #21
0
/*
 * 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 */
}
Beispiel #22
0
/*
 * 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);
	}
}
Beispiel #23
0
/*
 * 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);
}
Beispiel #24
0
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);
		}
	}