1d29b2c44Sab /*
2d29b2c44Sab * CDDL HEADER START
3d29b2c44Sab *
4d29b2c44Sab * The contents of this file are subject to the terms of the
5d29b2c44Sab * Common Development and Distribution License (the "License").
6d29b2c44Sab * You may not use this file except in compliance with the License.
7d29b2c44Sab *
8d29b2c44Sab * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9d29b2c44Sab * or http://www.opensolaris.org/os/licensing.
10d29b2c44Sab * See the License for the specific language governing permissions
11d29b2c44Sab * and limitations under the License.
12d29b2c44Sab *
13d29b2c44Sab * When distributing Covered Code, include this CDDL HEADER in each
14d29b2c44Sab * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15d29b2c44Sab * If applicable, add the following below this CDDL HEADER, with the
16d29b2c44Sab * fields enclosed by brackets "[]" replaced with your own identifying
17d29b2c44Sab * information: Portions Copyright [yyyy] [name of copyright owner]
18d29b2c44Sab *
19d29b2c44Sab * CDDL HEADER END
20d29b2c44Sab */
21d29b2c44Sab
22d29b2c44Sab /*
234f680cc6SAli Bahrami * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24d29b2c44Sab * Use is subject to license terms.
25d29b2c44Sab */
26d29b2c44Sab
27d29b2c44Sab #include <stdio.h>
28d29b2c44Sab #include <unistd.h>
29d29b2c44Sab #include <elfedit.h>
30d29b2c44Sab #include <strings.h>
31d29b2c44Sab #include <debug.h>
32d29b2c44Sab #include <conv.h>
33d29b2c44Sab #include <syminfo_msg.h>
34d29b2c44Sab
35d29b2c44Sab
36d29b2c44Sab
37d29b2c44Sab /*
38d29b2c44Sab * This module uses shared code for several of the commands.
39d29b2c44Sab * It is sometimes necessary to know which specific command
40d29b2c44Sab * is active.
41d29b2c44Sab */
42d29b2c44Sab typedef enum {
43d29b2c44Sab SYMINFO_CMD_T_DUMP = 0, /* syminfo:dump */
44d29b2c44Sab
45d29b2c44Sab SYMINFO_CMD_T_SI_BOUNDTO = 1, /* syminfo:si_boundto */
46d29b2c44Sab SYMINFO_CMD_T_SI_FLAGS = 2 /* syminfo:si_boundto */
47d29b2c44Sab } SYMINFO_CMD_T;
48d29b2c44Sab
49d29b2c44Sab
50d29b2c44Sab
51d29b2c44Sab #ifndef _ELF64
52d29b2c44Sab /*
53d29b2c44Sab * We supply this function for the msg module. Only one copy is needed.
54d29b2c44Sab */
55d29b2c44Sab const char *
_syminfo_msg(Msg mid)56d29b2c44Sab _syminfo_msg(Msg mid)
57d29b2c44Sab {
58d29b2c44Sab return (gettext(MSG_ORIG(mid)));
59d29b2c44Sab }
60d29b2c44Sab
61d29b2c44Sab #endif
62d29b2c44Sab
63d29b2c44Sab
64d29b2c44Sab
65d29b2c44Sab /*
66d29b2c44Sab * This function is supplied to elfedit through our elfedit_module_t
67d29b2c44Sab * definition. It translates the opaque elfedit_i18nhdl_t handles
68d29b2c44Sab * in our module interface into the actual strings for elfedit to
69d29b2c44Sab * use.
70d29b2c44Sab *
71d29b2c44Sab * note:
72d29b2c44Sab * This module uses Msg codes for its i18n handle type.
73d29b2c44Sab * So the translation is simply to use MSG_INTL() to turn
74d29b2c44Sab * it into a string and return it.
75d29b2c44Sab */
76d29b2c44Sab static const char *
mod_i18nhdl_to_str(elfedit_i18nhdl_t hdl)77d29b2c44Sab mod_i18nhdl_to_str(elfedit_i18nhdl_t hdl)
78d29b2c44Sab {
79d29b2c44Sab Msg msg = (Msg)hdl;
80d29b2c44Sab
81d29b2c44Sab return (MSG_INTL(msg));
82d29b2c44Sab }
83d29b2c44Sab
84d29b2c44Sab
85d29b2c44Sab
86d29b2c44Sab /*
87d29b2c44Sab * The sym_opt_t enum specifies a bit value for every optional
88d29b2c44Sab * argument allowed by a command in this module.
89d29b2c44Sab */
90d29b2c44Sab typedef enum {
91d29b2c44Sab SYMINFO_OPT_F_AND = 1, /* -and: AND (&) values to dest */
92d29b2c44Sab SYMINFO_OPT_F_CMP = 2, /* -cmp: Complement (~) values */
93d29b2c44Sab SYMINFO_OPT_F_NEEDED = 4, /* -needed: arg is name of object to */
94d29b2c44Sab /* be referenced via DT_NEEDED */
95d29b2c44Sab /* dynamic entry */
96d29b2c44Sab SYMINFO_OPT_F_OR = 8, /* -or: OR (|) values to dest */
97d29b2c44Sab SYMINFO_OPT_F_SYMNDX = 16 /* -symndx: Sym specified by index */
98d29b2c44Sab } syminfo_opt_t;
99d29b2c44Sab
100d29b2c44Sab
101d29b2c44Sab /*
102d29b2c44Sab * A variable of type ARGSTATE is used by each command to maintain
103d29b2c44Sab * information about the syminfo section being used, as and for any
104d29b2c44Sab * auxiliary sections that are related to it. This helps us to ensure
105d29b2c44Sab * that we only fetch each section a single time:
106d29b2c44Sab * - More efficient
107d29b2c44Sab * - Prevents multiple ELFEDIT_MSG_DEBUG messages from
108d29b2c44Sab * being produced for a given section.
109d29b2c44Sab */
110d29b2c44Sab typedef struct {
111d29b2c44Sab elfedit_obj_state_t *obj_state;
112*9320f495SToomas Soome syminfo_opt_t optmask; /* Mask of options used */
113d29b2c44Sab int argc; /* # of plain arguments */
114d29b2c44Sab const char **argv; /* Plain arguments */
115d29b2c44Sab struct { /* Syminfo */
116d29b2c44Sab elfedit_section_t *sec;
117d29b2c44Sab Syminfo *data;
118d29b2c44Sab Word n;
119d29b2c44Sab } syminfo;
120d29b2c44Sab struct { /* Symbol table */
121d29b2c44Sab elfedit_section_t *sec;
122d29b2c44Sab Sym *data;
123d29b2c44Sab Word n;
124d29b2c44Sab } sym;
125d29b2c44Sab struct { /* String table */
126d29b2c44Sab elfedit_section_t *sec;
127d29b2c44Sab } str;
128d29b2c44Sab struct { /* Dynamic section */
129d29b2c44Sab elfedit_section_t *sec;
130d29b2c44Sab Dyn *data;
131d29b2c44Sab Word n;
132d29b2c44Sab } dynamic;
133d29b2c44Sab } ARGSTATE;
134d29b2c44Sab
135d29b2c44Sab
136d29b2c44Sab
137d29b2c44Sab /*
138d29b2c44Sab * Standard argument processing for syminfo module
139d29b2c44Sab *
140d29b2c44Sab * entry
141d29b2c44Sab * obj_state, argc, argv - Standard command arguments
142d29b2c44Sab * optmask - Mask of allowed optional arguments.
143d29b2c44Sab * argstate - Address of ARGSTATE block to be initialized
144d29b2c44Sab *
145d29b2c44Sab * exit:
146d29b2c44Sab * On success, *argstate is initialized. On error,
147d29b2c44Sab * an error is issued and this routine does not return.
148d29b2c44Sab *
149d29b2c44Sab * note:
150d29b2c44Sab * Only the syminfo section is initially referenced by
151d29b2c44Sab * argstate. Use the argstate_add_XXX() routines below to
152d29b2c44Sab * access any other sections needed.
153d29b2c44Sab */
154d29b2c44Sab static void
process_args(elfedit_obj_state_t * obj_state,int argc,const char * argv[],SYMINFO_CMD_T cmd,ARGSTATE * argstate)155d29b2c44Sab process_args(elfedit_obj_state_t *obj_state, int argc, const char *argv[],
156d29b2c44Sab SYMINFO_CMD_T cmd, ARGSTATE *argstate)
157d29b2c44Sab {
158d29b2c44Sab elfedit_getopt_state_t getopt_state;
159d29b2c44Sab elfedit_getopt_ret_t *getopt_ret;
160d29b2c44Sab
161d29b2c44Sab bzero(argstate, sizeof (*argstate));
162d29b2c44Sab argstate->obj_state = obj_state;
163d29b2c44Sab
164d29b2c44Sab elfedit_getopt_init(&getopt_state, &argc, &argv);
165d29b2c44Sab
166d29b2c44Sab /* Add each new option to the options mask */
167d29b2c44Sab while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL)
168d29b2c44Sab argstate->optmask |= getopt_ret->gor_idmask;
169d29b2c44Sab
170d29b2c44Sab /*
171d29b2c44Sab * Usage error if there are too many plain arguments.
172d29b2c44Sab * - syminfo:dump accepts a single argument
173d29b2c44Sab * - syminfo:si_boundto accepts 2 arguments
174d29b2c44Sab * - syminfo:si_flags accepts an unbounded number
175d29b2c44Sab */
176d29b2c44Sab if (((cmd == SYMINFO_CMD_T_DUMP) && (argc > 1)) ||
177d29b2c44Sab ((cmd == SYMINFO_CMD_T_SI_BOUNDTO) && (argc > 2)))
178d29b2c44Sab elfedit_command_usage();
179d29b2c44Sab
180d29b2c44Sab /* If there may be an arbitrary amount of output, use a pager */
181d29b2c44Sab if (argc == 0)
182d29b2c44Sab elfedit_pager_init();
183d29b2c44Sab
184d29b2c44Sab /* Return the updated values of argc/argv */
185d29b2c44Sab argstate->argc = argc;
186d29b2c44Sab argstate->argv = argv;
187d29b2c44Sab
188d29b2c44Sab /* Locate the syminfo section */
189d29b2c44Sab argstate->syminfo.sec = elfedit_sec_getsyminfo(obj_state,
190d29b2c44Sab &argstate->syminfo.data, &argstate->syminfo.n);
191d29b2c44Sab }
192d29b2c44Sab
193d29b2c44Sab
194d29b2c44Sab
195d29b2c44Sab /*
196d29b2c44Sab * We maintain the state of the current syminfo table in a ARGSTATE
197d29b2c44Sab * structure. A syminfo is related to the dynamic symbol table, and
198d29b2c44Sab * can reference the dynamic section of the object. We don't look those
199d29b2c44Sab * things up unless we actually need them, both to be efficient, and
200d29b2c44Sab * to prevent duplicate ELFEDIT_MSG_DEBUG messages from being issued
201d29b2c44Sab * as they are located. Hence, process_args() is used to initialze the
202d29b2c44Sab * state block with just the syminfo section, and then one of the
203d29b2c44Sab * argstate_add_XXX() functions is used as needed to fetch the
204d29b2c44Sab * additional sections.
205d29b2c44Sab *
206d29b2c44Sab * entry:
207d29b2c44Sab * argstate - State block for current symbol table.
208d29b2c44Sab *
209d29b2c44Sab * exit:
210d29b2c44Sab * If the needed auxiliary section is not found, an error is
211d29b2c44Sab * issued and the argstate_add_XXX() routine does not return.
212d29b2c44Sab * Otherwise, the fields in argstate have been filled in, ready
213d29b2c44Sab * for use.
214d29b2c44Sab *
215d29b2c44Sab */
216d29b2c44Sab static void
argstate_add_sym(ARGSTATE * argstate)217d29b2c44Sab argstate_add_sym(ARGSTATE *argstate)
218d29b2c44Sab {
219d29b2c44Sab if (argstate->sym.sec != NULL)
220d29b2c44Sab return;
221d29b2c44Sab
222d29b2c44Sab argstate->sym.sec = elfedit_sec_getsymtab(argstate->obj_state,
223d29b2c44Sab 1, argstate->syminfo.sec->sec_shdr->sh_link, NULL,
224d29b2c44Sab &argstate->sym.data, &argstate->sym.n, NULL);
225d29b2c44Sab }
226d29b2c44Sab static void
argstate_add_str(ARGSTATE * argstate)227d29b2c44Sab argstate_add_str(ARGSTATE *argstate)
228d29b2c44Sab {
229d29b2c44Sab if (argstate->str.sec != NULL)
230d29b2c44Sab return;
231d29b2c44Sab
232d29b2c44Sab argstate_add_sym(argstate);
233d29b2c44Sab argstate->str.sec = elfedit_sec_getstr(argstate->obj_state,
23455ef6355Sab argstate->sym.sec->sec_shdr->sh_link, 0);
235d29b2c44Sab }
236d29b2c44Sab static void
argstate_add_dynamic(ARGSTATE * argstate)237d29b2c44Sab argstate_add_dynamic(ARGSTATE *argstate)
238d29b2c44Sab {
239d29b2c44Sab if (argstate->dynamic.sec != NULL)
240d29b2c44Sab return;
241d29b2c44Sab
242d29b2c44Sab argstate->dynamic.sec = elfedit_sec_getdyn(argstate->obj_state,
243d29b2c44Sab &argstate->dynamic.data, &argstate->dynamic.n);
244d29b2c44Sab }
245d29b2c44Sab
246d29b2c44Sab
247d29b2c44Sab
248d29b2c44Sab /*
249d29b2c44Sab * Display syminfo section entries in the style used by elfdump.
250d29b2c44Sab *
251d29b2c44Sab * entry:
252d29b2c44Sab * argstate - State block for current symbol table.
253d29b2c44Sab * ndx - Index of first symbol to display
254d29b2c44Sab * cnt - Number of symbols to display
255d29b2c44Sab */
256d29b2c44Sab static void
dump_syminfo(ARGSTATE * argstate,Word ndx,Word cnt)257d29b2c44Sab dump_syminfo(ARGSTATE *argstate, Word ndx, Word cnt)
258d29b2c44Sab {
259d29b2c44Sab Syminfo *syminfo;
260d29b2c44Sab Sym *sym;
261d29b2c44Sab Dyn *dyn;
262d29b2c44Sab
263d29b2c44Sab syminfo = argstate->syminfo.data + ndx;
264d29b2c44Sab
265d29b2c44Sab argstate_add_sym(argstate);
266d29b2c44Sab sym = argstate->sym.data + ndx;
267d29b2c44Sab
268d29b2c44Sab argstate_add_str(argstate);
269d29b2c44Sab
270d29b2c44Sab argstate_add_dynamic(argstate);
271d29b2c44Sab dyn = argstate->dynamic.data;
272d29b2c44Sab
273d29b2c44Sab /*
274d29b2c44Sab * Loop through the syminfo entries.
275d29b2c44Sab */
276d29b2c44Sab Elf_syminfo_title(0);
277d29b2c44Sab
278d29b2c44Sab for (; cnt-- > 0; ndx++, syminfo++, sym++) {
279d29b2c44Sab const char *needed = NULL, *name;
280d29b2c44Sab
281d29b2c44Sab name = elfedit_offset_to_str(argstate->str.sec,
282d29b2c44Sab sym->st_name, ELFEDIT_MSG_ERR, 0);
283d29b2c44Sab
284d29b2c44Sab if ((syminfo->si_boundto < SYMINFO_BT_LOWRESERVE) &&
285d29b2c44Sab (syminfo->si_boundto < argstate->dynamic.n) &&
286d29b2c44Sab ((dyn[syminfo->si_boundto].d_tag == DT_NEEDED) ||
287d29b2c44Sab (dyn[syminfo->si_boundto].d_tag == DT_USED)))
288d29b2c44Sab needed = elfedit_offset_to_str(argstate->str.sec,
289d29b2c44Sab dyn[syminfo->si_boundto].d_un.d_val,
290d29b2c44Sab ELFEDIT_MSG_ERR, 0);
291d29b2c44Sab else
292d29b2c44Sab needed = MSG_ORIG(MSG_STR_EMPTY);
293d29b2c44Sab
294d29b2c44Sab Elf_syminfo_entry(0, ndx, syminfo, name, needed);
295d29b2c44Sab }
296d29b2c44Sab }
297d29b2c44Sab
298d29b2c44Sab
299d29b2c44Sab
300d29b2c44Sab /*
301d29b2c44Sab * Print syminfo values, taking the calling command, and output style
302d29b2c44Sab * into account.
303d29b2c44Sab *
304d29b2c44Sab * entry:
305d29b2c44Sab * cmd - SYMINFO_CMD_T_* value giving identify of caller
306d29b2c44Sab * autoprint - If True, output is only produced if the elfedit
307d29b2c44Sab * autoprint flag is set. If False, output is always produced.
308d29b2c44Sab * argstate - State block for current symbol table.
309d29b2c44Sab * ndx - Index of first symbol to display
310d29b2c44Sab * cnt - Number of symbols to display
311d29b2c44Sab */
312d29b2c44Sab static void
print_syminfo(SYMINFO_CMD_T cmd,int autoprint,ARGSTATE * argstate,Word ndx,Word cnt)313d29b2c44Sab print_syminfo(SYMINFO_CMD_T cmd, int autoprint, ARGSTATE *argstate,
314d29b2c44Sab Word ndx, Word cnt)
315d29b2c44Sab {
316d29b2c44Sab elfedit_outstyle_t outstyle;
317d29b2c44Sab Syminfo *syminfo;
318d29b2c44Sab
319d29b2c44Sab if ((autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0)) ||
320d29b2c44Sab (cnt == 0))
321d29b2c44Sab return;
322d29b2c44Sab
323d29b2c44Sab /*
324d29b2c44Sab * Pick an output style. syminfo:dump is required to use the default
325d29b2c44Sab * style. The other commands use the current output style.
326d29b2c44Sab */
327d29b2c44Sab outstyle = (cmd == SYMINFO_CMD_T_DUMP) ?
328d29b2c44Sab ELFEDIT_OUTSTYLE_DEFAULT : elfedit_outstyle();
329d29b2c44Sab
330d29b2c44Sab /*
331d29b2c44Sab * If doing default output, use elfdump style where we
332d29b2c44Sab * show all symbol attributes. In this case, the command
333d29b2c44Sab * that called us doesn't matter
334d29b2c44Sab */
335d29b2c44Sab if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) {
336d29b2c44Sab dump_syminfo(argstate, ndx, cnt);
337d29b2c44Sab return;
338d29b2c44Sab }
339d29b2c44Sab
340d29b2c44Sab syminfo = argstate->syminfo.data;
341d29b2c44Sab
342d29b2c44Sab switch (cmd) {
343d29b2c44Sab case SYMINFO_CMD_T_SI_BOUNDTO:
344d29b2c44Sab if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
345d29b2c44Sab /* Find the dynamic section and string table */
346d29b2c44Sab argstate_add_dynamic(argstate);
347d29b2c44Sab argstate_add_str(argstate);
348d29b2c44Sab }
349d29b2c44Sab
350d29b2c44Sab for (syminfo += ndx; cnt--; syminfo++) {
351d29b2c44Sab Half bndto = syminfo->si_boundto;
352d29b2c44Sab
353d29b2c44Sab if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
354d29b2c44Sab const char *str = NULL;
355d29b2c44Sab
356d29b2c44Sab switch (bndto) {
357d29b2c44Sab case SYMINFO_BT_SELF:
358d29b2c44Sab str = elfedit_atoconst_value_to_str(
359d29b2c44Sab ELFEDIT_CONST_SYMINFO_BT,
360d29b2c44Sab SYMINFO_BT_SELF, 1);
361d29b2c44Sab break;
362d29b2c44Sab case SYMINFO_BT_PARENT:
363d29b2c44Sab str = elfedit_atoconst_value_to_str(
364d29b2c44Sab ELFEDIT_CONST_SYMINFO_BT,
365d29b2c44Sab SYMINFO_BT_PARENT, 1);
366d29b2c44Sab break;
367d29b2c44Sab case SYMINFO_BT_NONE:
368d29b2c44Sab str = elfedit_atoconst_value_to_str(
369d29b2c44Sab ELFEDIT_CONST_SYMINFO_BT,
370d29b2c44Sab SYMINFO_BT_NONE, 1);
371d29b2c44Sab break;
372d29b2c44Sab }
373d29b2c44Sab if ((str == NULL) &&
374d29b2c44Sab (bndto < SYMINFO_BT_LOWRESERVE) &&
375d29b2c44Sab (argstate->dynamic.sec != NULL) &&
376d29b2c44Sab (bndto < argstate->dynamic.n) &&
377d29b2c44Sab (argstate->dynamic.data[bndto].d_tag ==
378d29b2c44Sab DT_NEEDED))
379d29b2c44Sab str = elfedit_offset_to_str(
380d29b2c44Sab argstate->str.sec,
381d29b2c44Sab argstate->dynamic.data[bndto].
382d29b2c44Sab d_un.d_val, ELFEDIT_MSG_ERR, 0);
383d29b2c44Sab
384d29b2c44Sab if (str != NULL) {
385d29b2c44Sab elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
386d29b2c44Sab str);
387d29b2c44Sab continue;
388d29b2c44Sab }
389d29b2c44Sab }
390d29b2c44Sab
391d29b2c44Sab /*
392d29b2c44Sab * If we reach this point, we are either in numeric
393d29b2c44Sab * mode, or we were unable to find a string above.
394d29b2c44Sab * In either case, output as integer.
395d29b2c44Sab */
396d29b2c44Sab elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL),
397d29b2c44Sab EC_WORD(bndto));
398d29b2c44Sab }
399d29b2c44Sab break;
400d29b2c44Sab
401d29b2c44Sab case SYMINFO_CMD_T_SI_FLAGS:
402d29b2c44Sab for (syminfo += ndx; cnt--; syminfo++) {
403d29b2c44Sab if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
404d29b2c44Sab Conv_syminfo_flags_buf_t buf;
405d29b2c44Sab
406d29b2c44Sab elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
407d29b2c44Sab conv_syminfo_flags(syminfo->si_flags,
408d29b2c44Sab CONV_FMT_NOBKT, &buf));
409d29b2c44Sab } else {
410d29b2c44Sab elfedit_printf(MSG_ORIG(MSG_FMT_HEXNUMNL),
411d29b2c44Sab EC_WORD(syminfo->si_flags));
412d29b2c44Sab }
413d29b2c44Sab }
414d29b2c44Sab break;
415d29b2c44Sab }
416d29b2c44Sab }
417d29b2c44Sab
418d29b2c44Sab
419d29b2c44Sab /*
420d29b2c44Sab * Convert the given argument string into a symbol table index.
421d29b2c44Sab *
422d29b2c44Sab * entry:
423d29b2c44Sab * argstate - State block for current symbol table.
424d29b2c44Sab * arg - String containing symbol index argument.
425d29b2c44Sab *
426d29b2c44Sab * exit:
427d29b2c44Sab * On success, returns the symbol index. On failure, an error
428d29b2c44Sab * is issued and this routine does not return.
429d29b2c44Sab */
430d29b2c44Sab static Word
arg_to_symndx(ARGSTATE * argstate,const char * arg)431d29b2c44Sab arg_to_symndx(ARGSTATE *argstate, const char *arg)
432d29b2c44Sab {
433d29b2c44Sab Word symndx;
434d29b2c44Sab
435d29b2c44Sab /*
436d29b2c44Sab * If the -symndx option was specified, arg is an index
437d29b2c44Sab * into the symbol table.
438d29b2c44Sab */
439d29b2c44Sab if (argstate->optmask & SYMINFO_OPT_F_SYMNDX)
440d29b2c44Sab return (elfedit_atoui_range(arg, MSG_ORIG(MSG_STR_SYM),
441d29b2c44Sab 0, argstate->syminfo.n - 1, NULL));
442d29b2c44Sab
443d29b2c44Sab /*
444d29b2c44Sab * arg is a symbol name. Return the index of the first symbol
445d29b2c44Sab * that matches
446d29b2c44Sab */
447d29b2c44Sab argstate_add_sym(argstate);
448d29b2c44Sab argstate_add_str(argstate);
449d29b2c44Sab
450d29b2c44Sab (void) elfedit_name_to_symndx(argstate->sym.sec,
451d29b2c44Sab argstate->str.sec, arg, ELFEDIT_MSG_ERR, &symndx);
452d29b2c44Sab
453d29b2c44Sab return (symndx);
454d29b2c44Sab }
455d29b2c44Sab
456d29b2c44Sab
457d29b2c44Sab /*
458d29b2c44Sab * Given a string argument representing an object, return the index of
459d29b2c44Sab * the dynamic section that should be used for the si_boundto value.
460d29b2c44Sab */
461d29b2c44Sab static Half
needed_to_boundto(ARGSTATE * argstate,const char * arg)462d29b2c44Sab needed_to_boundto(ARGSTATE *argstate, const char *arg)
463d29b2c44Sab {
464d29b2c44Sab Conv_inv_buf_t inv_buf;
465d29b2c44Sab elfedit_dyn_elt_t strpad_elt;
466d29b2c44Sab elfedit_dyn_elt_t null_elt;
467d29b2c44Sab elfedit_section_t *dynsec;
468d29b2c44Sab Word null_cnt;
469d29b2c44Sab Dyn *dyn;
470d29b2c44Sab Word str_offset, ndx, numdyn;
471d29b2c44Sab int have_string;
472d29b2c44Sab
473d29b2c44Sab argstate_add_str(argstate);
474d29b2c44Sab argstate_add_dynamic(argstate);
475d29b2c44Sab dynsec = argstate->dynamic.sec;
476d29b2c44Sab numdyn = argstate->dynamic.n;
477d29b2c44Sab
478d29b2c44Sab /* Locate DT_SUNW_STRPAD element if present and locate the DT_NULLs */
479d29b2c44Sab elfedit_dyn_elt_init(&strpad_elt);
480d29b2c44Sab elfedit_dyn_elt_init(&null_elt);
481d29b2c44Sab null_cnt = 0;
482d29b2c44Sab strpad_elt.dn_dyn.d_un.d_val = 0;
483d29b2c44Sab dyn = argstate->dynamic.data;
484d29b2c44Sab for (ndx = 0; ndx < numdyn; dyn++, ndx++) {
485d29b2c44Sab switch (dyn->d_tag) {
486d29b2c44Sab case DT_NULL:
487d29b2c44Sab /* Count all the nulls, remember the first one */
488d29b2c44Sab null_cnt++;
489d29b2c44Sab if (!null_elt.dn_seen)
490d29b2c44Sab elfedit_dyn_elt_save(&null_elt, ndx, dyn);
491d29b2c44Sab break;
492d29b2c44Sab
493d29b2c44Sab case DT_SUNW_STRPAD:
4944f680cc6SAli Bahrami if (elfedit_test_osabi(argstate->obj_state,
4954f680cc6SAli Bahrami ELFOSABI_SOLARIS, 0))
4964f680cc6SAli Bahrami elfedit_dyn_elt_save(&strpad_elt, ndx, dyn);
497d29b2c44Sab break;
498d29b2c44Sab }
499d29b2c44Sab }
500d29b2c44Sab
501d29b2c44Sab /*
502d29b2c44Sab * Look up the string in the string table and get its offset. If
503d29b2c44Sab * this succeeds, then it is possible that there is a DT_NEEDED
504d29b2c44Sab * dynamic entry that references it.
505d29b2c44Sab */
506d29b2c44Sab have_string = elfedit_sec_findstr(argstate->str.sec,
507d29b2c44Sab strpad_elt.dn_dyn.d_un.d_val, arg, &str_offset) != 0;
508d29b2c44Sab if (have_string) {
509d29b2c44Sab dyn = argstate->dynamic.data;
510d29b2c44Sab for (ndx = 0; ndx < numdyn; dyn++, ndx++) {
511d29b2c44Sab if (((dyn->d_tag == DT_NEEDED) ||
512d29b2c44Sab (dyn->d_tag == DT_USED)) &&
513d29b2c44Sab (dyn->d_un.d_val == str_offset))
514d29b2c44Sab goto done;
515d29b2c44Sab }
516d29b2c44Sab }
517d29b2c44Sab
518d29b2c44Sab /*
519d29b2c44Sab * It doesn't already exist. We might be able to add a DT_NEEDED
520d29b2c44Sab * to the dynamic section if an extra DT_NULL is available.
521d29b2c44Sab * Otherwise, we have to fail here.
522d29b2c44Sab */
523d29b2c44Sab if (null_cnt < 2)
524d29b2c44Sab elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOEXTRANULL),
525d29b2c44Sab EC_WORD(dynsec->sec_shndx), dynsec->sec_name);
526d29b2c44Sab
527d29b2c44Sab /*
528d29b2c44Sab * If the string is not already in the string table, try to
529d29b2c44Sab * insert it. If it succeeds, we will convert the DT_NULL.
530d29b2c44Sab * Otherwise, an error will be issued and control will not
531d29b2c44Sab * return here.
532d29b2c44Sab */
533d29b2c44Sab if (!have_string)
534d29b2c44Sab str_offset = elfedit_dynstr_insert(dynsec,
535d29b2c44Sab argstate->str.sec, &strpad_elt, arg);
536d29b2c44Sab
537d29b2c44Sab /* Convert the extra DT_NULL */
538d29b2c44Sab ndx = null_elt.dn_ndx;
539d29b2c44Sab elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_CONVNULL),
540d29b2c44Sab EC_WORD(dynsec->sec_shndx), dynsec->sec_name, EC_WORD(ndx),
5414f680cc6SAli Bahrami conv_dyn_tag(DT_NEEDED,
5424f680cc6SAli Bahrami argstate->obj_state->os_ehdr->e_ident[EI_OSABI],
5434f680cc6SAli Bahrami argstate->obj_state->os_ehdr->e_machine,
544d29b2c44Sab 0, &inv_buf));
545d29b2c44Sab dyn = argstate->dynamic.data + ndx;
546d29b2c44Sab dyn->d_tag = DT_NEEDED;
547d29b2c44Sab dyn->d_un.d_val = str_offset;
548d29b2c44Sab elfedit_modified_data(dynsec);
549d29b2c44Sab
550d29b2c44Sab done:
551d29b2c44Sab elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDNEEDED),
552d29b2c44Sab dynsec->sec_shndx, dynsec->sec_name, ndx, arg);
553d29b2c44Sab return (ndx);
554d29b2c44Sab }
555d29b2c44Sab
556d29b2c44Sab /*
557d29b2c44Sab * Common body for the syminfo: module commands. These commands
558d29b2c44Sab * share a large amount of common behavior, so it is convenient
559d29b2c44Sab * to centralize things and use the cmd argument to handle the
560d29b2c44Sab * small differences.
561d29b2c44Sab *
562d29b2c44Sab * entry:
563d29b2c44Sab * cmd - One of the SYMINFO_CMD_T_* constants listed above, specifying
564d29b2c44Sab * which command to implement.
565d29b2c44Sab * obj_state, argc, argv - Standard command arguments
566d29b2c44Sab */
567d29b2c44Sab static elfedit_cmdret_t
cmd_body(SYMINFO_CMD_T cmd,elfedit_obj_state_t * obj_state,int argc,const char * argv[])568d29b2c44Sab cmd_body(SYMINFO_CMD_T cmd, elfedit_obj_state_t *obj_state,
569d29b2c44Sab int argc, const char *argv[])
570d29b2c44Sab {
571d29b2c44Sab ARGSTATE argstate;
572d29b2c44Sab Word ndx;
573d29b2c44Sab Syminfo *syminfo;
574d29b2c44Sab elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE;
575d29b2c44Sab
576d29b2c44Sab process_args(obj_state, argc, argv, cmd, &argstate);
577d29b2c44Sab
578d29b2c44Sab /* If there are no arguments, dump the whole table and return */
579d29b2c44Sab if (argstate.argc == 0) {
580d29b2c44Sab print_syminfo(cmd, 0, &argstate, 0, argstate.syminfo.n);
581d29b2c44Sab return (ELFEDIT_CMDRET_NONE);
582d29b2c44Sab }
583d29b2c44Sab
584d29b2c44Sab /* The first argument is the symbol name/index */
585d29b2c44Sab ndx = arg_to_symndx(&argstate, argstate.argv[0]);
586d29b2c44Sab
587d29b2c44Sab /* If there is a single argument, display that item and return */
588d29b2c44Sab if (argstate.argc == 1) {
589d29b2c44Sab print_syminfo(cmd, 0, &argstate, ndx, 1);
590d29b2c44Sab return (ELFEDIT_CMDRET_NONE);
591d29b2c44Sab }
592d29b2c44Sab
593d29b2c44Sab syminfo = &argstate.syminfo.data[ndx];
594d29b2c44Sab
595d29b2c44Sab /*
596d29b2c44Sab * Syminfo [0] holds the value SYMINFO_CURRENT, as a versioning
597d29b2c44Sab * technique. You're not supposed to mess with it.
598d29b2c44Sab */
599d29b2c44Sab if (ndx == 0)
600d29b2c44Sab elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_CHGSYMINFO0),
601d29b2c44Sab EC_WORD(argstate.syminfo.sec->sec_shndx),
602d29b2c44Sab argstate.syminfo.sec->sec_name, EC_WORD(ndx));
603d29b2c44Sab
604d29b2c44Sab /* The second value supplies a new value for the item */
605d29b2c44Sab switch (cmd) {
606d29b2c44Sab /*
607d29b2c44Sab * SYMINFO_CMD_T_DUMP can't get here: It never has more than
608d29b2c44Sab * one argument, and is handled above.
609d29b2c44Sab */
610d29b2c44Sab
611d29b2c44Sab case SYMINFO_CMD_T_SI_BOUNDTO:
612d29b2c44Sab {
613d29b2c44Sab const char *name = MSG_ORIG(MSG_CMD_SI_BOUNDTO);
614d29b2c44Sab Half boundto;
615d29b2c44Sab
616d29b2c44Sab if (argstate.optmask & SYMINFO_OPT_F_NEEDED)
617d29b2c44Sab boundto = needed_to_boundto(&argstate,
618d29b2c44Sab argstate.argv[1]);
619d29b2c44Sab else
620d29b2c44Sab boundto = elfedit_atoconst_range(
621d29b2c44Sab argstate.argv[1], MSG_ORIG(MSG_STR_VALUE),
622d29b2c44Sab 0, 0xffff, ELFEDIT_CONST_SYMINFO_BT);
623d29b2c44Sab
624d29b2c44Sab if (syminfo->si_boundto == boundto) {
625d29b2c44Sab elfedit_msg(ELFEDIT_MSG_DEBUG,
626d29b2c44Sab MSG_INTL(MSG_DEBUG_X_OK),
627d29b2c44Sab argstate.syminfo.sec->sec_shndx,
628d29b2c44Sab argstate.syminfo.sec->sec_name, ndx, name,
629d29b2c44Sab syminfo->si_boundto);
630d29b2c44Sab } else {
631d29b2c44Sab elfedit_msg(ELFEDIT_MSG_DEBUG,
632d29b2c44Sab MSG_INTL(MSG_DEBUG_X_CHG),
633d29b2c44Sab argstate.syminfo.sec->sec_shndx,
634d29b2c44Sab argstate.syminfo.sec->sec_name, ndx, name,
635d29b2c44Sab syminfo->si_boundto, boundto);
636d29b2c44Sab ret = ELFEDIT_CMDRET_MOD;
637d29b2c44Sab syminfo->si_boundto = boundto;
638d29b2c44Sab }
639d29b2c44Sab }
640d29b2c44Sab break;
641d29b2c44Sab
642d29b2c44Sab case SYMINFO_CMD_T_SI_FLAGS:
643d29b2c44Sab {
644d29b2c44Sab Conv_syminfo_flags_buf_t flags_buf1, flags_buf2;
645d29b2c44Sab const char *name = MSG_ORIG(MSG_CMD_SI_FLAGS);
646d29b2c44Sab Half flags = 0;
647d29b2c44Sab int i;
648d29b2c44Sab
649d29b2c44Sab /* Collect the arguments */
650d29b2c44Sab for (i = 1; i < argstate.argc; i++)
651d29b2c44Sab flags |= (Word)
652d29b2c44Sab elfedit_atoconst(argstate.argv[i],
653d29b2c44Sab ELFEDIT_CONST_SYMINFO_FLG);
654d29b2c44Sab
655d29b2c44Sab /* Complement the value? */
656d29b2c44Sab if (argstate.optmask & SYMINFO_OPT_F_CMP)
657d29b2c44Sab flags = ~flags;
658d29b2c44Sab
659d29b2c44Sab /* Perform any requested bit operations */
660d29b2c44Sab if (argstate.optmask & SYMINFO_OPT_F_AND)
661d29b2c44Sab flags &= syminfo->si_flags;
662d29b2c44Sab else if (argstate.optmask & SYMINFO_OPT_F_OR)
663d29b2c44Sab flags |= syminfo->si_flags;
664d29b2c44Sab
665d29b2c44Sab /* Set the value */
666d29b2c44Sab if (syminfo->si_flags == flags) {
667d29b2c44Sab elfedit_msg(ELFEDIT_MSG_DEBUG,
668d29b2c44Sab MSG_INTL(MSG_DEBUG_S_OK),
669d29b2c44Sab argstate.syminfo.sec->sec_shndx,
670d29b2c44Sab argstate.syminfo.sec->sec_name, ndx, name,
671d29b2c44Sab conv_syminfo_flags(syminfo->si_flags,
672d29b2c44Sab 0, &flags_buf1));
673d29b2c44Sab } else {
674d29b2c44Sab elfedit_msg(ELFEDIT_MSG_DEBUG,
675d29b2c44Sab MSG_INTL(MSG_DEBUG_S_CHG),
676d29b2c44Sab argstate.syminfo.sec->sec_shndx,
677d29b2c44Sab argstate.syminfo.sec->sec_name, ndx, name,
678d29b2c44Sab conv_syminfo_flags(syminfo->si_flags,
679d29b2c44Sab 0, &flags_buf1),
680d29b2c44Sab conv_syminfo_flags(flags, 0, &flags_buf2));
681d29b2c44Sab ret = ELFEDIT_CMDRET_MOD;
682d29b2c44Sab syminfo->si_flags = flags;
683d29b2c44Sab }
684d29b2c44Sab }
685d29b2c44Sab break;
686d29b2c44Sab }
687d29b2c44Sab
688d29b2c44Sab /*
689d29b2c44Sab * If we modified the syminfo section, tell libelf.
690d29b2c44Sab */
691d29b2c44Sab if (ret == ELFEDIT_CMDRET_MOD)
692d29b2c44Sab elfedit_modified_data(argstate.syminfo.sec);
693d29b2c44Sab
694d29b2c44Sab /* Do autoprint */
695d29b2c44Sab print_syminfo(cmd, 1, &argstate, ndx, 1);
696d29b2c44Sab
697d29b2c44Sab return (ret);
698d29b2c44Sab }
699d29b2c44Sab
700d29b2c44Sab
701d29b2c44Sab
702d29b2c44Sab
703d29b2c44Sab /*
704d29b2c44Sab * Command completion functions for the various commands
705d29b2c44Sab */
706d29b2c44Sab /*ARGSUSED*/
707d29b2c44Sab static void
cpl_si_boundto(elfedit_obj_state_t * obj_state,void * cpldata,int argc,const char * argv[],int num_opt)708d29b2c44Sab cpl_si_boundto(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
709d29b2c44Sab const char *argv[], int num_opt)
710d29b2c44Sab {
711d29b2c44Sab int i;
712d29b2c44Sab
713d29b2c44Sab /*
714d29b2c44Sab * If -needed option is not present, the second argument can be
715d29b2c44Sab * an SYMINFO_BT_ value.
716d29b2c44Sab */
717d29b2c44Sab if (argc != (num_opt + 2))
718d29b2c44Sab return;
719d29b2c44Sab
720d29b2c44Sab /* Is -needed there? If so, no completion is possible so return */
721d29b2c44Sab for (i = 0; i < num_opt; i++)
722d29b2c44Sab if (strcmp(argv[i], MSG_ORIG(MSG_STR_MINUS_NEEDED)) == 0)
723d29b2c44Sab return;
724d29b2c44Sab
725d29b2c44Sab elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SYMINFO_BT);
726d29b2c44Sab }
727d29b2c44Sab
728d29b2c44Sab /*ARGSUSED*/
729d29b2c44Sab static void
cpl_si_flags(elfedit_obj_state_t * obj_state,void * cpldata,int argc,const char * argv[],int num_opt)730d29b2c44Sab cpl_si_flags(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
731d29b2c44Sab const char *argv[], int num_opt)
732d29b2c44Sab {
733d29b2c44Sab /* The second argument can be an SYMINFO_FLG_ value */
734d29b2c44Sab if (argc == (num_opt + 2))
735d29b2c44Sab elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SYMINFO_FLG);
736d29b2c44Sab }
737d29b2c44Sab
738d29b2c44Sab
739d29b2c44Sab
740d29b2c44Sab /*
741d29b2c44Sab * Implementation functions for the commands
742d29b2c44Sab */
743d29b2c44Sab static elfedit_cmdret_t
cmd_dump(elfedit_obj_state_t * obj_state,int argc,const char * argv[])744d29b2c44Sab cmd_dump(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
745d29b2c44Sab {
746d29b2c44Sab return (cmd_body(SYMINFO_CMD_T_DUMP, obj_state, argc, argv));
747d29b2c44Sab }
748d29b2c44Sab
749d29b2c44Sab
750d29b2c44Sab static elfedit_cmdret_t
cmd_si_boundto(elfedit_obj_state_t * obj_state,int argc,const char * argv[])751d29b2c44Sab cmd_si_boundto(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
752d29b2c44Sab {
753d29b2c44Sab return (cmd_body(SYMINFO_CMD_T_SI_BOUNDTO, obj_state, argc, argv));
754d29b2c44Sab }
755d29b2c44Sab
756d29b2c44Sab
757d29b2c44Sab static elfedit_cmdret_t
cmd_si_flags(elfedit_obj_state_t * obj_state,int argc,const char * argv[])758d29b2c44Sab cmd_si_flags(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
759d29b2c44Sab {
760d29b2c44Sab return (cmd_body(SYMINFO_CMD_T_SI_FLAGS, obj_state, argc, argv));
761d29b2c44Sab }
762d29b2c44Sab
763d29b2c44Sab
764d29b2c44Sab
765d29b2c44Sab
766d29b2c44Sab /*ARGSUSED*/
767d29b2c44Sab elfedit_module_t *
elfedit_init(elfedit_module_version_t version)768d29b2c44Sab elfedit_init(elfedit_module_version_t version)
769d29b2c44Sab {
770d29b2c44Sab /* sym:dump */
771d29b2c44Sab static const char *name_dump[] = {
772d29b2c44Sab MSG_ORIG(MSG_CMD_DUMP),
773d29b2c44Sab MSG_ORIG(MSG_STR_EMPTY), /* "" makes this the default command */
774d29b2c44Sab NULL
775d29b2c44Sab };
776d29b2c44Sab static elfedit_cmd_optarg_t opt_dump[] = {
777d29b2c44Sab { MSG_ORIG(MSG_STR_MINUS_SYMNDX),
778d29b2c44Sab /* MSG_INTL(MSG_OPTDESC_SYMNDX) */
779d29b2c44Sab ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0,
780d29b2c44Sab SYMINFO_OPT_F_SYMNDX, 0 },
781d29b2c44Sab { NULL }
782d29b2c44Sab };
783d29b2c44Sab static elfedit_cmd_optarg_t arg_dump[] = {
784d29b2c44Sab { MSG_ORIG(MSG_STR_SYM),
785d29b2c44Sab /* MSG_INTL(MSG_A1_SYM) */
786d29b2c44Sab ELFEDIT_I18NHDL(MSG_A1_SYM),
787d29b2c44Sab ELFEDIT_CMDOA_F_OPT },
788d29b2c44Sab { NULL }
789d29b2c44Sab };
790d29b2c44Sab
791d29b2c44Sab /* sym:si_boundto */
792d29b2c44Sab static const char *name_si_boundto[] = {
793d29b2c44Sab MSG_ORIG(MSG_CMD_SI_BOUNDTO), NULL };
794d29b2c44Sab static elfedit_cmd_optarg_t opt_si_boundto[] = {
795d29b2c44Sab { MSG_ORIG(MSG_STR_MINUS_NEEDED),
796d29b2c44Sab /* MSG_INTL(MSG_OPTDESC_NEEDED) */
797d29b2c44Sab ELFEDIT_I18NHDL(MSG_OPTDESC_NEEDED), 0,
798d29b2c44Sab SYMINFO_OPT_F_NEEDED, 0 },
799*9320f495SToomas Soome { ELFEDIT_STDOA_OPT_O, 0,
800d29b2c44Sab ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
801d29b2c44Sab { MSG_ORIG(MSG_STR_MINUS_SYMNDX),
802d29b2c44Sab /* MSG_INTL(MSG_OPTDESC_SYMNDX) */
803d29b2c44Sab ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0,
804d29b2c44Sab SYMINFO_OPT_F_SYMNDX, 0 },
805d29b2c44Sab { NULL }
806d29b2c44Sab };
807d29b2c44Sab static elfedit_cmd_optarg_t arg_si_boundto[] = {
808d29b2c44Sab { MSG_ORIG(MSG_STR_SYM),
809d29b2c44Sab /* MSG_INTL(MSG_A1_SYM) */
810d29b2c44Sab ELFEDIT_I18NHDL(MSG_A1_SYM),
811d29b2c44Sab ELFEDIT_CMDOA_F_OPT },
812d29b2c44Sab { MSG_ORIG(MSG_STR_VALUE),
813d29b2c44Sab /* MSG_INTL(MSG_A2_DESC_SI_BOUNDTO) */
814d29b2c44Sab ELFEDIT_I18NHDL(MSG_A2_DESC_SI_BOUNDTO),
815d29b2c44Sab ELFEDIT_CMDOA_F_OPT },
816d29b2c44Sab { NULL }
817d29b2c44Sab };
818d29b2c44Sab
819d29b2c44Sab /* sym:si_flags */
820d29b2c44Sab static const char *name_si_flags[] = {
821d29b2c44Sab MSG_ORIG(MSG_CMD_SI_FLAGS), NULL };
822d29b2c44Sab static elfedit_cmd_optarg_t opt_si_flags[] = {
823*9320f495SToomas Soome { ELFEDIT_STDOA_OPT_AND, 0, ELFEDIT_CMDOA_F_INHERIT,
824d29b2c44Sab SYMINFO_OPT_F_AND, SYMINFO_OPT_F_OR },
825*9320f495SToomas Soome { ELFEDIT_STDOA_OPT_CMP, 0,
826d29b2c44Sab ELFEDIT_CMDOA_F_INHERIT, SYMINFO_OPT_F_CMP, 0 },
827*9320f495SToomas Soome { ELFEDIT_STDOA_OPT_O, 0,
828d29b2c44Sab ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
829*9320f495SToomas Soome { ELFEDIT_STDOA_OPT_OR, 0, ELFEDIT_CMDOA_F_INHERIT,
830d29b2c44Sab SYMINFO_OPT_F_OR, SYMINFO_OPT_F_AND },
831d29b2c44Sab { MSG_ORIG(MSG_STR_MINUS_SYMNDX),
832d29b2c44Sab /* MSG_INTL(MSG_OPTDESC_SYMNDX) */
833d29b2c44Sab ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0,
834d29b2c44Sab SYMINFO_OPT_F_SYMNDX, 0 },
835d29b2c44Sab { NULL }
836d29b2c44Sab };
837d29b2c44Sab static elfedit_cmd_optarg_t arg_si_flags[] = {
838d29b2c44Sab { MSG_ORIG(MSG_STR_SYM),
839d29b2c44Sab /* MSG_INTL(MSG_A1_SYM) */
840d29b2c44Sab ELFEDIT_I18NHDL(MSG_A1_SYM),
841d29b2c44Sab ELFEDIT_CMDOA_F_OPT },
842d29b2c44Sab { MSG_ORIG(MSG_STR_VALUE),
843d29b2c44Sab /* MSG_INTL(MSG_A2_DESC_SI_FLAGS) */
844d29b2c44Sab ELFEDIT_I18NHDL(MSG_A2_DESC_SI_FLAGS),
845d29b2c44Sab ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
846d29b2c44Sab { NULL }
847d29b2c44Sab };
848d29b2c44Sab
849d29b2c44Sab static elfedit_cmd_t cmds[] = {
850d29b2c44Sab /* sym:dump */
851d29b2c44Sab { cmd_dump, NULL, name_dump,
852d29b2c44Sab /* MSG_INTL(MSG_DESC_DUMP) */
853d29b2c44Sab ELFEDIT_I18NHDL(MSG_DESC_DUMP),
854d29b2c44Sab /* MSG_INTL(MSG_HELP_DUMP) */
855d29b2c44Sab ELFEDIT_I18NHDL(MSG_HELP_DUMP),
856d29b2c44Sab opt_dump, arg_dump },
857d29b2c44Sab
858d29b2c44Sab /* sym:si_boundto */
859d29b2c44Sab { cmd_si_boundto, cpl_si_boundto, name_si_boundto,
860d29b2c44Sab /* MSG_INTL(MSG_DESC_SI_BOUNDTO) */
861d29b2c44Sab ELFEDIT_I18NHDL(MSG_DESC_SI_BOUNDTO),
862d29b2c44Sab /* MSG_INTL(MSG_HELP_SI_BOUNDTO) */
863d29b2c44Sab ELFEDIT_I18NHDL(MSG_HELP_SI_BOUNDTO),
864d29b2c44Sab opt_si_boundto, arg_si_boundto },
865d29b2c44Sab
866d29b2c44Sab /* sym:si_flags */
867d29b2c44Sab { cmd_si_flags, cpl_si_flags, name_si_flags,
868d29b2c44Sab /* MSG_INTL(MSG_DESC_SI_FLAGS) */
869d29b2c44Sab ELFEDIT_I18NHDL(MSG_DESC_SI_FLAGS),
870d29b2c44Sab /* MSG_INTL(MSG_HELP_SI_FLAGS) */
871d29b2c44Sab ELFEDIT_I18NHDL(MSG_HELP_SI_FLAGS),
872d29b2c44Sab opt_si_flags, arg_si_flags },
873d29b2c44Sab
874d29b2c44Sab { NULL }
875d29b2c44Sab };
876d29b2c44Sab
877d29b2c44Sab static elfedit_module_t module = {
878d29b2c44Sab ELFEDIT_VER_CURRENT, MSG_ORIG(MSG_MOD_NAME),
879d29b2c44Sab /* MSG_INTL(MSG_MOD_DESC) */
880d29b2c44Sab ELFEDIT_I18NHDL(MSG_MOD_DESC),
881d29b2c44Sab cmds, mod_i18nhdl_to_str };
882d29b2c44Sab
883d29b2c44Sab return (&module);
884d29b2c44Sab }
885