15aefb655Srie /*
25aefb655Srie * CDDL HEADER START
35aefb655Srie *
45aefb655Srie * The contents of this file are subject to the terms of the
55aefb655Srie * Common Development and Distribution License (the "License").
65aefb655Srie * You may not use this file except in compliance with the License.
75aefb655Srie *
85aefb655Srie * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95aefb655Srie * or http://www.opensolaris.org/os/licensing.
105aefb655Srie * See the License for the specific language governing permissions
115aefb655Srie * and limitations under the License.
125aefb655Srie *
135aefb655Srie * When distributing Covered Code, include this CDDL HEADER in each
145aefb655Srie * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155aefb655Srie * If applicable, add the following below this CDDL HEADER, with the
165aefb655Srie * fields enclosed by brackets "[]" replaced with your own identifying
175aefb655Srie * information: Portions Copyright [yyyy] [name of copyright owner]
185aefb655Srie *
195aefb655Srie * CDDL HEADER END
205aefb655Srie */
215aefb655Srie
225aefb655Srie /*
23ba7866cdSAli Bahrami * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
245aefb655Srie */
255aefb655Srie
265aefb655Srie /*
275aefb655Srie * Dump an elf file.
285aefb655Srie */
295aefb655Srie #include <sys/param.h>
305aefb655Srie #include <fcntl.h>
315aefb655Srie #include <stdio.h>
32c809c407Sab #include <stdlib.h>
33c809c407Sab #include <ctype.h>
34ba7866cdSAli Bahrami #include <_libelf.h>
355aefb655Srie #include <link.h>
365aefb655Srie #include <stdarg.h>
375aefb655Srie #include <unistd.h>
385aefb655Srie #include <libgen.h>
395aefb655Srie #include <libintl.h>
405aefb655Srie #include <locale.h>
415aefb655Srie #include <errno.h>
425aefb655Srie #include <strings.h>
435aefb655Srie #include <debug.h>
445aefb655Srie #include <conv.h>
455aefb655Srie #include <msg.h>
465aefb655Srie #include <_elfdump.h>
47981a172dSab #include <sys/elf_SPARC.h>
48981a172dSab #include <sys/elf_amd64.h>
49981a172dSab
505aefb655Srie
5131fdd7caSab const Cache cache_init = {NULL, NULL, NULL, NULL, 0};
525aefb655Srie
53c809c407Sab
54c809c407Sab
55981a172dSab /*
56981a172dSab * The -I, -N, and -T options are called "match options", because
57981a172dSab * they allow selecting the items to be displayed based on matching
58981a172dSab * their index, name, or type.
59981a172dSab *
60981a172dSab * The ELF information to which -I, -N, or -T are applied in
61981a172dSab * the current invocation is called the "match item".
62981a172dSab */
63981a172dSab typedef enum {
64981a172dSab MATCH_ITEM_PT, /* Program header (PT_) */
65981a172dSab MATCH_ITEM_SHT /* Section header (SHT_) */
66981a172dSab } match_item_t;
67981a172dSab
68981a172dSab /* match_opt_t is used to note which match option was used */
69c809c407Sab typedef enum {
70981a172dSab MATCH_OPT_NAME, /* Record contains a name */
71981a172dSab MATCH_OPT_NDX, /* Record contains a single index */
72981a172dSab MATCH_OPT_RANGE, /* Record contains an index range */
73981a172dSab MATCH_OPT_TYPE, /* Record contains a type (shdr or phdr) */
74981a172dSab } match_opt_t;
75c809c407Sab
76c809c407Sab typedef struct _match {
77c809c407Sab struct _match *next; /* Pointer to next item in list */
78981a172dSab match_opt_t opt_type;
79c809c407Sab union {
80981a172dSab const char *name; /* MATCH_OPT_NAME */
81981a172dSab struct { /* MATCH_OPT_NDX and MATCH_OPT_RANGE */
82c809c407Sab int start;
83981a172dSab int end; /* Only for MATCH_OPT_RANGE */
84c809c407Sab } ndx;
85981a172dSab uint32_t type; /* MATCH_OPT_TYPE */
86c809c407Sab } value;
87981a172dSab } match_rec_t;
88981a172dSab
89981a172dSab static struct {
90981a172dSab match_item_t item_type; /* Type of item being matched */
91981a172dSab match_rec_t *list; /* Records for (-I, -N, -T) options */
92981a172dSab } match_state;
93981a172dSab
94981a172dSab
95981a172dSab
965aefb655Srie const char *
_elfdump_msg(Msg mid)975aefb655Srie _elfdump_msg(Msg mid)
985aefb655Srie {
995aefb655Srie return (gettext(MSG_ORIG(mid)));
1005aefb655Srie }
1015aefb655Srie
1025aefb655Srie /*
1035aefb655Srie * Determine whether a symbol name should be demangled.
1045aefb655Srie */
1055aefb655Srie const char *
demangle(const char * name,uint_t flags)1065aefb655Srie demangle(const char *name, uint_t flags)
1075aefb655Srie {
108981a172dSab if (flags & FLG_CTL_DEMANGLE)
1095aefb655Srie return (Elf_demangle_name(name));
1105aefb655Srie else
1115aefb655Srie return ((char *)name);
1125aefb655Srie }
1135aefb655Srie
1145aefb655Srie /*
1155aefb655Srie * Define our own standard error routine.
1165aefb655Srie */
1175aefb655Srie void
failure(const char * file,const char * func)1185aefb655Srie failure(const char *file, const char *func)
1195aefb655Srie {
1205aefb655Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_FAILURE),
1215aefb655Srie file, func, elf_errmsg(elf_errno()));
1225aefb655Srie }
1235aefb655Srie
1245aefb655Srie /*
1255aefb655Srie * The full usage message
1265aefb655Srie */
1275aefb655Srie static void
detail_usage()1285aefb655Srie detail_usage()
1295aefb655Srie {
1305aefb655Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL1));
1315aefb655Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL2));
1325aefb655Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL3));
1335aefb655Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL4));
1345aefb655Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL5));
1355aefb655Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL6));
1365aefb655Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL7));
1375aefb655Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL8));
1385aefb655Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL9));
1395aefb655Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL10));
1405aefb655Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL11));
1415aefb655Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL12));
1425aefb655Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL13));
1435aefb655Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL14));
1445aefb655Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL15));
1455aefb655Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL16));
1465aefb655Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL17));
1475aefb655Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL18));
1485aefb655Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL19));
1495aefb655Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL20));
150d579eb63Sab (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL21));
151c809c407Sab (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL22));
152c809c407Sab (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL23));
15339773e46Sab (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL24));
154981a172dSab (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL25));
1554f680cc6SAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL26));
156c809c407Sab }
157c809c407Sab
158c6c9aed4Sab /*
159c6c9aed4Sab * Output a block of raw data as hex bytes. Each row is given
160c6c9aed4Sab * the index of the first byte in the row.
161c6c9aed4Sab *
162c6c9aed4Sab * entry:
163c6c9aed4Sab * data - Pointer to first byte of data to be displayed
164c6c9aed4Sab * n - # of bytes of data
165c6c9aed4Sab * prefix - String to be output before each line. Useful
166c6c9aed4Sab * for indenting output.
167c6c9aed4Sab * bytes_per_col - # of space separated bytes to output
168c6c9aed4Sab * in each column.
169c6c9aed4Sab * col_per_row - # of columns to output per row
170c6c9aed4Sab *
171c6c9aed4Sab * exit:
172c6c9aed4Sab * The formatted data has been sent to stdout. Each row of output
173c6c9aed4Sab * shows (bytes_per_col * col_per_row) bytes of data.
174c6c9aed4Sab */
175c6c9aed4Sab void
dump_hex_bytes(const void * data,size_t n,int indent,int bytes_per_col,int col_per_row)1767e16fca0SAli Bahrami dump_hex_bytes(const void *data, size_t n, int indent,
177*d37b9759SRichard Lowe int bytes_per_col, int col_per_row)
178c6c9aed4Sab {
1797e16fca0SAli Bahrami const uchar_t *ldata = data;
180c6c9aed4Sab int bytes_per_row = bytes_per_col * col_per_row;
181c6c9aed4Sab int ndx, byte, word;
182c6c9aed4Sab char string[128], *str = string;
183c6c9aed4Sab char index[MAXNDXSIZE];
184c6c9aed4Sab int index_width;
185c6c9aed4Sab int sp_prefix = 0;
186c6c9aed4Sab
187c6c9aed4Sab
188c6c9aed4Sab /*
189c6c9aed4Sab * Determine the width to use for the index string. We follow
190c6c9aed4Sab * 8-byte tab rules, but don't use an actual \t character so
191c6c9aed4Sab * that the output can be arbitrarily shifted without odd
192c6c9aed4Sab * tab effects, and so that all the columns line up no matter
193c6c9aed4Sab * how many lines of output are produced.
194c6c9aed4Sab */
195c6c9aed4Sab ndx = n / bytes_per_row;
196c6c9aed4Sab (void) snprintf(index, sizeof (index),
197c6c9aed4Sab MSG_ORIG(MSG_FMT_INDEX2), EC_WORD(ndx));
198c6c9aed4Sab index_width = strlen(index);
199c6c9aed4Sab index_width = S_ROUND(index_width, 8);
200c6c9aed4Sab
2017e16fca0SAli Bahrami for (ndx = byte = word = 0; n > 0; n--, ldata++) {
202c6c9aed4Sab while (sp_prefix-- > 0)
203c6c9aed4Sab *str++ = ' ';
204c6c9aed4Sab
205c6c9aed4Sab (void) snprintf(str, sizeof (string),
2067e16fca0SAli Bahrami MSG_ORIG(MSG_HEXDUMP_TOK), (int)*ldata);
207c6c9aed4Sab str += 2;
208c6c9aed4Sab sp_prefix = 1;
209c6c9aed4Sab
210c6c9aed4Sab if (++byte == bytes_per_col) {
211c6c9aed4Sab sp_prefix += 2;
212c6c9aed4Sab word++;
213c6c9aed4Sab byte = 0;
214c6c9aed4Sab }
215c6c9aed4Sab if (word == col_per_row) {
216c6c9aed4Sab *str = '\0';
217c6c9aed4Sab (void) snprintf(index, sizeof (index),
218c6c9aed4Sab MSG_ORIG(MSG_FMT_INDEX2), EC_WORD(ndx));
219c6c9aed4Sab dbg_print(0, MSG_ORIG(MSG_HEXDUMP_ROW),
220c6c9aed4Sab indent, MSG_ORIG(MSG_STR_EMPTY),
221c6c9aed4Sab index_width, index, string);
222c6c9aed4Sab sp_prefix = 0;
223c6c9aed4Sab word = 0;
224c6c9aed4Sab ndx += bytes_per_row;
225c6c9aed4Sab str = string;
226c6c9aed4Sab }
227c6c9aed4Sab }
228c6c9aed4Sab if (byte || word) {
229c6c9aed4Sab *str = '\0'; /* */
230c6c9aed4Sab (void) snprintf(index, sizeof (index),
231c6c9aed4Sab MSG_ORIG(MSG_FMT_INDEX2), EC_WORD(ndx));
232c6c9aed4Sab dbg_print(0, MSG_ORIG(MSG_HEXDUMP_ROW), indent,
233c6c9aed4Sab MSG_ORIG(MSG_STR_EMPTY), index_width, index, string);
234c6c9aed4Sab }
235c6c9aed4Sab }
236c6c9aed4Sab
237c809c407Sab /*
238c809c407Sab * Convert the ASCII representation of an index, or index range, into
239c809c407Sab * binary form, and store it in rec:
240c809c407Sab *
241c809c407Sab * index: An positive or 0 valued integer
242c809c407Sab * range: Two indexes, separated by a ':' character, denoting
243c809c407Sab * a range of allowed values. If the second value is omitted,
244c809c407Sab * any values equal to or greater than the first will match.
245c809c407Sab *
246c809c407Sab * exit:
247981a172dSab * On success, *rec is filled in with a MATCH_OPT_NDX or MATCH_OPT_RANGE
248c809c407Sab * value, and this function returns (1). On failure, the contents
249c809c407Sab * of *rec are undefined, and (0) is returned.
250c809c407Sab */
251c809c407Sab int
process_index_opt(const char * str,match_rec_t * rec)252981a172dSab process_index_opt(const char *str, match_rec_t *rec)
253c809c407Sab {
254c809c407Sab #define SKIP_BLANK for (; *str && isspace(*str); str++)
255c809c407Sab
256c809c407Sab char *endptr;
257c809c407Sab
258c809c407Sab rec->value.ndx.start = strtol(str, &endptr, 10);
259c809c407Sab /* Value must use some of the input, and be 0 or positive */
260c809c407Sab if ((str == endptr) || (rec->value.ndx.start < 0))
261c809c407Sab return (0);
262c809c407Sab str = endptr;
263c809c407Sab
264c809c407Sab SKIP_BLANK;
265c809c407Sab if (*str != ':') {
266981a172dSab rec->opt_type = MATCH_OPT_NDX;
267c809c407Sab } else {
268c809c407Sab str++; /* Skip the ':' */
269981a172dSab rec->opt_type = MATCH_OPT_RANGE;
270c809c407Sab SKIP_BLANK;
271c809c407Sab if (*str == '\0') {
272c809c407Sab rec->value.ndx.end = -1; /* Indicates "to end" */
273c809c407Sab } else {
274c809c407Sab rec->value.ndx.end = strtol(str, &endptr, 10);
275c809c407Sab if ((str == endptr) || (rec->value.ndx.end < 0))
276c809c407Sab return (0);
277c809c407Sab str = endptr;
278c809c407Sab SKIP_BLANK;
279c809c407Sab }
280c809c407Sab }
281c809c407Sab
282c809c407Sab /* Syntax error if anything is left over */
283c809c407Sab if (*str != '\0')
284c809c407Sab return (0);
285c809c407Sab
286c809c407Sab return (1);
287c809c407Sab
288c809c407Sab #undef SKIP_BLANK
289c809c407Sab }
290c809c407Sab
291981a172dSab /*
2924f680cc6SAli Bahrami * Convert a string containing a specific type of ELF constant, or an ASCII
2934f680cc6SAli Bahrami * representation of a number, to an integer. Strings starting with '0'
294981a172dSab * are taken to be octal, those staring with '0x' are hex, and all
295981a172dSab * others are decimal.
296981a172dSab *
297981a172dSab * entry:
298981a172dSab * str - String to be converted
2994f680cc6SAli Bahrami * ctype - Constant type
300981a172dSab * v - Address of variable to receive resulting value.
301981a172dSab *
302981a172dSab * exit:
303981a172dSab * On success, returns True (1) and *v is set to the value.
304981a172dSab * On failure, returns False (0) and *v is undefined.
305981a172dSab */
3064f680cc6SAli Bahrami typedef enum {
3074f680cc6SAli Bahrami ATOUI_PT,
3084f680cc6SAli Bahrami ATOUI_SHT,
3094f680cc6SAli Bahrami ATOUI_OSABI
3104f680cc6SAli Bahrami } atoui_type_t;
3114f680cc6SAli Bahrami
312981a172dSab static int
atoui(const char * str,atoui_type_t type,uint32_t * v)3134f680cc6SAli Bahrami atoui(const char *str, atoui_type_t type, uint32_t *v)
314981a172dSab {
3154f680cc6SAli Bahrami conv_strtol_uvalue_t uvalue;
3164f680cc6SAli Bahrami char *endptr;
3174f680cc6SAli Bahrami
3184f680cc6SAli Bahrami if (conv_iter_strtol_init(str, &uvalue) != 0) {
3194f680cc6SAli Bahrami switch (type) {
3204f680cc6SAli Bahrami case ATOUI_PT:
3214f680cc6SAli Bahrami if (conv_iter_phdr_type(CONV_OSABI_ALL, CONV_FMT_ALT_CF,
3224f680cc6SAli Bahrami conv_iter_strtol, &uvalue) == CONV_ITER_DONE)
3234f680cc6SAli Bahrami break;
3244f680cc6SAli Bahrami (void) conv_iter_phdr_type(CONV_OSABI_ALL,
3254f680cc6SAli Bahrami CONV_FMT_ALT_NF, conv_iter_strtol, &uvalue);
3264f680cc6SAli Bahrami break;
3274f680cc6SAli Bahrami case ATOUI_SHT:
3284f680cc6SAli Bahrami if (conv_iter_sec_type(CONV_OSABI_ALL, CONV_MACH_ALL,
3294f680cc6SAli Bahrami CONV_FMT_ALT_CF, conv_iter_strtol, &uvalue) ==
3304f680cc6SAli Bahrami CONV_ITER_DONE)
3314f680cc6SAli Bahrami break;
3324f680cc6SAli Bahrami (void) conv_iter_sec_type(CONV_OSABI_ALL, CONV_MACH_ALL,
3334f680cc6SAli Bahrami CONV_FMT_ALT_NF, conv_iter_strtol, &uvalue);
3344f680cc6SAli Bahrami break;
3354f680cc6SAli Bahrami case ATOUI_OSABI:
3364f680cc6SAli Bahrami if (conv_iter_ehdr_osabi(CONV_FMT_ALT_CF,
3374f680cc6SAli Bahrami conv_iter_strtol, &uvalue) == CONV_ITER_DONE)
3384f680cc6SAli Bahrami break;
3394f680cc6SAli Bahrami (void) conv_iter_ehdr_osabi(CONV_FMT_ALT_NF,
3404f680cc6SAli Bahrami conv_iter_strtol, &uvalue);
3414f680cc6SAli Bahrami break;
3424f680cc6SAli Bahrami }
3434f680cc6SAli Bahrami if (uvalue.csl_found) {
3444f680cc6SAli Bahrami *v = uvalue.csl_value;
3454f680cc6SAli Bahrami return (1);
3464f680cc6SAli Bahrami }
3474f680cc6SAli Bahrami }
348981a172dSab
349981a172dSab *v = strtoull(str, &endptr, 0);
350981a172dSab
351981a172dSab /* If the left over part contains anything but whitespace, fail */
352981a172dSab for (; *endptr; endptr++)
353981a172dSab if (!isspace(*endptr))
354981a172dSab return (0);
355981a172dSab return (1);
356981a172dSab }
357981a172dSab
358981a172dSab /*
359981a172dSab * Called after getopt() processing is finished if there is a non-empty
360981a172dSab * match list. Prepares the matching code for use.
361981a172dSab *
362981a172dSab * exit:
363981a172dSab * Returns True (1) if no errors are encountered. Writes an
364981a172dSab * error string to stderr and returns False (0) otherwise.
365981a172dSab */
366981a172dSab static int
match_prepare(char * argv0,uint_t flags)367981a172dSab match_prepare(char *argv0, uint_t flags)
368981a172dSab {
369981a172dSab match_rec_t *list;
370981a172dSab const char *str;
371981a172dSab int minus_p = (flags & FLG_SHOW_PHDR) != 0;
3724f680cc6SAli Bahrami atoui_type_t atoui_type;
373981a172dSab
374981a172dSab /*
375981a172dSab * Flag ambiguous attempt to use match option with both -p and
376981a172dSab * and one or more section SHOW options. In this case, we
377981a172dSab * can't tell what type of item we're supposed to match against.
378981a172dSab */
379981a172dSab if (minus_p && (flags & FLG_MASK_SHOW_SHDR)) {
380981a172dSab (void) fprintf(stderr, MSG_INTL(MSG_ERR_AMBIG_MATCH),
381981a172dSab basename(argv0));
382981a172dSab return (0);
383981a172dSab }
384981a172dSab
385981a172dSab /* Set the match type, based on the presence of the -p option */
386981a172dSab if (minus_p) {
387981a172dSab match_state.item_type = MATCH_ITEM_PT;
3884f680cc6SAli Bahrami atoui_type = ATOUI_PT;
389981a172dSab } else {
390981a172dSab match_state.item_type = MATCH_ITEM_SHT;
3914f680cc6SAli Bahrami atoui_type = ATOUI_SHT;
392981a172dSab }
393981a172dSab
394981a172dSab /*
395981a172dSab * Scan match list and perform any necessary fixups:
396981a172dSab *
397981a172dSab * MATCH_OPT_NAME: If -p is specified, convert MATCH_OPT_NAME (-N)
398981a172dSab * requests into MATCH_OPT_TYPE (-T).
399981a172dSab *
400981a172dSab * MATCH_OPT_TYPE: Now that we know item type we are matching
401981a172dSab * against, we can convert the string saved in the name
402981a172dSab * field during getopt() processing into an integer and
403981a172dSab * write it into the type field.
404981a172dSab */
405981a172dSab for (list = match_state.list; list; list = list->next) {
406981a172dSab if ((list->opt_type == MATCH_OPT_NAME) && minus_p)
407981a172dSab list->opt_type = MATCH_OPT_TYPE;
408981a172dSab
409981a172dSab if (list->opt_type != MATCH_OPT_TYPE)
410981a172dSab continue;
411981a172dSab
412981a172dSab str = list->value.name;
4134f680cc6SAli Bahrami if (atoui(str, atoui_type, &list->value.type) == 0) {
414981a172dSab const char *fmt = minus_p ?
415981a172dSab MSG_INTL(MSG_ERR_BAD_T_PT) :
416981a172dSab MSG_INTL(MSG_ERR_BAD_T_SHT);
417981a172dSab
418981a172dSab (void) fprintf(stderr, fmt, basename(argv0), str);
419981a172dSab return (0);
420981a172dSab }
421981a172dSab }
422981a172dSab
423981a172dSab return (1);
424981a172dSab }
425981a172dSab
426981a172dSab
427c809c407Sab /*
428c809c407Sab * Returns True (1) if the item with the given name or index should
429c809c407Sab * be displayed, and False (0) if it should not be.
430c809c407Sab *
431c809c407Sab * entry:
432981a172dSab * match_flags - Bitmask specifying matching options, as described
433981a172dSab * in _elfdump.h.
434981a172dSab * name - If MATCH_F_NAME flag is set, name of item under
435981a172dSab * consideration. Otherwise ignored.
436c809c407Sab * should not be considered.
437981a172dSab * ndx - If MATCH_F_NDX flag is set, index of item under consideration.
438981a172dSab * type - If MATCH_F_TYPE is set, type of item under consideration.
439981a172dSab * If MATCH_F_PHDR is set, this would be a program
440981a172dSab * header type (PT_). Otherwise, a section header type (SHT_).
441c809c407Sab *
442c809c407Sab * exit:
443c809c407Sab * True will be returned if the given name/index matches those given
444981a172dSab * by one of the (-I, -N -T) command line options, or if no such option
445981a172dSab * was used in the command invocation and MATCH_F_STRICT is not
446981a172dSab * set.
447c809c407Sab */
448c809c407Sab int
match(match_flags_t match_flags,const char * name,uint_t ndx,uint_t type)449981a172dSab match(match_flags_t match_flags, const char *name, uint_t ndx, uint_t type)
450c809c407Sab {
451981a172dSab match_item_t item_type = (match_flags & MATCH_F_PHDR) ?
452981a172dSab MATCH_ITEM_PT : MATCH_ITEM_SHT;
453981a172dSab match_rec_t *list;
454981a172dSab
455981a172dSab /*
456981a172dSab * If there is no match list, then we use the MATCH_F_STRICT
457981a172dSab * flag to decide what to return. In the strict case, we return
458981a172dSab * False (0), in the normal case, True (1).
459981a172dSab */
460981a172dSab if (match_state.list == NULL)
461981a172dSab return ((match_flags & MATCH_F_STRICT) == 0);
462c809c407Sab
463981a172dSab /*
464981a172dSab * If item being checked is not the current match type,
465981a172dSab * then allow it.
466981a172dSab */
467981a172dSab if (item_type != match_state.item_type)
468c809c407Sab return (1);
469c809c407Sab
470c809c407Sab /* Run through the match records and check for a hit */
471981a172dSab for (list = match_state.list; list; list = list->next) {
472981a172dSab switch (list->opt_type) {
473981a172dSab case MATCH_OPT_NAME:
474981a172dSab if (((match_flags & MATCH_F_NAME) == 0) ||
475981a172dSab (name == NULL))
476981a172dSab break;
477981a172dSab if (strcmp(list->value.name, name) == 0)
478c809c407Sab return (1);
479c809c407Sab break;
480981a172dSab case MATCH_OPT_NDX:
481981a172dSab if ((match_flags & MATCH_F_NDX) &&
482981a172dSab (ndx == list->value.ndx.start))
483c809c407Sab return (1);
484c809c407Sab break;
485981a172dSab case MATCH_OPT_RANGE:
486c809c407Sab /*
487c809c407Sab * A range end value less than 0 means that any value
488c809c407Sab * above the start is acceptible.
489c809c407Sab */
490981a172dSab if ((match_flags & MATCH_F_NDX) &&
491981a172dSab (ndx >= list->value.ndx.start) &&
492c809c407Sab ((list->value.ndx.end < 0) ||
493c809c407Sab (ndx <= list->value.ndx.end)))
494c809c407Sab return (1);
495c809c407Sab break;
496981a172dSab
497981a172dSab case MATCH_OPT_TYPE:
498981a172dSab if ((match_flags & MATCH_F_TYPE) &&
499981a172dSab (type == list->value.type))
500981a172dSab return (1);
501981a172dSab break;
502c809c407Sab }
503c809c407Sab }
504c809c407Sab
505c809c407Sab /* Nothing matched */
506c809c407Sab return (0);
507c809c407Sab }
508c809c407Sab
509c809c407Sab /*
510981a172dSab * Add an entry to match_state.list for use by match(). This routine is for
511981a172dSab * use during getopt() processing. It should not be called once
512981a172dSab * match_prepare() has been called.
513c809c407Sab *
514c809c407Sab * Return True (1) for success. On failure, an error is written
515c809c407Sab * to stderr, and False (0) is returned.
516c809c407Sab */
517c809c407Sab static int
add_match_record(char * argv0,match_rec_t * data)518981a172dSab add_match_record(char *argv0, match_rec_t *data)
519c809c407Sab {
520981a172dSab match_rec_t *rec;
521981a172dSab match_rec_t *list;
522c809c407Sab
523c809c407Sab if ((rec = malloc(sizeof (*rec))) == NULL) {
524c809c407Sab int err = errno;
525c809c407Sab (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC),
526c809c407Sab basename(argv0), strerror(err));
527c809c407Sab return (0);
528c809c407Sab }
529c809c407Sab
530c809c407Sab *rec = *data;
531c809c407Sab
532981a172dSab /* Insert at end of match_state.list */
533981a172dSab if (match_state.list == NULL) {
534981a172dSab match_state.list = rec;
535c809c407Sab } else {
536981a172dSab for (list = match_state.list; list->next != NULL;
537981a172dSab list = list->next)
538c809c407Sab ;
539c809c407Sab list->next = rec;
540c809c407Sab }
541c809c407Sab
542c809c407Sab rec->next = NULL;
543c809c407Sab return (1);
5445aefb655Srie }
5455aefb655Srie
546981a172dSab static int
decide(const char * file,int fd,Elf * elf,uint_t flags,const char * wname,int wfd,uchar_t osabi)547981a172dSab decide(const char *file, int fd, Elf *elf, uint_t flags,
5484f680cc6SAli Bahrami const char *wname, int wfd, uchar_t osabi)
5495aefb655Srie {
550981a172dSab int r;
551981a172dSab
5525aefb655Srie if (gelf_getclass(elf) == ELFCLASS64)
5534f680cc6SAli Bahrami r = regular64(file, fd, elf, flags, wname, wfd, osabi);
5545aefb655Srie else
5554f680cc6SAli Bahrami r = regular32(file, fd, elf, flags, wname, wfd, osabi);
556981a172dSab
557981a172dSab return (r);
5585aefb655Srie }
5595aefb655Srie
560981a172dSab static int
archive(const char * file,int fd,Elf * elf,uint_t flags,const char * wname,int wfd,uchar_t osabi)561981a172dSab archive(const char *file, int fd, Elf *elf, uint_t flags,
5624f680cc6SAli Bahrami const char *wname, int wfd, uchar_t osabi)
5635aefb655Srie {
5645aefb655Srie Elf_Cmd cmd = ELF_C_READ;
5655aefb655Srie Elf_Arhdr *arhdr;
5667e16fca0SAli Bahrami Elf *_elf = NULL;
5675aefb655Srie size_t ptr;
5687e16fca0SAli Bahrami Elf_Arsym *arsym = NULL;
5695aefb655Srie
5705aefb655Srie /*
571d579eb63Sab * Determine if the archive symbol table itself is required.
5725aefb655Srie */
573981a172dSab if ((flags & FLG_SHOW_SYMBOLS) &&
574981a172dSab match(MATCH_F_NAME, MSG_ORIG(MSG_ELF_ARSYM), 0, 0)) {
5755aefb655Srie /*
5765aefb655Srie * Get the archive symbol table.
5775aefb655Srie */
5785aefb655Srie if (((arsym = elf_getarsym(elf, &ptr)) == 0) && elf_errno()) {
5795aefb655Srie /*
5805aefb655Srie * The arsym could be 0 even though there was no error.
5815aefb655Srie * Print the error message only when there was
5825aefb655Srie * real error from elf_getarsym().
5835aefb655Srie */
5845aefb655Srie failure(file, MSG_ORIG(MSG_ELF_GETARSYM));
585981a172dSab return (0);
5865aefb655Srie }
5875aefb655Srie }
5885aefb655Srie
5895aefb655Srie /*
5905aefb655Srie * Print the archive symbol table only when the archive symbol
5915aefb655Srie * table exists and it was requested to print.
5925aefb655Srie */
5935aefb655Srie if (arsym) {
5945aefb655Srie size_t cnt;
5955aefb655Srie char index[MAXNDXSIZE];
5965aefb655Srie size_t offset = 0, _offset = 0;
597ba7866cdSAli Bahrami const char *fmt_arsym1, *fmt_arsym2;
5985aefb655Srie
5995aefb655Srie /*
600ba7866cdSAli Bahrami * Print out all the symbol entries. The format width used
601ba7866cdSAli Bahrami * corresponds to whether the archive symbol table is 32
602ba7866cdSAli Bahrami * or 64-bit. We see them via Elf_Arhdr as size_t values
603ba7866cdSAli Bahrami * in either case with no information loss (see the comments
604ba7866cdSAli Bahrami * in libelf/getarsym.c) so this is done simply to improve
605ba7866cdSAli Bahrami * the user presentation.
6065aefb655Srie */
607ba7866cdSAli Bahrami if (_elf_getarsymwordsize(elf) == 8) {
608ba7866cdSAli Bahrami dbg_print(0, MSG_INTL(MSG_ARCHIVE_SYMTAB_64));
609ba7866cdSAli Bahrami dbg_print(0, MSG_INTL(MSG_ARCHIVE_FIELDS_64));
610ba7866cdSAli Bahrami
611ba7866cdSAli Bahrami fmt_arsym1 = MSG_ORIG(MSG_FMT_ARSYM1_64);
612ba7866cdSAli Bahrami fmt_arsym2 = MSG_ORIG(MSG_FMT_ARSYM2_64);
613ba7866cdSAli Bahrami } else {
614ba7866cdSAli Bahrami dbg_print(0, MSG_INTL(MSG_ARCHIVE_SYMTAB_32));
615ba7866cdSAli Bahrami dbg_print(0, MSG_INTL(MSG_ARCHIVE_FIELDS_32));
616ba7866cdSAli Bahrami
617ba7866cdSAli Bahrami fmt_arsym1 = MSG_ORIG(MSG_FMT_ARSYM1_32);
618ba7866cdSAli Bahrami fmt_arsym2 = MSG_ORIG(MSG_FMT_ARSYM2_32);
619ba7866cdSAli Bahrami }
6205aefb655Srie
6215aefb655Srie for (cnt = 0; cnt < ptr; cnt++, arsym++) {
6225aefb655Srie /*
6235aefb655Srie * For each object obtain an elf descriptor so that we
6245aefb655Srie * can establish the members name. Note, we have had
6255aefb655Srie * archives where the archive header has not been
6265aefb655Srie * obtainable so be lenient with errors.
6275aefb655Srie */
6285aefb655Srie if ((offset == 0) || ((arsym->as_off != 0) &&
6295aefb655Srie (arsym->as_off != _offset))) {
6305aefb655Srie
6315aefb655Srie if (_elf)
6325aefb655Srie (void) elf_end(_elf);
6335aefb655Srie
6345aefb655Srie if (elf_rand(elf, arsym->as_off) !=
6355aefb655Srie arsym->as_off) {
6365aefb655Srie failure(file, MSG_ORIG(MSG_ELF_RAND));
6377e16fca0SAli Bahrami arhdr = NULL;
6385aefb655Srie } else if ((_elf = elf_begin(fd,
6395aefb655Srie ELF_C_READ, elf)) == 0) {
6405aefb655Srie failure(file, MSG_ORIG(MSG_ELF_BEGIN));
6417e16fca0SAli Bahrami arhdr = NULL;
6425aefb655Srie } else if ((arhdr = elf_getarhdr(_elf)) == 0) {
6435aefb655Srie failure(file,
6445aefb655Srie MSG_ORIG(MSG_ELF_GETARHDR));
6457e16fca0SAli Bahrami arhdr = NULL;
6465aefb655Srie }
6475aefb655Srie
6485aefb655Srie _offset = arsym->as_off;
6495aefb655Srie if (offset == 0)
6505aefb655Srie offset = _offset;
6515aefb655Srie }
6525aefb655Srie
6535aefb655Srie (void) snprintf(index, MAXNDXSIZE,
6545aefb655Srie MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(cnt));
6555aefb655Srie if (arsym->as_off)
656ba7866cdSAli Bahrami dbg_print(0, fmt_arsym1, index,
657ba7866cdSAli Bahrami EC_XWORD(arsym->as_off),
658ba7866cdSAli Bahrami arhdr ? arhdr->ar_name :
6595aefb655Srie MSG_INTL(MSG_STR_UNKNOWN), (arsym->as_name ?
6605aefb655Srie demangle(arsym->as_name, flags) :
6615aefb655Srie MSG_INTL(MSG_STR_NULL)));
6625aefb655Srie else
663ba7866cdSAli Bahrami dbg_print(0, fmt_arsym2, index,
664ba7866cdSAli Bahrami EC_XWORD(arsym->as_off));
6655aefb655Srie }
6665aefb655Srie
6675aefb655Srie if (_elf)
6685aefb655Srie (void) elf_end(_elf);
6695aefb655Srie
6705aefb655Srie /*
6715aefb655Srie * If we only need the archive symbol table return.
6725aefb655Srie */
673981a172dSab if ((flags & FLG_SHOW_SYMBOLS) &&
674981a172dSab match(MATCH_F_STRICT | MATCH_F_NAME,
675981a172dSab MSG_ORIG(MSG_ELF_ARSYM), -1, -1))
676981a172dSab return (0);
6775aefb655Srie
6785aefb655Srie /*
6795aefb655Srie * Reset elf descriptor in preparation for processing each
6805aefb655Srie * member.
6815aefb655Srie */
6825aefb655Srie if (offset)
6835aefb655Srie (void) elf_rand(elf, offset);
6845aefb655Srie }
6855aefb655Srie
6865aefb655Srie /*
6875aefb655Srie * Process each object within the archive.
6885aefb655Srie */
6895aefb655Srie while ((_elf = elf_begin(fd, cmd, elf)) != NULL) {
6905aefb655Srie char name[MAXPATHLEN];
6915aefb655Srie
6925aefb655Srie if ((arhdr = elf_getarhdr(_elf)) == NULL) {
6935aefb655Srie failure(file, MSG_ORIG(MSG_ELF_GETARHDR));
694981a172dSab return (0);
6955aefb655Srie }
6965aefb655Srie if (*arhdr->ar_name != '/') {
6975aefb655Srie (void) snprintf(name, MAXPATHLEN,
6985aefb655Srie MSG_ORIG(MSG_FMT_ARNAME), file, arhdr->ar_name);
6995aefb655Srie dbg_print(0, MSG_ORIG(MSG_FMT_NLSTR), name);
7005aefb655Srie
7015aefb655Srie switch (elf_kind(_elf)) {
7025aefb655Srie case ELF_K_AR:
703981a172dSab if (archive(name, fd, _elf, flags,
7044f680cc6SAli Bahrami wname, wfd, osabi) == 1)
705981a172dSab return (1);
7065aefb655Srie break;
7075aefb655Srie case ELF_K_ELF:
708981a172dSab if (decide(name, fd, _elf, flags,
7094f680cc6SAli Bahrami wname, wfd, osabi) == 1)
710981a172dSab return (1);
7115aefb655Srie break;
7125aefb655Srie default:
7135aefb655Srie (void) fprintf(stderr,
7145aefb655Srie MSG_INTL(MSG_ERR_BADFILE), name);
7155aefb655Srie break;
7165aefb655Srie }
7175aefb655Srie }
7185aefb655Srie
7195aefb655Srie cmd = elf_next(_elf);
7205aefb655Srie (void) elf_end(_elf);
7215aefb655Srie }
722981a172dSab
723981a172dSab return (0);
7245aefb655Srie }
7255aefb655Srie
7265aefb655Srie int
main(int argc,char ** argv,char ** envp)7275aefb655Srie main(int argc, char **argv, char **envp)
7285aefb655Srie {
7295aefb655Srie Elf *elf;
7305aefb655Srie int var, fd, wfd = 0;
731981a172dSab char *wname = NULL;
7325aefb655Srie uint_t flags = 0;
733981a172dSab match_rec_t match_data;
734981a172dSab int ret;
7357879e8a6SToomas Soome uchar_t osabi = ELFOSABI_NONE;
7365aefb655Srie
7375aefb655Srie /*
7385aefb655Srie * Establish locale.
7395aefb655Srie */
7405aefb655Srie (void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY));
7415aefb655Srie (void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS));
7425aefb655Srie
7435aefb655Srie (void) setvbuf(stdout, NULL, _IOLBF, 0);
7445aefb655Srie (void) setvbuf(stderr, NULL, _IOLBF, 0);
7455aefb655Srie
7465aefb655Srie opterr = 0;
7475aefb655Srie while ((var = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != EOF) {
7485aefb655Srie switch (var) {
7495aefb655Srie case 'C':
750981a172dSab flags |= FLG_CTL_DEMANGLE;
7515aefb655Srie break;
7525aefb655Srie case 'c':
753981a172dSab flags |= FLG_SHOW_SHDR;
7545aefb655Srie break;
7555aefb655Srie case 'd':
756981a172dSab flags |= FLG_SHOW_DYNAMIC;
7575aefb655Srie break;
7585aefb655Srie case 'e':
759981a172dSab flags |= FLG_SHOW_EHDR;
7605aefb655Srie break;
7615aefb655Srie case 'G':
762981a172dSab flags |= FLG_SHOW_GOT;
7635aefb655Srie break;
7645aefb655Srie case 'g':
765981a172dSab flags |= FLG_SHOW_GROUP;
7665aefb655Srie break;
7675aefb655Srie case 'H':
768981a172dSab flags |= FLG_SHOW_CAP;
7695aefb655Srie break;
7705aefb655Srie case 'h':
771981a172dSab flags |= FLG_SHOW_HASH;
7725aefb655Srie break;
773c809c407Sab case 'I':
774981a172dSab if (!process_index_opt(optarg, &match_data))
775981a172dSab goto usage_brief;
776c809c407Sab if (!add_match_record(argv[0], &match_data))
777c809c407Sab return (1);
778981a172dSab flags |= FLG_CTL_MATCH;
779c809c407Sab break;
7805aefb655Srie case 'i':
781981a172dSab flags |= FLG_SHOW_INTERP;
7825aefb655Srie break;
7835aefb655Srie case 'k':
784981a172dSab flags |= FLG_CALC_CHECKSUM;
7855aefb655Srie break;
7865aefb655Srie case 'l':
787981a172dSab flags |= FLG_CTL_LONGNAME;
7885aefb655Srie break;
7895aefb655Srie case 'm':
790981a172dSab flags |= FLG_SHOW_MOVE;
7915aefb655Srie break;
7925aefb655Srie case 'N':
793981a172dSab match_data.opt_type = MATCH_OPT_NAME;
794c809c407Sab match_data.value.name = optarg;
795c809c407Sab if (!add_match_record(argv[0], &match_data))
796c809c407Sab return (1);
797981a172dSab flags |= FLG_CTL_MATCH;
7985aefb655Srie break;
7995aefb655Srie case 'n':
800981a172dSab flags |= FLG_SHOW_NOTE;
8015aefb655Srie break;
8024f680cc6SAli Bahrami case 'O':
8034f680cc6SAli Bahrami {
8044f680cc6SAli Bahrami uint32_t val;
8054f680cc6SAli Bahrami
8064f680cc6SAli Bahrami /*
8074f680cc6SAli Bahrami * osabi is a uchar_t in the ELF header.
8084f680cc6SAli Bahrami * Don't accept any value that exceeds
8094f680cc6SAli Bahrami * that range.
8104f680cc6SAli Bahrami */
8114f680cc6SAli Bahrami if ((atoui(optarg, ATOUI_OSABI, &val) == 0) ||
8124f680cc6SAli Bahrami (val > 255)) {
8134f680cc6SAli Bahrami (void) fprintf(stderr,
8144f680cc6SAli Bahrami MSG_INTL(MSG_ERR_BAD_T_OSABI),
8154f680cc6SAli Bahrami basename(argv[0]), optarg);
8164f680cc6SAli Bahrami return (1);
8174f680cc6SAli Bahrami }
8184f680cc6SAli Bahrami osabi = val;
8194f680cc6SAli Bahrami }
8204f680cc6SAli Bahrami flags |= FLG_CTL_OSABI;
8214f680cc6SAli Bahrami break;
82239773e46Sab case 'P':
823981a172dSab flags |= FLG_CTL_FAKESHDR;
82439773e46Sab break;
8255aefb655Srie case 'p':
826981a172dSab flags |= FLG_SHOW_PHDR;
8275aefb655Srie break;
8285aefb655Srie case 'r':
829981a172dSab flags |= FLG_SHOW_RELOC;
8305aefb655Srie break;
831d579eb63Sab case 'S':
832981a172dSab flags |= FLG_SHOW_SORT;
833d579eb63Sab break;
8345aefb655Srie case 's':
835981a172dSab flags |= FLG_SHOW_SYMBOLS;
836981a172dSab break;
837981a172dSab case 'T':
838981a172dSab /*
839981a172dSab * We can't evaluate the value yet, because
840981a172dSab * we need to know if -p is used or not in
841981a172dSab * order to tell if we're seeing section header
842981a172dSab * or program header types. So, we save the
843981a172dSab * string in the name field, and then convert
844981a172dSab * it to a type integer in a following pass.
845981a172dSab */
846981a172dSab match_data.opt_type = MATCH_OPT_TYPE;
847981a172dSab match_data.value.name = optarg;
848981a172dSab if (!add_match_record(argv[0], &match_data))
849981a172dSab return (1);
850981a172dSab flags |= FLG_CTL_MATCH;
8515aefb655Srie break;
8525aefb655Srie case 'u':
853981a172dSab flags |= FLG_SHOW_UNWIND;
8545aefb655Srie break;
8555aefb655Srie case 'v':
856981a172dSab flags |= FLG_SHOW_VERSIONS;
8575aefb655Srie break;
8585aefb655Srie case 'w':
8595aefb655Srie wname = optarg;
8605aefb655Srie break;
8615aefb655Srie case 'y':
862981a172dSab flags |= FLG_SHOW_SYMINFO;
8635aefb655Srie break;
8645aefb655Srie case '?':
8655aefb655Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF),
8665aefb655Srie basename(argv[0]));
8675aefb655Srie detail_usage();
8685aefb655Srie return (1);
8695aefb655Srie default:
8705aefb655Srie break;
8715aefb655Srie }
8725aefb655Srie }
8735aefb655Srie
874981a172dSab /* -p and -w are mutually exclusive. -w only works with sections */
875981a172dSab if (((flags & FLG_SHOW_PHDR) != 0) && (wname != NULL))
876981a172dSab goto usage_brief;
877981a172dSab
878981a172dSab /* If a match argument is present, prepare the match state */
879981a172dSab if ((match_state.list != NULL) && (match_prepare(argv[0], flags) == 0))
880981a172dSab return (1);
881981a172dSab
8825aefb655Srie /*
883981a172dSab * Decide what to do if no options specifying something to
884981a172dSab * show or do are present.
885981a172dSab *
886981a172dSab * If there is no -w and no match options, then we will set all
887981a172dSab * the show flags, causing a full display of everything in the
888981a172dSab * file that we know how to handle.
889981a172dSab *
890981a172dSab * Otherwise, if there is no match list, we generate a usage
891981a172dSab * error and quit.
892981a172dSab *
893981a172dSab * In the case where there is a match list, we go ahead and call
894981a172dSab * regular() anyway, leaving it to decide what to do. If -w is
895981a172dSab * present, regular() will use the match list to handle it.
896981a172dSab * In addition, in the absence of explicit show/calc flags, regular()
897981a172dSab * will compare the section headers to the match list and use
898981a172dSab * that to generate the FLG_ bits that will display the information
899981a172dSab * specified by the match list.
9005aefb655Srie */
901981a172dSab if ((flags & ~FLG_MASK_CTL) == 0) {
902981a172dSab if (!wname && (match_state.list == NULL))
903981a172dSab flags |= FLG_MASK_SHOW;
904981a172dSab else if (match_state.list == NULL)
905981a172dSab goto usage_brief;
9065aefb655Srie }
9075aefb655Srie
908981a172dSab /* There needs to be at least 1 filename left following the options */
909981a172dSab if ((var = argc - optind) == 0)
910981a172dSab goto usage_brief;
9115aefb655Srie
9125aefb655Srie /*
9135aefb655Srie * If the -l/-C option is specified, set up the liblddbg.so.
9145aefb655Srie */
915981a172dSab if (flags & FLG_CTL_LONGNAME)
9165aefb655Srie dbg_desc->d_extra |= DBG_E_LONG;
917981a172dSab if (flags & FLG_CTL_DEMANGLE)
9185aefb655Srie dbg_desc->d_extra |= DBG_E_DEMANGLE;
9195aefb655Srie
9205aefb655Srie /*
9215aefb655Srie * If the -w option has indicated an output file open it. It's
9225aefb655Srie * arguable whether this option has much use when multiple files are
9235aefb655Srie * being processed.
924981a172dSab *
925981a172dSab * If wname is non-NULL, we know that -p was not specified, due
926981a172dSab * to the test above.
9275aefb655Srie */
9285aefb655Srie if (wname) {
9295aefb655Srie if ((wfd = open(wname, (O_RDWR | O_CREAT | O_TRUNC),
9305aefb655Srie 0666)) < 0) {
9315aefb655Srie int err = errno;
9325aefb655Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN),
9335aefb655Srie wname, strerror(err));
934981a172dSab return (1);
9355aefb655Srie }
9365aefb655Srie }
9375aefb655Srie
9385aefb655Srie /*
939981a172dSab * Open the input file, initialize the elf interface, and
940981a172dSab * process it.
9415aefb655Srie */
942981a172dSab ret = 0;
943981a172dSab for (; (optind < argc) && (ret == 0); optind++) {
9445aefb655Srie const char *file = argv[optind];
9455aefb655Srie
9465aefb655Srie if ((fd = open(argv[optind], O_RDONLY)) == -1) {
9475aefb655Srie int err = errno;
9485aefb655Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN),
9495aefb655Srie file, strerror(err));
9505aefb655Srie continue;
9515aefb655Srie }
9525aefb655Srie (void) elf_version(EV_CURRENT);
9535aefb655Srie if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
9545aefb655Srie failure(file, MSG_ORIG(MSG_ELF_BEGIN));
9555aefb655Srie (void) close(fd);
9565aefb655Srie continue;
9575aefb655Srie }
9585aefb655Srie
9595aefb655Srie if (var > 1)
9605aefb655Srie dbg_print(0, MSG_ORIG(MSG_FMT_NLSTRNL), file);
9615aefb655Srie
9625aefb655Srie switch (elf_kind(elf)) {
9635aefb655Srie case ELF_K_AR:
9644f680cc6SAli Bahrami ret = archive(file, fd, elf, flags, wname, wfd, osabi);
9655aefb655Srie break;
9665aefb655Srie case ELF_K_ELF:
9674f680cc6SAli Bahrami ret = decide(file, fd, elf, flags, wname, wfd, osabi);
9685aefb655Srie break;
9695aefb655Srie default:
9705aefb655Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADFILE), file);
9715aefb655Srie break;
9725aefb655Srie }
9735aefb655Srie
9745aefb655Srie (void) close(fd);
9755aefb655Srie (void) elf_end(elf);
9765aefb655Srie }
9775aefb655Srie
9785aefb655Srie if (wfd)
9795aefb655Srie (void) close(wfd);
980981a172dSab return (ret);
981981a172dSab
982981a172dSab usage_brief:
983981a172dSab /* Control comes here for a simple usage message and exit */
984981a172dSab (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF),
985981a172dSab basename(argv[0]));
986981a172dSab return (1);
987981a172dSab
9885aefb655Srie }
989