1a85fe12eSEd Maste /*- 2a85fe12eSEd Maste * Copyright (c) 2007 Hyogeol Lee <hyogeollee@gmail.com> 3a85fe12eSEd Maste * All rights reserved. 4a85fe12eSEd Maste * 5a85fe12eSEd Maste * Redistribution and use in source and binary forms, with or without 6a85fe12eSEd Maste * modification, are permitted provided that the following conditions 7a85fe12eSEd Maste * are met: 8a85fe12eSEd Maste * 1. Redistributions of source code must retain the above copyright 9a85fe12eSEd Maste * notice, this list of conditions and the following disclaimer 10a85fe12eSEd Maste * in this position and unchanged. 11a85fe12eSEd Maste * 2. Redistributions in binary form must reproduce the above copyright 12a85fe12eSEd Maste * notice, this list of conditions and the following disclaimer in the 13a85fe12eSEd Maste * documentation and/or other materials provided with the distribution. 14a85fe12eSEd Maste * 15a85fe12eSEd Maste * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 16a85fe12eSEd Maste * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17a85fe12eSEd Maste * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18a85fe12eSEd Maste * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19a85fe12eSEd Maste * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20a85fe12eSEd Maste * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21a85fe12eSEd Maste * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22a85fe12eSEd Maste * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23a85fe12eSEd Maste * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24a85fe12eSEd Maste * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25a85fe12eSEd Maste */ 26a85fe12eSEd Maste 27a85fe12eSEd Maste #include <sys/queue.h> 28a85fe12eSEd Maste #include <sys/types.h> 29a85fe12eSEd Maste #include <sys/stat.h> 30a85fe12eSEd Maste #include <ar.h> 31a85fe12eSEd Maste #include <assert.h> 32a85fe12eSEd Maste #include <ctype.h> 33a85fe12eSEd Maste #include <dwarf.h> 34a85fe12eSEd Maste #include <err.h> 35a85fe12eSEd Maste #include <errno.h> 36a85fe12eSEd Maste #include <fcntl.h> 37a85fe12eSEd Maste #include <gelf.h> 38a85fe12eSEd Maste #include <getopt.h> 39a85fe12eSEd Maste #include <inttypes.h> 40a85fe12eSEd Maste #include <libdwarf.h> 41a85fe12eSEd Maste #include <libelftc.h> 42a85fe12eSEd Maste #include <stdbool.h> 43a85fe12eSEd Maste #include <stdio.h> 44a85fe12eSEd Maste #include <stdlib.h> 45a85fe12eSEd Maste #include <string.h> 46a85fe12eSEd Maste #include <strings.h> 47a85fe12eSEd Maste #include <unistd.h> 48a85fe12eSEd Maste 49a85fe12eSEd Maste #include "_elftc.h" 50a85fe12eSEd Maste 51a85fe12eSEd Maste ELFTC_VCSID("$Id: nm.c 2484 2012-04-07 15:52:05Z kaiwang27 $"); 52a85fe12eSEd Maste 53a85fe12eSEd Maste /* symbol information list */ 54a85fe12eSEd Maste STAILQ_HEAD(sym_head, sym_entry); 55a85fe12eSEd Maste 56a85fe12eSEd Maste struct sym_entry { 57a85fe12eSEd Maste char *name; 58a85fe12eSEd Maste GElf_Sym *sym; 59a85fe12eSEd Maste STAILQ_ENTRY(sym_entry) sym_entries; 60a85fe12eSEd Maste }; 61a85fe12eSEd Maste 62a85fe12eSEd Maste typedef int (*fn_sort)(const void *, const void *); 63a85fe12eSEd Maste typedef void (*fn_elem_print)(char, const char *, const GElf_Sym *, const char *); 64a85fe12eSEd Maste typedef void (*fn_sym_print)(const GElf_Sym *); 65a85fe12eSEd Maste typedef int (*fn_filter)(char, const GElf_Sym *, const char *); 66a85fe12eSEd Maste 67a85fe12eSEd Maste /* output filter list */ 68*50f69bfbSEd Maste static SLIST_HEAD(filter_head, filter_entry) nm_out_filter = 69a85fe12eSEd Maste SLIST_HEAD_INITIALIZER(nm_out_filter); 70a85fe12eSEd Maste 71a85fe12eSEd Maste struct filter_entry { 72a85fe12eSEd Maste fn_filter fn; 73a85fe12eSEd Maste SLIST_ENTRY(filter_entry) filter_entries; 74a85fe12eSEd Maste }; 75a85fe12eSEd Maste 76a85fe12eSEd Maste struct sym_print_data { 77a85fe12eSEd Maste struct sym_head *headp; 78a85fe12eSEd Maste size_t sh_num, list_num; 79a85fe12eSEd Maste const char *t_table, **s_table, *filename, *objname; 80a85fe12eSEd Maste }; 81a85fe12eSEd Maste 82a85fe12eSEd Maste struct nm_prog_info { 83a85fe12eSEd Maste const char *name; 84a85fe12eSEd Maste const char *def_filename; 85a85fe12eSEd Maste }; 86a85fe12eSEd Maste 87a85fe12eSEd Maste /* List for line number information. */ 88a85fe12eSEd Maste struct line_info_entry { 89a85fe12eSEd Maste uint64_t addr; /* address */ 90a85fe12eSEd Maste uint64_t line; /* line number */ 91a85fe12eSEd Maste char *file; /* file name with path */ 92a85fe12eSEd Maste SLIST_ENTRY(line_info_entry) entries; 93a85fe12eSEd Maste }; 94a85fe12eSEd Maste SLIST_HEAD(line_info_head, line_info_entry); 95a85fe12eSEd Maste 96a85fe12eSEd Maste /* List for function line number information. */ 97a85fe12eSEd Maste struct func_info_entry { 98a85fe12eSEd Maste char *name; /* function name */ 99a85fe12eSEd Maste char *file; /* file name with path */ 100a85fe12eSEd Maste uint64_t lowpc; /* low address */ 101a85fe12eSEd Maste uint64_t highpc; /* high address */ 102a85fe12eSEd Maste uint64_t line; /* line number */ 103a85fe12eSEd Maste SLIST_ENTRY(func_info_entry) entries; 104a85fe12eSEd Maste }; 105a85fe12eSEd Maste SLIST_HEAD(func_info_head, func_info_entry); 106a85fe12eSEd Maste 107a85fe12eSEd Maste /* List for variable line number information. */ 108a85fe12eSEd Maste struct var_info_entry { 109a85fe12eSEd Maste char *name; /* variable name */ 110a85fe12eSEd Maste char *file; /* file name with path */ 111a85fe12eSEd Maste uint64_t addr; /* address */ 112a85fe12eSEd Maste uint64_t line; /* line number */ 113a85fe12eSEd Maste SLIST_ENTRY(var_info_entry) entries; 114a85fe12eSEd Maste }; 115a85fe12eSEd Maste SLIST_HEAD(var_info_head, var_info_entry); 116a85fe12eSEd Maste 117a85fe12eSEd Maste /* output numric type */ 118a85fe12eSEd Maste enum radix { 119a85fe12eSEd Maste RADIX_OCT, 120a85fe12eSEd Maste RADIX_HEX, 121a85fe12eSEd Maste RADIX_DEC 122a85fe12eSEd Maste }; 123a85fe12eSEd Maste 124a85fe12eSEd Maste /* output symbol type, PRINT_SYM_DYN for dynamic symbol only */ 125a85fe12eSEd Maste enum print_symbol { 126a85fe12eSEd Maste PRINT_SYM_SYM, 127a85fe12eSEd Maste PRINT_SYM_DYN 128a85fe12eSEd Maste }; 129a85fe12eSEd Maste 130a85fe12eSEd Maste /* output name type */ 131a85fe12eSEd Maste enum print_name { 132a85fe12eSEd Maste PRINT_NAME_NONE, 133a85fe12eSEd Maste PRINT_NAME_FULL, 134a85fe12eSEd Maste PRINT_NAME_MULTI 135a85fe12eSEd Maste }; 136a85fe12eSEd Maste 137a85fe12eSEd Maste struct nm_prog_options { 138a85fe12eSEd Maste enum print_symbol print_symbol; 139a85fe12eSEd Maste enum print_name print_name; 140a85fe12eSEd Maste enum radix t; 141a85fe12eSEd Maste int demangle_type; 142a85fe12eSEd Maste bool print_debug; 143a85fe12eSEd Maste bool print_armap; 144a85fe12eSEd Maste int print_size; 145a85fe12eSEd Maste bool debug_line; 146a85fe12eSEd Maste int def_only; 147a85fe12eSEd Maste bool undef_only; 148a85fe12eSEd Maste int sort_size; 149a85fe12eSEd Maste bool sort_reverse; 150a85fe12eSEd Maste int no_demangle; 151a85fe12eSEd Maste 152a85fe12eSEd Maste /* 153a85fe12eSEd Maste * function pointer to sort symbol list. 154a85fe12eSEd Maste * possible function - cmp_name, cmp_none, cmp_size, cmp_value 155a85fe12eSEd Maste */ 156a85fe12eSEd Maste fn_sort sort_fn; 157a85fe12eSEd Maste 158a85fe12eSEd Maste /* 159a85fe12eSEd Maste * function pointer to print symbol elem. 160a85fe12eSEd Maste * possible function - sym_elem_print_all 161a85fe12eSEd Maste * sym_elem_print_all_portable 162a85fe12eSEd Maste * sym_elem_print_all_sysv 163a85fe12eSEd Maste */ 164a85fe12eSEd Maste fn_elem_print elem_print_fn; 165a85fe12eSEd Maste 166a85fe12eSEd Maste fn_sym_print value_print_fn; 167a85fe12eSEd Maste fn_sym_print size_print_fn; 168a85fe12eSEd Maste }; 169a85fe12eSEd Maste 170a85fe12eSEd Maste #define CHECK_SYM_PRINT_DATA(p) (p->headp == NULL || p->sh_num == 0 || \ 171a85fe12eSEd Maste p->t_table == NULL || p->s_table == NULL || p->filename == NULL) 172a85fe12eSEd Maste #define IS_SYM_TYPE(t) ((t) == '?' || isalpha((t)) != 0) 173a85fe12eSEd Maste #define IS_UNDEF_SYM_TYPE(t) ((t) == 'U' || (t) == 'v' || (t) == 'w') 174a85fe12eSEd Maste #define UNUSED(p) ((void)p) 175a85fe12eSEd Maste 176a85fe12eSEd Maste static int cmp_name(const void *, const void *); 177a85fe12eSEd Maste static int cmp_none(const void *, const void *); 178a85fe12eSEd Maste static int cmp_size(const void *, const void *); 179a85fe12eSEd Maste static int cmp_value(const void *, const void *); 180a85fe12eSEd Maste static void filter_dest(void); 181a85fe12eSEd Maste static int filter_insert(fn_filter); 182a85fe12eSEd Maste static void get_opt(int, char **); 183a85fe12eSEd Maste static int get_sym(Elf *, struct sym_head *, int, size_t, size_t, 184a85fe12eSEd Maste const char *, const char **, int); 185a85fe12eSEd Maste static const char * get_sym_name(Elf *, const GElf_Sym *, size_t, 186a85fe12eSEd Maste const char **, int); 187a85fe12eSEd Maste static char get_sym_type(const GElf_Sym *, const char *); 188a85fe12eSEd Maste static void global_dest(void); 189a85fe12eSEd Maste static void global_init(void); 190a85fe12eSEd Maste static bool is_sec_data(GElf_Shdr *); 191a85fe12eSEd Maste static bool is_sec_debug(const char *); 192a85fe12eSEd Maste static bool is_sec_nobits(GElf_Shdr *); 193a85fe12eSEd Maste static bool is_sec_readonly(GElf_Shdr *); 194a85fe12eSEd Maste static bool is_sec_text(GElf_Shdr *); 195a85fe12eSEd Maste static void print_ar_index(int, Elf *); 196a85fe12eSEd Maste static void print_header(const char *, const char *); 197a85fe12eSEd Maste static void print_version(void); 198a85fe12eSEd Maste static int read_elf(Elf *, const char *, Elf_Kind); 199a85fe12eSEd Maste static int read_object(const char *); 200a85fe12eSEd Maste static int read_files(int, char **); 201a85fe12eSEd Maste static void set_opt_value_print_fn(enum radix); 202a85fe12eSEd Maste static int sym_elem_def(char, const GElf_Sym *, const char *); 203a85fe12eSEd Maste static int sym_elem_global(char, const GElf_Sym *, const char *); 204a85fe12eSEd Maste static int sym_elem_global_static(char, const GElf_Sym *, 205a85fe12eSEd Maste const char *); 206a85fe12eSEd Maste static int sym_elem_nondebug(char, const GElf_Sym *, const char *); 207a85fe12eSEd Maste static int sym_elem_nonzero_size(char, const GElf_Sym *, 208a85fe12eSEd Maste const char *); 209a85fe12eSEd Maste static void sym_elem_print_all(char, const char *, 210a85fe12eSEd Maste const GElf_Sym *, const char *); 211a85fe12eSEd Maste static void sym_elem_print_all_portable(char, const char *, 212a85fe12eSEd Maste const GElf_Sym *, const char *); 213a85fe12eSEd Maste static void sym_elem_print_all_sysv(char, const char *, 214a85fe12eSEd Maste const GElf_Sym *, const char *); 215a85fe12eSEd Maste static int sym_elem_undef(char, const GElf_Sym *, const char *); 216a85fe12eSEd Maste static void sym_list_dest(struct sym_head *); 217a85fe12eSEd Maste static int sym_list_insert(struct sym_head *, const char *, 218a85fe12eSEd Maste const GElf_Sym *); 219a85fe12eSEd Maste static void sym_list_print(struct sym_print_data *, 220a85fe12eSEd Maste struct func_info_head *, struct var_info_head *, 221a85fe12eSEd Maste struct line_info_head *); 222a85fe12eSEd Maste static void sym_list_print_each(struct sym_entry *, 223a85fe12eSEd Maste struct sym_print_data *, struct func_info_head *, 224a85fe12eSEd Maste struct var_info_head *, struct line_info_head *); 225a85fe12eSEd Maste static struct sym_entry *sym_list_sort(struct sym_print_data *); 226a85fe12eSEd Maste static void sym_size_oct_print(const GElf_Sym *); 227a85fe12eSEd Maste static void sym_size_hex_print(const GElf_Sym *); 228a85fe12eSEd Maste static void sym_size_dec_print(const GElf_Sym *); 229a85fe12eSEd Maste static void sym_value_oct_print(const GElf_Sym *); 230a85fe12eSEd Maste static void sym_value_hex_print(const GElf_Sym *); 231a85fe12eSEd Maste static void sym_value_dec_print(const GElf_Sym *); 232a85fe12eSEd Maste static void usage(int); 233a85fe12eSEd Maste 234a85fe12eSEd Maste static struct nm_prog_info nm_info; 235a85fe12eSEd Maste static struct nm_prog_options nm_opts; 236a85fe12eSEd Maste static int nm_elfclass; 237a85fe12eSEd Maste 238a85fe12eSEd Maste /* 239a85fe12eSEd Maste * Point to current sym_print_data to use portable qsort function. 240a85fe12eSEd Maste * (e.g. There is no qsort_r function in NetBSD.) 241a85fe12eSEd Maste * 242a85fe12eSEd Maste * Using in sym_list_sort. 243a85fe12eSEd Maste */ 244a85fe12eSEd Maste static struct sym_print_data *nm_print_data; 245a85fe12eSEd Maste 246a85fe12eSEd Maste static const struct option nm_longopts[] = { 247a85fe12eSEd Maste { "debug-syms", no_argument, NULL, 'a' }, 248a85fe12eSEd Maste { "defined-only", no_argument, &nm_opts.def_only, 1}, 249a85fe12eSEd Maste { "demangle", optional_argument, NULL, 'C' }, 250a85fe12eSEd Maste { "dynamic", no_argument, NULL, 'D' }, 251a85fe12eSEd Maste { "format", required_argument, NULL, 'F' }, 252a85fe12eSEd Maste { "help", no_argument, NULL, 'h' }, 253a85fe12eSEd Maste { "line-numbers", no_argument, NULL, 'l' }, 254a85fe12eSEd Maste { "no-demangle", no_argument, &nm_opts.no_demangle, 255a85fe12eSEd Maste 1}, 256a85fe12eSEd Maste { "no-sort", no_argument, NULL, 'p' }, 257a85fe12eSEd Maste { "numeric-sort", no_argument, NULL, 'v' }, 258a85fe12eSEd Maste { "print-armap", no_argument, NULL, 's' }, 259a85fe12eSEd Maste { "print-file-name", no_argument, NULL, 'A' }, 260a85fe12eSEd Maste { "print-size", no_argument, NULL, 'S' }, 261a85fe12eSEd Maste { "radix", required_argument, NULL, 't' }, 262a85fe12eSEd Maste { "reverse-sort", no_argument, NULL, 'r' }, 263a85fe12eSEd Maste { "size-sort", no_argument, &nm_opts.sort_size, 1}, 264a85fe12eSEd Maste { "undefined-only", no_argument, NULL, 'u' }, 265a85fe12eSEd Maste { "version", no_argument, NULL, 'V' }, 266a85fe12eSEd Maste { NULL, 0, NULL, 0 } 267a85fe12eSEd Maste }; 268a85fe12eSEd Maste 269a85fe12eSEd Maste #if defined(ELFTC_NEED_BYTEORDER_EXTENSIONS) 270a85fe12eSEd Maste static __inline uint32_t 271a85fe12eSEd Maste be32dec(const void *pp) 272a85fe12eSEd Maste { 273a85fe12eSEd Maste unsigned char const *p = (unsigned char const *)pp; 274a85fe12eSEd Maste 275a85fe12eSEd Maste return ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]); 276a85fe12eSEd Maste } 277a85fe12eSEd Maste 278a85fe12eSEd Maste static __inline uint32_t 279a85fe12eSEd Maste le32dec(const void *pp) 280a85fe12eSEd Maste { 281a85fe12eSEd Maste unsigned char const *p = (unsigned char const *)pp; 282a85fe12eSEd Maste 283a85fe12eSEd Maste return ((p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]); 284a85fe12eSEd Maste } 285a85fe12eSEd Maste 286a85fe12eSEd Maste static __inline uint64_t 287a85fe12eSEd Maste be64dec(const void *pp) 288a85fe12eSEd Maste { 289a85fe12eSEd Maste unsigned char const *p = (unsigned char const *)pp; 290a85fe12eSEd Maste 291a85fe12eSEd Maste return (((uint64_t)be32dec(p) << 32) | be32dec(p + 4)); 292a85fe12eSEd Maste } 293a85fe12eSEd Maste 294a85fe12eSEd Maste static __inline uint64_t 295a85fe12eSEd Maste le64dec(const void *pp) 296a85fe12eSEd Maste { 297a85fe12eSEd Maste unsigned char const *p = (unsigned char const *)pp; 298a85fe12eSEd Maste 299a85fe12eSEd Maste return (((uint64_t)le32dec(p + 4) << 32) | le32dec(p)); 300a85fe12eSEd Maste } 301a85fe12eSEd Maste #endif 302a85fe12eSEd Maste 303a85fe12eSEd Maste static int 304a85fe12eSEd Maste cmp_name(const void *l, const void *r) 305a85fe12eSEd Maste { 306a85fe12eSEd Maste 307a85fe12eSEd Maste assert(l != NULL); 308a85fe12eSEd Maste assert(r != NULL); 309a85fe12eSEd Maste assert(((const struct sym_entry *)l)->name != NULL); 310a85fe12eSEd Maste assert(((const struct sym_entry *)r)->name != NULL); 311a85fe12eSEd Maste 312a85fe12eSEd Maste return (strcmp(((const struct sym_entry *)l)->name, 313a85fe12eSEd Maste ((const struct sym_entry *)r)->name)); 314a85fe12eSEd Maste } 315a85fe12eSEd Maste 316a85fe12eSEd Maste static int 317a85fe12eSEd Maste cmp_none(const void *l, const void *r) 318a85fe12eSEd Maste { 319a85fe12eSEd Maste 320a85fe12eSEd Maste UNUSED(l); 321a85fe12eSEd Maste UNUSED(r); 322a85fe12eSEd Maste 323a85fe12eSEd Maste return (0); 324a85fe12eSEd Maste } 325a85fe12eSEd Maste 326a85fe12eSEd Maste /* Size comparison. If l and r have same size, compare their name. */ 327a85fe12eSEd Maste static int 328a85fe12eSEd Maste cmp_size(const void *lp, const void *rp) 329a85fe12eSEd Maste { 330a85fe12eSEd Maste const struct sym_entry *l, *r; 331a85fe12eSEd Maste 332a85fe12eSEd Maste l = lp; 333a85fe12eSEd Maste r = rp; 334a85fe12eSEd Maste 335a85fe12eSEd Maste assert(l != NULL); 336a85fe12eSEd Maste assert(l->name != NULL); 337a85fe12eSEd Maste assert(l->sym != NULL); 338a85fe12eSEd Maste assert(r != NULL); 339a85fe12eSEd Maste assert(r->name != NULL); 340a85fe12eSEd Maste assert(r->sym != NULL); 341a85fe12eSEd Maste 342a85fe12eSEd Maste if (l->sym->st_size == r->sym->st_size) 343a85fe12eSEd Maste return (strcmp(l->name, r->name)); 344a85fe12eSEd Maste 345a85fe12eSEd Maste return (l->sym->st_size - r->sym->st_size); 346a85fe12eSEd Maste } 347a85fe12eSEd Maste 348a85fe12eSEd Maste /* Value comparison. Undefined symbols come first. */ 349a85fe12eSEd Maste static int 350a85fe12eSEd Maste cmp_value(const void *lp, const void *rp) 351a85fe12eSEd Maste { 352a85fe12eSEd Maste const struct sym_entry *l, *r; 353a85fe12eSEd Maste const char *ttable; 354a85fe12eSEd Maste int l_is_undef, r_is_undef; 355a85fe12eSEd Maste 356a85fe12eSEd Maste l = lp; 357a85fe12eSEd Maste r = rp; 358a85fe12eSEd Maste 359a85fe12eSEd Maste assert(nm_print_data != NULL); 360a85fe12eSEd Maste ttable = nm_print_data->t_table; 361a85fe12eSEd Maste 362a85fe12eSEd Maste assert(l != NULL); 363a85fe12eSEd Maste assert(l->name != NULL); 364a85fe12eSEd Maste assert(l->sym != NULL); 365a85fe12eSEd Maste assert(r != NULL); 366a85fe12eSEd Maste assert(r->name != NULL); 367a85fe12eSEd Maste assert(r->sym != NULL); 368a85fe12eSEd Maste assert(ttable != NULL); 369a85fe12eSEd Maste 370a85fe12eSEd Maste l_is_undef = IS_UNDEF_SYM_TYPE(get_sym_type(l->sym, ttable)) ? 1 : 0; 371a85fe12eSEd Maste r_is_undef = IS_UNDEF_SYM_TYPE(get_sym_type(r->sym, ttable)) ? 1 : 0; 372a85fe12eSEd Maste 373a85fe12eSEd Maste assert(l_is_undef + r_is_undef >= 0); 374a85fe12eSEd Maste assert(l_is_undef + r_is_undef <= 2); 375a85fe12eSEd Maste 376a85fe12eSEd Maste switch (l_is_undef + r_is_undef) { 377a85fe12eSEd Maste case 0: 378a85fe12eSEd Maste /* Both defined */ 379a85fe12eSEd Maste if (l->sym->st_value == r->sym->st_value) 380a85fe12eSEd Maste return (strcmp(l->name, r->name)); 381a85fe12eSEd Maste return (l->sym->st_value - r->sym->st_value); 382a85fe12eSEd Maste case 1: 383a85fe12eSEd Maste /* One undefined */ 384a85fe12eSEd Maste return (l_is_undef == 0 ? 1 : -1); 385a85fe12eSEd Maste case 2: 386a85fe12eSEd Maste /* Both undefined */ 387a85fe12eSEd Maste return (strcmp(l->name, r->name)); 388a85fe12eSEd Maste } 389a85fe12eSEd Maste /* NOTREACHED */ 390a85fe12eSEd Maste 391a85fe12eSEd Maste return (l->sym->st_value - r->sym->st_value); 392a85fe12eSEd Maste } 393a85fe12eSEd Maste 394a85fe12eSEd Maste static void 395a85fe12eSEd Maste filter_dest(void) 396a85fe12eSEd Maste { 397a85fe12eSEd Maste struct filter_entry *e; 398a85fe12eSEd Maste 399a85fe12eSEd Maste while (!SLIST_EMPTY(&nm_out_filter)) { 400a85fe12eSEd Maste e = SLIST_FIRST(&nm_out_filter); 401a85fe12eSEd Maste SLIST_REMOVE_HEAD(&nm_out_filter, filter_entries); 402a85fe12eSEd Maste free(e); 403a85fe12eSEd Maste } 404a85fe12eSEd Maste } 405a85fe12eSEd Maste 406a85fe12eSEd Maste static int 407a85fe12eSEd Maste filter_insert(fn_filter filter_fn) 408a85fe12eSEd Maste { 409a85fe12eSEd Maste struct filter_entry *e; 410a85fe12eSEd Maste 411a85fe12eSEd Maste assert(filter_fn != NULL); 412a85fe12eSEd Maste 413a85fe12eSEd Maste if ((e = malloc(sizeof(struct filter_entry))) == NULL) { 414a85fe12eSEd Maste warn("malloc"); 415a85fe12eSEd Maste return (0); 416a85fe12eSEd Maste } 417a85fe12eSEd Maste e->fn = filter_fn; 418a85fe12eSEd Maste SLIST_INSERT_HEAD(&nm_out_filter, e, filter_entries); 419a85fe12eSEd Maste 420a85fe12eSEd Maste return (1); 421a85fe12eSEd Maste } 422a85fe12eSEd Maste 423a85fe12eSEd Maste static int 424a85fe12eSEd Maste parse_demangle_option(const char *opt) 425a85fe12eSEd Maste { 426a85fe12eSEd Maste 427a85fe12eSEd Maste if (opt == NULL) 428a85fe12eSEd Maste return (ELFTC_DEM_UNKNOWN); 429a85fe12eSEd Maste else if (!strncasecmp(opt, "gnu-v2", 6)) 430a85fe12eSEd Maste return (ELFTC_DEM_GNU2); 431a85fe12eSEd Maste else if (!strncasecmp(opt, "gnu-v3", 6)) 432a85fe12eSEd Maste return (ELFTC_DEM_GNU3); 433a85fe12eSEd Maste else if (!strncasecmp(opt, "arm", 3)) 434a85fe12eSEd Maste return (ELFTC_DEM_ARM); 435a85fe12eSEd Maste else 436a85fe12eSEd Maste errx(EXIT_FAILURE, "unknown demangling style '%s'", opt); 437a85fe12eSEd Maste 438a85fe12eSEd Maste /* NOTREACHED */ 439a85fe12eSEd Maste return (0); 440a85fe12eSEd Maste } 441a85fe12eSEd Maste 442a85fe12eSEd Maste static void 443a85fe12eSEd Maste get_opt(int argc, char **argv) 444a85fe12eSEd Maste { 445a85fe12eSEd Maste int ch; 446a85fe12eSEd Maste bool is_posix, oflag; 447a85fe12eSEd Maste 448a85fe12eSEd Maste if (argc <= 0 || argv == NULL) 449a85fe12eSEd Maste return; 450a85fe12eSEd Maste 451a85fe12eSEd Maste oflag = is_posix = false; 452a85fe12eSEd Maste nm_opts.t = RADIX_HEX; 453a85fe12eSEd Maste while ((ch = getopt_long(argc, argv, "ABCDF:PSVaefghlnoprst:uvx", 454a85fe12eSEd Maste nm_longopts, NULL)) != -1) { 455a85fe12eSEd Maste switch (ch) { 456a85fe12eSEd Maste case 'A': 457a85fe12eSEd Maste nm_opts.print_name = PRINT_NAME_FULL; 458a85fe12eSEd Maste break; 459a85fe12eSEd Maste case 'B': 460a85fe12eSEd Maste nm_opts.elem_print_fn = &sym_elem_print_all; 461a85fe12eSEd Maste break; 462a85fe12eSEd Maste case 'C': 463a85fe12eSEd Maste nm_opts.demangle_type = parse_demangle_option(optarg); 464a85fe12eSEd Maste break; 465a85fe12eSEd Maste case 'D': 466a85fe12eSEd Maste nm_opts.print_symbol = PRINT_SYM_DYN; 467a85fe12eSEd Maste break; 468a85fe12eSEd Maste case 'F': 469a85fe12eSEd Maste /* sysv, bsd, posix */ 470a85fe12eSEd Maste switch (optarg[0]) { 471a85fe12eSEd Maste case 'B': 472a85fe12eSEd Maste case 'b': 473a85fe12eSEd Maste nm_opts.elem_print_fn = &sym_elem_print_all; 474a85fe12eSEd Maste break; 475a85fe12eSEd Maste case 'P': 476a85fe12eSEd Maste case 'p': 477a85fe12eSEd Maste is_posix = true; 478a85fe12eSEd Maste nm_opts.elem_print_fn = 479a85fe12eSEd Maste &sym_elem_print_all_portable; 480a85fe12eSEd Maste break; 481a85fe12eSEd Maste case 'S': 482a85fe12eSEd Maste case 's': 483a85fe12eSEd Maste nm_opts.elem_print_fn = 484a85fe12eSEd Maste &sym_elem_print_all_sysv; 485a85fe12eSEd Maste break; 486a85fe12eSEd Maste default: 487a85fe12eSEd Maste warnx("%s: Invalid format", optarg); 488a85fe12eSEd Maste usage(1); 489a85fe12eSEd Maste } 490a85fe12eSEd Maste 491a85fe12eSEd Maste break; 492a85fe12eSEd Maste case 'P': 493a85fe12eSEd Maste is_posix = true; 494a85fe12eSEd Maste nm_opts.elem_print_fn = &sym_elem_print_all_portable; 495a85fe12eSEd Maste break; 496a85fe12eSEd Maste case 'S': 497a85fe12eSEd Maste nm_opts.print_size = 1; 498a85fe12eSEd Maste break; 499a85fe12eSEd Maste case 'V': 500a85fe12eSEd Maste print_version(); 501a85fe12eSEd Maste /* NOTREACHED */ 502a85fe12eSEd Maste case 'a': 503a85fe12eSEd Maste nm_opts.print_debug = true; 504a85fe12eSEd Maste break; 505a85fe12eSEd Maste case 'e': 506a85fe12eSEd Maste filter_insert(sym_elem_global_static); 507a85fe12eSEd Maste break; 508a85fe12eSEd Maste case 'f': 509a85fe12eSEd Maste break; 510a85fe12eSEd Maste case 'g': 511a85fe12eSEd Maste filter_insert(sym_elem_global); 512a85fe12eSEd Maste break; 513a85fe12eSEd Maste case 'h': 514a85fe12eSEd Maste usage(0); 515a85fe12eSEd Maste break; 516a85fe12eSEd Maste case 'l': 517a85fe12eSEd Maste nm_opts.debug_line = true; 518a85fe12eSEd Maste break; 519a85fe12eSEd Maste case 'n': 520a85fe12eSEd Maste case 'v': 521a85fe12eSEd Maste nm_opts.sort_fn = &cmp_value; 522a85fe12eSEd Maste break; 523a85fe12eSEd Maste case 'o': 524a85fe12eSEd Maste oflag = true; 525a85fe12eSEd Maste break; 526a85fe12eSEd Maste case 'p': 527a85fe12eSEd Maste nm_opts.sort_fn = &cmp_none; 528a85fe12eSEd Maste break; 529a85fe12eSEd Maste case 'r': 530a85fe12eSEd Maste nm_opts.sort_reverse = true; 531a85fe12eSEd Maste break; 532a85fe12eSEd Maste case 's': 533a85fe12eSEd Maste nm_opts.print_armap = true; 534a85fe12eSEd Maste break; 535a85fe12eSEd Maste case 't': 536a85fe12eSEd Maste /* t require always argument to getopt_long */ 537a85fe12eSEd Maste switch (optarg[0]) { 538a85fe12eSEd Maste case 'd': 539a85fe12eSEd Maste nm_opts.t = RADIX_DEC; 540a85fe12eSEd Maste break; 541a85fe12eSEd Maste case 'o': 542a85fe12eSEd Maste nm_opts.t = RADIX_OCT; 543a85fe12eSEd Maste break; 544a85fe12eSEd Maste case 'x': 545a85fe12eSEd Maste nm_opts.t = RADIX_HEX; 546a85fe12eSEd Maste break; 547a85fe12eSEd Maste default: 548a85fe12eSEd Maste warnx("%s: Invalid radix", optarg); 549a85fe12eSEd Maste usage(1); 550a85fe12eSEd Maste } 551a85fe12eSEd Maste break; 552a85fe12eSEd Maste case 'u': 553a85fe12eSEd Maste filter_insert(sym_elem_undef); 554a85fe12eSEd Maste nm_opts.undef_only = true; 555a85fe12eSEd Maste break; 556a85fe12eSEd Maste /* case 'v': see case 'n' above. */ 557a85fe12eSEd Maste case 'x': 558a85fe12eSEd Maste nm_opts.t = RADIX_HEX; 559a85fe12eSEd Maste break; 560a85fe12eSEd Maste case 0: 561a85fe12eSEd Maste if (nm_opts.sort_size != 0) { 562a85fe12eSEd Maste nm_opts.sort_fn = &cmp_size; 563a85fe12eSEd Maste filter_insert(sym_elem_def); 564a85fe12eSEd Maste filter_insert(sym_elem_nonzero_size); 565a85fe12eSEd Maste } 566a85fe12eSEd Maste if (nm_opts.def_only != 0) 567a85fe12eSEd Maste filter_insert(sym_elem_def); 568a85fe12eSEd Maste if (nm_opts.no_demangle != 0) 569a85fe12eSEd Maste nm_opts.demangle_type = -1; 570a85fe12eSEd Maste break; 571a85fe12eSEd Maste default : 572a85fe12eSEd Maste usage(1); 573a85fe12eSEd Maste } 574a85fe12eSEd Maste } 575a85fe12eSEd Maste 576a85fe12eSEd Maste /* 577a85fe12eSEd Maste * In POSIX mode, the '-o' option controls the output radix. 578a85fe12eSEd Maste * In non-POSIX mode, the option is a synonym for the '-A' and 579a85fe12eSEd Maste * '--print-file-name' options. 580a85fe12eSEd Maste */ 581a85fe12eSEd Maste if (oflag) { 582a85fe12eSEd Maste if (is_posix) 583a85fe12eSEd Maste nm_opts.t = RADIX_OCT; 584a85fe12eSEd Maste else 585a85fe12eSEd Maste nm_opts.print_name = PRINT_NAME_FULL; 586a85fe12eSEd Maste } 587a85fe12eSEd Maste 588a85fe12eSEd Maste assert(nm_opts.sort_fn != NULL && "nm_opts.sort_fn is null"); 589a85fe12eSEd Maste assert(nm_opts.elem_print_fn != NULL && 590a85fe12eSEd Maste "nm_opts.elem_print_fn is null"); 591a85fe12eSEd Maste assert(nm_opts.value_print_fn != NULL && 592a85fe12eSEd Maste "nm_opts.value_print_fn is null"); 593a85fe12eSEd Maste 594a85fe12eSEd Maste set_opt_value_print_fn(nm_opts.t); 595a85fe12eSEd Maste 596a85fe12eSEd Maste if (nm_opts.undef_only == true) { 597a85fe12eSEd Maste if (nm_opts.sort_fn == &cmp_size) 598a85fe12eSEd Maste errx(EXIT_FAILURE, 599a85fe12eSEd Maste "--size-sort with -u is meaningless"); 600a85fe12eSEd Maste if (nm_opts.def_only != 0) 601a85fe12eSEd Maste errx(EXIT_FAILURE, 602a85fe12eSEd Maste "-u with --defined-only is meaningless"); 603a85fe12eSEd Maste } 604a85fe12eSEd Maste if (nm_opts.print_debug == false) 605a85fe12eSEd Maste filter_insert(sym_elem_nondebug); 606a85fe12eSEd Maste if (nm_opts.sort_reverse == true && nm_opts.sort_fn == cmp_none) 607a85fe12eSEd Maste nm_opts.sort_reverse = false; 608a85fe12eSEd Maste } 609a85fe12eSEd Maste 610a85fe12eSEd Maste /* 611a85fe12eSEd Maste * Get symbol information from elf. 612a85fe12eSEd Maste */ 613a85fe12eSEd Maste static int 614a85fe12eSEd Maste get_sym(Elf *elf, struct sym_head *headp, int shnum, size_t dynndx, 615a85fe12eSEd Maste size_t strndx, const char *type_table, const char **sec_table, 616a85fe12eSEd Maste int sec_table_size) 617a85fe12eSEd Maste { 618a85fe12eSEd Maste Elf_Scn *scn; 619a85fe12eSEd Maste Elf_Data *data; 620a85fe12eSEd Maste GElf_Shdr shdr; 621a85fe12eSEd Maste GElf_Sym sym; 622a85fe12eSEd Maste struct filter_entry *fep; 623a85fe12eSEd Maste size_t ndx; 624a85fe12eSEd Maste int rtn; 625a85fe12eSEd Maste const char *sym_name; 626a85fe12eSEd Maste char type; 627a85fe12eSEd Maste bool filter; 628a85fe12eSEd Maste int i, j; 629a85fe12eSEd Maste 630a85fe12eSEd Maste assert(elf != NULL); 631a85fe12eSEd Maste assert(headp != NULL); 632a85fe12eSEd Maste 633a85fe12eSEd Maste rtn = 0; 634a85fe12eSEd Maste for (i = 1; i < shnum; i++) { 635a85fe12eSEd Maste if ((scn = elf_getscn(elf, i)) == NULL) { 636a85fe12eSEd Maste warnx("elf_getscn failed: %s", elf_errmsg(-1)); 637a85fe12eSEd Maste continue; 638a85fe12eSEd Maste } 639a85fe12eSEd Maste if (gelf_getshdr(scn, &shdr) != &shdr) { 640a85fe12eSEd Maste warnx("gelf_getshdr failed: %s", elf_errmsg(-1)); 641a85fe12eSEd Maste continue; 642a85fe12eSEd Maste } 643a85fe12eSEd Maste if (shdr.sh_type == SHT_SYMTAB) { 644a85fe12eSEd Maste if (nm_opts.print_symbol != PRINT_SYM_SYM) 645a85fe12eSEd Maste continue; 646a85fe12eSEd Maste } else if (shdr.sh_type == SHT_DYNSYM) { 647a85fe12eSEd Maste if (nm_opts.print_symbol != PRINT_SYM_DYN) 648a85fe12eSEd Maste continue; 649a85fe12eSEd Maste } else 650a85fe12eSEd Maste continue; 651a85fe12eSEd Maste 652a85fe12eSEd Maste ndx = shdr.sh_type == SHT_DYNSYM ? dynndx : strndx; 653a85fe12eSEd Maste 654a85fe12eSEd Maste data = NULL; 655a85fe12eSEd Maste while ((data = elf_getdata(scn, data)) != NULL) { 656a85fe12eSEd Maste j = 1; 657a85fe12eSEd Maste while (gelf_getsym(data, j++, &sym) != NULL) { 658a85fe12eSEd Maste sym_name = get_sym_name(elf, &sym, ndx, 659a85fe12eSEd Maste sec_table, sec_table_size); 660a85fe12eSEd Maste filter = false; 661a85fe12eSEd Maste type = get_sym_type(&sym, type_table); 662a85fe12eSEd Maste SLIST_FOREACH(fep, &nm_out_filter, 663a85fe12eSEd Maste filter_entries) { 664a85fe12eSEd Maste if (!fep->fn(type, &sym, sym_name)) { 665a85fe12eSEd Maste filter = true; 666a85fe12eSEd Maste break; 667a85fe12eSEd Maste } 668a85fe12eSEd Maste } 669a85fe12eSEd Maste if (filter == false) { 670a85fe12eSEd Maste if (sym_list_insert(headp, sym_name, 671a85fe12eSEd Maste &sym) == 0) 672a85fe12eSEd Maste return (0); 673a85fe12eSEd Maste rtn++; 674a85fe12eSEd Maste } 675a85fe12eSEd Maste } 676a85fe12eSEd Maste } 677a85fe12eSEd Maste } 678a85fe12eSEd Maste 679a85fe12eSEd Maste return (rtn); 680a85fe12eSEd Maste } 681a85fe12eSEd Maste 682a85fe12eSEd Maste static const char * 683a85fe12eSEd Maste get_sym_name(Elf *elf, const GElf_Sym *sym, size_t ndx, const char **sec_table, 684a85fe12eSEd Maste int sec_table_size) 685a85fe12eSEd Maste { 686a85fe12eSEd Maste const char *sym_name; 687a85fe12eSEd Maste 688a85fe12eSEd Maste sym_name = NULL; 689a85fe12eSEd Maste 690a85fe12eSEd Maste /* Show section name as symbol name for STT_SECTION symbols. */ 691a85fe12eSEd Maste if (GELF_ST_TYPE(sym->st_info) == STT_SECTION) { 692a85fe12eSEd Maste if (sec_table != NULL && sym->st_shndx < sec_table_size) 693a85fe12eSEd Maste sym_name = sec_table[sym->st_shndx]; 694a85fe12eSEd Maste } else 695a85fe12eSEd Maste sym_name = elf_strptr(elf, ndx, sym->st_name); 696a85fe12eSEd Maste 697a85fe12eSEd Maste if (sym_name == NULL) 698a85fe12eSEd Maste sym_name = "(null)"; 699a85fe12eSEd Maste 700a85fe12eSEd Maste return (sym_name); 701a85fe12eSEd Maste } 702a85fe12eSEd Maste 703a85fe12eSEd Maste static char 704a85fe12eSEd Maste get_sym_type(const GElf_Sym *sym, const char *type_table) 705a85fe12eSEd Maste { 706a85fe12eSEd Maste bool is_local; 707a85fe12eSEd Maste 708a85fe12eSEd Maste if (sym == NULL || type_table == NULL) 709a85fe12eSEd Maste return ('?'); 710a85fe12eSEd Maste 711a85fe12eSEd Maste is_local = sym->st_info >> 4 == STB_LOCAL; 712a85fe12eSEd Maste 713a85fe12eSEd Maste if (sym->st_shndx == SHN_ABS) /* absolute */ 714a85fe12eSEd Maste return (is_local ? 'a' : 'A'); 715a85fe12eSEd Maste 716a85fe12eSEd Maste if (sym->st_shndx == SHN_COMMON) /* common */ 717a85fe12eSEd Maste return ('C'); 718a85fe12eSEd Maste 719a85fe12eSEd Maste if ((sym->st_info) >> 4 == STB_WEAK) { /* weak */ 720a85fe12eSEd Maste if ((sym->st_info & 0xf) == STT_OBJECT) 721a85fe12eSEd Maste return (sym->st_shndx == SHN_UNDEF ? 'v' : 'V'); 722a85fe12eSEd Maste 723a85fe12eSEd Maste return (sym->st_shndx == SHN_UNDEF ? 'w' : 'W'); 724a85fe12eSEd Maste } 725a85fe12eSEd Maste 726a85fe12eSEd Maste if (sym->st_shndx == SHN_UNDEF) /* undefined */ 727a85fe12eSEd Maste return ('U'); 728a85fe12eSEd Maste 729a85fe12eSEd Maste return (is_local == true && type_table[sym->st_shndx] != 'N' ? 730a85fe12eSEd Maste tolower((unsigned char) type_table[sym->st_shndx]) : 731a85fe12eSEd Maste type_table[sym->st_shndx]); 732a85fe12eSEd Maste } 733a85fe12eSEd Maste 734a85fe12eSEd Maste static void 735a85fe12eSEd Maste global_dest(void) 736a85fe12eSEd Maste { 737a85fe12eSEd Maste 738a85fe12eSEd Maste filter_dest(); 739a85fe12eSEd Maste } 740a85fe12eSEd Maste 741a85fe12eSEd Maste static void 742a85fe12eSEd Maste global_init(void) 743a85fe12eSEd Maste { 744a85fe12eSEd Maste 745a85fe12eSEd Maste if (elf_version(EV_CURRENT) == EV_NONE) 746a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_version error"); 747a85fe12eSEd Maste 748a85fe12eSEd Maste nm_info.name = ELFTC_GETPROGNAME(); 749a85fe12eSEd Maste nm_info.def_filename = "a.out"; 750a85fe12eSEd Maste nm_opts.print_symbol = PRINT_SYM_SYM; 751a85fe12eSEd Maste nm_opts.print_name = PRINT_NAME_NONE; 752a85fe12eSEd Maste nm_opts.demangle_type = -1; 753a85fe12eSEd Maste nm_opts.print_debug = false; 754a85fe12eSEd Maste nm_opts.print_armap = false; 755a85fe12eSEd Maste nm_opts.print_size = 0; 756a85fe12eSEd Maste nm_opts.debug_line = false; 757a85fe12eSEd Maste nm_opts.def_only = 0; 758a85fe12eSEd Maste nm_opts.undef_only = false; 759a85fe12eSEd Maste nm_opts.sort_size = 0; 760a85fe12eSEd Maste nm_opts.sort_reverse = false; 761a85fe12eSEd Maste nm_opts.no_demangle = 0; 762a85fe12eSEd Maste nm_opts.sort_fn = &cmp_name; 763a85fe12eSEd Maste nm_opts.elem_print_fn = &sym_elem_print_all; 764a85fe12eSEd Maste nm_opts.value_print_fn = &sym_value_dec_print; 765a85fe12eSEd Maste nm_opts.size_print_fn = &sym_size_dec_print; 766a85fe12eSEd Maste SLIST_INIT(&nm_out_filter); 767a85fe12eSEd Maste } 768a85fe12eSEd Maste 769a85fe12eSEd Maste static bool 770a85fe12eSEd Maste is_sec_data(GElf_Shdr *s) 771a85fe12eSEd Maste { 772a85fe12eSEd Maste 773a85fe12eSEd Maste assert(s != NULL && "shdr is NULL"); 774a85fe12eSEd Maste 775a85fe12eSEd Maste return (((s->sh_flags & SHF_ALLOC) != 0) && s->sh_type != SHT_NOBITS); 776a85fe12eSEd Maste } 777a85fe12eSEd Maste 778a85fe12eSEd Maste static bool 779a85fe12eSEd Maste is_sec_debug(const char *shname) 780a85fe12eSEd Maste { 781a85fe12eSEd Maste const char *dbg_sec[] = { 782a85fe12eSEd Maste ".debug", 783a85fe12eSEd Maste ".gnu.linkonce.wi.", 784a85fe12eSEd Maste ".line", 785a85fe12eSEd Maste ".rel.debug", 786a85fe12eSEd Maste ".rela.debug", 787a85fe12eSEd Maste ".stab", 788a85fe12eSEd Maste NULL 789a85fe12eSEd Maste }; 790a85fe12eSEd Maste const char **p; 791a85fe12eSEd Maste 792a85fe12eSEd Maste assert(shname != NULL && "shname is NULL"); 793a85fe12eSEd Maste 794a85fe12eSEd Maste for (p = dbg_sec; *p; p++) { 795a85fe12eSEd Maste if (!strncmp(shname, *p, strlen(*p))) 796a85fe12eSEd Maste return (true); 797a85fe12eSEd Maste } 798a85fe12eSEd Maste 799a85fe12eSEd Maste return (false); 800a85fe12eSEd Maste } 801a85fe12eSEd Maste 802a85fe12eSEd Maste static bool 803a85fe12eSEd Maste is_sec_nobits(GElf_Shdr *s) 804a85fe12eSEd Maste { 805a85fe12eSEd Maste 806a85fe12eSEd Maste assert(s != NULL && "shdr is NULL"); 807a85fe12eSEd Maste 808a85fe12eSEd Maste return (s->sh_type == SHT_NOBITS); 809a85fe12eSEd Maste } 810a85fe12eSEd Maste 811a85fe12eSEd Maste static bool 812a85fe12eSEd Maste is_sec_readonly(GElf_Shdr *s) 813a85fe12eSEd Maste { 814a85fe12eSEd Maste 815a85fe12eSEd Maste assert(s != NULL && "shdr is NULL"); 816a85fe12eSEd Maste 817a85fe12eSEd Maste return ((s->sh_flags & SHF_WRITE) == 0); 818a85fe12eSEd Maste } 819a85fe12eSEd Maste 820a85fe12eSEd Maste static bool 821a85fe12eSEd Maste is_sec_text(GElf_Shdr *s) 822a85fe12eSEd Maste { 823a85fe12eSEd Maste 824a85fe12eSEd Maste assert(s != NULL && "shdr is NULL"); 825a85fe12eSEd Maste 826a85fe12eSEd Maste return ((s->sh_flags & SHF_EXECINSTR) != 0); 827a85fe12eSEd Maste } 828a85fe12eSEd Maste 829a85fe12eSEd Maste static void 830a85fe12eSEd Maste print_ar_index(int fd, Elf *arf) 831a85fe12eSEd Maste { 832a85fe12eSEd Maste Elf *elf; 833a85fe12eSEd Maste Elf_Arhdr *arhdr; 834a85fe12eSEd Maste Elf_Arsym *arsym; 835a85fe12eSEd Maste Elf_Cmd cmd; 836a85fe12eSEd Maste off_t start; 837a85fe12eSEd Maste size_t arsym_size; 838a85fe12eSEd Maste 839a85fe12eSEd Maste if (arf == NULL) 840a85fe12eSEd Maste return; 841a85fe12eSEd Maste 842a85fe12eSEd Maste if ((arsym = elf_getarsym(arf, &arsym_size)) == NULL) 843a85fe12eSEd Maste return; 844a85fe12eSEd Maste 845a85fe12eSEd Maste printf("\nArchive index:\n"); 846a85fe12eSEd Maste 847a85fe12eSEd Maste start = arsym->as_off; 848a85fe12eSEd Maste cmd = ELF_C_READ; 849a85fe12eSEd Maste while (arsym_size > 1) { 850a85fe12eSEd Maste if (elf_rand(arf, arsym->as_off) == arsym->as_off && 851a85fe12eSEd Maste (elf = elf_begin(fd, cmd, arf)) != NULL) { 852a85fe12eSEd Maste if ((arhdr = elf_getarhdr(elf)) != NULL) 853a85fe12eSEd Maste printf("%s in %s\n", arsym->as_name, 854a85fe12eSEd Maste arhdr->ar_name != NULL ? 855a85fe12eSEd Maste arhdr->ar_name : arhdr->ar_rawname); 856a85fe12eSEd Maste elf_end(elf); 857a85fe12eSEd Maste } 858a85fe12eSEd Maste ++arsym; 859a85fe12eSEd Maste --arsym_size; 860a85fe12eSEd Maste } 861a85fe12eSEd Maste 862a85fe12eSEd Maste elf_rand(arf, start); 863a85fe12eSEd Maste } 864a85fe12eSEd Maste 865a85fe12eSEd Maste #define DEMANGLED_BUFFER_SIZE (8 * 1024) 866a85fe12eSEd Maste #define PRINT_DEMANGLED_NAME(FORMAT, NAME) do { \ 867a85fe12eSEd Maste char _demangled[DEMANGLED_BUFFER_SIZE]; \ 868a85fe12eSEd Maste if (nm_opts.demangle_type < 0 || \ 869a85fe12eSEd Maste elftc_demangle((NAME), _demangled, sizeof(_demangled), \ 870a85fe12eSEd Maste nm_opts.demangle_type) < 0) \ 871a85fe12eSEd Maste printf((FORMAT), (NAME)); \ 872a85fe12eSEd Maste else \ 873a85fe12eSEd Maste printf((FORMAT), _demangled); \ 874a85fe12eSEd Maste } while (0) 875a85fe12eSEd Maste 876a85fe12eSEd Maste static void 877a85fe12eSEd Maste print_header(const char *file, const char *obj) 878a85fe12eSEd Maste { 879a85fe12eSEd Maste 880a85fe12eSEd Maste if (file == NULL) 881a85fe12eSEd Maste return; 882a85fe12eSEd Maste 883a85fe12eSEd Maste if (nm_opts.elem_print_fn == &sym_elem_print_all_sysv) { 884a85fe12eSEd Maste printf("\n\n%s from %s", 885a85fe12eSEd Maste nm_opts.undef_only == false ? "Symbols" : 886a85fe12eSEd Maste "Undefined symbols", file); 887a85fe12eSEd Maste if (obj != NULL) 888a85fe12eSEd Maste printf("[%s]", obj); 889a85fe12eSEd Maste printf(":\n\n"); 890a85fe12eSEd Maste 891a85fe12eSEd Maste printf("\ 892a85fe12eSEd Maste Name Value Class Type Size Line Section\n\n"); 893a85fe12eSEd Maste } else { 894a85fe12eSEd Maste /* archive file without -A option and POSIX */ 895a85fe12eSEd Maste if (nm_opts.print_name != PRINT_NAME_FULL && obj != NULL) { 896a85fe12eSEd Maste if (nm_opts.elem_print_fn == 897a85fe12eSEd Maste sym_elem_print_all_portable) 898a85fe12eSEd Maste printf("%s[%s]:\n", file, obj); 899a85fe12eSEd Maste else if (nm_opts.elem_print_fn == sym_elem_print_all) 900a85fe12eSEd Maste printf("\n%s:\n", obj); 901a85fe12eSEd Maste /* multiple files(not archive) without -A option */ 902a85fe12eSEd Maste } else if (nm_opts.print_name == PRINT_NAME_MULTI) { 903a85fe12eSEd Maste if (nm_opts.elem_print_fn == sym_elem_print_all) 904a85fe12eSEd Maste printf("\n"); 905a85fe12eSEd Maste printf("%s:\n", file); 906a85fe12eSEd Maste } 907a85fe12eSEd Maste } 908a85fe12eSEd Maste } 909a85fe12eSEd Maste 910a85fe12eSEd Maste static void 911a85fe12eSEd Maste print_version(void) 912a85fe12eSEd Maste { 913a85fe12eSEd Maste 914a85fe12eSEd Maste (void) printf("%s (%s)\n", nm_info.name, elftc_version()); 915a85fe12eSEd Maste exit(0); 916a85fe12eSEd Maste } 917a85fe12eSEd Maste 918a85fe12eSEd Maste static uint64_t 919a85fe12eSEd Maste get_block_value(Dwarf_Debug dbg, Dwarf_Block *block) 920a85fe12eSEd Maste { 921a85fe12eSEd Maste Elf *elf; 922a85fe12eSEd Maste GElf_Ehdr eh; 923a85fe12eSEd Maste Dwarf_Error de; 924a85fe12eSEd Maste 925a85fe12eSEd Maste if (dwarf_get_elf(dbg, &elf, &de) != DW_DLV_OK) { 926a85fe12eSEd Maste warnx("dwarf_get_elf failed: %s", dwarf_errmsg(de)); 927a85fe12eSEd Maste return (0); 928a85fe12eSEd Maste } 929a85fe12eSEd Maste 930a85fe12eSEd Maste if (gelf_getehdr(elf, &eh) != &eh) { 931a85fe12eSEd Maste warnx("gelf_getehdr failed: %s", elf_errmsg(-1)); 932a85fe12eSEd Maste return (0); 933a85fe12eSEd Maste } 934a85fe12eSEd Maste 935a85fe12eSEd Maste if (block->bl_len == 5) { 936a85fe12eSEd Maste if (eh.e_ident[EI_DATA] == ELFDATA2LSB) 937a85fe12eSEd Maste return (le32dec((uint8_t *) block->bl_data + 1)); 938a85fe12eSEd Maste else 939a85fe12eSEd Maste return (be32dec((uint8_t *) block->bl_data + 1)); 940a85fe12eSEd Maste } else if (block->bl_len == 9) { 941a85fe12eSEd Maste if (eh.e_ident[EI_DATA] == ELFDATA2LSB) 942a85fe12eSEd Maste return (le64dec((uint8_t *) block->bl_data + 1)); 943a85fe12eSEd Maste else 944a85fe12eSEd Maste return (be64dec((uint8_t *) block->bl_data + 1)); 945a85fe12eSEd Maste } 946a85fe12eSEd Maste 947a85fe12eSEd Maste return (0); 948a85fe12eSEd Maste } 949a85fe12eSEd Maste 950a85fe12eSEd Maste static void 951a85fe12eSEd Maste search_line_attr(Dwarf_Debug dbg, struct func_info_head *func_info, 952a85fe12eSEd Maste struct var_info_head *var_info, Dwarf_Die die, char **src_files, 953a85fe12eSEd Maste Dwarf_Signed filecount) 954a85fe12eSEd Maste { 955a85fe12eSEd Maste Dwarf_Attribute at; 956a85fe12eSEd Maste Dwarf_Unsigned udata; 957a85fe12eSEd Maste Dwarf_Half tag; 958a85fe12eSEd Maste Dwarf_Block *block; 959a85fe12eSEd Maste Dwarf_Bool flag; 960a85fe12eSEd Maste Dwarf_Die ret_die; 961a85fe12eSEd Maste Dwarf_Error de; 962a85fe12eSEd Maste struct func_info_entry *func; 963a85fe12eSEd Maste struct var_info_entry *var; 964a85fe12eSEd Maste const char *str; 965a85fe12eSEd Maste int ret; 966a85fe12eSEd Maste 967a85fe12eSEd Maste if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) { 968a85fe12eSEd Maste warnx("dwarf_tag failed: %s", dwarf_errmsg(de)); 969a85fe12eSEd Maste goto cont_search; 970a85fe12eSEd Maste } 971a85fe12eSEd Maste 972a85fe12eSEd Maste /* We're interested in DIEs which define functions or variables. */ 973a85fe12eSEd Maste if (tag != DW_TAG_subprogram && tag != DW_TAG_entry_point && 974a85fe12eSEd Maste tag != DW_TAG_inlined_subroutine && tag != DW_TAG_variable) 975a85fe12eSEd Maste goto cont_search; 976a85fe12eSEd Maste 977a85fe12eSEd Maste if (tag == DW_TAG_variable) { 978a85fe12eSEd Maste 979a85fe12eSEd Maste /* Ignore "artificial" variable. */ 980a85fe12eSEd Maste if (dwarf_attrval_flag(die, DW_AT_artificial, &flag, &de) == 981a85fe12eSEd Maste DW_DLV_OK && flag) 982a85fe12eSEd Maste goto cont_search; 983a85fe12eSEd Maste 984a85fe12eSEd Maste /* Ignore pure declaration. */ 985a85fe12eSEd Maste if (dwarf_attrval_flag(die, DW_AT_declaration, &flag, &de) == 986a85fe12eSEd Maste DW_DLV_OK && flag) 987a85fe12eSEd Maste goto cont_search; 988a85fe12eSEd Maste 989a85fe12eSEd Maste /* Ignore stack varaibles. */ 990a85fe12eSEd Maste if (dwarf_attrval_flag(die, DW_AT_external, &flag, &de) != 991a85fe12eSEd Maste DW_DLV_OK || !flag) 992a85fe12eSEd Maste goto cont_search; 993a85fe12eSEd Maste 994a85fe12eSEd Maste if ((var = calloc(1, sizeof(*var))) == NULL) { 995a85fe12eSEd Maste warn("calloc failed"); 996a85fe12eSEd Maste goto cont_search; 997a85fe12eSEd Maste } 998a85fe12eSEd Maste 999a85fe12eSEd Maste if (dwarf_attrval_unsigned(die, DW_AT_decl_file, &udata, 1000a85fe12eSEd Maste &de) == DW_DLV_OK && udata > 0 && 1001a85fe12eSEd Maste (Dwarf_Signed) (udata - 1) < filecount) { 1002a85fe12eSEd Maste var->file = strdup(src_files[udata - 1]); 1003a85fe12eSEd Maste if (var->file == NULL) { 1004a85fe12eSEd Maste warn("strdup"); 1005a85fe12eSEd Maste free(var); 1006a85fe12eSEd Maste goto cont_search; 1007a85fe12eSEd Maste } 1008a85fe12eSEd Maste } 1009a85fe12eSEd Maste 1010a85fe12eSEd Maste if (dwarf_attrval_unsigned(die, DW_AT_decl_line, &udata, &de) == 1011a85fe12eSEd Maste DW_DLV_OK) 1012a85fe12eSEd Maste var->line = udata; 1013a85fe12eSEd Maste 1014a85fe12eSEd Maste if (dwarf_attrval_string(die, DW_AT_name, &str, &de) == 1015a85fe12eSEd Maste DW_DLV_OK) { 1016a85fe12eSEd Maste var->name = strdup(str); 1017a85fe12eSEd Maste if (var->name == NULL) { 1018a85fe12eSEd Maste warn("strdup"); 1019a85fe12eSEd Maste if (var->file) 1020a85fe12eSEd Maste free(var->file); 1021a85fe12eSEd Maste free(var); 1022a85fe12eSEd Maste goto cont_search; 1023a85fe12eSEd Maste } 1024a85fe12eSEd Maste } 1025a85fe12eSEd Maste 1026a85fe12eSEd Maste if (dwarf_attr(die, DW_AT_location, &at, &de) == DW_DLV_OK && 1027a85fe12eSEd Maste dwarf_formblock(at, &block, &de) == DW_DLV_OK) { 1028a85fe12eSEd Maste /* 1029a85fe12eSEd Maste * Since we ignored stack variables, the rest are the 1030a85fe12eSEd Maste * external varaibles which should always use DW_OP_addr 1031a85fe12eSEd Maste * operator for DW_AT_location value. 1032a85fe12eSEd Maste */ 1033a85fe12eSEd Maste if (*((uint8_t *)block->bl_data) == DW_OP_addr) 1034a85fe12eSEd Maste var->addr = get_block_value(dbg, block); 1035a85fe12eSEd Maste } 1036a85fe12eSEd Maste 1037a85fe12eSEd Maste SLIST_INSERT_HEAD(var_info, var, entries); 1038a85fe12eSEd Maste 1039a85fe12eSEd Maste } else { 1040a85fe12eSEd Maste 1041a85fe12eSEd Maste if ((func = calloc(1, sizeof(*func))) == NULL) { 1042a85fe12eSEd Maste warn("calloc failed"); 1043a85fe12eSEd Maste goto cont_search; 1044a85fe12eSEd Maste } 1045a85fe12eSEd Maste 1046a85fe12eSEd Maste /* 1047a85fe12eSEd Maste * Note that dwarf_attrval_unsigned() handles DW_AT_abstract_origin 1048a85fe12eSEd Maste * internally, so it can retrieve DW_AT_decl_file/DW_AT_decl_line 1049a85fe12eSEd Maste * attributes for inlined functions as well. 1050a85fe12eSEd Maste */ 1051a85fe12eSEd Maste if (dwarf_attrval_unsigned(die, DW_AT_decl_file, &udata, 1052a85fe12eSEd Maste &de) == DW_DLV_OK && udata > 0 && 1053a85fe12eSEd Maste (Dwarf_Signed) (udata - 1) < filecount) { 1054a85fe12eSEd Maste func->file = strdup(src_files[udata - 1]); 1055a85fe12eSEd Maste if (func->file == NULL) { 1056a85fe12eSEd Maste warn("strdup"); 1057a85fe12eSEd Maste free(func); 1058a85fe12eSEd Maste goto cont_search; 1059a85fe12eSEd Maste } 1060a85fe12eSEd Maste } 1061a85fe12eSEd Maste 1062a85fe12eSEd Maste if (dwarf_attrval_unsigned(die, DW_AT_decl_line, &udata, &de) == 1063a85fe12eSEd Maste DW_DLV_OK) 1064a85fe12eSEd Maste func->line = udata; 1065a85fe12eSEd Maste 1066a85fe12eSEd Maste if (dwarf_attrval_string(die, DW_AT_name, &str, &de) == 1067a85fe12eSEd Maste DW_DLV_OK) { 1068a85fe12eSEd Maste func->name = strdup(str); 1069a85fe12eSEd Maste if (func->name == NULL) { 1070a85fe12eSEd Maste warn("strdup"); 1071a85fe12eSEd Maste if (func->file) 1072a85fe12eSEd Maste free(func->file); 1073a85fe12eSEd Maste free(func); 1074a85fe12eSEd Maste goto cont_search; 1075a85fe12eSEd Maste } 1076a85fe12eSEd Maste } 1077a85fe12eSEd Maste 1078a85fe12eSEd Maste if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &udata, &de) == 1079a85fe12eSEd Maste DW_DLV_OK) 1080a85fe12eSEd Maste func->lowpc = udata; 1081a85fe12eSEd Maste if (dwarf_attrval_unsigned(die, DW_AT_high_pc, &udata, &de) == 1082a85fe12eSEd Maste DW_DLV_OK) 1083a85fe12eSEd Maste func->highpc = udata; 1084a85fe12eSEd Maste 1085a85fe12eSEd Maste SLIST_INSERT_HEAD(func_info, func, entries); 1086a85fe12eSEd Maste } 1087a85fe12eSEd Maste 1088a85fe12eSEd Maste cont_search: 1089a85fe12eSEd Maste 1090a85fe12eSEd Maste /* Search children. */ 1091a85fe12eSEd Maste ret = dwarf_child(die, &ret_die, &de); 1092a85fe12eSEd Maste if (ret == DW_DLV_ERROR) 1093a85fe12eSEd Maste warnx("dwarf_child: %s", dwarf_errmsg(de)); 1094a85fe12eSEd Maste else if (ret == DW_DLV_OK) 1095a85fe12eSEd Maste search_line_attr(dbg, func_info, var_info, ret_die, src_files, 1096a85fe12eSEd Maste filecount); 1097a85fe12eSEd Maste 1098a85fe12eSEd Maste /* Search sibling. */ 1099a85fe12eSEd Maste ret = dwarf_siblingof(dbg, die, &ret_die, &de); 1100a85fe12eSEd Maste if (ret == DW_DLV_ERROR) 1101a85fe12eSEd Maste warnx("dwarf_siblingof: %s", dwarf_errmsg(de)); 1102a85fe12eSEd Maste else if (ret == DW_DLV_OK) 1103a85fe12eSEd Maste search_line_attr(dbg, func_info, var_info, ret_die, src_files, 1104a85fe12eSEd Maste filecount); 1105a85fe12eSEd Maste 1106a85fe12eSEd Maste dwarf_dealloc(dbg, die, DW_DLA_DIE); 1107a85fe12eSEd Maste } 1108a85fe12eSEd Maste 1109a85fe12eSEd Maste /* 1110a85fe12eSEd Maste * Read elf file and collect symbol information, sort them, print. 1111a85fe12eSEd Maste * Return 1 at failed, 0 at success. 1112a85fe12eSEd Maste */ 1113a85fe12eSEd Maste static int 1114a85fe12eSEd Maste read_elf(Elf *elf, const char *filename, Elf_Kind kind) 1115a85fe12eSEd Maste { 1116a85fe12eSEd Maste Dwarf_Debug dbg; 1117a85fe12eSEd Maste Dwarf_Die die; 1118a85fe12eSEd Maste Dwarf_Error de; 1119a85fe12eSEd Maste Dwarf_Half tag; 1120a85fe12eSEd Maste Elf_Arhdr *arhdr; 1121a85fe12eSEd Maste Elf_Scn *scn; 1122a85fe12eSEd Maste GElf_Shdr shdr; 1123a85fe12eSEd Maste GElf_Half i; 1124a85fe12eSEd Maste Dwarf_Line *lbuf; 1125a85fe12eSEd Maste Dwarf_Unsigned lineno; 1126a85fe12eSEd Maste Dwarf_Signed lcount, filecount; 1127a85fe12eSEd Maste Dwarf_Addr lineaddr; 1128a85fe12eSEd Maste struct sym_print_data p_data; 1129a85fe12eSEd Maste struct sym_head list_head; 1130a85fe12eSEd Maste struct line_info_head *line_info; 1131a85fe12eSEd Maste struct func_info_head *func_info; 1132a85fe12eSEd Maste struct var_info_head *var_info; 1133a85fe12eSEd Maste struct line_info_entry *lie; 1134a85fe12eSEd Maste struct func_info_entry *func; 1135a85fe12eSEd Maste struct var_info_entry *var; 1136a85fe12eSEd Maste const char *shname, *objname; 1137a85fe12eSEd Maste char *type_table, **sec_table, *sfile, **src_files; 1138a85fe12eSEd Maste size_t shstrndx, shnum, dynndx, strndx; 1139a85fe12eSEd Maste int ret, rtn, e_err; 1140a85fe12eSEd Maste 1141a85fe12eSEd Maste #define OBJNAME (objname == NULL ? filename : objname) 1142a85fe12eSEd Maste 1143a85fe12eSEd Maste assert(filename != NULL && "filename is null"); 1144a85fe12eSEd Maste 1145a85fe12eSEd Maste STAILQ_INIT(&list_head); 1146a85fe12eSEd Maste type_table = NULL; 1147a85fe12eSEd Maste sec_table = NULL; 1148a85fe12eSEd Maste line_info = NULL; 1149a85fe12eSEd Maste func_info = NULL; 1150a85fe12eSEd Maste var_info = NULL; 1151a85fe12eSEd Maste objname = NULL; 1152a85fe12eSEd Maste dynndx = SHN_UNDEF; 1153a85fe12eSEd Maste strndx = SHN_UNDEF; 1154a85fe12eSEd Maste rtn = 0; 1155a85fe12eSEd Maste 1156a85fe12eSEd Maste nm_elfclass = gelf_getclass(elf); 1157a85fe12eSEd Maste 1158a85fe12eSEd Maste if (kind == ELF_K_AR) { 1159a85fe12eSEd Maste if ((arhdr = elf_getarhdr(elf)) == NULL) 1160a85fe12eSEd Maste goto next_cmd; 1161a85fe12eSEd Maste objname = arhdr->ar_name != NULL ? arhdr->ar_name : 1162a85fe12eSEd Maste arhdr->ar_rawname; 1163a85fe12eSEd Maste } 1164a85fe12eSEd Maste if (!elf_getshnum(elf, &shnum)) { 1165a85fe12eSEd Maste if ((e_err = elf_errno()) != 0) 1166a85fe12eSEd Maste warnx("%s: %s", OBJNAME, elf_errmsg(e_err)); 1167a85fe12eSEd Maste else 1168a85fe12eSEd Maste warnx("%s: cannot get section number", OBJNAME); 1169a85fe12eSEd Maste rtn = 1; 1170a85fe12eSEd Maste goto next_cmd; 1171a85fe12eSEd Maste } 1172a85fe12eSEd Maste if (shnum == 0) { 1173a85fe12eSEd Maste warnx("%s: has no section", OBJNAME); 1174a85fe12eSEd Maste rtn = 1; 1175a85fe12eSEd Maste goto next_cmd; 1176a85fe12eSEd Maste } 1177a85fe12eSEd Maste if (!elf_getshstrndx(elf, &shstrndx)) { 1178a85fe12eSEd Maste warnx("%s: cannot get str index", OBJNAME); 1179a85fe12eSEd Maste rtn = 1; 1180a85fe12eSEd Maste goto next_cmd; 1181a85fe12eSEd Maste } 1182a85fe12eSEd Maste /* type_table for type determine */ 1183a85fe12eSEd Maste if ((type_table = malloc(sizeof(char) * shnum)) == NULL) { 1184a85fe12eSEd Maste warn("%s: malloc", OBJNAME); 1185a85fe12eSEd Maste rtn = 1; 1186a85fe12eSEd Maste goto next_cmd; 1187a85fe12eSEd Maste } 1188a85fe12eSEd Maste /* sec_table for section name to display in sysv format */ 1189a85fe12eSEd Maste if ((sec_table = calloc(shnum, sizeof(char *))) == NULL) { 1190a85fe12eSEd Maste warn("%s: calloc", OBJNAME); 1191a85fe12eSEd Maste rtn = 1; 1192a85fe12eSEd Maste goto next_cmd; 1193a85fe12eSEd Maste } 1194a85fe12eSEd Maste 1195a85fe12eSEd Maste type_table[0] = 'U'; 1196a85fe12eSEd Maste if ((sec_table[0] = strdup("*UND*")) == NULL) { 1197a85fe12eSEd Maste warn("strdup"); 1198a85fe12eSEd Maste goto next_cmd; 1199a85fe12eSEd Maste } 1200a85fe12eSEd Maste 1201a85fe12eSEd Maste for (i = 1; i < shnum; ++i) { 1202a85fe12eSEd Maste type_table[i] = 'U'; 1203a85fe12eSEd Maste if ((scn = elf_getscn(elf, i)) == NULL) { 1204a85fe12eSEd Maste if ((e_err = elf_errno()) != 0) 1205a85fe12eSEd Maste warnx("%s: %s", OBJNAME, elf_errmsg(e_err)); 1206a85fe12eSEd Maste else 1207a85fe12eSEd Maste warnx("%s: cannot get section", OBJNAME); 1208a85fe12eSEd Maste rtn = 1; 1209a85fe12eSEd Maste goto next_cmd; 1210a85fe12eSEd Maste } 1211a85fe12eSEd Maste if (gelf_getshdr(scn, &shdr) == NULL) 1212a85fe12eSEd Maste goto next_cmd; 1213a85fe12eSEd Maste 1214a85fe12eSEd Maste /* 1215a85fe12eSEd Maste * Cannot test by type and attribute for dynstr, strtab 1216a85fe12eSEd Maste */ 1217a85fe12eSEd Maste shname = elf_strptr(elf, shstrndx, (size_t) shdr.sh_name); 1218a85fe12eSEd Maste if (shname != NULL) { 1219a85fe12eSEd Maste if ((sec_table[i] = strdup(shname)) == NULL) { 1220a85fe12eSEd Maste warn("strdup"); 1221a85fe12eSEd Maste goto next_cmd; 1222a85fe12eSEd Maste } 1223a85fe12eSEd Maste if (!strncmp(shname, ".dynstr", 7)) { 1224a85fe12eSEd Maste dynndx = elf_ndxscn(scn); 1225a85fe12eSEd Maste if (dynndx == SHN_UNDEF) { 1226a85fe12eSEd Maste warnx("%s: elf_ndxscn failed: %s", 1227a85fe12eSEd Maste OBJNAME, elf_errmsg(-1)); 1228a85fe12eSEd Maste goto next_cmd; 1229a85fe12eSEd Maste } 1230a85fe12eSEd Maste } 1231a85fe12eSEd Maste if (!strncmp(shname, ".strtab", 7)) { 1232a85fe12eSEd Maste strndx = elf_ndxscn(scn); 1233a85fe12eSEd Maste if (strndx == SHN_UNDEF) { 1234a85fe12eSEd Maste warnx("%s: elf_ndxscn failed: %s", 1235a85fe12eSEd Maste OBJNAME, elf_errmsg(-1)); 1236a85fe12eSEd Maste goto next_cmd; 1237a85fe12eSEd Maste } 1238a85fe12eSEd Maste } 1239a85fe12eSEd Maste } else { 1240a85fe12eSEd Maste sec_table[i] = strdup("*UND*"); 1241a85fe12eSEd Maste if (sec_table[i] == NULL) { 1242a85fe12eSEd Maste warn("strdup"); 1243a85fe12eSEd Maste goto next_cmd; 1244a85fe12eSEd Maste } 1245a85fe12eSEd Maste } 1246a85fe12eSEd Maste 1247a85fe12eSEd Maste 1248a85fe12eSEd Maste if (is_sec_text(&shdr)) 1249a85fe12eSEd Maste type_table[i] = 'T'; 1250a85fe12eSEd Maste else if (is_sec_data(&shdr)) { 1251a85fe12eSEd Maste if (is_sec_readonly(&shdr)) 1252a85fe12eSEd Maste type_table[i] = 'R'; 1253a85fe12eSEd Maste else 1254a85fe12eSEd Maste type_table[i] = 'D'; 1255a85fe12eSEd Maste } else if (is_sec_nobits(&shdr)) 1256a85fe12eSEd Maste type_table[i] = 'B'; 1257a85fe12eSEd Maste else if (is_sec_debug(shname)) 1258a85fe12eSEd Maste type_table[i] = 'N'; 1259a85fe12eSEd Maste else if (is_sec_readonly(&shdr) && !is_sec_nobits(&shdr)) 1260a85fe12eSEd Maste type_table[i] = 'n'; 1261a85fe12eSEd Maste } 1262a85fe12eSEd Maste 1263a85fe12eSEd Maste print_header(filename, objname); 1264a85fe12eSEd Maste 1265a85fe12eSEd Maste if ((dynndx == SHN_UNDEF && nm_opts.print_symbol == PRINT_SYM_DYN) || 1266a85fe12eSEd Maste (strndx == SHN_UNDEF && nm_opts.print_symbol == PRINT_SYM_SYM)) { 1267a85fe12eSEd Maste warnx("%s: no symbols", OBJNAME); 1268a85fe12eSEd Maste /* This is not an error case */ 1269a85fe12eSEd Maste goto next_cmd; 1270a85fe12eSEd Maste } 1271a85fe12eSEd Maste 1272a85fe12eSEd Maste STAILQ_INIT(&list_head); 1273a85fe12eSEd Maste 1274a85fe12eSEd Maste if (!nm_opts.debug_line) 1275a85fe12eSEd Maste goto process_sym; 1276a85fe12eSEd Maste 1277a85fe12eSEd Maste /* 1278a85fe12eSEd Maste * Collect dwarf line number information. 1279a85fe12eSEd Maste */ 1280a85fe12eSEd Maste 1281a85fe12eSEd Maste if (dwarf_elf_init(elf, DW_DLC_READ, NULL, NULL, &dbg, &de) != 1282a85fe12eSEd Maste DW_DLV_OK) { 1283a85fe12eSEd Maste warnx("dwarf_elf_init failed: %s", dwarf_errmsg(de)); 1284a85fe12eSEd Maste goto process_sym; 1285a85fe12eSEd Maste } 1286a85fe12eSEd Maste 1287a85fe12eSEd Maste line_info = malloc(sizeof(struct line_info_head)); 1288a85fe12eSEd Maste func_info = malloc(sizeof(struct func_info_head)); 1289a85fe12eSEd Maste var_info = malloc(sizeof(struct var_info_head)); 1290a85fe12eSEd Maste if (line_info == NULL || func_info == NULL || var_info == NULL) { 1291a85fe12eSEd Maste warn("malloc"); 1292a85fe12eSEd Maste (void) dwarf_finish(dbg, &de); 1293a85fe12eSEd Maste goto process_sym; 1294a85fe12eSEd Maste } 1295a85fe12eSEd Maste SLIST_INIT(line_info); 1296a85fe12eSEd Maste SLIST_INIT(func_info); 1297a85fe12eSEd Maste SLIST_INIT(var_info); 1298a85fe12eSEd Maste 1299a85fe12eSEd Maste while ((ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL, 1300a85fe12eSEd Maste &de)) == DW_DLV_OK) { 1301a85fe12eSEd Maste die = NULL; 1302a85fe12eSEd Maste while (dwarf_siblingof(dbg, die, &die, &de) == DW_DLV_OK) { 1303a85fe12eSEd Maste if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) { 1304a85fe12eSEd Maste warnx("dwarf_tag failed: %s", 1305a85fe12eSEd Maste dwarf_errmsg(de)); 1306a85fe12eSEd Maste continue; 1307a85fe12eSEd Maste } 1308a85fe12eSEd Maste /* XXX: What about DW_TAG_partial_unit? */ 1309a85fe12eSEd Maste if (tag == DW_TAG_compile_unit) 1310a85fe12eSEd Maste break; 1311a85fe12eSEd Maste } 1312a85fe12eSEd Maste if (die == NULL) { 1313a85fe12eSEd Maste warnx("could not find DW_TAG_compile_unit die"); 1314a85fe12eSEd Maste continue; 1315a85fe12eSEd Maste } 1316a85fe12eSEd Maste 1317a85fe12eSEd Maste /* Retrieve source file list. */ 1318a85fe12eSEd Maste ret = dwarf_srcfiles(die, &src_files, &filecount, &de); 1319a85fe12eSEd Maste if (ret == DW_DLV_ERROR) 1320a85fe12eSEd Maste warnx("dwarf_srclines: %s", dwarf_errmsg(de)); 1321a85fe12eSEd Maste if (ret != DW_DLV_OK) 1322a85fe12eSEd Maste continue; 1323a85fe12eSEd Maste 1324a85fe12eSEd Maste /* 1325a85fe12eSEd Maste * Retrieve line number information from .debug_line section. 1326a85fe12eSEd Maste */ 1327a85fe12eSEd Maste 1328a85fe12eSEd Maste ret = dwarf_srclines(die, &lbuf, &lcount, &de); 1329a85fe12eSEd Maste if (ret == DW_DLV_ERROR) 1330a85fe12eSEd Maste warnx("dwarf_srclines: %s", dwarf_errmsg(de)); 1331a85fe12eSEd Maste if (ret != DW_DLV_OK) 1332a85fe12eSEd Maste goto line_attr; 1333a85fe12eSEd Maste for (i = 0; (Dwarf_Signed) i < lcount; i++) { 1334a85fe12eSEd Maste if (dwarf_lineaddr(lbuf[i], &lineaddr, &de)) { 1335a85fe12eSEd Maste warnx("dwarf_lineaddr: %s", dwarf_errmsg(de)); 1336a85fe12eSEd Maste continue; 1337a85fe12eSEd Maste } 1338a85fe12eSEd Maste if (dwarf_lineno(lbuf[i], &lineno, &de)) { 1339a85fe12eSEd Maste warnx("dwarf_lineno: %s", dwarf_errmsg(de)); 1340a85fe12eSEd Maste continue; 1341a85fe12eSEd Maste } 1342a85fe12eSEd Maste if (dwarf_linesrc(lbuf[i], &sfile, &de)) { 1343a85fe12eSEd Maste warnx("dwarf_linesrc: %s", dwarf_errmsg(de)); 1344a85fe12eSEd Maste continue; 1345a85fe12eSEd Maste } 1346a85fe12eSEd Maste if ((lie = malloc(sizeof(*lie))) == NULL) { 1347a85fe12eSEd Maste warn("malloc"); 1348a85fe12eSEd Maste continue; 1349a85fe12eSEd Maste } 1350a85fe12eSEd Maste lie->addr = lineaddr; 1351a85fe12eSEd Maste lie->line = lineno; 1352a85fe12eSEd Maste lie->file = strdup(sfile); 1353a85fe12eSEd Maste if (lie->file == NULL) { 1354a85fe12eSEd Maste warn("strdup"); 1355a85fe12eSEd Maste free(lie); 1356a85fe12eSEd Maste continue; 1357a85fe12eSEd Maste } 1358a85fe12eSEd Maste SLIST_INSERT_HEAD(line_info, lie, entries); 1359a85fe12eSEd Maste } 1360a85fe12eSEd Maste 1361a85fe12eSEd Maste line_attr: 1362a85fe12eSEd Maste /* Retrieve line number information from DIEs. */ 1363a85fe12eSEd Maste search_line_attr(dbg, func_info, var_info, die, src_files, filecount); 1364a85fe12eSEd Maste } 1365a85fe12eSEd Maste 1366a85fe12eSEd Maste (void) dwarf_finish(dbg, &de); 1367a85fe12eSEd Maste 1368a85fe12eSEd Maste process_sym: 1369a85fe12eSEd Maste 1370a85fe12eSEd Maste p_data.list_num = get_sym(elf, &list_head, shnum, dynndx, strndx, 1371a85fe12eSEd Maste type_table, (void *) sec_table, shnum); 1372a85fe12eSEd Maste 1373a85fe12eSEd Maste if (p_data.list_num == 0) 1374a85fe12eSEd Maste goto next_cmd; 1375a85fe12eSEd Maste 1376a85fe12eSEd Maste p_data.headp = &list_head; 1377a85fe12eSEd Maste p_data.sh_num = shnum; 1378a85fe12eSEd Maste p_data.t_table = type_table; 1379a85fe12eSEd Maste p_data.s_table = (void *) sec_table; 1380a85fe12eSEd Maste p_data.filename = filename; 1381a85fe12eSEd Maste p_data.objname = objname; 1382a85fe12eSEd Maste 1383a85fe12eSEd Maste sym_list_print(&p_data, func_info, var_info, line_info); 1384a85fe12eSEd Maste 1385a85fe12eSEd Maste next_cmd: 1386a85fe12eSEd Maste if (nm_opts.debug_line) { 1387a85fe12eSEd Maste if (func_info != NULL) { 1388a85fe12eSEd Maste while (!SLIST_EMPTY(func_info)) { 1389a85fe12eSEd Maste func = SLIST_FIRST(func_info); 1390a85fe12eSEd Maste SLIST_REMOVE_HEAD(func_info, entries); 1391a85fe12eSEd Maste free(func->file); 1392a85fe12eSEd Maste free(func->name); 1393a85fe12eSEd Maste free(func); 1394a85fe12eSEd Maste } 1395a85fe12eSEd Maste free(func_info); 1396a85fe12eSEd Maste func_info = NULL; 1397a85fe12eSEd Maste } 1398a85fe12eSEd Maste if (var_info != NULL) { 1399a85fe12eSEd Maste while (!SLIST_EMPTY(var_info)) { 1400a85fe12eSEd Maste var = SLIST_FIRST(var_info); 1401a85fe12eSEd Maste SLIST_REMOVE_HEAD(var_info, entries); 1402a85fe12eSEd Maste free(var->file); 1403a85fe12eSEd Maste free(var->name); 1404a85fe12eSEd Maste free(var); 1405a85fe12eSEd Maste } 1406a85fe12eSEd Maste free(var_info); 1407a85fe12eSEd Maste var_info = NULL; 1408a85fe12eSEd Maste } 1409a85fe12eSEd Maste if (line_info != NULL) { 1410a85fe12eSEd Maste while (!SLIST_EMPTY(line_info)) { 1411a85fe12eSEd Maste lie = SLIST_FIRST(line_info); 1412a85fe12eSEd Maste SLIST_REMOVE_HEAD(line_info, entries); 1413a85fe12eSEd Maste free(lie->file); 1414a85fe12eSEd Maste free(lie); 1415a85fe12eSEd Maste } 1416a85fe12eSEd Maste free(line_info); 1417a85fe12eSEd Maste line_info = NULL; 1418a85fe12eSEd Maste } 1419a85fe12eSEd Maste } 1420a85fe12eSEd Maste 1421a85fe12eSEd Maste if (sec_table != NULL) 1422a85fe12eSEd Maste for (i = 0; i < shnum; ++i) 1423a85fe12eSEd Maste free(sec_table[i]); 1424a85fe12eSEd Maste free(sec_table); 1425a85fe12eSEd Maste free(type_table); 1426a85fe12eSEd Maste 1427a85fe12eSEd Maste sym_list_dest(&list_head); 1428a85fe12eSEd Maste 1429a85fe12eSEd Maste return (rtn); 1430a85fe12eSEd Maste 1431a85fe12eSEd Maste #undef OBJNAME 1432a85fe12eSEd Maste } 1433a85fe12eSEd Maste 1434a85fe12eSEd Maste static int 1435a85fe12eSEd Maste read_object(const char *filename) 1436a85fe12eSEd Maste { 1437a85fe12eSEd Maste Elf *elf, *arf; 1438a85fe12eSEd Maste Elf_Cmd elf_cmd; 1439a85fe12eSEd Maste Elf_Kind kind; 1440a85fe12eSEd Maste int fd, rtn, e_err; 1441a85fe12eSEd Maste 1442a85fe12eSEd Maste assert(filename != NULL && "filename is null"); 1443a85fe12eSEd Maste 1444a85fe12eSEd Maste if ((fd = open(filename, O_RDONLY)) == -1) { 1445a85fe12eSEd Maste warn("'%s'", filename); 1446a85fe12eSEd Maste return (1); 1447a85fe12eSEd Maste } 1448a85fe12eSEd Maste 1449a85fe12eSEd Maste elf_cmd = ELF_C_READ; 1450a85fe12eSEd Maste if ((arf = elf_begin(fd, elf_cmd, (Elf *) NULL)) == NULL) { 1451a85fe12eSEd Maste if ((e_err = elf_errno()) != 0) 1452a85fe12eSEd Maste warnx("elf_begin error: %s", elf_errmsg(e_err)); 1453a85fe12eSEd Maste else 1454a85fe12eSEd Maste warnx("elf_begin error"); 1455a85fe12eSEd Maste close(fd); 1456a85fe12eSEd Maste return (1); 1457a85fe12eSEd Maste } 1458a85fe12eSEd Maste 1459a85fe12eSEd Maste assert(arf != NULL && "arf is null."); 1460a85fe12eSEd Maste 1461a85fe12eSEd Maste rtn = 0; 1462a85fe12eSEd Maste if ((kind = elf_kind(arf)) == ELF_K_NONE) { 1463a85fe12eSEd Maste warnx("%s: File format not recognized", filename); 1464a85fe12eSEd Maste elf_end(arf); 1465a85fe12eSEd Maste close(fd); 1466a85fe12eSEd Maste return (1); 1467a85fe12eSEd Maste } 1468a85fe12eSEd Maste if (kind == ELF_K_AR) { 1469a85fe12eSEd Maste if (nm_opts.print_name == PRINT_NAME_MULTI && 1470a85fe12eSEd Maste nm_opts.elem_print_fn == sym_elem_print_all) 1471a85fe12eSEd Maste printf("\n%s:\n", filename); 1472a85fe12eSEd Maste if (nm_opts.print_armap == true) 1473a85fe12eSEd Maste print_ar_index(fd, arf); 1474a85fe12eSEd Maste } 1475a85fe12eSEd Maste 1476a85fe12eSEd Maste while ((elf = elf_begin(fd, elf_cmd, arf)) != NULL) { 1477a85fe12eSEd Maste rtn |= read_elf(elf, filename, kind); 1478a85fe12eSEd Maste 1479a85fe12eSEd Maste /* 1480a85fe12eSEd Maste * If file is not archive, elf_next return ELF_C_NULL and 1481a85fe12eSEd Maste * stop the loop. 1482a85fe12eSEd Maste */ 1483a85fe12eSEd Maste elf_cmd = elf_next(elf); 1484a85fe12eSEd Maste elf_end(elf); 1485a85fe12eSEd Maste } 1486a85fe12eSEd Maste 1487a85fe12eSEd Maste elf_end(arf); 1488a85fe12eSEd Maste close(fd); 1489a85fe12eSEd Maste 1490a85fe12eSEd Maste return (rtn); 1491a85fe12eSEd Maste } 1492a85fe12eSEd Maste 1493a85fe12eSEd Maste static int 1494a85fe12eSEd Maste read_files(int argc, char **argv) 1495a85fe12eSEd Maste { 1496a85fe12eSEd Maste int rtn = 0; 1497a85fe12eSEd Maste 1498a85fe12eSEd Maste if (argc < 0 || argv == NULL) 1499a85fe12eSEd Maste return (1); 1500a85fe12eSEd Maste 1501a85fe12eSEd Maste if (argc == 0) 1502a85fe12eSEd Maste rtn |= read_object(nm_info.def_filename); 1503a85fe12eSEd Maste else { 1504a85fe12eSEd Maste if (nm_opts.print_name == PRINT_NAME_NONE && argc > 1) 1505a85fe12eSEd Maste nm_opts.print_name = PRINT_NAME_MULTI; 1506a85fe12eSEd Maste while (argc > 0) { 1507a85fe12eSEd Maste rtn |= read_object(*argv); 1508a85fe12eSEd Maste --argc; 1509a85fe12eSEd Maste ++argv; 1510a85fe12eSEd Maste } 1511a85fe12eSEd Maste } 1512a85fe12eSEd Maste 1513a85fe12eSEd Maste return (rtn); 1514a85fe12eSEd Maste } 1515a85fe12eSEd Maste 1516a85fe12eSEd Maste static void 1517a85fe12eSEd Maste print_lineno(struct sym_entry *ep, struct func_info_head *func_info, 1518a85fe12eSEd Maste struct var_info_head *var_info, struct line_info_head *line_info) 1519a85fe12eSEd Maste { 1520a85fe12eSEd Maste struct func_info_entry *func; 1521a85fe12eSEd Maste struct var_info_entry *var; 1522a85fe12eSEd Maste struct line_info_entry *lie; 1523a85fe12eSEd Maste 1524a85fe12eSEd Maste /* For function symbol, search the function line information list. */ 1525a85fe12eSEd Maste if ((ep->sym->st_info & 0xf) == STT_FUNC && func_info != NULL) { 1526a85fe12eSEd Maste SLIST_FOREACH(func, func_info, entries) { 1527a85fe12eSEd Maste if (!strcmp(ep->name, func->name) && 1528a85fe12eSEd Maste ep->sym->st_value >= func->lowpc && 1529a85fe12eSEd Maste ep->sym->st_value < func->highpc) { 1530a85fe12eSEd Maste printf("\t%s:%" PRIu64, func->file, func->line); 1531a85fe12eSEd Maste return; 1532a85fe12eSEd Maste } 1533a85fe12eSEd Maste } 1534a85fe12eSEd Maste } 1535a85fe12eSEd Maste 1536a85fe12eSEd Maste /* For variable symbol, search the variable line information list. */ 1537a85fe12eSEd Maste if ((ep->sym->st_info & 0xf) == STT_OBJECT && var_info != NULL) { 1538a85fe12eSEd Maste SLIST_FOREACH(var, var_info, entries) { 1539a85fe12eSEd Maste if (!strcmp(ep->name, var->name) && 1540a85fe12eSEd Maste ep->sym->st_value == var->addr) { 1541a85fe12eSEd Maste printf("\t%s:%" PRIu64, var->file, var->line); 1542a85fe12eSEd Maste return; 1543a85fe12eSEd Maste } 1544a85fe12eSEd Maste } 1545a85fe12eSEd Maste } 1546a85fe12eSEd Maste 1547a85fe12eSEd Maste /* Otherwise search line number information the .debug_line section. */ 1548a85fe12eSEd Maste if (line_info != NULL) { 1549a85fe12eSEd Maste SLIST_FOREACH(lie, line_info, entries) { 1550a85fe12eSEd Maste if (ep->sym->st_value == lie->addr) { 1551a85fe12eSEd Maste printf("\t%s:%" PRIu64, lie->file, lie->line); 1552a85fe12eSEd Maste return; 1553a85fe12eSEd Maste } 1554a85fe12eSEd Maste } 1555a85fe12eSEd Maste } 1556a85fe12eSEd Maste } 1557a85fe12eSEd Maste 1558a85fe12eSEd Maste static void 1559a85fe12eSEd Maste set_opt_value_print_fn(enum radix t) 1560a85fe12eSEd Maste { 1561a85fe12eSEd Maste 1562a85fe12eSEd Maste switch (t) { 1563a85fe12eSEd Maste case RADIX_OCT: 1564a85fe12eSEd Maste nm_opts.value_print_fn = &sym_value_oct_print; 1565a85fe12eSEd Maste nm_opts.size_print_fn = &sym_size_oct_print; 1566a85fe12eSEd Maste 1567a85fe12eSEd Maste break; 1568a85fe12eSEd Maste case RADIX_DEC: 1569a85fe12eSEd Maste nm_opts.value_print_fn = &sym_value_dec_print; 1570a85fe12eSEd Maste nm_opts.size_print_fn = &sym_size_dec_print; 1571a85fe12eSEd Maste 1572a85fe12eSEd Maste break; 1573a85fe12eSEd Maste case RADIX_HEX: 1574a85fe12eSEd Maste default : 1575a85fe12eSEd Maste nm_opts.value_print_fn = &sym_value_hex_print; 1576a85fe12eSEd Maste nm_opts.size_print_fn = &sym_size_hex_print; 1577a85fe12eSEd Maste } 1578a85fe12eSEd Maste 1579a85fe12eSEd Maste assert(nm_opts.value_print_fn != NULL && 1580a85fe12eSEd Maste "nm_opts.value_print_fn is null"); 1581a85fe12eSEd Maste } 1582a85fe12eSEd Maste 1583a85fe12eSEd Maste static void 1584a85fe12eSEd Maste sym_elem_print_all(char type, const char *sec, const GElf_Sym *sym, 1585a85fe12eSEd Maste const char *name) 1586a85fe12eSEd Maste { 1587a85fe12eSEd Maste 1588a85fe12eSEd Maste if (sec == NULL || sym == NULL || name == NULL || 1589a85fe12eSEd Maste nm_opts.value_print_fn == NULL) 1590a85fe12eSEd Maste return; 1591a85fe12eSEd Maste 1592a85fe12eSEd Maste if (IS_UNDEF_SYM_TYPE(type)) { 1593a85fe12eSEd Maste if (nm_opts.t == RADIX_HEX && nm_elfclass == ELFCLASS32) 1594a85fe12eSEd Maste printf("%-8s", ""); 1595a85fe12eSEd Maste else 1596a85fe12eSEd Maste printf("%-16s", ""); 1597a85fe12eSEd Maste } else { 1598a85fe12eSEd Maste switch ((nm_opts.sort_fn == & cmp_size ? 2 : 0) + 1599a85fe12eSEd Maste nm_opts.print_size) { 1600a85fe12eSEd Maste case 3: 1601a85fe12eSEd Maste if (sym->st_size != 0) { 1602a85fe12eSEd Maste nm_opts.value_print_fn(sym); 1603a85fe12eSEd Maste printf(" "); 1604a85fe12eSEd Maste nm_opts.size_print_fn(sym); 1605a85fe12eSEd Maste } 1606a85fe12eSEd Maste break; 1607a85fe12eSEd Maste 1608a85fe12eSEd Maste case 2: 1609a85fe12eSEd Maste if (sym->st_size != 0) 1610a85fe12eSEd Maste nm_opts.size_print_fn(sym); 1611a85fe12eSEd Maste break; 1612a85fe12eSEd Maste 1613a85fe12eSEd Maste case 1: 1614a85fe12eSEd Maste nm_opts.value_print_fn(sym); 1615a85fe12eSEd Maste if (sym->st_size != 0) { 1616a85fe12eSEd Maste printf(" "); 1617a85fe12eSEd Maste nm_opts.size_print_fn(sym); 1618a85fe12eSEd Maste } 1619a85fe12eSEd Maste break; 1620a85fe12eSEd Maste 1621a85fe12eSEd Maste case 0: 1622a85fe12eSEd Maste default: 1623a85fe12eSEd Maste nm_opts.value_print_fn(sym); 1624a85fe12eSEd Maste } 1625a85fe12eSEd Maste } 1626a85fe12eSEd Maste 1627a85fe12eSEd Maste printf(" %c ", type); 1628a85fe12eSEd Maste PRINT_DEMANGLED_NAME("%s", name); 1629a85fe12eSEd Maste } 1630a85fe12eSEd Maste 1631a85fe12eSEd Maste static void 1632a85fe12eSEd Maste sym_elem_print_all_portable(char type, const char *sec, const GElf_Sym *sym, 1633a85fe12eSEd Maste const char *name) 1634a85fe12eSEd Maste { 1635a85fe12eSEd Maste 1636a85fe12eSEd Maste if (sec == NULL || sym == NULL || name == NULL || 1637a85fe12eSEd Maste nm_opts.value_print_fn == NULL) 1638a85fe12eSEd Maste return; 1639a85fe12eSEd Maste 1640a85fe12eSEd Maste PRINT_DEMANGLED_NAME("%s", name); 1641a85fe12eSEd Maste printf(" %c ", type); 1642a85fe12eSEd Maste if (!IS_UNDEF_SYM_TYPE(type)) { 1643a85fe12eSEd Maste nm_opts.value_print_fn(sym); 1644a85fe12eSEd Maste printf(" "); 1645a85fe12eSEd Maste if (sym->st_size != 0) 1646a85fe12eSEd Maste nm_opts.size_print_fn(sym); 1647a85fe12eSEd Maste } else 1648a85fe12eSEd Maste printf(" "); 1649a85fe12eSEd Maste } 1650a85fe12eSEd Maste 1651a85fe12eSEd Maste static void 1652a85fe12eSEd Maste sym_elem_print_all_sysv(char type, const char *sec, const GElf_Sym *sym, 1653a85fe12eSEd Maste const char *name) 1654a85fe12eSEd Maste { 1655a85fe12eSEd Maste 1656a85fe12eSEd Maste if (sec == NULL || sym == NULL || name == NULL || 1657a85fe12eSEd Maste nm_opts.value_print_fn == NULL) 1658a85fe12eSEd Maste return; 1659a85fe12eSEd Maste 1660a85fe12eSEd Maste PRINT_DEMANGLED_NAME("%-20s|", name); 1661a85fe12eSEd Maste if (IS_UNDEF_SYM_TYPE(type)) 1662a85fe12eSEd Maste printf(" "); 1663a85fe12eSEd Maste else 1664a85fe12eSEd Maste nm_opts.value_print_fn(sym); 1665a85fe12eSEd Maste 1666a85fe12eSEd Maste printf("| %c |", type); 1667a85fe12eSEd Maste 1668a85fe12eSEd Maste switch (sym->st_info & 0xf) { 1669a85fe12eSEd Maste case STT_OBJECT: 1670a85fe12eSEd Maste printf("%18s|", "OBJECT"); 1671a85fe12eSEd Maste break; 1672a85fe12eSEd Maste 1673a85fe12eSEd Maste case STT_FUNC: 1674a85fe12eSEd Maste printf("%18s|", "FUNC"); 1675a85fe12eSEd Maste break; 1676a85fe12eSEd Maste 1677a85fe12eSEd Maste case STT_SECTION: 1678a85fe12eSEd Maste printf("%18s|", "SECTION"); 1679a85fe12eSEd Maste break; 1680a85fe12eSEd Maste 1681a85fe12eSEd Maste case STT_FILE: 1682a85fe12eSEd Maste printf("%18s|", "FILE"); 1683a85fe12eSEd Maste break; 1684a85fe12eSEd Maste 1685a85fe12eSEd Maste case STT_LOPROC: 1686a85fe12eSEd Maste printf("%18s|", "LOPROC"); 1687a85fe12eSEd Maste break; 1688a85fe12eSEd Maste 1689a85fe12eSEd Maste case STT_HIPROC: 1690a85fe12eSEd Maste printf("%18s|", "HIPROC"); 1691a85fe12eSEd Maste break; 1692a85fe12eSEd Maste 1693a85fe12eSEd Maste case STT_NOTYPE: 1694a85fe12eSEd Maste default: 1695a85fe12eSEd Maste printf("%18s|", "NOTYPE"); 1696a85fe12eSEd Maste }; 1697a85fe12eSEd Maste 1698a85fe12eSEd Maste if (sym->st_size != 0) 1699a85fe12eSEd Maste nm_opts.size_print_fn(sym); 1700a85fe12eSEd Maste else 1701a85fe12eSEd Maste printf(" "); 1702a85fe12eSEd Maste 1703a85fe12eSEd Maste printf("| |%s", sec); 1704a85fe12eSEd Maste } 1705a85fe12eSEd Maste 1706a85fe12eSEd Maste static int 1707a85fe12eSEd Maste sym_elem_def(char type, const GElf_Sym *sym, const char *name) 1708a85fe12eSEd Maste { 1709a85fe12eSEd Maste 1710a85fe12eSEd Maste assert(IS_SYM_TYPE((unsigned char) type)); 1711a85fe12eSEd Maste 1712a85fe12eSEd Maste UNUSED(sym); 1713a85fe12eSEd Maste UNUSED(name); 1714a85fe12eSEd Maste 1715a85fe12eSEd Maste return (!IS_UNDEF_SYM_TYPE((unsigned char) type)); 1716a85fe12eSEd Maste } 1717a85fe12eSEd Maste 1718a85fe12eSEd Maste static int 1719a85fe12eSEd Maste sym_elem_global(char type, const GElf_Sym *sym, const char *name) 1720a85fe12eSEd Maste { 1721a85fe12eSEd Maste 1722a85fe12eSEd Maste assert(IS_SYM_TYPE((unsigned char) type)); 1723a85fe12eSEd Maste 1724a85fe12eSEd Maste UNUSED(sym); 1725a85fe12eSEd Maste UNUSED(name); 1726a85fe12eSEd Maste 1727a85fe12eSEd Maste /* weak symbols resemble global. */ 1728a85fe12eSEd Maste return (isupper((unsigned char) type) || type == 'w'); 1729a85fe12eSEd Maste } 1730a85fe12eSEd Maste 1731a85fe12eSEd Maste static int 1732a85fe12eSEd Maste sym_elem_global_static(char type, const GElf_Sym *sym, const char *name) 1733a85fe12eSEd Maste { 1734a85fe12eSEd Maste unsigned char info; 1735a85fe12eSEd Maste 1736a85fe12eSEd Maste assert(sym != NULL); 1737a85fe12eSEd Maste 1738a85fe12eSEd Maste UNUSED(type); 1739a85fe12eSEd Maste UNUSED(name); 1740a85fe12eSEd Maste 1741a85fe12eSEd Maste info = sym->st_info >> 4; 1742a85fe12eSEd Maste 1743a85fe12eSEd Maste return (info == STB_LOCAL || 1744a85fe12eSEd Maste info == STB_GLOBAL || 1745a85fe12eSEd Maste info == STB_WEAK); 1746a85fe12eSEd Maste } 1747a85fe12eSEd Maste 1748a85fe12eSEd Maste static int 1749a85fe12eSEd Maste sym_elem_nondebug(char type, const GElf_Sym *sym, const char *name) 1750a85fe12eSEd Maste { 1751a85fe12eSEd Maste 1752a85fe12eSEd Maste assert(sym != NULL); 1753a85fe12eSEd Maste 1754a85fe12eSEd Maste UNUSED(type); 1755a85fe12eSEd Maste UNUSED(name); 1756a85fe12eSEd Maste 1757a85fe12eSEd Maste if (sym->st_value == 0 && (sym->st_info & 0xf) == STT_FILE) 1758a85fe12eSEd Maste return (0); 1759a85fe12eSEd Maste if (sym->st_name == 0) 1760a85fe12eSEd Maste return (0); 1761a85fe12eSEd Maste 1762a85fe12eSEd Maste return (1); 1763a85fe12eSEd Maste } 1764a85fe12eSEd Maste 1765a85fe12eSEd Maste static int 1766a85fe12eSEd Maste sym_elem_nonzero_size(char type, const GElf_Sym *sym, const char *name) 1767a85fe12eSEd Maste { 1768a85fe12eSEd Maste 1769a85fe12eSEd Maste assert(sym != NULL); 1770a85fe12eSEd Maste 1771a85fe12eSEd Maste UNUSED(type); 1772a85fe12eSEd Maste UNUSED(name); 1773a85fe12eSEd Maste 1774a85fe12eSEd Maste return (sym->st_size > 0); 1775a85fe12eSEd Maste } 1776a85fe12eSEd Maste 1777a85fe12eSEd Maste static int 1778a85fe12eSEd Maste sym_elem_undef(char type, const GElf_Sym *sym, const char *name) 1779a85fe12eSEd Maste { 1780a85fe12eSEd Maste 1781a85fe12eSEd Maste assert(IS_SYM_TYPE((unsigned char) type)); 1782a85fe12eSEd Maste 1783a85fe12eSEd Maste UNUSED(sym); 1784a85fe12eSEd Maste UNUSED(name); 1785a85fe12eSEd Maste 1786a85fe12eSEd Maste return (IS_UNDEF_SYM_TYPE((unsigned char) type)); 1787a85fe12eSEd Maste } 1788a85fe12eSEd Maste 1789a85fe12eSEd Maste static void 1790a85fe12eSEd Maste sym_list_dest(struct sym_head *headp) 1791a85fe12eSEd Maste { 1792a85fe12eSEd Maste struct sym_entry *ep, *ep_n; 1793a85fe12eSEd Maste 1794a85fe12eSEd Maste if (headp == NULL) 1795a85fe12eSEd Maste return; 1796a85fe12eSEd Maste 1797a85fe12eSEd Maste ep = STAILQ_FIRST(headp); 1798a85fe12eSEd Maste while (ep != NULL) { 1799a85fe12eSEd Maste ep_n = STAILQ_NEXT(ep, sym_entries); 1800a85fe12eSEd Maste free(ep->sym); 1801a85fe12eSEd Maste free(ep->name); 1802a85fe12eSEd Maste free(ep); 1803a85fe12eSEd Maste ep = ep_n; 1804a85fe12eSEd Maste } 1805a85fe12eSEd Maste } 1806a85fe12eSEd Maste 1807a85fe12eSEd Maste static int 1808a85fe12eSEd Maste sym_list_insert(struct sym_head *headp, const char *name, const GElf_Sym *sym) 1809a85fe12eSEd Maste { 1810a85fe12eSEd Maste struct sym_entry *e; 1811a85fe12eSEd Maste 1812a85fe12eSEd Maste if (headp == NULL || name == NULL || sym == NULL) 1813a85fe12eSEd Maste return (0); 1814a85fe12eSEd Maste if ((e = malloc(sizeof(struct sym_entry))) == NULL) { 1815a85fe12eSEd Maste warn("malloc"); 1816a85fe12eSEd Maste return (0); 1817a85fe12eSEd Maste } 1818a85fe12eSEd Maste if ((e->name = strdup(name)) == NULL) { 1819a85fe12eSEd Maste warn("strdup"); 1820a85fe12eSEd Maste free(e); 1821a85fe12eSEd Maste return (0); 1822a85fe12eSEd Maste } 1823a85fe12eSEd Maste if ((e->sym = malloc(sizeof(GElf_Sym))) == NULL) { 1824a85fe12eSEd Maste warn("malloc"); 1825a85fe12eSEd Maste free(e->name); 1826a85fe12eSEd Maste free(e); 1827a85fe12eSEd Maste return (0); 1828a85fe12eSEd Maste } 1829a85fe12eSEd Maste 1830a85fe12eSEd Maste memcpy(e->sym, sym, sizeof(GElf_Sym)); 1831a85fe12eSEd Maste 1832a85fe12eSEd Maste /* Display size instead of value for common symbol. */ 1833a85fe12eSEd Maste if (sym->st_shndx == SHN_COMMON) 1834a85fe12eSEd Maste e->sym->st_value = sym->st_size; 1835a85fe12eSEd Maste 1836a85fe12eSEd Maste STAILQ_INSERT_TAIL(headp, e, sym_entries); 1837a85fe12eSEd Maste 1838a85fe12eSEd Maste return (1); 1839a85fe12eSEd Maste } 1840a85fe12eSEd Maste 1841a85fe12eSEd Maste /* If file has not .debug_info, line_info will be NULL */ 1842a85fe12eSEd Maste static void 1843a85fe12eSEd Maste sym_list_print(struct sym_print_data *p, struct func_info_head *func_info, 1844a85fe12eSEd Maste struct var_info_head *var_info, struct line_info_head *line_info) 1845a85fe12eSEd Maste { 1846a85fe12eSEd Maste struct sym_entry *e_v; 1847a85fe12eSEd Maste size_t si; 1848a85fe12eSEd Maste int i; 1849a85fe12eSEd Maste 1850a85fe12eSEd Maste if (p == NULL || CHECK_SYM_PRINT_DATA(p)) 1851a85fe12eSEd Maste return; 1852a85fe12eSEd Maste if ((e_v = sym_list_sort(p)) == NULL) 1853a85fe12eSEd Maste return; 1854a85fe12eSEd Maste if (nm_opts.sort_reverse == false) 1855a85fe12eSEd Maste for (si = 0; si != p->list_num; ++si) 1856a85fe12eSEd Maste sym_list_print_each(&e_v[si], p, func_info, var_info, 1857a85fe12eSEd Maste line_info); 1858a85fe12eSEd Maste else 1859a85fe12eSEd Maste for (i = p->list_num - 1; i != -1; --i) 1860a85fe12eSEd Maste sym_list_print_each(&e_v[i], p, func_info, var_info, 1861a85fe12eSEd Maste line_info); 1862a85fe12eSEd Maste 1863a85fe12eSEd Maste free(e_v); 1864a85fe12eSEd Maste } 1865a85fe12eSEd Maste 1866a85fe12eSEd Maste /* If file has not .debug_info, line_info will be NULL */ 1867a85fe12eSEd Maste static void 1868a85fe12eSEd Maste sym_list_print_each(struct sym_entry *ep, struct sym_print_data *p, 1869a85fe12eSEd Maste struct func_info_head *func_info, struct var_info_head *var_info, 1870a85fe12eSEd Maste struct line_info_head *line_info) 1871a85fe12eSEd Maste { 1872a85fe12eSEd Maste const char *sec; 1873a85fe12eSEd Maste char type; 1874a85fe12eSEd Maste 1875a85fe12eSEd Maste if (ep == NULL || CHECK_SYM_PRINT_DATA(p)) 1876a85fe12eSEd Maste return; 1877a85fe12eSEd Maste 1878a85fe12eSEd Maste assert(ep->name != NULL); 1879a85fe12eSEd Maste assert(ep->sym != NULL); 1880a85fe12eSEd Maste 1881a85fe12eSEd Maste type = get_sym_type(ep->sym, p->t_table); 1882a85fe12eSEd Maste 1883a85fe12eSEd Maste if (nm_opts.print_name == PRINT_NAME_FULL) { 1884a85fe12eSEd Maste printf("%s", p->filename); 1885a85fe12eSEd Maste if (nm_opts.elem_print_fn == &sym_elem_print_all_portable) { 1886a85fe12eSEd Maste if (p->objname != NULL) 1887a85fe12eSEd Maste printf("[%s]", p->objname); 1888a85fe12eSEd Maste printf(": "); 1889a85fe12eSEd Maste } else { 1890a85fe12eSEd Maste if (p->objname != NULL) 1891a85fe12eSEd Maste printf(":%s", p->objname); 1892a85fe12eSEd Maste printf(":"); 1893a85fe12eSEd Maste } 1894a85fe12eSEd Maste } 1895a85fe12eSEd Maste 1896a85fe12eSEd Maste switch (ep->sym->st_shndx) { 1897a85fe12eSEd Maste case SHN_LOPROC: 1898a85fe12eSEd Maste /* LOPROC or LORESERVE */ 1899a85fe12eSEd Maste sec = "*LOPROC*"; 1900a85fe12eSEd Maste break; 1901a85fe12eSEd Maste case SHN_HIPROC: 1902a85fe12eSEd Maste sec = "*HIPROC*"; 1903a85fe12eSEd Maste break; 1904a85fe12eSEd Maste case SHN_LOOS: 1905a85fe12eSEd Maste sec = "*LOOS*"; 1906a85fe12eSEd Maste break; 1907a85fe12eSEd Maste case SHN_HIOS: 1908a85fe12eSEd Maste sec = "*HIOS*"; 1909a85fe12eSEd Maste break; 1910a85fe12eSEd Maste case SHN_ABS: 1911a85fe12eSEd Maste sec = "*ABS*"; 1912a85fe12eSEd Maste break; 1913a85fe12eSEd Maste case SHN_COMMON: 1914a85fe12eSEd Maste sec = "*COM*"; 1915a85fe12eSEd Maste break; 1916a85fe12eSEd Maste case SHN_HIRESERVE: 1917a85fe12eSEd Maste /* HIRESERVE or XINDEX */ 1918a85fe12eSEd Maste sec = "*HIRESERVE*"; 1919a85fe12eSEd Maste break; 1920a85fe12eSEd Maste default: 1921a85fe12eSEd Maste if (ep->sym->st_shndx > p->sh_num) 1922a85fe12eSEd Maste return; 1923a85fe12eSEd Maste sec = p->s_table[ep->sym->st_shndx]; 1924a85fe12eSEd Maste break; 1925a85fe12eSEd Maste }; 1926a85fe12eSEd Maste 1927a85fe12eSEd Maste nm_opts.elem_print_fn(type, sec, ep->sym, ep->name); 1928a85fe12eSEd Maste 1929a85fe12eSEd Maste if (nm_opts.debug_line == true && !IS_UNDEF_SYM_TYPE(type)) 1930a85fe12eSEd Maste print_lineno(ep, func_info, var_info, line_info); 1931a85fe12eSEd Maste 1932a85fe12eSEd Maste printf("\n"); 1933a85fe12eSEd Maste } 1934a85fe12eSEd Maste 1935a85fe12eSEd Maste static struct sym_entry * 1936a85fe12eSEd Maste sym_list_sort(struct sym_print_data *p) 1937a85fe12eSEd Maste { 1938a85fe12eSEd Maste struct sym_entry *ep, *e_v; 1939a85fe12eSEd Maste int idx; 1940a85fe12eSEd Maste 1941a85fe12eSEd Maste if (p == NULL || CHECK_SYM_PRINT_DATA(p)) 1942a85fe12eSEd Maste return (NULL); 1943a85fe12eSEd Maste 1944a85fe12eSEd Maste if ((e_v = malloc(sizeof(struct sym_entry) * p->list_num)) == NULL) { 1945a85fe12eSEd Maste warn("malloc"); 1946a85fe12eSEd Maste return (NULL); 1947a85fe12eSEd Maste } 1948a85fe12eSEd Maste 1949a85fe12eSEd Maste idx = 0; 1950a85fe12eSEd Maste STAILQ_FOREACH(ep, p->headp, sym_entries) { 1951a85fe12eSEd Maste if (ep->name != NULL && ep->sym != NULL) { 1952a85fe12eSEd Maste e_v[idx].name = ep->name; 1953a85fe12eSEd Maste e_v[idx].sym = ep->sym; 1954a85fe12eSEd Maste ++idx; 1955a85fe12eSEd Maste } 1956a85fe12eSEd Maste } 1957a85fe12eSEd Maste 1958a85fe12eSEd Maste assert((size_t)idx == p->list_num); 1959a85fe12eSEd Maste 1960a85fe12eSEd Maste if (nm_opts.sort_fn != &cmp_none) { 1961a85fe12eSEd Maste nm_print_data = p; 1962a85fe12eSEd Maste assert(nm_print_data != NULL); 1963a85fe12eSEd Maste qsort(e_v, p->list_num, sizeof(struct sym_entry), 1964a85fe12eSEd Maste nm_opts.sort_fn); 1965a85fe12eSEd Maste } 1966a85fe12eSEd Maste 1967a85fe12eSEd Maste return (e_v); 1968a85fe12eSEd Maste } 1969a85fe12eSEd Maste 1970a85fe12eSEd Maste static void 1971a85fe12eSEd Maste sym_size_oct_print(const GElf_Sym *sym) 1972a85fe12eSEd Maste { 1973a85fe12eSEd Maste 1974a85fe12eSEd Maste assert(sym != NULL && "sym is null"); 1975a85fe12eSEd Maste printf("%016" PRIo64, sym->st_size); 1976a85fe12eSEd Maste } 1977a85fe12eSEd Maste 1978a85fe12eSEd Maste static void 1979a85fe12eSEd Maste sym_size_hex_print(const GElf_Sym *sym) 1980a85fe12eSEd Maste { 1981a85fe12eSEd Maste 1982a85fe12eSEd Maste assert(sym != NULL && "sym is null"); 1983a85fe12eSEd Maste if (nm_elfclass == ELFCLASS32) 1984a85fe12eSEd Maste printf("%08" PRIx64, sym->st_size); 1985a85fe12eSEd Maste else 1986a85fe12eSEd Maste printf("%016" PRIx64, sym->st_size); 1987a85fe12eSEd Maste } 1988a85fe12eSEd Maste 1989a85fe12eSEd Maste static void 1990a85fe12eSEd Maste sym_size_dec_print(const GElf_Sym *sym) 1991a85fe12eSEd Maste { 1992a85fe12eSEd Maste 1993a85fe12eSEd Maste assert(sym != NULL && "sym is null"); 1994a85fe12eSEd Maste printf("%016" PRId64, sym->st_size); 1995a85fe12eSEd Maste } 1996a85fe12eSEd Maste 1997a85fe12eSEd Maste static void 1998a85fe12eSEd Maste sym_value_oct_print(const GElf_Sym *sym) 1999a85fe12eSEd Maste { 2000a85fe12eSEd Maste 2001a85fe12eSEd Maste assert(sym != NULL && "sym is null"); 2002a85fe12eSEd Maste printf("%016" PRIo64, sym->st_value); 2003a85fe12eSEd Maste } 2004a85fe12eSEd Maste 2005a85fe12eSEd Maste static void 2006a85fe12eSEd Maste sym_value_hex_print(const GElf_Sym *sym) 2007a85fe12eSEd Maste { 2008a85fe12eSEd Maste 2009a85fe12eSEd Maste assert(sym != NULL && "sym is null"); 2010a85fe12eSEd Maste if (nm_elfclass == ELFCLASS32) 2011a85fe12eSEd Maste printf("%08" PRIx64, sym->st_value); 2012a85fe12eSEd Maste else 2013a85fe12eSEd Maste printf("%016" PRIx64, sym->st_value); 2014a85fe12eSEd Maste } 2015a85fe12eSEd Maste 2016a85fe12eSEd Maste static void 2017a85fe12eSEd Maste sym_value_dec_print(const GElf_Sym *sym) 2018a85fe12eSEd Maste { 2019a85fe12eSEd Maste 2020a85fe12eSEd Maste assert(sym != NULL && "sym is null"); 2021a85fe12eSEd Maste printf("%016" PRId64, sym->st_value); 2022a85fe12eSEd Maste } 2023a85fe12eSEd Maste 2024a85fe12eSEd Maste static void 2025a85fe12eSEd Maste usage(int exitcode) 2026a85fe12eSEd Maste { 2027a85fe12eSEd Maste 2028a85fe12eSEd Maste printf("Usage: %s [options] file ...\ 2029a85fe12eSEd Maste \n Display symbolic information in file.\n\ 2030a85fe12eSEd Maste \n Options: \ 2031a85fe12eSEd Maste \n -A, --print-file-name Write the full pathname or library name of an\ 2032a85fe12eSEd Maste \n object on each line.\ 2033a85fe12eSEd Maste \n -a, --debug-syms Display all symbols include debugger-only\ 2034a85fe12eSEd Maste \n symbols.", nm_info.name); 2035a85fe12eSEd Maste printf("\ 2036a85fe12eSEd Maste \n -B Equivalent to specifying \"--format=bsd\".\ 2037a85fe12eSEd Maste \n -C, --demangle[=style] Decode low-level symbol names.\ 2038a85fe12eSEd Maste \n --no-demangle Do not demangle low-level symbol names.\ 2039a85fe12eSEd Maste \n -D, --dynamic Display only dynamic symbols.\ 2040a85fe12eSEd Maste \n -e Display only global and static symbols."); 2041a85fe12eSEd Maste printf("\ 2042a85fe12eSEd Maste \n -f Produce full output (default).\ 2043a85fe12eSEd Maste \n --format=format Display output in specific format. Allowed\ 2044a85fe12eSEd Maste \n formats are: \"bsd\", \"posix\" and \"sysv\".\ 2045a85fe12eSEd Maste \n -g Display only global symbol information.\ 2046a85fe12eSEd Maste \n -h, --help Show this help message.\ 2047a85fe12eSEd Maste \n -l, --line-numbers Display filename and linenumber using\ 2048a85fe12eSEd Maste \n debugging information.\ 2049a85fe12eSEd Maste \n -n, --numeric-sort Sort symbols numerically by value."); 2050a85fe12eSEd Maste printf("\ 2051a85fe12eSEd Maste \n -o Write numeric values in octal. Equivalent to\ 2052a85fe12eSEd Maste \n specifying \"-t o\".\ 2053a85fe12eSEd Maste \n -p, --no-sort Do not sort symbols.\ 2054a85fe12eSEd Maste \n -P Write information in a portable output format.\ 2055a85fe12eSEd Maste \n Equivalent to specifying \"--format=posix\".\ 2056a85fe12eSEd Maste \n -r, --reverse-sort Reverse the order of the sort.\ 2057a85fe12eSEd Maste \n -S, --print-size Print symbol sizes instead values.\ 2058a85fe12eSEd Maste \n -s, --print-armap Include an index of archive members.\ 2059a85fe12eSEd Maste \n --size-sort Sort symbols by size."); 2060a85fe12eSEd Maste printf("\ 2061a85fe12eSEd Maste \n -t, --radix=format Write each numeric value in the specified\ 2062a85fe12eSEd Maste \n format:\ 2063a85fe12eSEd Maste \n d In decimal,\ 2064a85fe12eSEd Maste \n o In octal,\ 2065a85fe12eSEd Maste \n x In hexadecimal."); 2066a85fe12eSEd Maste printf("\ 2067a85fe12eSEd Maste \n -u, --undefined-only Display only undefined symbols.\ 2068a85fe12eSEd Maste \n --defined-only Display only defined symbols.\ 2069a85fe12eSEd Maste \n -V, --version Show the version identifier for %s.\ 2070a85fe12eSEd Maste \n -v Sort output by value.\ 2071a85fe12eSEd Maste \n -x Write numeric values in hexadecimal.\ 2072a85fe12eSEd Maste \n Equivalent to specifying \"-t x\".", 2073a85fe12eSEd Maste nm_info.name); 2074a85fe12eSEd Maste printf("\n\ 2075a85fe12eSEd Maste \n The default options are: output in bsd format, use a hexadecimal radix,\ 2076a85fe12eSEd Maste \n sort by symbol name, do not demangle names.\n"); 2077a85fe12eSEd Maste 2078a85fe12eSEd Maste exit(exitcode); 2079a85fe12eSEd Maste } 2080a85fe12eSEd Maste 2081a85fe12eSEd Maste /* 2082a85fe12eSEd Maste * Display symbolic information in file. 2083a85fe12eSEd Maste * Return 0 at success, >0 at failed. 2084a85fe12eSEd Maste */ 2085a85fe12eSEd Maste int 2086a85fe12eSEd Maste main(int argc, char **argv) 2087a85fe12eSEd Maste { 2088a85fe12eSEd Maste int rtn; 2089a85fe12eSEd Maste 2090a85fe12eSEd Maste global_init(); 2091a85fe12eSEd Maste get_opt(argc, argv); 2092a85fe12eSEd Maste rtn = read_files(argc - optind, argv + optind); 2093a85fe12eSEd Maste global_dest(); 2094a85fe12eSEd Maste 2095a85fe12eSEd Maste exit(rtn); 2096a85fe12eSEd Maste } 2097