sods.c revision 29042
168651Skris/* 268651Skris * Copyright (C) 1996-1997 John D. Polstra. All rights reserved. 368651Skris * 468651Skris * Redistribution and use in source and binary forms, with or without 568651Skris * modification, are permitted provided that the following conditions 668651Skris * are met: 768651Skris * 1. Redistributions of source code must retain the above copyright 8296465Sdelphij * notice, this list of conditions and the following disclaimer. 968651Skris * 2. Redistributions in binary form must reproduce the above copyright 1068651Skris * notice, this list of conditions and the following disclaimer in the 1168651Skris * documentation and/or other materials provided with the distribution. 1268651Skris * 1368651Skris * THIS SOFTWARE IS PROVIDED BY JOHN D. POLSTRA AND CONTRIBUTORS ``AS IS'' AND 1468651Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15296465Sdelphij * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1668651Skris * ARE DISCLAIMED. IN NO EVENT SHALL JOHN D. POLSTRA OR CONTRIBUTORS BE LIABLE 1768651Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1868651Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 1968651Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2068651Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2168651Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22296465Sdelphij * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2368651Skris * SUCH DAMAGE. 2468651Skris * 2568651Skris * $Id: sods.c,v 1.4 1997/02/22 15:46:44 peter Exp $ 2668651Skris */ 2768651Skris 2868651Skris#include <assert.h> 2968651Skris#include <ctype.h> 3068651Skris#include <fcntl.h> 3168651Skris#include <stdarg.h> 3268651Skris#include <stdio.h> 3368651Skris#include <stdlib.h> 3468651Skris#include <string.h> 3568651Skris#include <unistd.h> 3668651Skris 37296465Sdelphij#include <sys/types.h> 3868651Skris#include <sys/mman.h> 3968651Skris#include <sys/stat.h> 40296465Sdelphij 4168651Skris#include <a.out.h> 4268651Skris#include <link.h> 4368651Skris#include <stab.h> 4468651Skris 4568651Skris#define PAGE_SIZE 4096 /* i386 specific */ 4668651Skris 4768651Skris#ifndef N_SETA 4868651Skris#define N_SETA 0x14 /* Absolute set element symbol */ 4968651Skris#endif /* This is input to LD, in a .o file. */ 5068651Skris 5168651Skris#ifndef N_SETT 52296465Sdelphij#define N_SETT 0x16 /* Text set element symbol */ 5368651Skris#endif /* This is input to LD, in a .o file. */ 5468651Skris 5568651Skris#ifndef N_SETD 5668651Skris#define N_SETD 0x18 /* Data set element symbol */ 5768651Skris#endif /* This is input to LD, in a .o file. */ 5868651Skris 5968651Skris#ifndef N_SETB 6068651Skris#define N_SETB 0x1A /* Bss set element symbol */ 6168651Skris#endif /* This is input to LD, in a .o file. */ 6268651Skris 63160814Ssimon#ifndef N_SETV 6468651Skris#define N_SETV 0x1C /* Pointer to set vector in data area. */ 6568651Skris#endif /* This is output from LD. */ 6668651Skris 6768651Skris#ifdef STANDALONE 6868651Skrisstatic 6968651Skris#endif 7068651Skrisvoid dump_file(const char *); 7168651Skris 7268651Skrisstatic void dump_rels(const char *, const struct relocation_info *, 7368651Skris unsigned long, const char *(*)(unsigned long), unsigned char *); 7468651Skrisstatic void dump_segs(); 75296465Sdelphijstatic void dump_sods(); 7668651Skrisstatic void dump_sym(const struct nlist *); 7768651Skrisstatic void dump_syms(); 78296465Sdelphij 7968651Skrisstatic void dump_rtsyms(); 8068651Skris 8168651Skrisstatic void error(const char *, ...); 8268651Skrisstatic const char *rtsym_name(unsigned long); 8368651Skrisstatic const char *sym_name(unsigned long); 8468651Skris 85109998Smarkm#ifdef STANDALONE 86109998Smarkmstatic 87109998Smarkm#endif 88109998Smarkmint error_count; 89109998Smarkm 9068651Skris/* 91296465Sdelphij * Variables ending in _base are pointers to things in our address space, 9268651Skris * i.e., in the file itself. 9368651Skris * 94296465Sdelphij * Variables ending in _addr are adjusted according to where things would 95296465Sdelphij * actually appear in memory if the file were loaded. 96296465Sdelphij */ 97296465Sdelphijstatic const char *file_base; 98296465Sdelphijstatic const char *text_base; 99296465Sdelphijstatic const char *data_base; 100296465Sdelphijstatic const struct relocation_info *rel_base; 101296465Sdelphijstatic const struct nlist *sym_base; 102296465Sdelphijstatic const char *str_base; 103296465Sdelphij 104296465Sdelphijstatic const struct relocation_info *rtrel_base; 10568651Skrisstatic const struct nzlist *rtsym_base; 10668651Skrisstatic const char *rtstr_base; 107296465Sdelphij 108296465Sdelphijstatic const struct exec *ex; 109296465Sdelphijstatic const struct _dynamic *dyn; 110296465Sdelphijstatic const struct section_dispatch_table *sdt; 111296465Sdelphij 112296465Sdelphijstatic const char *text_addr; 113296465Sdelphijstatic const char *data_addr; 114296465Sdelphij 115296465Sdelphijstatic unsigned long rel_count; 116296465Sdelphijstatic unsigned long sym_count; 117296465Sdelphij 11868651Skrisstatic unsigned long rtrel_count; 11968651Skrisstatic unsigned long rtsym_count; 120296465Sdelphij 121296465Sdelphij/* Dynamically allocated flags, 1 byte per symbol, to record whether each 122296465Sdelphij symbol was referenced by a relocation entry. */ 123296465Sdelphijstatic unsigned char *sym_used; 12468651Skrisstatic unsigned char *rtsym_used; 125296465Sdelphij 126296465Sdelphijstatic unsigned long origin; /* What values are relocated relative to */ 127296465Sdelphij 12868651Skris#ifdef STANDALONE 12968651Skrismain(int argc, char *argv[]) 130296465Sdelphij{ 131296465Sdelphij int i; 13268651Skris 133296465Sdelphij for (i = 1; i < argc; ++i) 134296465Sdelphij dump_file(argv[i]); 135296465Sdelphij 136296465Sdelphij return error_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE; 137296465Sdelphij} 138296465Sdelphij#endif 139296465Sdelphij 140296465Sdelphij#ifdef STANDALONE 141296465Sdelphijstatic 14268651Skris#endif 143296465Sdelphijvoid 144296465Sdelphijdump_file(const char *fname) 145296465Sdelphij{ 14668651Skris int fd; 147296465Sdelphij struct stat sb; 148296465Sdelphij caddr_t objbase; 149296465Sdelphij 15068651Skris if (stat(fname, &sb) == -1) { 151296465Sdelphij error("Cannot stat \"%s\"", fname); 152296465Sdelphij return; 15368651Skris } 15468651Skris 155296465Sdelphij if ((sb.st_mode & S_IFMT) != S_IFREG) { 156296465Sdelphij error("\"%s\" is not a regular file", fname); 157296465Sdelphij return; 15868651Skris } 159296465Sdelphij 160296465Sdelphij if ((fd = open(fname, O_RDONLY, 0)) == -1) { 161296465Sdelphij error("Cannot open \"%s\"", fname); 16268651Skris return; 163296465Sdelphij } 164296465Sdelphij 16568651Skris objbase = mmap(0, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); 16668651Skris if (objbase == (caddr_t) -1) { 167296465Sdelphij error("Cannot mmap \"%s\"", fname); 168296465Sdelphij close(fd); 169296465Sdelphij return; 170296465Sdelphij } 171296465Sdelphij 172296465Sdelphij close(fd); 173296465Sdelphij 17468651Skris file_base = (const char *) objbase; /* Makes address arithmetic easier */ 17568651Skris 176296465Sdelphij ex = (const struct exec *) file_base; 177296465Sdelphij 178296465Sdelphij printf("%s: a_midmag = 0x%lx\n", fname, ex->a_midmag); 179296465Sdelphij printf(" magic = 0x%lx = 0%lo, netmagic = 0x%lx = 0%lo\n", 180296465Sdelphij N_GETMAGIC(*ex), N_GETMAGIC(*ex), 181296465Sdelphij N_GETMAGIC_NET(*ex), N_GETMAGIC_NET(*ex)); 18268651Skris 183109998Smarkm if (N_BADMAG(*ex)) { 184296465Sdelphij error("%s: Bad magic number", fname); 185296465Sdelphij munmap(objbase, sb.st_size); 186296465Sdelphij return; 187109998Smarkm } 188109998Smarkm 189296465Sdelphij printf(" a_text = 0x%lx\n", ex->a_text); 190109998Smarkm printf(" a_data = 0x%lx\n", ex->a_data); 191296465Sdelphij printf(" a_bss = 0x%lx\n", ex->a_bss); 192109998Smarkm printf(" a_syms = 0x%lx\n", ex->a_syms); 193296465Sdelphij printf(" a_entry = 0x%lx\n", ex->a_entry); 194296465Sdelphij printf(" a_trsize = 0x%lx\n", ex->a_trsize); 195296465Sdelphij printf(" a_drsize = 0x%lx\n", ex->a_drsize); 196296465Sdelphij 197296465Sdelphij text_base = file_base + N_TXTOFF(*ex); 198296465Sdelphij data_base = file_base + N_DATOFF(*ex); 199296465Sdelphij rel_base = (const struct relocation_info *) (file_base + N_RELOFF(*ex)); 200109998Smarkm sym_base = (const struct nlist *) (file_base + N_SYMOFF(*ex)); 201296465Sdelphij str_base = file_base + N_STROFF(*ex); 202296465Sdelphij 203109998Smarkm rel_count = (ex->a_trsize + ex->a_drsize) / sizeof rel_base[0]; 204296465Sdelphij assert(rel_count * sizeof rel_base[0] == ex->a_trsize + ex->a_drsize); 205296465Sdelphij sym_count = ex->a_syms / sizeof sym_base[0]; 206109998Smarkm assert(sym_count * sizeof sym_base[0] == ex->a_syms); 207109998Smarkm 208296465Sdelphij if (sym_count != 0) { 209109998Smarkm sym_used = (unsigned char *) calloc(sym_count, sizeof(unsigned char)); 210296465Sdelphij assert(sym_used != NULL); 211296465Sdelphij } 212296465Sdelphij 213296465Sdelphij printf(" Entry = 0x%lx\n", ex->a_entry); 214296465Sdelphij printf(" Text offset = %x, address = %x\n", N_TXTOFF(*ex), 215296465Sdelphij N_TXTADDR(*ex)); 216296465Sdelphij printf(" Data offset = %lx, address = %lx\n", N_DATOFF(*ex), 217296465Sdelphij N_DATADDR(*ex)); 218296465Sdelphij 219296465Sdelphij /* 220296465Sdelphij * In an executable program file, everything is relocated relative to 221296465Sdelphij * the assumed run-time load address, i.e., N_TXTADDR(*ex), i.e., 0x1000. 222296465Sdelphij * 223296465Sdelphij * In a shared library file, everything is relocated relative to the 22468651Skris * start of the file, i.e., N_TXTOFF(*ex), i.e., 0. 225296465Sdelphij * 226296465Sdelphij * The way to tell the difference is by looking at ex->a_entry. If it 227296465Sdelphij * is >= 0x1000, then we have an executable program. Otherwise, we 228296465Sdelphij * have a shared library. 22968651Skris * 230296465Sdelphij * When a program is executed, the entire file is mapped into memory, 231296465Sdelphij * including the a.out header and so forth. But it is not mapped at 232296465Sdelphij * address 0; rather it is mapped at address 0x1000. The first page 233296465Sdelphij * of the user's address space is left unmapped in order to catch null 234296465Sdelphij * pointer dereferences. 235296465Sdelphij * 23668651Skris * In this program, when we map in an executable program, we have to 237296465Sdelphij * simulate the empty page by decrementing our assumed base address by 238296465Sdelphij * a pagesize. 239296465Sdelphij */ 240296465Sdelphij 24168651Skris text_addr = text_base; 242296465Sdelphij data_addr = data_base; 243296465Sdelphij origin = 0; 244296465Sdelphij 245296465Sdelphij if (ex->a_entry >= PAGE_SIZE) { /* Executable, not a shared library */ 246296465Sdelphij /* 247296465Sdelphij * The fields in the object have already been relocated on the 24868651Skris * assumption that the object will be loaded at N_TXTADDR(*ex). 249296465Sdelphij * We have to compensate for that. 250296465Sdelphij */ 251296465Sdelphij text_addr -= PAGE_SIZE; 252296465Sdelphij data_addr -= PAGE_SIZE; 253296465Sdelphij origin = PAGE_SIZE; 254296465Sdelphij printf(" Program, origin = %lx\n", origin); 255296465Sdelphij } else if (N_GETFLAG(*ex) & EX_DYNAMIC) 256296465Sdelphij printf(" Shared library, origin = %lx\n", origin); 257296465Sdelphij else 258296465Sdelphij printf(" Object file, origin = %lx\n", origin); 259296465Sdelphij 260296465Sdelphij if (N_GETFLAG(*ex) & EX_DYNAMIC) { 261296465Sdelphij dyn = (const struct _dynamic *) data_base; 262296465Sdelphij printf(" Dynamic version = %d\n", dyn->d_version); 263296465Sdelphij 264296465Sdelphij sdt = (const struct section_dispatch_table *) 265296465Sdelphij (text_addr + (unsigned long) dyn->d_un.d_sdt); 266296465Sdelphij 267296465Sdelphij rtrel_base = 268296465Sdelphij (const struct relocation_info *) (text_addr + sdt->sdt_rel); 269296465Sdelphij rtrel_count = (sdt->sdt_hash - sdt->sdt_rel) / sizeof rtrel_base[0]; 270296465Sdelphij assert(rtrel_count * sizeof rtrel_base[0] == 271296465Sdelphij sdt->sdt_hash - sdt->sdt_rel); 272296465Sdelphij 273296465Sdelphij rtsym_base = (const struct nzlist *) (text_addr + sdt->sdt_nzlist); 274296465Sdelphij rtsym_count = (sdt->sdt_strings - sdt->sdt_nzlist) / 275296465Sdelphij sizeof rtsym_base[0]; 276296465Sdelphij assert(rtsym_count * sizeof rtsym_base[0] == 277296465Sdelphij sdt->sdt_strings - sdt->sdt_nzlist); 278296465Sdelphij 27968651Skris if (rtsym_count != 0) { 280296465Sdelphij rtsym_used = (unsigned char *) calloc(rtsym_count, 28168651Skris sizeof(unsigned char)); 282296465Sdelphij assert(rtsym_used != NULL); 283296465Sdelphij } 28468651Skris 285296465Sdelphij rtstr_base = text_addr + sdt->sdt_strings; 286296465Sdelphij } 287296465Sdelphij 288296465Sdelphij dump_segs(); 289296465Sdelphij dump_sods(); 290296465Sdelphij dump_rels("Relocations", rel_base, rel_count, sym_name, sym_used); 291296465Sdelphij dump_syms(); 292296465Sdelphij 293296465Sdelphij dump_rels("Run-time relocations", rtrel_base, rtrel_count, rtsym_name, 294296465Sdelphij rtsym_used); 295296465Sdelphij dump_rtsyms(); 296296465Sdelphij 297296465Sdelphij if (rtsym_used != NULL) { 298296465Sdelphij free(rtsym_used); 299296465Sdelphij rtsym_used = NULL; 300296465Sdelphij } 301296465Sdelphij if (sym_used != NULL) { 30268651Skris free(sym_used); 303296465Sdelphij sym_used = NULL; 304296465Sdelphij } 305296465Sdelphij munmap(objbase, sb.st_size); 306296465Sdelphij} 307296465Sdelphij 308296465Sdelphijstatic void 30968651Skrisdump_rels(const char *label, const struct relocation_info *base, 310296465Sdelphij unsigned long count, const char *(*name)(unsigned long), 311296465Sdelphij unsigned char *sym_used_flags) 312296465Sdelphij{ 313296465Sdelphij unsigned long i; 314296465Sdelphij 315296465Sdelphij printf(" %s:\n", label); 316296465Sdelphij for (i = 0; i < count; ++i) { 317296465Sdelphij const struct relocation_info *r = &base[i]; 318296465Sdelphij unsigned int size; 319296465Sdelphij char contents[16]; 320296465Sdelphij 321296465Sdelphij size = 1u << r->r_length; 322296465Sdelphij 323296465Sdelphij if (origin <= r->r_address 324296465Sdelphij && r->r_address < origin + ex->a_text + ex->a_data 325296465Sdelphij && 1 <= size && size <= 4) { 326296465Sdelphij /* 327296465Sdelphij * XXX - This can cause unaligned accesses. OK for the 328296465Sdelphij * i386, not so for other architectures. 329296465Sdelphij */ 330296465Sdelphij switch (size) { 331296465Sdelphij case 1: 332296465Sdelphij snprintf(contents, sizeof contents, " [%02x]", 333296465Sdelphij *(unsigned char *)(text_addr + r->r_address)); 334296465Sdelphij break; 335296465Sdelphij case 2: 336296465Sdelphij snprintf(contents, sizeof contents, " [%04x]", 337296465Sdelphij *(unsigned short *)(text_addr + r->r_address)); 338296465Sdelphij break; 339296465Sdelphij case 4: 340296465Sdelphij snprintf(contents, sizeof contents, "[%08lx]", 341296465Sdelphij *(unsigned long *)(text_addr + r->r_address)); 342296465Sdelphij break; 343296465Sdelphij } 344296465Sdelphij } else 345296465Sdelphij snprintf(contents, sizeof contents, " "); 346296465Sdelphij 347296465Sdelphij printf(" %6lu %8x/%u %s %c%c%c%c%c%c", i, 348296465Sdelphij r->r_address, size, 349296465Sdelphij contents, 350296465Sdelphij r->r_extern ? 'e' : '-', 351296465Sdelphij r->r_jmptable ? 'j' : '-', 352296465Sdelphij r->r_relative ? 'r' : '-', 353296465Sdelphij r->r_baserel ? 'b' : '-', 354296465Sdelphij r->r_pcrel ? 'p' : '-', 355296465Sdelphij r->r_copy ? 'c' : '-'); 356296465Sdelphij 357296465Sdelphij if (r->r_extern || r->r_baserel || r->r_jmptable || r->r_copy) { 358296465Sdelphij printf(" %4u %s", r->r_symbolnum, name(r->r_symbolnum)); 359296465Sdelphij sym_used_flags[r->r_symbolnum] = 1; 360296465Sdelphij } 361296465Sdelphij 362296465Sdelphij printf("\n"); 36368651Skris } 364296465Sdelphij} 365296465Sdelphij 366296465Sdelphijstatic void 367296465Sdelphijdump_rtsyms() 368296465Sdelphij{ 369296465Sdelphij unsigned long i; 370296465Sdelphij 371296465Sdelphij printf(" Run-time symbols:\n"); 372296465Sdelphij for (i = 0; i < rtsym_count; ++i) { 373296465Sdelphij printf(" %6lu%c ", i, rtsym_used[i] ? '*' : ' '); 374296465Sdelphij dump_sym(&rtsym_base[i].nlist); 375296465Sdelphij printf("/%-5ld %s\n", rtsym_base[i].nz_size, rtsym_name(i)); 376296465Sdelphij } 377296465Sdelphij} 378296465Sdelphij 37968651Skrisstatic void 380296465Sdelphijdump_segs() 381296465Sdelphij{ 382296465Sdelphij printf(" Text segment starts at address %lx\n", origin + N_TXTOFF(*ex)); 383296465Sdelphij if (N_GETFLAG(*ex) & EX_DYNAMIC) { 384296465Sdelphij printf(" rel starts at %lx\n", sdt->sdt_rel); 385296465Sdelphij printf(" hash starts at %lx\n", sdt->sdt_hash); 386296465Sdelphij printf(" nzlist starts at %lx\n", sdt->sdt_nzlist); 387296465Sdelphij printf(" strings starts at %lx\n", sdt->sdt_strings); 388296465Sdelphij } 389296465Sdelphij 390296465Sdelphij printf(" Data segment starts at address %lx\n", origin + N_DATOFF(*ex)); 391296465Sdelphij if (N_GETFLAG(*ex) & EX_DYNAMIC) { 392296465Sdelphij printf(" _dynamic starts at %lx\n", origin + N_DATOFF(*ex)); 393296465Sdelphij printf(" so_debug starts at %lx\n", (unsigned long) dyn->d_debug); 39468651Skris printf(" sdt starts at %lx\n", (unsigned long) dyn->d_un.d_sdt); 395296465Sdelphij printf(" got starts at %lx\n", sdt->sdt_got); 396296465Sdelphij printf(" plt starts at %lx\n", sdt->sdt_plt); 397296465Sdelphij printf(" rest of stuff starts at %lx\n", 398296465Sdelphij sdt->sdt_plt + sdt->sdt_plt_sz); 39968651Skris } 400296465Sdelphij} 401296465Sdelphij 402296465Sdelphijstatic void 403296465Sdelphijdump_sods() 404296465Sdelphij{ 405296465Sdelphij long sod_offset; 406296465Sdelphij long paths_offset; 407296465Sdelphij 408296465Sdelphij if (dyn == NULL) /* Not a shared object */ 409296465Sdelphij return; 410296465Sdelphij 411296465Sdelphij sod_offset = sdt->sdt_sods; 41268651Skris printf(" Shared object dependencies:\n"); 413296465Sdelphij while (sod_offset != 0) { 414296465Sdelphij const struct sod *sodp = (const struct sod *) (text_addr + sod_offset); 415296465Sdelphij const char *name = (const char *) (text_addr + sodp->sod_name); 416296465Sdelphij 417296465Sdelphij if (sodp->sod_library) 418296465Sdelphij printf(" -l%-16s version %d.%d\n", name, sodp->sod_major, 419296465Sdelphij sodp->sod_minor); 420296465Sdelphij else 421296465Sdelphij printf(" %s\n", name); 422296465Sdelphij sod_offset = sodp->sod_next; 423296465Sdelphij } 424296465Sdelphij paths_offset = sdt->sdt_paths; 425296465Sdelphij printf(" Shared object additional paths:\n"); 426296465Sdelphij if (paths_offset != 0) { 427296465Sdelphij char *path = (char *)(text_addr + paths_offset); 428296465Sdelphij printf(" %s\n", path); 429296465Sdelphij } else { 430296465Sdelphij printf(" (none)\n"); 431296465Sdelphij } 432296465Sdelphij} 433296465Sdelphij 434296465Sdelphijstatic void 435296465Sdelphijdump_sym(const struct nlist *np) 436296465Sdelphij{ 437296465Sdelphij char type[8]; 438296465Sdelphij char weak; 439296465Sdelphij char *p; 440296465Sdelphij 441296465Sdelphij switch (np->n_type & ~N_EXT) { 442296465Sdelphij case N_UNDF: strcpy(type, "undf"); break; 443296465Sdelphij case N_ABS: strcpy(type, "abs"); break; 44468651Skris case N_TEXT: strcpy(type, "text"); break; 44568651Skris case N_DATA: strcpy(type, "data"); break; 446296465Sdelphij case N_BSS: strcpy(type, "bss"); break; 447296465Sdelphij case N_INDR: strcpy(type, "indr"); break; 448296465Sdelphij case N_SIZE: strcpy(type, "size"); break; 449296465Sdelphij case N_COMM: strcpy(type, "comm"); break; 450296465Sdelphij case N_SETA: strcpy(type, "seta"); break; 451296465Sdelphij case N_SETT: strcpy(type, "sett"); break; 452296465Sdelphij case N_SETD: strcpy(type, "setd"); break; 453296465Sdelphij case N_SETB: strcpy(type, "setb"); break; 454296465Sdelphij case N_SETV: strcpy(type, "setv"); break; 455296465Sdelphij case N_FN: strcpy(type, np->n_type&N_EXT ? "fn" : "warn"); break; 456296465Sdelphij case N_GSYM: strcpy(type, "gsym"); break; 45768651Skris case N_FNAME: strcpy(type, "fname"); break; 458296465Sdelphij case N_FUN: strcpy(type, "fun"); break; 459296465Sdelphij case N_STSYM: strcpy(type, "stsym"); break; 460296465Sdelphij case N_LCSYM: strcpy(type, "lcsym"); break; 461296465Sdelphij case N_MAIN: strcpy(type, "main"); break; 462296465Sdelphij case N_PC: strcpy(type, "pc"); break; 463296465Sdelphij case N_RSYM: strcpy(type, "rsym"); break; 464296465Sdelphij case N_SLINE: strcpy(type, "sline"); break; 465296465Sdelphij case N_DSLINE: strcpy(type, "dsline"); break; 466296465Sdelphij case N_BSLINE: strcpy(type, "bsline"); break; 467296465Sdelphij case N_SSYM: strcpy(type, "ssym"); break; 468296465Sdelphij case N_SO: strcpy(type, "so"); break; 469296465Sdelphij case N_LSYM: strcpy(type, "lsym"); break; 470296465Sdelphij case N_BINCL: strcpy(type, "bincl"); break; 471296465Sdelphij case N_SOL: strcpy(type, "sol"); break; 472296465Sdelphij case N_PSYM: strcpy(type, "psym"); break; 473296465Sdelphij case N_EINCL: strcpy(type, "eincl"); break; 474296465Sdelphij case N_ENTRY: strcpy(type, "entry"); break; 475296465Sdelphij case N_LBRAC: strcpy(type, "lbrac"); break; 476296465Sdelphij case N_EXCL: strcpy(type, "excl"); break; 477296465Sdelphij case N_RBRAC: strcpy(type, "rbrac"); break; 478296465Sdelphij case N_BCOMM: strcpy(type, "bcomm"); break; 479296465Sdelphij case N_ECOMM: strcpy(type, "ecomm"); break; 480296465Sdelphij case N_ECOML: strcpy(type, "ecoml"); break; 48168651Skris case N_LENG: strcpy(type, "leng"); break; 48268651Skris default: snprintf(type, sizeof type, "0x%02x", np->n_type); 483296465Sdelphij } 484296465Sdelphij 485296465Sdelphij if (np->n_type & N_EXT && type[0] != '0') 486296465Sdelphij for (p = type; *p != '\0'; ++p) 48768651Skris *p = toupper(*p); 488296465Sdelphij 489296465Sdelphij weak = N_BIND(np) == BIND_WEAK ? 'w' : ' '; 49068651Skris 491296465Sdelphij printf("%c%-5s %8lx", weak, type, np->n_value); 492296465Sdelphij} 493296465Sdelphij 49468651Skrisstatic void 495296465Sdelphijdump_syms() 496296465Sdelphij{ 497296465Sdelphij unsigned long i; 498296465Sdelphij 499296465Sdelphij printf(" Symbols:\n"); 500296465Sdelphij for (i = 0; i < sym_count; ++i) { 501296465Sdelphij printf(" %6lu%c ", i, sym_used[i] ? '*' : ' '); 502296465Sdelphij dump_sym(&sym_base[i]); 503296465Sdelphij printf(" %s\n", sym_name(i)); 504296465Sdelphij } 505296465Sdelphij} 506296465Sdelphij 507296465Sdelphijstatic void 508296465Sdelphijerror(const char *format, ...) 509296465Sdelphij{ 510296465Sdelphij va_list ap; 511296465Sdelphij 512296465Sdelphij va_start(ap, format); 513296465Sdelphij vfprintf(stderr, format, ap); 514296465Sdelphij va_end(ap); 515296465Sdelphij putc('\n', stderr); 516296465Sdelphij 517296465Sdelphij ++error_count; 518296465Sdelphij} 519296465Sdelphij 520296465Sdelphijstatic const char * 521296465Sdelphijrtsym_name(unsigned long n) 522296465Sdelphij{ 523296465Sdelphij assert(n < rtsym_count); 524296465Sdelphij if (rtsym_base[n].nz_strx == 0) 525296465Sdelphij return ""; 526296465Sdelphij return rtstr_base + rtsym_base[n].nz_strx; 527296465Sdelphij} 528296465Sdelphij 529296465Sdelphijstatic const char * 530296465Sdelphijsym_name(unsigned long n) 531296465Sdelphij{ 532296465Sdelphij assert(n < sym_count); 533296465Sdelphij if (sym_base[n].n_un.n_strx == 0) 534296465Sdelphij return ""; 535296465Sdelphij return str_base + sym_base[n].n_un.n_strx; 536296465Sdelphij} 537296465Sdelphij