home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1994 #1 / monster.zip / monster / PROG_GEN / FSDB091A.ZIP / SYMS.C < prev    next >
C/C++ Source or Header  |  1994-02-26  |  18KB  |  780 lines

  1. /* This is file SYMS.C */
  2. /*
  3. ** Copyright (C) 1993 DJ Delorie, 24 Kirsten Ave, Rochester NH 03867-2954
  4. **
  5. ** This file is distributed under the terms listed in the document
  6. ** "copying.dj", available from DJ Delorie at the address above.
  7. ** A copy of "copying.dj" should accompany this file; if not, a copy
  8. ** should be available from where this file was obtained.  This file
  9. ** may not be distributed without a verbatim copy of "copying.dj".
  10. **
  11. ** This file is distributed WITHOUT ANY WARRANTY; without even the implied
  12. ** warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  13. */
  14.  
  15. /* Modified by Morten Welinder, terra@diku.dk, for use with full screen
  16.    debugger.  These changes are copyright 1994 by Morten Welinder.  */
  17.  
  18. #include <stdio.h>
  19. #include <fcntl.h>
  20. #include <string.h>
  21. #include <stdlib.h>
  22. #include <ctype.h>
  23. #include <dos.h>
  24. #include <io.h>
  25.  
  26. #include "ed.h"
  27. #include "coff.h"
  28. #include "syms.h"
  29. #include "stab.h"
  30.  
  31. #define DO_SYMS 1
  32.  
  33. int undefined_symbol=0;
  34.  
  35. #define Ofs(n) ((int)&(((TSS *)0)->n))
  36.  
  37. struct {
  38.   char *name;
  39.   int size;
  40.   int ofs;
  41.   } regs[] = {
  42.   "%eip", 4, Ofs(tss_eip),
  43.   "%eflags", 4, Ofs(tss_eflags),
  44.   "%eax", 4, Ofs(tss_eax),
  45.   "%ebx", 4, Ofs(tss_ebx),
  46.   "%ecx", 4, Ofs(tss_ecx),
  47.   "%edx", 4, Ofs(tss_edx),
  48.   "%esp", 4, Ofs(tss_esp),
  49.   "%ebp", 4, Ofs(tss_ebp),
  50.   "%esi", 4, Ofs(tss_esi),
  51.   "%edi", 4, Ofs(tss_edi),
  52.   "%ax", 2, Ofs(tss_eax),
  53.   "%bx", 2, Ofs(tss_ebx),
  54.   "%cx", 2, Ofs(tss_ecx),
  55.   "%dx", 2, Ofs(tss_edx),
  56.   "%ah", 1, Ofs(tss_eax)+1,
  57.   "%bh", 1, Ofs(tss_ebx)+1,
  58.   "%ch", 1, Ofs(tss_ecx)+1,
  59.   "%dh", 1, Ofs(tss_edx)+1,
  60.   "%al", 1, Ofs(tss_eax),
  61.   "%bl", 1, Ofs(tss_ebx),
  62.   "%cl", 1, Ofs(tss_ecx),
  63.   "%dl", 1, Ofs(tss_edx),
  64.   0, 0, 0
  65. };
  66.  
  67. #if !DO_SYMS
  68.  
  69. void syms_init(char *fname) {}
  70. void syms_list(int byval) {}
  71. void syms_listwild(char *pattern) {}
  72.  
  73. word32 syms_name2val(char *name)
  74. {
  75.   if (isdigit(name[0]))
  76.   {
  77.     int v;
  78.     if (strncmp(name, "0x", 2) == 0)
  79.       sscanf(name+2, "%x", &v);
  80.     else
  81.       sscanf(name, "%d", &v);
  82.     undefined_symbol = 0;
  83.     return v;
  84.   }
  85.   else
  86.   {
  87.     undefined_symbol = 1;
  88.     return 0;
  89.   }
  90. }
  91.  
  92. char *syms_val2name(word32 val, word32 *delta)
  93. {
  94.   static char noname_buf[20];
  95.   sprintf(noname_buf, "%#lx", val);
  96.   *delta = 0;
  97.   return noname_buf;
  98. }
  99.  
  100. char *syms_val2line(word32 val, int *lineret, int exact)
  101. {
  102.   return 0;
  103. }
  104.  
  105. #else
  106.  
  107. /* From the file */
  108.  
  109. typedef struct SYM_ENTRY {
  110.   word32 string_off;
  111.   word8 type;
  112.   word8 other;
  113.   word16 desc;
  114.   word32 val;
  115. } SYM_ENTRY;
  116.  
  117. static FILHDR f_fh;
  118. static AOUTHDR f_ah;
  119. static SCNHDR *f_sh;
  120. static SYMENT *f_symtab;
  121. static SYM_ENTRY *f_aoutsyms;
  122. static AUXENT *f_aux;
  123. static LINENO **f_lnno;
  124. static char *f_string_table;
  125. static char *f_types;
  126.  
  127. /* built internally */
  128.  
  129. typedef struct {
  130.   char *filename;
  131.   word32 first_address;
  132.   word32 last_address;
  133.   LINENO *lines;
  134.   int num_lines;
  135. } FileNode;
  136.  
  137. static FileNode *files;
  138. static int num_files;
  139.  
  140. typedef struct SymNode {
  141.   char *name;
  142.   word32 address;
  143.   char type_c;
  144. } SymNode;
  145.  
  146. static SymNode *syms;
  147. static SymNode *syms_byname;
  148. static int num_syms;
  149.  
  150. static int syms_sort_bn(const void *a, const void *b)
  151. {
  152.   SymNode *sa = (SymNode *)a;
  153.   SymNode *sb = (SymNode *)b;
  154.   return strcmp(sa->name, sb->name);
  155. }
  156.  
  157. static int syms_sort_bv(const void *a, const void *b)
  158. {
  159.   SymNode *sa = (SymNode *)a;
  160.   SymNode *sb = (SymNode *)b;
  161.   return sa->address - sb->address;
  162. }
  163.  
  164. static char *symndup(char *s, int len)
  165. {
  166.   char c = s[len], *rv;
  167.   s[len] = 0;
  168.   rv = strdup(s);
  169.   s[len] = c;
  170.   return rv;
  171. }
  172.  
  173. static int valid_symbol(int i)
  174. {
  175.   char *sn;
  176.   if (f_symtab[i].e.e.e_zeroes)
  177.     sn = f_symtab[i].e.e_name; 
  178.   else
  179.     sn = f_string_table + f_symtab[i].e.e.e_offset;
  180.   if (sn[0] != '_')
  181.     return 0;
  182.   if (strncmp(sn, "___gnu_compiled", 15) == 0)
  183.     return 0;
  184.   if (strcmp(sn, "__DYNAMIC") == 0)
  185.     return 0;
  186.   return 1;
  187. }
  188.  
  189. static void process_coff(FILE *fd, long ofs)
  190. {
  191.   int i, f, s, f_pending;
  192.   LINENO *l;
  193.   int l_pending;
  194.   word32 strsize;
  195.   char *name;
  196.  
  197.   fseek(fd, ofs, 0);
  198.   fread(&f_fh, 1, FILHSZ, fd);
  199.   fread(&f_ah, 1, AOUTSZ, fd);
  200.   f_sh = (SCNHDR *)malloc(f_fh.f_nscns * SCNHSZ);
  201.   f_types = (char *)malloc(f_fh.f_nscns);
  202.   f_lnno = (LINENO **)malloc(f_fh.f_nscns * sizeof(LINENO *));
  203.   fread(f_sh, f_fh.f_nscns, SCNHSZ, fd);
  204.  
  205.   for (i=0; i<f_fh.f_nscns; i++)
  206.   {
  207.     if (f_sh[i].s_flags & STYP_TEXT)
  208.       f_types[i] = 'T';
  209.     if (f_sh[i].s_flags & STYP_DATA)
  210.       f_types[i] = 'D';
  211.     if (f_sh[i].s_flags & STYP_BSS)
  212.       f_types[i] = 'B';
  213.     if (f_sh[i].s_nlnno)
  214.     {
  215.       fseek(fd, ofs + f_sh[i].s_lnnoptr, 0L);
  216.       f_lnno[i] = (LINENO *)malloc(f_sh[i].s_nlnno * LINESZ);
  217.       fread(f_lnno[i], LINESZ, f_sh[i].s_nlnno, fd);
  218.     }
  219.     else
  220.       f_lnno[i] = 0;
  221.   }
  222.  
  223.   fseek(fd, ofs + f_fh.f_symptr + f_fh.f_nsyms * SYMESZ, 0);
  224.   fread(&strsize, 1, 4, fd);
  225.   f_string_table = (char *)malloc(strsize);
  226.   fread(f_string_table+4, 1, strsize-4, fd);
  227.   f_string_table[0] = 0;
  228.  
  229.   fseek(fd, ofs+f_fh.f_symptr, 0);
  230.   f_symtab = (SYMENT *)malloc(f_fh.f_nsyms * SYMESZ);
  231.   fread(f_symtab, SYMESZ, f_fh.f_nsyms, fd);
  232.   f_aux = (AUXENT *)f_symtab;
  233.  
  234.   num_syms = num_files = 0;
  235.   for (i=0; i<f_fh.f_nsyms; i++)
  236.   {
  237.     switch (f_symtab[i].e_sclass)
  238.     {
  239.       case C_FILE:
  240.         num_files++;
  241.         break;
  242.       case C_EXT:
  243.       case C_STAT:
  244.         if (!valid_symbol(i))
  245.           break;
  246.         num_syms++;
  247.         break;
  248.     }
  249.     i += f_symtab[i].e_numaux;
  250.   }
  251.  
  252.   files = (FileNode *)malloc(num_files * sizeof(FileNode));
  253.  
  254.   syms = (SymNode *)malloc(num_syms * sizeof(SymNode));
  255.  
  256.   f = s = f_pending = l_pending = 0;
  257.   for (i=0; i<f_fh.f_nsyms; i++)
  258.   {
  259.     switch (f_symtab[i].e_sclass)
  260.     {
  261.       case C_FILE:
  262.         if (f_aux[i+1].x_file.x_n.x_zeroes)
  263.           files[f].filename = symndup(f_aux[i+1].x_file.x_fname, 16);
  264.         else
  265.           files[f].filename = f_string_table + f_aux[i+1].x_file.x_n.x_offset;
  266.         files[f].lines = 0;
  267.         f_pending = 1;
  268.     f++;
  269.         break;
  270.       case C_EXT:
  271.       case C_STAT:
  272.  
  273.         if (f_symtab[i].e.e.e_zeroes)
  274.           name = f_symtab[i].e.e_name;
  275.         else
  276.           name = f_string_table + f_symtab[i].e.e.e_offset;
  277.  
  278.         if (f_pending && strcmp(name, ".text") == 0)
  279.         {
  280.           files[f-1].first_address = f_symtab[i].e_value;
  281.           files[f-1].last_address = f_symtab[i].e_value + f_aux[i+1].x_scn.x_scnlen - 1;
  282.           files[f-1].num_lines = f_aux[i+1].x_scn.x_nlinno;
  283.           f_pending = 0;
  284.         }
  285.  
  286.         if (ISFCN(f_symtab[i].e_type))
  287.         {
  288.           int scn = f_symtab[i].e_scnum - 1;
  289.           l = f_lnno[scn] + ((f_aux[i+1].x_sym.x_fcnary.x_fcn.x_lnnoptr - f_sh[scn].s_lnnoptr)/LINESZ);
  290.           l_pending = 1;
  291.           l->l_addr.l_paddr = f_symtab[i].e_value;
  292.         }
  293.  
  294.         if (!valid_symbol(i))
  295.           break;
  296.  
  297.         syms[s].address = f_symtab[i].e_value;
  298.         if (f_symtab[i].e.e.e_zeroes)
  299.           syms[s].name = symndup(f_symtab[i].e.e_name, 8);
  300.         else
  301.           syms[s].name = f_string_table + f_symtab[i].e.e.e_offset;
  302.         
  303.         switch (f_symtab[i].e_scnum)
  304.         {
  305.           case 1 ... 10:
  306.             syms[s].type_c = f_types[f_symtab[i].e_scnum-1];
  307.             break;
  308.           case N_UNDEF:
  309.             syms[s].type_c = 'U';
  310.             break;
  311.           case N_ABS:
  312.             syms[s].type_c = 'A';
  313.             break;
  314.           case N_DEBUG:
  315.             syms[s].type_c = 'D';
  316.             break;
  317.         }
  318.         if (f_symtab[i].e_sclass == C_STAT)
  319.           syms[s].type_c += 'a' - 'A';
  320.  
  321.         s++;
  322.         break;
  323.       case C_FCN:
  324.         if (f_pending && files[f-1].lines == 0)
  325.         {
  326.           files[f-1].lines = l;
  327.         }
  328.         if (l_pending)
  329.         {
  330.           int lbase = f_aux[i+1].x_sym.x_misc.x_lnsz.x_lnno - 1;
  331.           int i2;
  332.           l->l_lnno = lbase;
  333.           l++;
  334.           for (i2=0; l[i2].l_lnno; i2++)
  335.             l[i2].l_lnno += lbase;
  336.           l_pending = 0;
  337.         }
  338.         break;
  339.     }
  340.     i += f_symtab[i].e_numaux;
  341.   }
  342. }
  343.  
  344. static void process_aout(FILE *fd, long ofs)
  345. {
  346.   GNU_AOUT header;
  347.   word32 string_table_length;
  348.   int nsyms, i, f, s, l;
  349.  
  350.   fseek(fd, ofs, 0);
  351.   fread(&header, 1, sizeof(header), fd);
  352.  
  353.   fseek(fd, ofs + sizeof(header) + header.tsize + header.dsize + header.txrel + header.dtrel, 0);
  354.   nsyms = header.symsize / sizeof(SYM_ENTRY);
  355.   f_aoutsyms = (SYM_ENTRY *)malloc(header.symsize);
  356.   fread(f_aoutsyms, 1, header.symsize, fd);
  357.  
  358.   fread(&string_table_length, 1, 4, fd);
  359.   f_string_table = (char *)malloc(string_table_length);
  360.   fread(f_string_table+4, 1, string_table_length-4, fd);
  361.   f_string_table[0] = 0;
  362.  
  363.   num_files = num_syms = 0;
  364.   for (i=0; i<nsyms; i++)
  365.   {
  366.     char *symn = f_string_table + f_aoutsyms[i].string_off;
  367.     char *cp;
  368.     switch (f_aoutsyms[i].type & ~N_EXT)
  369.     {
  370.       case N_SO:
  371.         if (symn[strlen(symn)-1] == '/')
  372.           break;
  373.         num_files++;
  374.         break;
  375.       case N_TEXT:
  376.         cp = symn + strlen(symn) - 2;
  377.     if (strncmp(symn, "___gnu", 6) == 0 ||
  378.         strcmp(cp, "d.") == 0 /* as in gcc_compiled. */ ||
  379.         strcmp(cp, ".o") == 0)
  380.       break;
  381.       case N_DATA:
  382.       case N_ABS:
  383.       case N_BSS:
  384.       case N_FN:
  385.       case N_SETV:
  386.       case N_SETA:
  387.       case N_SETT:
  388.       case N_SETD:
  389.       case N_SETB:
  390.       case N_INDR:
  391.         num_syms ++;
  392.         break;
  393.     }
  394.   }
  395.   
  396.   syms = (SymNode *)malloc(num_syms * sizeof(SymNode));
  397.   memset(syms, num_syms * sizeof(SymNode), 0);
  398.   files = (FileNode *)malloc(num_files * sizeof(FileNode));
  399.   memset(files, num_files * sizeof(FileNode), 0);
  400.  
  401.   f = s = 0;
  402.   for (i=0; i<nsyms; i++)
  403.   {
  404.     char c, *cp;
  405.     char *symn = f_string_table + f_aoutsyms[i].string_off;
  406.     switch (f_aoutsyms[i].type & ~N_EXT)
  407.     {
  408.       case N_SO:
  409.         if (symn[strlen(symn)-1] == '/')
  410.           break;
  411.         if (f && files[f-1].last_address == 0)
  412.           files[f-1].last_address = f_aoutsyms[i].val - 1;
  413.         files[f].filename = symn;
  414.         files[f].first_address = f_aoutsyms[i].val;
  415.         f ++;
  416.         break;
  417.       case N_SLINE:
  418.         files[f-1].num_lines++;
  419.         break;
  420.       case N_TEXT:
  421.         cp = symn + strlen(symn) - 2;
  422.     if (strncmp(symn, "___gnu", 6) == 0 ||
  423.         strcmp(cp, "d.") == 0 /* as in gcc_compiled. */ ||
  424.         strcmp(cp, ".o") == 0)
  425.         {
  426.           if (f && files[f-1].last_address == 0)
  427.             files[f-1].last_address = f_aoutsyms[i].val - 1;
  428.           break;
  429.         }
  430.     c = 't';
  431.     goto sym_c;
  432.       case N_DATA:
  433.     c = 'd';
  434.     goto sym_c;
  435.       case N_ABS:
  436.     c = 'a';
  437.     goto sym_c;
  438.       case N_BSS:
  439.     c = 'b';
  440.     goto sym_c;
  441.       case N_FN:
  442.     c = 'f';
  443.     goto sym_c;
  444.       case N_SETV:
  445.     c = 'v';
  446.     goto sym_c;
  447.       case N_SETA:
  448.     c = 'v';
  449.     goto sym_c;
  450.       case N_SETT:
  451.     c = 'v';
  452.     goto sym_c;
  453.       case N_SETD:
  454.     c = 'v';
  455.     goto sym_c;
  456.       case N_SETB:
  457.     c = 'v';
  458.     goto sym_c;
  459.       case N_INDR:
  460.     c = 'i';
  461.     sym_c:
  462.         syms[s].name = symn;
  463.         syms[s].address = f_aoutsyms[i].val;
  464.         syms[s].type_c = (f_aoutsyms[i].type & N_EXT) ? (c+'A'-'a') : c;
  465.         s ++;
  466.         break;
  467.     }
  468.   }
  469.   
  470.   l = f = 0;
  471.   for (i=0; i<nsyms; i++)
  472.   {
  473.     char c, *cp;
  474.     char *symn = f_string_table + f_aoutsyms[i].string_off;
  475.     switch (f_aoutsyms[i].type & ~N_EXT)
  476.     {
  477.       case N_SO:
  478.         if (symn[strlen(symn)-1] == '/')
  479.           break;
  480.         files[f].lines = (LINENO *)malloc(files[f].num_lines * sizeof(LINENO));
  481.         f++;
  482.         l = 0;
  483.         break;
  484.       case N_SLINE:
  485.         files[f-1].lines[l].l_addr.l_paddr = f_aoutsyms[i].val;
  486.         files[f-1].lines[l].l_lnno = f_aoutsyms[i].desc;
  487.         l ++;
  488.         break;
  489.     }
  490.   }
  491.   
  492. }
  493.  
  494. static void process_file(FILE *fd, long ofs)
  495. {
  496.   short s, exe[2];
  497.   fseek(fd, ofs, 0);
  498.   fread(&s, 1, 2, fd);
  499.   switch (s)
  500.   {
  501.     case 0x5a4d:    /* .exe */
  502.       fread(exe, 2, 2, fd);
  503.       ofs += (long)exe[1] * 512L;
  504.       if (exe[0])
  505.         ofs += (long)exe[0] - 512L;
  506.       process_file(fd, ofs);
  507.       break;
  508.     case 0x014c:    /* .coff */
  509.       process_coff(fd, ofs);
  510.       break;
  511.     case 0x010b:    /* a.out ZMAGIC */
  512.     case 0x0107:    /* a.out object */
  513.       process_aout(fd, ofs);
  514.       break;
  515.   }
  516. }
  517.  
  518. void syms_init(char *fname)
  519. {
  520.   FILE *fd = fopen(fname, "rb");
  521.   if (fd == 0)
  522.   {
  523.     perror(fname);
  524.   }
  525.   else
  526.   {
  527.     process_file(fd, 0);
  528.  
  529.     syms_byname = (SymNode *)malloc(num_syms * sizeof(SymNode));
  530.     memcpy(syms_byname, syms, num_syms * sizeof(SymNode));
  531.     qsort(syms_byname, num_syms, sizeof(SymNode), syms_sort_bn);
  532.     qsort(syms, num_syms, sizeof(SymNode), syms_sort_bv);
  533.  
  534.     fclose(fd);
  535.   }
  536. }
  537.  
  538. int lookup_sym_byname(char *name, int idx, int ofs)
  539. {
  540.   int below, above;
  541.   char ch = name[idx];
  542.   name[idx] = 0;
  543.   
  544.   below = -1;
  545.   above = num_syms;
  546.   while (above - below > 1)
  547.   {
  548.     int mid = (above + below) / 2;
  549.     int c = 0;
  550.     if (ofs)
  551.       c = '_' - syms_byname[mid].name[0];
  552.     if (c == 0)
  553.       c = strcmp(name, syms_byname[mid].name+ofs);
  554.     if (c == 0)
  555.     {
  556.       name[idx] = ch;
  557.       return mid;
  558.     }
  559.     if (c < 0)
  560.       above = mid;
  561.     else
  562.       below = mid;
  563.   }
  564.   name[idx] = ch;
  565.   return -1;
  566. }
  567.  
  568. word32 syms_name2val(char *name)
  569. {
  570.   int cval, idx, sign=1, i;
  571.   word32 v;
  572.   char *cp;
  573.  
  574.   undefined_symbol = 0;
  575.  
  576.   idx = 0;
  577.   sscanf(name, "%s", name);
  578.  
  579.   if (name[0] == 0)
  580.     return 0;
  581.  
  582.   if (name[0] == '-')
  583.   {
  584.     sign = -1;
  585.     name++;
  586.   }
  587.   else if (name[0] == '+')
  588.   {
  589.     name++;
  590.   }
  591.   if (isdigit(name[0]))
  592.   {
  593.     if (sign == -1)
  594.       return -strtoul(name, 0, 0);
  595.     return strtoul(name, 0, 0);
  596.   }
  597.  
  598.   cp = strpbrk(name, "+-");
  599.   if (cp)
  600.     idx = cp-name;
  601.   else
  602.     idx = strlen(name);
  603.  
  604.   if (name[0] == '%') /* register */
  605.   {
  606.     for (i=0; regs[i].name; i++)
  607.       if (strncmp(name, regs[i].name, idx) == 0)
  608.       {
  609.     switch (regs[i].size)
  610.     {
  611.       case 1:
  612.         v = *(word8 *)((word8 *)(&a_tss) + regs[i].ofs);
  613.         break;
  614.       case 2:
  615.         v = *(word16 *)((word8 *)(&a_tss) + regs[i].ofs);
  616.         break;
  617.       case 4:
  618.         v = *(word32 *)((word8 *)(&a_tss) + regs[i].ofs);
  619.         break;
  620.     }
  621.     return v + syms_name2val(name+idx);
  622.       }
  623.   }
  624.  
  625.   for (i=0; i<idx; i++)
  626.     if (name[i] == '#')
  627.     {
  628.       int f;
  629.       int lnum, l;
  630.       sscanf(name+i+1, "%d", &lnum);
  631.       for (f=0; f<num_files; f++)
  632.       {
  633.     if ((strncmp(name, files[f].filename, i) == 0) && (files[f].filename[i] == 0))
  634.     {
  635.       for (l=0; l<files[f].num_lines; l++)
  636.       {
  637.         if (files[f].lines[l].l_lnno == lnum)
  638.           return files[f].lines[l].l_addr.l_paddr + syms_name2val(name+idx);
  639.       }
  640. #ifndef FULLSCR
  641.       printf("undefined line number %.*s\n", idx, name);
  642. #endif
  643.       undefined_symbol = 1;
  644.       return 0;
  645.     }
  646.       }
  647. #ifndef FULLSCR
  648.       printf("Undefined file name %.*s\n", i, name);
  649. #endif
  650.       undefined_symbol = 1;
  651.       return 0;
  652.     }
  653.  
  654.   i = lookup_sym_byname(name, idx, 0);
  655.   if (i == -1)
  656.     i = lookup_sym_byname(name, idx, 1);
  657.   if (i != -1)
  658.     return syms_byname[i].address * sign + syms_name2val(name+idx);
  659. #ifndef FULLSCR
  660.   printf("Undefined symbol %.*s\n", idx, name);
  661. #endif
  662.   undefined_symbol = 1;
  663.   return 0;
  664. }
  665.  
  666. static char noname_buf[11];
  667.  
  668. char *syms_val2name(word32 val, word32 *delta)
  669. {
  670.   static char buf[1000];
  671.   int above, below, mid;
  672.  
  673.   if (delta)
  674.     *delta = 0;
  675.  
  676.   if (num_syms <= 0)
  677.     goto noname;  
  678.   above = num_syms;
  679.   below = -1;
  680.   while (above-below > 1)
  681.   {
  682.     mid = (above+below)/2;
  683.     if (syms[mid].address == val)
  684.       break;
  685.     if (syms[mid].address > val)
  686.       above = mid;
  687.     else
  688.       below = mid;
  689.   }
  690.   if (syms[mid].address > val)
  691.   {
  692.     if (mid == 0)
  693.       goto noname;
  694.     mid--; /* the last below was it */
  695.   }
  696.   if (mid < 0)
  697.     goto noname;
  698.   if (strcmp(syms[mid].name, "_end") == 0)
  699.     goto noname;
  700.   if (strcmp(syms[mid].name, "__end") == 0)
  701.     goto noname;
  702.   if (strcmp(syms[mid].name, "_etext") == 0)
  703.     goto noname;
  704.   if (delta)
  705.     *delta = val - syms[mid].address;
  706.   return syms[mid].name;
  707. noname:
  708.   sprintf(noname_buf, "%#lx", val);
  709.   return noname_buf;
  710. }
  711.  
  712. char *syms_val2line(word32 val, int *lineret, int exact)
  713. {
  714.   int f, l;
  715.   for (f=0; f<num_files; f++)
  716.   {
  717.     if (val >= files[f].first_address && val <= files[f].last_address && files[f].lines)
  718.     {
  719.       for (l=files[f].num_lines-1; l >= 0 && files[f].lines[l].l_addr.l_paddr > val; l--);
  720.       if ((files[f].lines[l].l_addr.l_paddr != val) && exact)
  721.         return 0;
  722.       *lineret = files[f].lines[l].l_lnno;
  723.       return files[f].filename;
  724.     }
  725.   }
  726.   return 0;
  727. }
  728.  
  729. #ifdef FULLSCR
  730. void syms_listwild(char *pattern,
  731.            void (*handler)(word32, char, char *, char *, int))
  732. #else
  733. void syms_listwild(char *pattern)
  734. #endif
  735. {
  736.   int linecnt = 0;
  737.   int lnum;
  738.   char *name;
  739.   int i, key;
  740.  
  741.   for (i=0; i<num_syms; i++)
  742.     if (wild(pattern, syms_byname[i]))
  743.     {
  744. #ifdef FULLSCR
  745.       name = syms_val2line(syms_byname[i].address, &lnum, 0);
  746.       handler (syms_byname[i].address,
  747.            syms_byname[i].type_c,
  748.            syms_byname[i].name,
  749.            name, lnum);
  750. #else
  751.       if (++linecnt > 20)
  752.       {
  753.         printf("--- More ---");
  754.         fflush(stdout);
  755.         key = getkey();
  756.         printf("\r            \r");
  757.         switch (key)
  758.         {
  759.       case ' ':
  760.           linecnt = 0;
  761.         break;
  762.       case 13:
  763.         linecnt--;
  764.         break;
  765.       case 'q':
  766.       case 27:
  767.         return;
  768.         }
  769.       }
  770.       printf("0x%08lx %c %s", syms_byname[i].address, syms_byname[i].type_c, syms_byname[i].name);
  771.       name = syms_val2line(syms_byname[i].address, &lnum, 0);
  772.       if (name)
  773.         printf(", line %d of %s", lnum, name);
  774.       putchar('\n');
  775. #endif
  776.     }
  777. }
  778.  
  779. #endif
  780.