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