1330449Seadler/*-
2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3330449Seadler *
429042Sjdp * Copyright (C) 1996-1997 John D. Polstra.  All rights reserved.
518600Speter *
618600Speter * Redistribution and use in source and binary forms, with or without
718600Speter * modification, are permitted provided that the following conditions
818600Speter * are met:
918600Speter * 1. Redistributions of source code must retain the above copyright
1018600Speter *    notice, this list of conditions and the following disclaimer.
1118600Speter * 2. Redistributions in binary form must reproduce the above copyright
1218600Speter *    notice, this list of conditions and the following disclaimer in the
1318600Speter *    documentation and/or other materials provided with the distribution.
1418600Speter *
1518600Speter * THIS SOFTWARE IS PROVIDED BY JOHN D. POLSTRA AND CONTRIBUTORS ``AS IS'' AND
1618600Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1718600Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1818600Speter * ARE DISCLAIMED.  IN NO EVENT SHALL JOHN D. POLSTRA OR CONTRIBUTORS BE LIABLE
1918600Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2018600Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2118600Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2218600Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2318600Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2418600Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2518600Speter * SUCH DAMAGE.
2618600Speter */
2718600Speter
2895648Smarkm#include <sys/cdefs.h>
2995648Smarkm__FBSDID("$FreeBSD: stable/11/usr.bin/ldd/sods.c 335521 2018-06-22 00:30:24Z emaste $");
3069827Scharnier
3195648Smarkm#include <sys/types.h>
3295648Smarkm#include <sys/mman.h>
3395648Smarkm#include <sys/stat.h>
3495648Smarkm
3595648Smarkm#include <machine/elf.h>
3695648Smarkm
3795153Smike#include <arpa/inet.h>
3895648Smarkm
3995648Smarkm#include <a.out.h>
4018600Speter#include <assert.h>
4118600Speter#include <ctype.h>
4269827Scharnier#include <err.h>
4318600Speter#include <fcntl.h>
44103436Speter#include <sys/link_aout.h>
4595648Smarkm#include <stab.h>
4618600Speter#include <stdio.h>
4718600Speter#include <stdlib.h>
48125857Sdwmalone#include <string.h>
4918600Speter#include <unistd.h>
5018600Speter
5195648Smarkm#include "extern.h"
5218600Speter
5329042Sjdp#define PAGE_SIZE	4096	/* i386 specific */
5429042Sjdp
5518600Speter#ifndef N_SETA
5618600Speter#define	N_SETA	0x14		/* Absolute set element symbol */
5718600Speter#endif				/* This is input to LD, in a .o file.  */
5818600Speter
5918600Speter#ifndef N_SETT
6018600Speter#define	N_SETT	0x16		/* Text set element symbol */
6118600Speter#endif				/* This is input to LD, in a .o file.  */
6218600Speter
6318600Speter#ifndef N_SETD
6418600Speter#define	N_SETD	0x18		/* Data set element symbol */
6518600Speter#endif				/* This is input to LD, in a .o file. */
6618600Speter
6718600Speter#ifndef N_SETB
6818600Speter#define	N_SETB	0x1A		/* Bss set element symbol */
6918600Speter#endif				/* This is input to LD, in a .o file. */
7018600Speter
7118600Speter#ifndef N_SETV
7218600Speter#define N_SETV	0x1C		/* Pointer to set vector in data area. */
7318600Speter#endif				/* This is output from LD. */
7418600Speter
7518600Speter#ifdef STANDALONE
7618600Speterstatic
7718600Speter#endif
7818600Speter
7918600Speterstatic void dump_rels(const char *, const struct relocation_info *,
8018600Speter    unsigned long, const char *(*)(unsigned long), unsigned char *);
8195648Smarkmstatic void dump_segs(void);
8295648Smarkmstatic void dump_sods(void);
8318600Speterstatic void dump_sym(const struct nlist *);
8495648Smarkmstatic void dump_syms(void);
8518600Speter
8695648Smarkmstatic void dump_rtsyms(void);
8718600Speter
8818600Speterstatic const char *rtsym_name(unsigned long);
8918600Speterstatic const char *sym_name(unsigned long);
9018600Speter
9118600Speter#ifdef STANDALONE
9218600Speterstatic
9318600Speter#endif
9418600Speterint error_count;
9518600Speter
9618600Speter/*
9718600Speter * Variables ending in _base are pointers to things in our address space,
9818600Speter * i.e., in the file itself.
9918600Speter *
10018600Speter * Variables ending in _addr are adjusted according to where things would
10118600Speter * actually appear in memory if the file were loaded.
10218600Speter */
10318600Speterstatic const char *file_base;
10418600Speterstatic const char *text_base;
10518600Speterstatic const char *data_base;
10618600Speterstatic const struct relocation_info *rel_base;
10718600Speterstatic const struct nlist *sym_base;
10818600Speterstatic const char *str_base;
10918600Speter
11018600Speterstatic const struct relocation_info *rtrel_base;
11118600Speterstatic const struct nzlist *rtsym_base;
11218600Speterstatic const char *rtstr_base;
11318600Speter
11418600Speterstatic const struct exec *ex;
11518600Speterstatic const struct _dynamic *dyn;
11618600Speterstatic const struct section_dispatch_table *sdt;
11718600Speter
11818600Speterstatic const char *text_addr;
11918600Speterstatic const char *data_addr;
12018600Speter
12118600Speterstatic unsigned long rel_count;
12218600Speterstatic unsigned long sym_count;
12318600Speter
12418600Speterstatic unsigned long rtrel_count;
12518600Speterstatic unsigned long rtsym_count;
12618600Speter
12718600Speter/* Dynamically allocated flags, 1 byte per symbol, to record whether each
12818600Speter   symbol was referenced by a relocation entry. */
12918600Speterstatic unsigned char *sym_used;
13018600Speterstatic unsigned char *rtsym_used;
13118600Speter
13218600Speterstatic unsigned long origin;	/* What values are relocated relative to */
13318600Speter
13418600Speter#ifdef STANDALONE
13569827Scharnierint
13618600Spetermain(int argc, char *argv[])
13718600Speter{
13818600Speter    int i;
13918600Speter
14029042Sjdp    for (i = 1;  i < argc;  ++i)
14118600Speter	dump_file(argv[i]);
14218600Speter
14318600Speter    return error_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
14418600Speter}
14518600Speter#endif
14618600Speter
147223262Sbenlstatic inline const void *align_struct(const void *expr)
148223262Sbenl{
149223262Sbenl  assert(!(((int)expr) & 3));
150223262Sbenl  return expr;
151223262Sbenl}
152223262Sbenl
153223262Sbenlstatic inline const void *align_long(const void *expr)
154223262Sbenl{
155223262Sbenl  assert(!(((int)expr) & 3));
156223262Sbenl  return expr;
157223262Sbenl}
158223262Sbenl
159223262Sbenlstatic inline const void *align_short(const void *expr)
160223262Sbenl{
161223262Sbenl  assert(!(((int)expr) & 1));
162223262Sbenl  return expr;
163223262Sbenl}
164223262Sbenl
16518600Speter#ifdef STANDALONE
16618600Speterstatic
16718600Speter#endif
16818600Spetervoid
16918600Speterdump_file(const char *fname)
17018600Speter{
17118600Speter    int fd;
17218600Speter    struct stat sb;
17318600Speter    caddr_t objbase;
17418600Speter
17529042Sjdp    if (stat(fname, &sb) == -1) {
17669827Scharnier	warnx("cannot stat \"%s\"", fname);
17769827Scharnier	++error_count;
17818600Speter	return;
17918600Speter    }
18018600Speter
18129042Sjdp    if ((sb.st_mode & S_IFMT) != S_IFREG) {
18269827Scharnier	warnx("\"%s\" is not a regular file", fname);
18369827Scharnier	++error_count;
18418600Speter	return;
18518600Speter    }
18618600Speter
18729042Sjdp    if ((fd = open(fname, O_RDONLY, 0)) == -1) {
18869827Scharnier	warnx("cannot open \"%s\"", fname);
18969827Scharnier	++error_count;
19018600Speter	return;
19118600Speter    }
19218600Speter
19318600Speter    objbase = mmap(0, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
19429042Sjdp    if (objbase == (caddr_t) -1) {
19569827Scharnier	warnx("cannot mmap \"%s\"", fname);
19669827Scharnier	++error_count;
19718600Speter	close(fd);
19818600Speter	return;
19918600Speter    }
20018600Speter
20118600Speter    close(fd);
20218600Speter
20318600Speter    file_base = (const char *) objbase;	/* Makes address arithmetic easier */
20418600Speter
205223262Sbenl    if (IS_ELF(*(const Elf32_Ehdr*) align_struct(file_base))) {
206335521Semaste	warnx("%s: this is an ELF program; use readelf to examine", fname);
20769827Scharnier	++error_count;
20835575Sdfr	munmap(objbase, sb.st_size);
20935575Sdfr	return;
21035575Sdfr    }
21135575Sdfr
212223262Sbenl    ex = (const struct exec *) align_struct(file_base);
21318600Speter
214131291Sdwmalone    printf("%s: a_midmag = 0x%lx\n", fname, (long)ex->a_midmag);
21529042Sjdp    printf("  magic = 0x%lx = 0%lo, netmagic = 0x%lx = 0%lo\n",
216131291Sdwmalone	(long)N_GETMAGIC(*ex), (long)N_GETMAGIC(*ex),
21785647Sdillon	(long)N_GETMAGIC_NET(*ex), (long)N_GETMAGIC_NET(*ex));
21818600Speter
21929042Sjdp    if (N_BADMAG(*ex)) {
22069827Scharnier	warnx("%s: bad magic number", fname);
22169827Scharnier	++error_count;
22218600Speter	munmap(objbase, sb.st_size);
22318600Speter	return;
22418600Speter    }
22518600Speter
226131291Sdwmalone    printf("  a_text   = 0x%lx\n", (long)ex->a_text);
227131291Sdwmalone    printf("  a_data   = 0x%lx\n", (long)ex->a_data);
228131291Sdwmalone    printf("  a_bss    = 0x%lx\n", (long)ex->a_bss);
229131291Sdwmalone    printf("  a_syms   = 0x%lx\n", (long)ex->a_syms);
230131291Sdwmalone    printf("  a_entry  = 0x%lx\n", (long)ex->a_entry);
231131291Sdwmalone    printf("  a_trsize = 0x%lx\n", (long)ex->a_trsize);
232131291Sdwmalone    printf("  a_drsize = 0x%lx\n", (long)ex->a_drsize);
23318600Speter
23418600Speter    text_base = file_base + N_TXTOFF(*ex);
23518600Speter    data_base = file_base + N_DATOFF(*ex);
236223262Sbenl    rel_base = (const struct relocation_info *)
237223262Sbenl	align_struct(file_base + N_RELOFF(*ex));
238223262Sbenl    sym_base = (const struct nlist *) align_struct(file_base + N_SYMOFF(*ex));
23918600Speter    str_base = file_base + N_STROFF(*ex);
24018600Speter
24118600Speter    rel_count = (ex->a_trsize + ex->a_drsize) / sizeof rel_base[0];
24218600Speter    assert(rel_count * sizeof rel_base[0] == ex->a_trsize + ex->a_drsize);
24318600Speter    sym_count = ex->a_syms / sizeof sym_base[0];
24418600Speter    assert(sym_count * sizeof sym_base[0] == ex->a_syms);
24518600Speter
24629042Sjdp    if (sym_count != 0) {
24718600Speter	sym_used = (unsigned char *) calloc(sym_count, sizeof(unsigned char));
24818600Speter	assert(sym_used != NULL);
24918600Speter    }
25018600Speter
251131291Sdwmalone    printf("  Entry = 0x%lx\n", (long)ex->a_entry);
25235575Sdfr    printf("  Text offset = %x, address = %lx\n", N_TXTOFF(*ex),
253131291Sdwmalone	(long)N_TXTADDR(*ex));
254131291Sdwmalone    printf("  Data offset = %lx, address = %lx\n", (long)N_DATOFF(*ex),
255131291Sdwmalone	(long)N_DATADDR(*ex));
25618600Speter
25718600Speter    /*
25818600Speter     * In an executable program file, everything is relocated relative to
25918600Speter     * the assumed run-time load address, i.e., N_TXTADDR(*ex), i.e., 0x1000.
26018600Speter     *
26118600Speter     * In a shared library file, everything is relocated relative to the
26218600Speter     * start of the file, i.e., N_TXTOFF(*ex), i.e., 0.
26318600Speter     *
26418600Speter     * The way to tell the difference is by looking at ex->a_entry.   If it
26518600Speter     * is >= 0x1000, then we have an executable program.  Otherwise, we
26618600Speter     * have a shared library.
26718600Speter     *
26818600Speter     * When a program is executed, the entire file is mapped into memory,
26918600Speter     * including the a.out header and so forth.  But it is not mapped at
27018600Speter     * address 0; rather it is mapped at address 0x1000.  The first page
27118600Speter     * of the user's address space is left unmapped in order to catch null
27218600Speter     * pointer dereferences.
27318600Speter     *
27418600Speter     * In this program, when we map in an executable program, we have to
27518600Speter     * simulate the empty page by decrementing our assumed base address by
27618600Speter     * a pagesize.
27718600Speter     */
27818600Speter
27918600Speter    text_addr = text_base;
28018600Speter    data_addr = data_base;
28118600Speter    origin = 0;
28218600Speter
28329042Sjdp    if (ex->a_entry >= PAGE_SIZE) {	/* Executable, not a shared library */
28418600Speter	/*
28518600Speter	 * The fields in the object have already been relocated on the
28618600Speter	 * assumption that the object will be loaded at N_TXTADDR(*ex).
28718600Speter	 * We have to compensate for that.
28818600Speter	 */
28929042Sjdp	text_addr -= PAGE_SIZE;
29029042Sjdp	data_addr -= PAGE_SIZE;
29129042Sjdp	origin = PAGE_SIZE;
29218600Speter	printf("  Program, origin = %lx\n", origin);
29329042Sjdp    } else if (N_GETFLAG(*ex) & EX_DYNAMIC)
29429042Sjdp	printf("  Shared library, origin = %lx\n", origin);
29529042Sjdp    else
29629042Sjdp	printf("  Object file, origin = %lx\n", origin);
29718600Speter
29829042Sjdp    if (N_GETFLAG(*ex) & EX_DYNAMIC) {
299223262Sbenl	dyn = (const struct _dynamic *) align_struct(data_base);
30029042Sjdp	printf("  Dynamic version = %d\n", dyn->d_version);
30129042Sjdp
30218600Speter	sdt = (const struct section_dispatch_table *)
303223262Sbenl	    align_struct(text_addr + (unsigned long) dyn->d_un.d_sdt);
30418600Speter
305223262Sbenl	rtrel_base = (const struct relocation_info *)
306223262Sbenl	    align_struct(text_addr + sdt->sdt_rel);
30718600Speter	rtrel_count = (sdt->sdt_hash - sdt->sdt_rel) / sizeof rtrel_base[0];
30818600Speter	assert(rtrel_count * sizeof rtrel_base[0] ==
309125857Sdwmalone	    (size_t)(sdt->sdt_hash - sdt->sdt_rel));
31018600Speter
311223262Sbenl	rtsym_base = (const struct nzlist *)
312223262Sbenl	    align_struct(text_addr + sdt->sdt_nzlist);
31318600Speter	rtsym_count = (sdt->sdt_strings - sdt->sdt_nzlist) /
31418600Speter	    sizeof rtsym_base[0];
31518600Speter	assert(rtsym_count * sizeof rtsym_base[0] ==
316125857Sdwmalone	    (size_t)(sdt->sdt_strings - sdt->sdt_nzlist));
31718600Speter
31829042Sjdp	if (rtsym_count != 0) {
31918600Speter	    rtsym_used = (unsigned char *) calloc(rtsym_count,
32018600Speter		sizeof(unsigned char));
32118600Speter	    assert(rtsym_used != NULL);
32218600Speter	}
32318600Speter
32418600Speter	rtstr_base = text_addr + sdt->sdt_strings;
32518600Speter    }
32618600Speter
32718600Speter    dump_segs();
32818600Speter    dump_sods();
32918600Speter    dump_rels("Relocations", rel_base, rel_count, sym_name, sym_used);
33018600Speter    dump_syms();
33118600Speter
33218600Speter    dump_rels("Run-time relocations", rtrel_base, rtrel_count, rtsym_name,
33318600Speter	rtsym_used);
33418600Speter    dump_rtsyms();
33518600Speter
33629042Sjdp    if (rtsym_used != NULL) {
33718600Speter	free(rtsym_used);
33818600Speter	rtsym_used = NULL;
33918600Speter    }
34029042Sjdp    if (sym_used != NULL) {
34118600Speter	free(sym_used);
34218600Speter	sym_used = NULL;
34318600Speter    }
34418600Speter    munmap(objbase, sb.st_size);
34518600Speter}
34618600Speter
34718600Speterstatic void
34818600Speterdump_rels(const char *label, const struct relocation_info *base,
34918600Speter    unsigned long count, const char *(*name)(unsigned long),
35018600Speter    unsigned char *sym_used_flags)
35118600Speter{
35218600Speter    unsigned long i;
35318600Speter
35418600Speter    printf("  %s:\n", label);
35529042Sjdp    for (i = 0;  i < count;  ++i) {
35618600Speter	const struct relocation_info *r = &base[i];
35729042Sjdp	unsigned int size;
35829042Sjdp	char contents[16];
35918600Speter
36029042Sjdp	size = 1u << r->r_length;
36129042Sjdp
362125857Sdwmalone	if (origin <= (unsigned long)r->r_address
363125857Sdwmalone	  && (unsigned long)r->r_address < origin + ex->a_text + ex->a_data
36429042Sjdp	  && 1 <= size && size <= 4) {
36529042Sjdp	    /*
36629042Sjdp	     * XXX - This can cause unaligned accesses.  OK for the
36729042Sjdp	     * i386, not so for other architectures.
36829042Sjdp	     */
36929042Sjdp	    switch (size) {
37029042Sjdp	    case 1:
37129042Sjdp		snprintf(contents, sizeof contents, "      [%02x]",
37295648Smarkm		  *(unsigned const char *)(text_addr + r->r_address));
37329042Sjdp		break;
37429042Sjdp	    case 2:
37529042Sjdp		snprintf(contents, sizeof contents, "    [%04x]",
376223262Sbenl			 *(unsigned const short *)
377223262Sbenl			 align_short(text_addr + r->r_address));
37829042Sjdp		break;
37929042Sjdp	    case 4:
38029042Sjdp		snprintf(contents, sizeof contents, "[%08lx]",
381223262Sbenl			 *(unsigned const long *)
382223262Sbenl			 align_long(text_addr + r->r_address));
38329042Sjdp		break;
38429042Sjdp	    }
38529042Sjdp	} else
38629042Sjdp	    snprintf(contents, sizeof contents, "          ");
38729042Sjdp
38829042Sjdp	printf("    %6lu %8x/%u %s %c%c%c%c%c%c", i,
38929042Sjdp	    r->r_address, size,
39029042Sjdp	    contents,
39118600Speter	    r->r_extern   ? 'e' : '-',
39218600Speter	    r->r_jmptable ? 'j' : '-',
39318600Speter	    r->r_relative ? 'r' : '-',
39418600Speter	    r->r_baserel  ? 'b' : '-',
39518600Speter	    r->r_pcrel    ? 'p' : '-',
39618600Speter	    r->r_copy     ? 'c' : '-');
39718600Speter
39829042Sjdp	if (r->r_extern || r->r_baserel || r->r_jmptable || r->r_copy) {
39918600Speter	    printf(" %4u %s", r->r_symbolnum, name(r->r_symbolnum));
40018600Speter	    sym_used_flags[r->r_symbolnum] = 1;
40118600Speter	}
40218600Speter
40318600Speter	printf("\n");
40418600Speter    }
40518600Speter}
40618600Speter
40718600Speterstatic void
40895648Smarkmdump_rtsyms(void)
40918600Speter{
41018600Speter    unsigned long i;
41118600Speter
41218600Speter    printf("  Run-time symbols:\n");
41329042Sjdp    for (i = 0;  i < rtsym_count;  ++i) {
41418600Speter	printf("    %6lu%c ", i, rtsym_used[i] ? '*' : ' ');
41518600Speter	dump_sym(&rtsym_base[i].nlist);
41618600Speter	printf("/%-5ld %s\n", rtsym_base[i].nz_size, rtsym_name(i));
41718600Speter    }
41818600Speter}
41918600Speter
42018600Speterstatic void
42195648Smarkmdump_segs(void)
42218600Speter{
42318600Speter    printf("  Text segment starts at address %lx\n", origin + N_TXTOFF(*ex));
42429042Sjdp    if (N_GETFLAG(*ex) & EX_DYNAMIC) {
42518600Speter	printf("    rel starts at %lx\n", sdt->sdt_rel);
42618600Speter	printf("    hash starts at %lx\n", sdt->sdt_hash);
42718600Speter	printf("    nzlist starts at %lx\n", sdt->sdt_nzlist);
42818600Speter	printf("    strings starts at %lx\n", sdt->sdt_strings);
42918600Speter    }
43018600Speter
43118600Speter    printf("  Data segment starts at address %lx\n", origin + N_DATOFF(*ex));
43229042Sjdp    if (N_GETFLAG(*ex) & EX_DYNAMIC) {
43318600Speter	printf("    _dynamic starts at %lx\n", origin + N_DATOFF(*ex));
43418600Speter	printf("    so_debug starts at %lx\n", (unsigned long) dyn->d_debug);
43518600Speter	printf("    sdt starts at %lx\n", (unsigned long) dyn->d_un.d_sdt);
43618600Speter	printf("    got starts at %lx\n", sdt->sdt_got);
43718600Speter	printf("    plt starts at %lx\n", sdt->sdt_plt);
43818600Speter	printf("    rest of stuff starts at %lx\n",
43918600Speter	    sdt->sdt_plt + sdt->sdt_plt_sz);
44018600Speter    }
44118600Speter}
44218600Speter
44318600Speterstatic void
44495648Smarkmdump_sods(void)
44518600Speter{
44618600Speter    long sod_offset;
44718600Speter    long paths_offset;
44818600Speter
44929042Sjdp    if (dyn == NULL)		/* Not a shared object */
45018600Speter	return;
45118600Speter
45218600Speter    sod_offset = sdt->sdt_sods;
45318600Speter    printf("  Shared object dependencies:\n");
45429042Sjdp    while (sod_offset != 0) {
455223262Sbenl      const struct sod *sodp = (const struct sod *) align_struct((text_addr + sod_offset));
45618600Speter	const char *name = (const char *) (text_addr + sodp->sod_name);
45718600Speter
45821469Sjdp	if (sodp->sod_library)
45921469Sjdp	    printf("    -l%-16s version %d.%d\n", name, sodp->sod_major,
46021469Sjdp		sodp->sod_minor);
46121469Sjdp	else
46221469Sjdp	    printf("    %s\n", name);
46318600Speter	sod_offset = sodp->sod_next;
46418600Speter    }
46518600Speter    paths_offset = sdt->sdt_paths;
46618600Speter    printf("  Shared object additional paths:\n");
46718600Speter    if (paths_offset != 0) {
46895648Smarkm	printf("    %s\n", (const char *)(text_addr + paths_offset));
46918600Speter    } else {
47029042Sjdp	printf("    (none)\n");
47118600Speter    }
47218600Speter}
47318600Speter
47418600Speterstatic void
47518600Speterdump_sym(const struct nlist *np)
47618600Speter{
47718600Speter    char type[8];
47831442Sjdp    char aux[8];
47929042Sjdp    char weak;
48018600Speter    char *p;
48118600Speter
48229042Sjdp    switch (np->n_type & ~N_EXT) {
48318600Speter    case N_UNDF:	strcpy(type, "undf");  break;
48418600Speter    case N_ABS:		strcpy(type, "abs");  break;
48518600Speter    case N_TEXT:	strcpy(type, "text");  break;
48618600Speter    case N_DATA:	strcpy(type, "data");  break;
48718600Speter    case N_BSS:		strcpy(type, "bss");  break;
48818600Speter    case N_INDR:	strcpy(type, "indr");  break;
48918600Speter    case N_SIZE:	strcpy(type, "size");  break;
49018600Speter    case N_COMM:	strcpy(type, "comm");  break;
49118600Speter    case N_SETA:	strcpy(type, "seta");  break;
49218600Speter    case N_SETT:	strcpy(type, "sett");  break;
49318600Speter    case N_SETD:	strcpy(type, "setd");  break;
49418600Speter    case N_SETB:	strcpy(type, "setb");  break;
49518600Speter    case N_SETV:	strcpy(type, "setv");  break;
49618600Speter    case N_FN:		strcpy(type, np->n_type&N_EXT ? "fn" : "warn");  break;
49718600Speter    case N_GSYM:	strcpy(type, "gsym");  break;
49818600Speter    case N_FNAME:	strcpy(type, "fname");  break;
49918600Speter    case N_FUN:		strcpy(type, "fun");  break;
50018600Speter    case N_STSYM:	strcpy(type, "stsym");  break;
50118600Speter    case N_LCSYM:	strcpy(type, "lcsym");  break;
50218600Speter    case N_MAIN:	strcpy(type, "main");  break;
50318600Speter    case N_PC:		strcpy(type, "pc");  break;
50418600Speter    case N_RSYM:	strcpy(type, "rsym");  break;
50518600Speter    case N_SLINE:	strcpy(type, "sline");  break;
50618600Speter    case N_DSLINE:	strcpy(type, "dsline");  break;
50718600Speter    case N_BSLINE:	strcpy(type, "bsline");  break;
50818600Speter    case N_SSYM:	strcpy(type, "ssym");  break;
50918600Speter    case N_SO:		strcpy(type, "so");  break;
51018600Speter    case N_LSYM:	strcpy(type, "lsym");  break;
51118600Speter    case N_BINCL:	strcpy(type, "bincl");  break;
51218600Speter    case N_SOL:		strcpy(type, "sol");  break;
51318600Speter    case N_PSYM:	strcpy(type, "psym");  break;
51418600Speter    case N_EINCL:	strcpy(type, "eincl");  break;
51518600Speter    case N_ENTRY:	strcpy(type, "entry");  break;
51618600Speter    case N_LBRAC:	strcpy(type, "lbrac");  break;
51718600Speter    case N_EXCL:	strcpy(type, "excl");  break;
51818600Speter    case N_RBRAC:	strcpy(type, "rbrac");  break;
51918600Speter    case N_BCOMM:	strcpy(type, "bcomm");  break;
52018600Speter    case N_ECOMM:	strcpy(type, "ecomm");  break;
52118600Speter    case N_ECOML:	strcpy(type, "ecoml");  break;
52218600Speter    case N_LENG:	strcpy(type, "leng");  break;
52331442Sjdp    default:
52431442Sjdp	snprintf(type, sizeof type, "%#02x", np->n_type);
52531442Sjdp	break;
52618600Speter    }
52718600Speter
52829042Sjdp    if (np->n_type & N_EXT && type[0] != '0')
52929042Sjdp	for (p = type;  *p != '\0';  ++p)
53018600Speter	    *p = toupper(*p);
53118600Speter
53231442Sjdp    switch (N_AUX(np)) {
53331442Sjdp    case 0:		strcpy(aux, "");  break;
53431442Sjdp    case AUX_OBJECT:	strcpy(aux, "objt");  break;
53531442Sjdp    case AUX_FUNC:	strcpy(aux, "func");  break;
53631442Sjdp    default:		snprintf(aux, sizeof aux, "%#01x", N_AUX(np));  break;
53731442Sjdp    }
53831442Sjdp
53929042Sjdp    weak = N_BIND(np) == BIND_WEAK ? 'w' : ' ';
54029042Sjdp
54131442Sjdp    printf("%c%-6s %-4s %8lx", weak, type, aux, np->n_value);
54218600Speter}
54318600Speter
54418600Speterstatic void
54595648Smarkmdump_syms(void)
54618600Speter{
54718600Speter    unsigned long i;
54818600Speter
54918600Speter    printf("  Symbols:\n");
55029042Sjdp    for (i = 0;  i < sym_count;  ++i) {
55118600Speter	printf("    %6lu%c ", i, sym_used[i] ? '*' : ' ');
55218600Speter	dump_sym(&sym_base[i]);
55318600Speter	printf(" %s\n", sym_name(i));
55418600Speter    }
55518600Speter}
55618600Speter
55718600Speterstatic const char *
55818600Speterrtsym_name(unsigned long n)
55918600Speter{
56018600Speter    assert(n < rtsym_count);
56129042Sjdp    if (rtsym_base[n].nz_strx == 0)
56218600Speter	return "";
56318600Speter    return rtstr_base + rtsym_base[n].nz_strx;
56418600Speter}
56518600Speter
56618600Speterstatic const char *
56718600Spetersym_name(unsigned long n)
56818600Speter{
56918600Speter    assert(n < sym_count);
57029042Sjdp    if (sym_base[n].n_un.n_strx == 0)
57118600Speter	return "";
57218600Speter    return str_base + sym_base[n].n_un.n_strx;
57318600Speter}
574