cap.c revision 9273:9a0603d78ad3
190792Sgshapiro/*
2261363Sgshapiro * CDDL HEADER START
390792Sgshapiro *
490792Sgshapiro * The contents of this file are subject to the terms of the
590792Sgshapiro * Common Development and Distribution License (the "License").
690792Sgshapiro * You may not use this file except in compliance with the License.
790792Sgshapiro *
890792Sgshapiro * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9266692Sgshapiro * or http://www.opensolaris.org/os/licensing.
1090792Sgshapiro * See the License for the specific language governing permissions
1190792Sgshapiro * and limitations under the License.
1290792Sgshapiro *
1390792Sgshapiro * When distributing Covered Code, include this CDDL HEADER in each
1490792Sgshapiro * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1590792Sgshapiro * If applicable, add the following below this CDDL HEADER, with the
1690792Sgshapiro * fields enclosed by brackets "[]" replaced with your own identifying
1790792Sgshapiro * information: Portions Copyright [yyyy] [name of copyright owner]
1890792Sgshapiro *
1990792Sgshapiro * CDDL HEADER END
2090792Sgshapiro */
2190792Sgshapiro
2290792Sgshapiro/*
2390792Sgshapiro * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2490792Sgshapiro * Use is subject to license terms.
2590792Sgshapiro */
2690792Sgshapiro
2790792Sgshapiro#include	<ctype.h>
2890792Sgshapiro#include	<elfedit.h>
2990792Sgshapiro#include	<sys/elf_SPARC.h>
3090792Sgshapiro#include	<strings.h>
3190792Sgshapiro#include	<debug.h>
3290792Sgshapiro#include	<conv.h>
3390792Sgshapiro#include	<cap_msg.h>
3490792Sgshapiro
3590792Sgshapiro
3690792Sgshapiro/*
3790792Sgshapiro * Capabilities section
3890792Sgshapiro */
3990792Sgshapiro
4090792Sgshapiro
4190792Sgshapiro
4290792Sgshapiro
4390792Sgshapiro/*
4490792Sgshapiro * This module uses shared code for several of the commands.
4590792Sgshapiro * It is sometimes necessary to know which specific command
4690792Sgshapiro * is active.
4790792Sgshapiro */
4890792Sgshapirotypedef enum {
4990792Sgshapiro	/* Dump command, used as module default to display dynamic section */
5090792Sgshapiro	CAP_CMD_T_DUMP =	0,	/* cap:dump */
5190792Sgshapiro
5290792Sgshapiro	/* Commands that do not correspond directly to a specific DT tag */
5390792Sgshapiro	CAP_CMD_T_TAG =		1,	/* cap:tag */
5490792Sgshapiro	CAP_CMD_T_VALUE =	2,	/* cap:value */
5590792Sgshapiro	CAP_CMD_T_DELETE =	3,	/* cap:delete */
5690792Sgshapiro	CAP_CMD_T_MOVE =	4,	/* cap:shift */
5790792Sgshapiro
5890792Sgshapiro	/* Commands that embody tag specific knowledge */
5990792Sgshapiro	CAP_CMD_T_HW1 =		5,	/* cap:hw1 */
6090792Sgshapiro	CAP_CMD_T_SF1 =		6,	/* cap:sf1 */
6190792Sgshapiro} CAP_CMD_T;
6290792Sgshapiro
6390792Sgshapiro
6490792Sgshapiro
6590792Sgshapiro#ifndef _ELF64
6690792Sgshapiro/*
6790792Sgshapiro * We supply this function for the msg module
6890792Sgshapiro */
6990792Sgshapiroconst char *
7090792Sgshapiro_cap_msg(Msg mid)
7190792Sgshapiro{
7290792Sgshapiro	return (gettext(MSG_ORIG(mid)));
7390792Sgshapiro}
7490792Sgshapiro#endif
7590792Sgshapiro
7690792Sgshapiro
7790792Sgshapiro/*
7890792Sgshapiro * This function is supplied to elfedit through our elfedit_module_t
7990792Sgshapiro * definition. It translates the opaque elfedit_i18nhdl_t handles
8090792Sgshapiro * in our module interface into the actual strings for elfedit to
8190792Sgshapiro * use.
8290792Sgshapiro *
8390792Sgshapiro * note:
8490792Sgshapiro *	This module uses Msg codes for its i18n handle type.
8590792Sgshapiro *	So the translation is simply to use MSG_INTL() to turn
8690792Sgshapiro *	it into a string and return it.
8790792Sgshapiro */
8890792Sgshapirostatic const char *
8990792Sgshapiromod_i18nhdl_to_str(elfedit_i18nhdl_t hdl)
9090792Sgshapiro{
9190792Sgshapiro	Msg msg = (Msg)hdl;
9290792Sgshapiro
9390792Sgshapiro	return (MSG_INTL(msg));
9490792Sgshapiro}
9590792Sgshapiro
9690792Sgshapiro
9790792Sgshapiro
9890792Sgshapiro/*
9990792Sgshapiro * The cap_opt_t enum specifies a bit value for every optional
10090792Sgshapiro * argument allowed by a command in this module.
10190792Sgshapiro */
10290792Sgshapirotypedef enum {
10390792Sgshapiro	CAP_OPT_F_AND =		1,	/* -and: AND (&) values to dest */
10490792Sgshapiro	CAP_OPT_F_CMP =		2,	/* -cmp: Complement (~) values */
10590792Sgshapiro	CAP_OPT_F_CAPNDX =	4,	/* -capndx: elt is tag index, */
10690792Sgshapiro					/*	not name */
10790792Sgshapiro	CAP_OPT_F_OR =		8,	/* -or: OR (|) values to dest */
10890792Sgshapiro} cap_opt_t;
10990792Sgshapiro
11090792Sgshapiro
11190792Sgshapiro/*
11290792Sgshapiro * A variable of type ARGSTATE is used by each command to maintain
11390792Sgshapiro * information about the arguments and related things. It is
114 * initialized by process_args(), and used by the other routines.
115 */
116typedef struct {
117	elfedit_obj_state_t	*obj_state;
118	struct {
119		elfedit_section_t *sec;	/* Capabilities section reference */
120		Cap	*data;		/* Start of capabilities section data */
121		Word	num;		/* # Capabilities elts */
122	} cap;
123	cap_opt_t	optmask;   	/* Mask of options used */
124	int		argc;		/* # of plain arguments */
125	const char	**argv;		/* Plain arguments */
126} ARGSTATE;
127
128
129
130/*
131 * Standard argument processing for cap module
132 *
133 * entry
134 *	obj_state, argc, argv - Standard command arguments
135 *	argstate - Address of ARGSTATE block to be initialized
136 *
137 * exit:
138 *	On success, *argstate is initialized. On error,
139 *	an error is issued and this routine does not return.
140 */
141static void
142process_args(elfedit_obj_state_t *obj_state, int argc, const char *argv[],
143    ARGSTATE *argstate)
144{
145	elfedit_getopt_state_t	getopt_state;
146	elfedit_getopt_ret_t	*getopt_ret;
147
148	bzero(argstate, sizeof (*argstate));
149	argstate->obj_state = obj_state;
150
151	elfedit_getopt_init(&getopt_state, &argc, &argv);
152
153	/* Add each new option to the options mask */
154	while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL)
155		argstate->optmask |= getopt_ret->gor_idmask;
156
157	/* If there may be an arbitrary amount of output, use a pager */
158	if (argc == 0)
159		elfedit_pager_init();
160
161	/* Return the updated values of argc/argv */
162	argstate->argc = argc;
163	argstate->argv = argv;
164
165	/* Locate the capabilities section */
166	argstate->cap.sec = elfedit_sec_getcap(obj_state, &argstate->cap.data,
167	    &argstate->cap.num);
168}
169
170
171
172/*
173 * Print ELF capabilities values, taking the calling command, and output style
174 * into account.
175 *
176 * entry:
177 *	cmd - CAP_CMD_T_* value giving identify of caller
178 *	autoprint - If True, output is only produced if the elfedit
179 *		autoprint flag is set. If False, output is always produced.
180 *	argstate - Argument state block
181 *	print_type - Specifies which capabilities elements to display.
182 *	ndx = If print_type is PRINT_CAP_T_NDX, displays the index specified.
183 *		Otherwise ignored.
184 */
185typedef enum {
186	PRINT_CAP_T_ALL =	0,	/* Show all indexes */
187	PRINT_CAP_T_NDX =	1,	/* Show capabilities[arg] only */
188	PRINT_CAP_T_TAG =	2	/* Show all elts with tag type */
189					/*	given by arg */
190} PRINT_CAP_T;
191
192static void
193print_cap(CAP_CMD_T cmd, int autoprint, ARGSTATE *argstate,
194    PRINT_CAP_T print_type, Word arg)
195{
196	elfedit_outstyle_t	outstyle;
197	Word	cnt, ndx, printed = 0;
198	Cap	*cap;
199	int	header_done = 0;
200	Xword	last_c_val = 0;
201
202	if (autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0))
203		return;
204
205	/*
206	 * Pick an output style. cap:dump is required to use the default
207	 * style. The other commands use the current output style.
208	 */
209	outstyle = (cmd == CAP_CMD_T_DUMP) ?
210	    ELFEDIT_OUTSTYLE_DEFAULT : elfedit_outstyle();
211
212	/* How many elements do we examine? */
213	if (print_type == PRINT_CAP_T_NDX) {
214		if (arg >= argstate->cap.num)
215			return;		/* Out of range */
216		ndx = arg;
217		cnt = 1;
218	} else {
219		ndx = 0;
220		cnt = argstate->cap.num;
221	}
222
223	cap = &argstate->cap.data[ndx];
224	for (; cnt--; cap++, ndx++) {
225		/*
226		 * If we are only displaying certain tag types and
227		 * this isn't one of those, move on to next element.
228		 */
229		if ((print_type == PRINT_CAP_T_TAG) && (cap->c_tag != arg))
230			continue;
231
232		if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) {
233			if (header_done == 0) {
234				header_done = 1;
235				Elf_cap_title(0);
236			}
237			Elf_cap_entry(NULL, cap, ndx,
238			    argstate->obj_state->os_ehdr->e_machine);
239		} else {
240			/*
241			 * In simple or numeric mode under a print type
242			 * that is based on tag type rather than on index,
243			 * quietly: If we've already printed this value,
244			 * don't print it again. A common example of this
245			 * is PRINT_CAP_T_RUNPATH when both CA_RPATH and
246			 * CA_RUNPATH are present with the same value.
247			 */
248			if ((print_type == PRINT_CAP_T_TAG) && printed &&
249			    (last_c_val == cap->c_un.c_val))
250				continue;
251
252			if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
253				union {
254					Conv_cap_val_hw1_buf_t	hw1;
255					Conv_cap_val_sf1_buf_t	sf1;
256				} c_buf;
257
258				switch (cap->c_tag) {
259				case CA_SUNW_HW_1:
260					elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
261					    conv_cap_val_hw1(cap->c_un.c_val,
262					    argstate->obj_state->os_ehdr->
263					    e_machine,
264					    CONV_FMT_NOBKT, &c_buf.hw1));
265					printed = 1;
266					continue;
267				case CA_SUNW_SF_1:
268					elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
269					    conv_cap_val_sf1(cap->c_un.c_val,
270					    argstate->obj_state->os_ehdr->
271					    e_machine,
272					    CONV_FMT_NOBKT, &c_buf.sf1));
273					printed = 1;
274					continue;
275				}
276			}
277			elfedit_printf(MSG_ORIG(MSG_FMT_HEXXWORDNL),
278			    cap->c_un.c_val);
279		}
280		printed = 1;
281		last_c_val = cap->c_un.c_val;
282	}
283
284	/*
285	 * If nothing was output under the print types that are
286	 * based on tag type, issue an error saying it doesn't exist.
287	 */
288	if (!printed && (print_type == PRINT_CAP_T_TAG)) {
289		Conv_inv_buf_t inv_buf;
290
291		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOCAELT),
292		    EC_WORD(argstate->cap.sec->sec_shndx),
293		    argstate->cap.sec->sec_name,
294		    conv_cap_tag(arg, 0, &inv_buf));
295	}
296}
297
298
299/*
300 * Process the elt argument: This will be a tag type if -capndx is
301 * not present and this is a print request. It will be an index otherwise.
302 *
303 * entry:
304 *	argstate - Argument state block
305 *	arg - Argument string to be converted into an index
306 *	argname - String giving the name by which the argument is
307 *		referred in the online help for the command.
308 *	print_request - True if the command is to print the current
309 *		value(s) and return without changing anything.
310 *	print_type - Address of variable containing PRINT_CAP_T_
311 *		code specifying how the elements will be displayed.
312 *
313 * exit:
314 *	If print_request is False: arg is converted into an integer value.
315 *	If -capndx was used, we convert it into an integer. If it was not
316 *	used, then arg is a tag name --- we find the first capabilities entry
317 *	that matches. If no entry matches, and there is an extra CA_NULL,
318 *	it is added. Otherwise an error is issued. *print_type is set
319 *	to PRINT_CAP_T_NDX.
320 *
321 *	If print_request is True: If -capndx was used, arg is converted into
322 *	an integer value, *print_type is set to PRINT_CAP_T_NDX, and
323 *	the value is returned. If -capndx was not used, *print_type is set to
324 *	PRINT_CAP_T_TAG, and the tag value is returned.
325 */
326static Word
327arg_to_index(ARGSTATE *argstate, const char *arg, const char *argname,
328    int print_request, PRINT_CAP_T *print_type)
329{
330	Word	ndx, ca_value;
331
332
333	/* Assume we are returning an index, alter as needed below */
334	*print_type = PRINT_CAP_T_NDX;
335
336	/* If -capndx was used, this is a simple numeric index */
337	if ((argstate->optmask & CAP_OPT_F_CAPNDX) != 0)
338		return ((Word) elfedit_atoui_range(arg, argname, 0,
339		    argstate->cap.num - 1, NULL));
340
341	/* The argument is a CA_ tag type, not a numeric index */
342	ca_value = (Word) elfedit_atoconst(arg, ELFEDIT_CONST_CA);
343
344	/*
345	 * If this is a printing request, then we let print_cap() show
346	 * all the items with this tag type.
347	 */
348	if (print_request) {
349		*print_type = PRINT_CAP_T_TAG;
350		return (ca_value);
351	}
352
353	/* Locate the first entry with the given tag type */
354	for (ndx = 0; ndx < argstate->cap.num; ndx++) {
355		if (argstate->cap.data[ndx].c_tag == ca_value) {
356			elfedit_msg(ELFEDIT_MSG_DEBUG,
357			    MSG_INTL(MSG_DEBUG_CA2NDX),
358			    EC_WORD(argstate->cap.sec->sec_shndx),
359			    argstate->cap.sec->sec_name, EC_WORD(ndx), arg);
360			return (ndx);
361		}
362	}
363
364	/* No room to create one, so we're out of options and must fail */
365	elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOCAELT),
366	    EC_WORD(argstate->cap.sec->sec_shndx),
367	    argstate->cap.sec->sec_name, arg);
368
369	/*NOTREACHED*/
370	return (0);		/* For lint */
371}
372
373
374/*
375 * Argument processing for the bitmask commands. Convert the arguments
376 * to integer form, apply -and/-cmp/-or, and return the resulting value.
377 *
378 * entry:
379 *	argstate - Argument state block
380 *	orig - Value of original bitmask
381 *	const_sym - NULL, or array of name->integer mappings for
382 *		applicable symbolic constant names.
383 */
384static Word
385flag_bitop(ARGSTATE *argstate, Word orig, const elfedit_atoui_sym_t *const_sym)
386{
387	Word flags = 0;
388	int i;
389
390	/* Collect the arguments */
391	for (i = 0; i < argstate->argc; i++)
392		flags |= (Word) elfedit_atoui(argstate->argv[i], const_sym);
393
394	/* Complement the value? */
395	if (argstate->optmask & CAP_OPT_F_CMP)
396		flags = ~flags;
397
398	/* Perform any requested bit operations */
399	if (argstate->optmask & CAP_OPT_F_AND)
400		flags &= orig;
401	else if (argstate->optmask & CAP_OPT_F_OR)
402		flags |= orig;
403
404	return (flags);
405}
406
407
408
409/*
410 * Common body for the cap: module commands. These commands
411 * share a large amount of common behavior, so it is convenient
412 * to centralize things and use the cmd argument to handle the
413 * small differences.
414 *
415 * entry:
416 *	cmd - One of the CAP_CMD_T_* constants listed above, specifying
417 *		which command to implement.
418 *	obj_state, argc, argv - Standard command arguments
419 */
420static elfedit_cmdret_t
421cmd_body(CAP_CMD_T cmd, elfedit_obj_state_t *obj_state,
422    int argc, const char *argv[])
423{
424	ARGSTATE		argstate;
425	Cap			*cap;
426	const char		*cap_name;
427	Word			cap_ndx, cap_num;
428	elfedit_cmdret_t	ret = ELFEDIT_CMDRET_NONE;
429	PRINT_CAP_T		print_type = PRINT_CAP_T_ALL;
430	Word			ndx;
431	int			print_only = 0;
432	int			do_autoprint = 1;
433
434	/* Process the optional arguments */
435	process_args(obj_state, argc, argv, &argstate);
436
437	cap = argstate.cap.data;
438	cap_num = argstate.cap.num;
439	cap_name = argstate.cap.sec->sec_name;
440	cap_ndx = argstate.cap.sec->sec_shndx;
441
442	/* Check number of arguments, gather information */
443	switch (cmd) {
444	case CAP_CMD_T_DUMP:
445		/* cap:dump can accept an optional index argument */
446		if (argstate.argc > 1)
447			elfedit_command_usage();
448		print_only = 1;
449		if (argstate.argc == 1)
450			ndx = arg_to_index(&argstate, argstate.argv[0],
451			    MSG_ORIG(MSG_STR_ELT), print_only, &print_type);
452		break;
453
454	case CAP_CMD_T_TAG:
455	case CAP_CMD_T_VALUE:
456		print_only = (argstate.argc != 2);
457		if (argstate.argc > 0) {
458			if (argstate.argc > 2)
459				elfedit_command_usage();
460			ndx = arg_to_index(&argstate, argstate.argv[0],
461			    MSG_ORIG(MSG_STR_ELT), print_only, &print_type);
462		}
463		break;
464
465	case CAP_CMD_T_DELETE:
466		if ((argstate.argc < 1) || (argstate.argc > 2))
467			elfedit_command_usage();
468		ndx = arg_to_index(&argstate, argstate.argv[0],
469		    MSG_ORIG(MSG_STR_ELT),
470		    0, &print_type);
471		do_autoprint = 0;
472		break;
473
474	case CAP_CMD_T_MOVE:
475		if ((argstate.argc < 2) || (argstate.argc > 3))
476			elfedit_command_usage();
477		ndx = arg_to_index(&argstate, argstate.argv[0],
478		    MSG_ORIG(MSG_STR_ELT), 0, &print_type);
479		do_autoprint = 0;
480		break;
481
482	case CAP_CMD_T_HW1:
483		print_only = (argstate.argc == 0);
484		ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str(
485		    ELFEDIT_CONST_CA, CA_SUNW_HW_1, 1),
486		    MSG_ORIG(MSG_STR_VALUE), print_only, &print_type);
487		break;
488
489	case CAP_CMD_T_SF1:
490		print_only = (argstate.argc == 0);
491		ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str(
492		    ELFEDIT_CONST_CA, CA_SUNW_SF_1, 1),
493		    MSG_ORIG(MSG_STR_VALUE), print_only, &print_type);
494		break;
495
496	default:
497		/* Note expected: All commands should have been caught above */
498		elfedit_command_usage();
499		break;
500	}
501
502
503	/* If this is a request to print current values, do it and return */
504	if (print_only) {
505		print_cap(cmd, 0, &argstate, print_type, ndx);
506		return (ELFEDIT_CMDRET_NONE);
507	}
508
509
510	switch (cmd) {
511		/*
512		 * CAP_CMD_T_DUMP can't get here: It is a print-only
513		 * command.
514		 */
515
516	case CAP_CMD_T_TAG:
517		{
518			Conv_inv_buf_t	inv_buf1, inv_buf2;
519			Word c_tag = (Word) elfedit_atoconst(argstate.argv[1],
520			    ELFEDIT_CONST_CA);
521
522			if (cap[ndx].c_tag == c_tag) {
523				elfedit_msg(ELFEDIT_MSG_DEBUG,
524				    MSG_INTL(MSG_DEBUG_S_OK),
525				    cap_ndx, cap_name, EC_WORD(ndx),
526				    conv_cap_tag(c_tag, 0, &inv_buf1));
527			} else {
528				elfedit_msg(ELFEDIT_MSG_DEBUG,
529				    MSG_INTL(MSG_DEBUG_S_CHG),
530				    cap_ndx, cap_name, EC_WORD(ndx),
531				    conv_cap_tag(cap[ndx].c_tag, 0, &inv_buf1),
532				    conv_cap_tag(c_tag, 0, &inv_buf2));
533				cap[ndx].c_tag = c_tag;
534				ret = ELFEDIT_CMDRET_MOD;
535			}
536		}
537		break;
538
539	case CAP_CMD_T_VALUE:
540		{
541			Xword c_val = (Xword)
542			    elfedit_atoui(argstate.argv[1], NULL);
543
544			if (cap[ndx].c_un.c_val == c_val) {
545				elfedit_msg(ELFEDIT_MSG_DEBUG,
546				    MSG_INTL(MSG_DEBUG_X_OK),
547				    argstate.cap.sec->sec_shndx,
548				    argstate.cap.sec->sec_name,
549				    EC_WORD(ndx), EC_XWORD(c_val));
550			} else {
551				elfedit_msg(ELFEDIT_MSG_DEBUG,
552				    MSG_INTL(MSG_DEBUG_X_CHG),
553				    argstate.cap.sec->sec_shndx,
554				    argstate.cap.sec->sec_name,
555				    EC_WORD(ndx), EC_XWORD(cap[ndx].c_un.c_val),
556				    EC_XWORD(c_val));
557				cap[ndx].c_un.c_val = c_val;
558				ret = ELFEDIT_CMDRET_MOD;
559			}
560		}
561		break;
562
563	case CAP_CMD_T_DELETE:
564		{
565			Word cnt = (argstate.argc == 1) ? 1 :
566			    (Word) elfedit_atoui_range(argstate.argv[1],
567			    MSG_ORIG(MSG_STR_COUNT), 1, cap_num - ndx, NULL);
568			const char *msg_prefix =
569			    elfedit_sec_msgprefix(argstate.cap.sec);
570
571			elfedit_array_elts_delete(msg_prefix, argstate.cap.data,
572			    sizeof (Cap), cap_num, ndx, cnt);
573			ret = ELFEDIT_CMDRET_MOD;
574		}
575		break;
576
577	case CAP_CMD_T_MOVE:
578		{
579			Cap	save;
580			Word	cnt;
581			Word	dstndx;
582			const char *msg_prefix =
583			    elfedit_sec_msgprefix(argstate.cap.sec);
584
585			dstndx = (Word)
586			    elfedit_atoui_range(argstate.argv[1],
587			    MSG_ORIG(MSG_STR_DST_INDEX), 0, cap_num - 1,
588			    NULL);
589			if (argstate.argc == 2) {
590				cnt = 1;
591			} else {
592				cnt = (Word) elfedit_atoui_range(
593				    argstate.argv[2], MSG_ORIG(MSG_STR_COUNT),
594				    1, cap_num, NULL);
595			}
596			elfedit_array_elts_move(msg_prefix, argstate.cap.data,
597			    sizeof (save), cap_num, ndx, dstndx, cnt, &save);
598			ret = ELFEDIT_CMDRET_MOD;
599		}
600		break;
601
602
603	case CAP_CMD_T_HW1:
604		{
605			Conv_cap_val_hw1_buf_t buf1, buf2;
606			Half	mach = argstate.obj_state->os_ehdr->e_machine;
607			Xword	hw1;
608
609			hw1 = flag_bitop(&argstate, cap[ndx].c_un.c_val,
610			    elfedit_const_to_atoui(ELFEDIT_CONST_AV));
611
612			/* Set the value */
613			if (cap[ndx].c_un.c_val == hw1) {
614				elfedit_msg(ELFEDIT_MSG_DEBUG,
615				    MSG_INTL(MSG_DEBUG_BSB_OK), cap_ndx,
616				    cap_name, EC_WORD(ndx),
617				    conv_cap_val_hw1(cap[ndx].c_un.c_val, mach,
618				    CONV_FMT_NOBKT, &buf1));
619			} else {
620				elfedit_msg(ELFEDIT_MSG_DEBUG,
621				    MSG_INTL(MSG_DEBUG_BSB_CHG),
622				    cap_ndx, cap_name, EC_WORD(ndx),
623				    conv_cap_val_hw1(cap[ndx].c_un.c_val, mach,
624				    CONV_FMT_NOBKT, &buf1),
625				    conv_cap_val_hw1(hw1, mach,
626				    CONV_FMT_NOBKT, &buf2));
627				ret = ELFEDIT_CMDRET_MOD;
628				cap[ndx].c_un.c_val = hw1;
629			}
630		}
631		break;
632
633	case CAP_CMD_T_SF1:
634		{
635			Conv_cap_val_sf1_buf_t buf1, buf2;
636			Half	mach = argstate.obj_state->os_ehdr->e_machine;
637			Xword	sf1;
638
639			sf1 = flag_bitop(&argstate, cap[ndx].c_un.c_val,
640			    elfedit_const_to_atoui(ELFEDIT_CONST_SF1_SUNW));
641
642			/* Set the value */
643			if (cap[ndx].c_un.c_val == sf1) {
644				elfedit_msg(ELFEDIT_MSG_DEBUG,
645				    MSG_INTL(MSG_DEBUG_BSB_OK), cap_ndx,
646				    cap_name, EC_WORD(ndx),
647				    conv_cap_val_sf1(cap[ndx].c_un.c_val, mach,
648				    CONV_FMT_NOBKT, &buf1));
649			} else {
650				elfedit_msg(ELFEDIT_MSG_DEBUG,
651				    MSG_INTL(MSG_DEBUG_BSB_CHG),
652				    cap_ndx, cap_name, EC_WORD(ndx),
653				    conv_cap_val_sf1(cap[ndx].c_un.c_val, mach,
654				    CONV_FMT_NOBKT, &buf1),
655				    conv_cap_val_sf1(sf1, mach,
656				    CONV_FMT_NOBKT, &buf2));
657				ret = ELFEDIT_CMDRET_MOD;
658				cap[ndx].c_un.c_val = sf1;
659			}
660		}
661		break;
662	}
663
664	/*
665	 * If we modified the capabilities section header, tell libelf.
666	 */
667	if (ret == ELFEDIT_CMDRET_MOD)
668		elfedit_modified_data(argstate.cap.sec);
669
670	/* Do autoprint */
671	if (do_autoprint)
672		print_cap(cmd, 1, &argstate, print_type, ndx);
673
674	return (ret);
675}
676
677
678
679/*
680 * Command completion functions for the commands
681 */
682
683/*
684 * Command completion for the first argument, which specifies
685 * the capabilities element to use. Examines the options to see if
686 * -capndx is present, and if not, supplies the completion
687 * strings for argument 1.
688 */
689/*ARGSUSED*/
690static void
691cpl_eltarg(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
692    const char *argv[], int num_opt)
693{
694	Word			i;
695
696	/* Make sure it's the first argument */
697	if ((argc - num_opt) != 1)
698		return;
699
700	/* Is -capndx present? If so, we don't complete tag types */
701	for (i = 0; i < num_opt; i++)
702		if (strcmp(argv[i], MSG_ORIG(MSG_STR_MINUS_CAPNDX)) == 0)
703			return;
704
705	/*
706	 * Supply capability tag names. There are very few of these, so
707	 * rather than worry about whether a given tag exists in the
708	 * file or not, we simply serve up all the possibilities.
709	 */
710	elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_CA);
711}
712
713
714/*ARGSUSED*/
715static void
716cpl_tag(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
717    const char *argv[], int num_opt)
718{
719	/* First argument */
720	if ((argc - num_opt) == 1) {
721		cpl_eltarg(obj_state, cpldata, argc, argv, num_opt);
722		return;
723	}
724
725	/* The second argument is always a tag value */
726	if ((argc - num_opt) == 2)
727		elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_CA);
728}
729
730/*ARGSUSED*/
731static void
732cpl_hw1(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
733    const char *argv[], int num_opt)
734{
735	/* This routine allows multiple flags to be specified */
736
737	elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_AV);
738}
739
740/*ARGSUSED*/
741static void
742cpl_sf1(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
743    const char *argv[], int num_opt)
744{
745	/* This routine allows multiple flags to be specified */
746	elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SF1_SUNW);
747}
748
749
750/*
751 * Implementation functions for the commands
752 */
753static elfedit_cmdret_t
754cmd_dump(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
755{
756	return (cmd_body(CAP_CMD_T_DUMP, obj_state, argc, argv));
757}
758
759static elfedit_cmdret_t
760cmd_tag(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
761{
762	return (cmd_body(CAP_CMD_T_TAG, obj_state, argc, argv));
763}
764
765static elfedit_cmdret_t
766cmd_value(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
767{
768	return (cmd_body(CAP_CMD_T_VALUE, obj_state, argc, argv));
769}
770
771static elfedit_cmdret_t
772cmd_delete(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
773{
774	return (cmd_body(CAP_CMD_T_DELETE, obj_state, argc, argv));
775}
776
777static elfedit_cmdret_t
778cmd_move(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
779{
780	return (cmd_body(CAP_CMD_T_MOVE, obj_state, argc, argv));
781}
782
783static elfedit_cmdret_t
784cmd_hw1(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
785{
786	return (cmd_body(CAP_CMD_T_HW1, obj_state, argc, argv));
787}
788
789static elfedit_cmdret_t
790cmd_sf1(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
791{
792	return (cmd_body(CAP_CMD_T_SF1, obj_state, argc, argv));
793}
794
795
796
797/*ARGSUSED*/
798elfedit_module_t *
799elfedit_init(elfedit_module_version_t version)
800{
801	/* For commands that only accept -and, -cmp, -o, and -or */
802	static elfedit_cmd_optarg_t opt_ostyle_bitop[] = {
803		{ ELFEDIT_STDOA_OPT_AND, NULL,
804		    ELFEDIT_CMDOA_F_INHERIT, CAP_OPT_F_AND, CAP_OPT_F_OR },
805		{ ELFEDIT_STDOA_OPT_CMP, NULL,
806		    ELFEDIT_CMDOA_F_INHERIT, CAP_OPT_F_CMP, 0 },
807		{ ELFEDIT_STDOA_OPT_O, NULL,
808		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
809		{ ELFEDIT_STDOA_OPT_OR, NULL,
810		    ELFEDIT_CMDOA_F_INHERIT, CAP_OPT_F_OR, CAP_OPT_F_AND },
811		{ NULL }
812	};
813
814	/* For commands that only accept -capndx */
815	static elfedit_cmd_optarg_t opt_capndx[] = {
816		{ MSG_ORIG(MSG_STR_MINUS_CAPNDX),
817		    /* MSG_INTL(MSG_OPTDESC_CAPNDX) */
818		    ELFEDIT_I18NHDL(MSG_OPTDESC_CAPNDX), 0,
819		    CAP_OPT_F_CAPNDX, 0 },
820		{ NULL }
821	};
822
823	/* For commands thataccept -capndx and output styles */
824	static elfedit_cmd_optarg_t opt_ostyle_capndx[] = {
825		{ MSG_ORIG(MSG_STR_MINUS_CAPNDX),
826		    /* MSG_INTL(MSG_OPTDESC_CAPNDX) */
827		    ELFEDIT_I18NHDL(MSG_OPTDESC_CAPNDX), 0,
828		    CAP_OPT_F_CAPNDX, 0 },
829		{ ELFEDIT_STDOA_OPT_O, NULL,
830		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
831		{ NULL }
832	};
833
834
835	/* cap:dump */
836	static const char *name_dump[] = {
837	    MSG_ORIG(MSG_CMD_DUMP),
838	    MSG_ORIG(MSG_STR_EMPTY),	/* "" makes this the default command */
839	    NULL
840	};
841	static elfedit_cmd_optarg_t arg_dump[] = {
842		{ MSG_ORIG(MSG_STR_ELT),
843		    /* MSG_INTL(MSG_ARGDESC_ELT) */
844		    ELFEDIT_I18NHDL(MSG_ARGDESC_ELT),
845		    ELFEDIT_CMDOA_F_OPT },
846		{ NULL }
847	};
848
849
850	/* cap:tag */
851	static const char *name_tag[] = { MSG_ORIG(MSG_CMD_TAG), NULL };
852	static elfedit_cmd_optarg_t arg_tag[] = {
853		{ MSG_ORIG(MSG_STR_ELT),
854		    /* MSG_INTL(MSG_A1_TAG_ELT) */
855		    ELFEDIT_I18NHDL(MSG_A1_TAG_ELT),
856		    ELFEDIT_CMDOA_F_OPT },
857		{ MSG_ORIG(MSG_STR_VALUE),
858		    /* MSG_INTL(MSG_A2_TAG_VALUE) */
859		    ELFEDIT_I18NHDL(MSG_A2_TAG_VALUE),
860		    ELFEDIT_CMDOA_F_OPT },
861		{ NULL }
862	};
863
864
865	/* cap:value */
866	static const char *name_value[] = { MSG_ORIG(MSG_CMD_VALUE), NULL };
867	static elfedit_cmd_optarg_t arg_value[] = {
868		{ MSG_ORIG(MSG_STR_ELT),
869		    /* MSG_INTL(MSG_ARGDESC_ELT) */
870		    ELFEDIT_I18NHDL(MSG_ARGDESC_ELT),
871		    ELFEDIT_CMDOA_F_OPT },
872		{ MSG_ORIG(MSG_STR_VALUE),
873		    /* MSG_INTL(MSG_A2_VALUE_VALUE) */
874		    ELFEDIT_I18NHDL(MSG_A2_VALUE_VALUE),
875		    ELFEDIT_CMDOA_F_OPT },
876		{ NULL }
877	};
878
879	/* cap:delete */
880	static const char *name_delete[] = { MSG_ORIG(MSG_CMD_DELETE), NULL };
881	static elfedit_cmd_optarg_t arg_delete[] = {
882		{ MSG_ORIG(MSG_STR_ELT),
883		    /* MSG_INTL(MSG_ARGDESC_ELT) */
884		    ELFEDIT_I18NHDL(MSG_ARGDESC_ELT),
885		    0 },
886		{ MSG_ORIG(MSG_STR_COUNT),
887		    /* MSG_INTL(MSG_A2_DELETE_COUNT) */
888		    ELFEDIT_I18NHDL(MSG_A2_DELETE_COUNT),
889		    ELFEDIT_CMDOA_F_OPT },
890		{ NULL }
891	};
892
893	/* cap:move */
894	static const char *name_move[] = { MSG_ORIG(MSG_CMD_MOVE), NULL };
895	static elfedit_cmd_optarg_t arg_move[] = {
896		{ MSG_ORIG(MSG_STR_ELT),
897		    /* MSG_INTL(MSG_ARGDESC_ELT) */
898		    ELFEDIT_I18NHDL(MSG_ARGDESC_ELT),
899		    0 },
900		{ MSG_ORIG(MSG_STR_DST_INDEX),
901		    /* MSG_INTL(MSG_A2_MOVE_DST_INDEX) */
902		    ELFEDIT_I18NHDL(MSG_A2_MOVE_DST_INDEX),
903		    0 },
904		{ MSG_ORIG(MSG_STR_COUNT),
905		    /* MSG_INTL(MSG_A3_MOVE_COUNT) */
906		    ELFEDIT_I18NHDL(MSG_A3_MOVE_COUNT),
907		    ELFEDIT_CMDOA_F_OPT },
908		{ NULL }
909	};
910
911	/* cap:hw1 */
912	static const char *name_hw1[] = { MSG_ORIG(MSG_CMD_HW1), NULL };
913	static elfedit_cmd_optarg_t arg_hw1[] = {
914		{ MSG_ORIG(MSG_STR_VALUE),
915		    /* MSG_INTL(MSG_A1_HW1_VALUE) */
916		    ELFEDIT_I18NHDL(MSG_A1_HW1_VALUE),
917		    ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
918		{ NULL }
919	};
920
921	/* cap:sf1 */
922	static const char *name_sf1[] = { MSG_ORIG(MSG_CMD_SF1), NULL };
923	static elfedit_cmd_optarg_t arg_sf1[] = {
924		{ MSG_ORIG(MSG_STR_VALUE),
925		    /* MSG_INTL(MSG_A1_SF1_VALUE) */
926		    ELFEDIT_I18NHDL(MSG_A1_SF1_VALUE),
927		    ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
928		{ NULL }
929	};
930
931
932
933
934	static elfedit_cmd_t cmds[] = {
935		/* cap:dump */
936		{ cmd_dump, cpl_eltarg, name_dump,
937		    /* MSG_INTL(MSG_DESC_DUMP) */
938		    ELFEDIT_I18NHDL(MSG_DESC_DUMP),
939		    /* MSG_INTL(MSG_HELP_DUMP) */
940		    ELFEDIT_I18NHDL(MSG_HELP_DUMP),
941		    opt_capndx, arg_dump },
942
943		/* cap:tag */
944		{ cmd_tag, cpl_tag, name_tag,
945		    /* MSG_INTL(MSG_DESC_TAG) */
946		    ELFEDIT_I18NHDL(MSG_DESC_TAG),
947		    /* MSG_INTL(MSG_HELP_TAG) */
948		    ELFEDIT_I18NHDL(MSG_HELP_TAG),
949		    opt_ostyle_capndx, arg_tag },
950
951		/* cap:value */
952		{ cmd_value, cpl_eltarg, name_value,
953		    /* MSG_INTL(MSG_DESC_VALUE) */
954		    ELFEDIT_I18NHDL(MSG_DESC_VALUE),
955		    /* MSG_INTL(MSG_HELP_VALUE) */
956		    ELFEDIT_I18NHDL(MSG_HELP_VALUE),
957		    opt_ostyle_capndx, arg_value },
958
959		/* cap:delete */
960		{ cmd_delete, cpl_eltarg, name_delete,
961		    /* MSG_INTL(MSG_DESC_DELETE) */
962		    ELFEDIT_I18NHDL(MSG_DESC_DELETE),
963		    /* MSG_INTL(MSG_HELP_DELETE) */
964		    ELFEDIT_I18NHDL(MSG_HELP_DELETE),
965		    opt_capndx, arg_delete },
966
967		/* cap:move */
968		{ cmd_move, cpl_eltarg, name_move,
969		    /* MSG_INTL(MSG_DESC_MOVE) */
970		    ELFEDIT_I18NHDL(MSG_DESC_MOVE),
971		    /* MSG_INTL(MSG_HELP_MOVE) */
972		    ELFEDIT_I18NHDL(MSG_HELP_MOVE),
973		    opt_capndx, arg_move },
974
975		/* cap:hw1 */
976		{ cmd_hw1, cpl_hw1, name_hw1,
977		    /* MSG_INTL(MSG_DESC_HW1) */
978		    ELFEDIT_I18NHDL(MSG_DESC_HW1),
979		    /* MSG_INTL(MSG_HELP_HW1) */
980		    ELFEDIT_I18NHDL(MSG_HELP_HW1),
981		    opt_ostyle_bitop, arg_hw1 },
982
983		/* cap:sf1 */
984		{ cmd_sf1, cpl_sf1, name_sf1,
985		    /* MSG_INTL(MSG_DESC_SF1) */
986		    ELFEDIT_I18NHDL(MSG_DESC_SF1),
987		    /* MSG_INTL(MSG_HELP_SF1) */
988		    ELFEDIT_I18NHDL(MSG_HELP_SF1),
989		    opt_ostyle_bitop, arg_sf1 },
990
991		{ NULL }
992	};
993
994	static elfedit_module_t module = {
995	    ELFEDIT_VER_CURRENT, MSG_ORIG(MSG_MOD_NAME),
996	    /* MSG_INTL(MSG_MOD_DESC) */
997	    ELFEDIT_I18NHDL(MSG_MOD_DESC),
998	    cmds, mod_i18nhdl_to_str };
999
1000	return (&module);
1001}
1002