home *** CD-ROM | disk | FTP | other *** search
/ PC Extra Super CD 1998 January / PCPLUS131.iso / DJGPP / V2 / DJLSR201.ZIP / src / debug / common / syms.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-22  |  17.3 KB  |  726 lines

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