Back to index

cell-binutils  2.17cvs20070401
listing.c
Go to the documentation of this file.
00001 /* listing.c - maintain assembly listings
00002    Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
00003    2001, 2002, 2003, 2005, 2006
00004    Free Software Foundation, Inc.
00005 
00006    This file is part of GAS, the GNU Assembler.
00007 
00008    GAS is free software; you can redistribute it and/or modify
00009    it under the terms of the GNU General Public License as published by
00010    the Free Software Foundation; either version 2, or (at your option)
00011    any later version.
00012 
00013    GAS is distributed in the hope that it will be useful,
00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016    GNU General Public License for more details.
00017 
00018    You should have received a copy of the GNU General Public License
00019    along with GAS; see the file COPYING.  If not, write to the Free
00020    Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
00021    02110-1301, USA.  */
00022 
00023 /* Contributed by Steve Chamberlain <sac@cygnus.com>
00024 
00025  A listing page looks like:
00026 
00027  LISTING_HEADER  sourcefilename pagenumber
00028  TITLE LINE
00029  SUBTITLE LINE
00030  linenumber address data  source
00031  linenumber address data  source
00032  linenumber address data  source
00033  linenumber address data  source
00034 
00035  If not overridden, the listing commands are:
00036 
00037  .title  "stuff"
00038        Put "stuff" onto the title line
00039  .sbttl  "stuff"
00040         Put stuff onto the subtitle line
00041 
00042   If these commands come within 10 lines of the top of the page, they
00043   will affect the page they are on, as well as any subsequent page
00044 
00045  .eject
00046        Thow a page
00047  .list
00048        Increment the enable listing counter
00049  .nolist
00050        Decrement the enable listing counter
00051 
00052  .psize Y[,X]
00053        Set the paper size to X wide and Y high. Setting a psize Y of
00054        zero will suppress form feeds except where demanded by .eject
00055 
00056  If the counter goes below zero, listing is suppressed.
00057 
00058  Listings are a maintained by read calling various listing_<foo>
00059  functions.  What happens most is that the macro NO_LISTING is not
00060  defined (from the Makefile), then the macro LISTING_NEWLINE expands
00061  into a call to listing_newline.  The call is done from read.c, every
00062  time it sees a newline, and -l is on the command line.
00063 
00064  The function listing_newline remembers the frag associated with the
00065  newline, and creates a new frag - note that this is wasteful, but not
00066  a big deal, since listing slows things down a lot anyway.  The
00067  function also remembers when the filename changes.
00068 
00069  When all the input has finished, and gas has had a chance to settle
00070  down, the listing is output. This is done by running down the list of
00071  frag/source file records, and opening the files as needed and printing
00072  out the bytes and chars associated with them.
00073 
00074  The only things which the architecture can change about the listing
00075  are defined in these macros:
00076 
00077  LISTING_HEADER             The name of the architecture
00078  LISTING_WORD_SIZE      The make of the number of bytes in a word, this determines
00079                      the clumping of the output data. eg a value of
00080                      2 makes words look like 1234 5678, whilst 1
00081                      would make the same value look like 12 34 56
00082                      78
00083  LISTING_LHS_WIDTH      Number of words of above size for the lhs
00084 
00085  LISTING_LHS_WIDTH_SECOND   Number of words for the data on the lhs
00086                      for the second line
00087 
00088  LISTING_LHS_CONT_LINES     Max number of lines to use up for a continuation
00089  LISTING_RHS_WIDTH      Number of chars from the input file to print
00090                         on a line.  */
00091 
00092 #include "as.h"
00093 #include "obstack.h"
00094 #include "safe-ctype.h"
00095 #include "input-file.h"
00096 #include "subsegs.h"
00097 
00098 #ifndef NO_LISTING
00099 
00100 #ifndef LISTING_HEADER
00101 #define LISTING_HEADER "GAS LISTING"
00102 #endif
00103 #ifndef LISTING_WORD_SIZE
00104 #define LISTING_WORD_SIZE 4
00105 #endif
00106 #ifndef LISTING_LHS_WIDTH
00107 #define LISTING_LHS_WIDTH ((LISTING_WORD_SIZE) > 4 ? 1 : 4 / (LISTING_WORD_SIZE))
00108 #endif
00109 #ifndef LISTING_LHS_WIDTH_SECOND
00110 #define LISTING_LHS_WIDTH_SECOND LISTING_LHS_WIDTH
00111 #endif
00112 #ifndef LISTING_RHS_WIDTH
00113 #define LISTING_RHS_WIDTH 100
00114 #endif
00115 #ifndef LISTING_LHS_CONT_LINES
00116 #define LISTING_LHS_CONT_LINES 4
00117 #endif
00118 
00119 /* This structure remembers which .s were used.  */
00120 typedef struct file_info_struct
00121 {
00122   struct file_info_struct * next;
00123   char *                    filename;
00124   long                      pos;
00125   unsigned int              linenum;
00126   int                       at_end;
00127 } file_info_type;
00128 
00129 /* This structure remembers which line from which file goes into which
00130    frag.  */
00131 struct list_info_struct
00132 {
00133   /* Frag which this line of source is nearest to.  */
00134   fragS *frag;
00135 
00136   /* The actual line in the source file.  */
00137   unsigned int line;
00138 
00139   /* Pointer to the file info struct for the file which this line
00140      belongs to.  */
00141   file_info_type *file;
00142 
00143   /* The expanded text of any macro that may have been executing.  */
00144   char *line_contents;
00145 
00146   /* Next in list.  */
00147   struct list_info_struct *next;
00148 
00149   /* Pointer to the file info struct for the high level language
00150      source line that belongs here.  */
00151   file_info_type *hll_file;
00152 
00153   /* High level language source line.  */
00154   unsigned int hll_line;
00155 
00156   /* Pointer to any error message associated with this line.  */
00157   char *message;
00158 
00159   enum
00160     {
00161       EDICT_NONE,
00162       EDICT_SBTTL,
00163       EDICT_TITLE,
00164       EDICT_NOLIST,
00165       EDICT_LIST,
00166       EDICT_NOLIST_NEXT,
00167       EDICT_EJECT
00168     } edict;
00169   char *edict_arg;
00170 
00171   /* Nonzero if this line is to be omitted because it contains
00172      debugging information.  This can become a flags field if we come
00173      up with more information to store here.  */
00174   int debugging;
00175 };
00176 
00177 typedef struct list_info_struct list_info_type;
00178 
00179 int listing_lhs_width        = LISTING_LHS_WIDTH;
00180 int listing_lhs_width_second = LISTING_LHS_WIDTH_SECOND;
00181 int listing_lhs_cont_lines   = LISTING_LHS_CONT_LINES;
00182 int listing_rhs_width        = LISTING_RHS_WIDTH;
00183 
00184 struct list_info_struct *        listing_tail;
00185 
00186 static file_info_type *          file_info_head;
00187 static file_info_type *          last_open_file_info;
00188 static FILE *                    last_open_file;
00189 static struct list_info_struct * head;
00190 static int                       paper_width = 200;
00191 static int                       paper_height = 60;
00192 
00193 extern int                       listing;
00194 
00195 /* File to output listings to.  */
00196 static FILE *list_file;
00197 
00198 /* This static array is used to keep the text of data to be printed
00199    before the start of the line.  */
00200 
00201 #define MAX_BYTES                                              \
00202   (((LISTING_WORD_SIZE * 2) + 1) * listing_lhs_width                  \
00203    + ((((LISTING_WORD_SIZE * 2) + 1) * listing_lhs_width_second)      \
00204       * listing_lhs_cont_lines)                                       \
00205    + 20)
00206 
00207 static char *data_buffer;
00208 
00209 /* Prototypes.  */
00210 static void listing_message (const char *, const char *);
00211 static file_info_type *file_info (const char *);
00212 static void new_frag (void);
00213 static char *buffer_line (file_info_type *, char *, unsigned int);
00214 static void listing_page (list_info_type *);
00215 static unsigned int calc_hex (list_info_type *);
00216 static void print_lines (list_info_type *, unsigned int, char *, unsigned int);
00217 static void list_symbol_table (void);
00218 static void print_source (file_info_type *, list_info_type *, char *, unsigned int);
00219 static int debugging_pseudo (list_info_type *, const char *);
00220 static void listing_listing (char *);
00221 
00222 static void
00223 listing_message (const char *name, const char *message)
00224 {
00225   if (listing_tail != (list_info_type *) NULL)
00226     {
00227       unsigned int l = strlen (name) + strlen (message) + 1;
00228       char *n = (char *) xmalloc (l);
00229       strcpy (n, name);
00230       strcat (n, message);
00231       listing_tail->message = n;
00232     }
00233 }
00234 
00235 void
00236 listing_warning (const char *message)
00237 {
00238   listing_message (_("Warning:"), message);
00239 }
00240 
00241 void
00242 listing_error (const char *message)
00243 {
00244   listing_message (_("Error:"), message);
00245 }
00246 
00247 static file_info_type *
00248 file_info (const char *file_name)
00249 {
00250   /* Find an entry with this file name.  */
00251   file_info_type *p = file_info_head;
00252 
00253   while (p != (file_info_type *) NULL)
00254     {
00255       if (strcmp (p->filename, file_name) == 0)
00256        return p;
00257       p = p->next;
00258     }
00259 
00260   /* Make new entry.  */
00261   p = xmalloc (sizeof (file_info_type));
00262   p->next = file_info_head;
00263   file_info_head = p;
00264   p->filename = xstrdup (file_name);
00265   p->pos = 0;
00266   p->linenum = 0;
00267   p->at_end = 0;
00268 
00269   return p;
00270 }
00271 
00272 static void
00273 new_frag (void)
00274 {
00275   frag_wane (frag_now);
00276   frag_new (0);
00277 }
00278 
00279 void
00280 listing_newline (char *ps)
00281 {
00282   char *file;
00283   unsigned int line;
00284   static unsigned int last_line = 0xffff;
00285   static char *last_file = NULL;
00286   list_info_type *new = NULL;
00287 
00288   if (listing == 0)
00289     return;
00290 
00291   if (now_seg == absolute_section)
00292     return;
00293 
00294 #ifdef OBJ_ELF
00295   /* In ELF, anything in a section beginning with .debug or .line is
00296      considered to be debugging information.  This includes the
00297      statement which switches us into the debugging section, which we
00298      can only set after we are already in the debugging section.  */
00299   if ((listing & LISTING_NODEBUG) != 0
00300       && listing_tail != NULL
00301       && ! listing_tail->debugging)
00302     {
00303       const char *segname;
00304 
00305       segname = segment_name (now_seg);
00306       if (strncmp (segname, ".debug", sizeof ".debug" - 1) == 0
00307          || strncmp (segname, ".line", sizeof ".line" - 1) == 0)
00308        listing_tail->debugging = 1;
00309     }
00310 #endif
00311 
00312   as_where (&file, &line);
00313   if (ps == NULL)
00314     {
00315       if (line == last_line
00316          && !(last_file && file && strcmp (file, last_file)))
00317        return;
00318 
00319       new = (list_info_type *) xmalloc (sizeof (list_info_type));
00320 
00321       /* Detect if we are reading from stdin by examining the file
00322         name returned by as_where().
00323 
00324         [FIXME: We rely upon the name in the strcmp below being the
00325         same as the one used by input_scrub_new_file(), if that is
00326         not true, then this code will fail].
00327 
00328         If we are reading from stdin, then we need to save each input
00329         line here (assuming of course that we actually have a line of
00330         input to read), so that it can be displayed in the listing
00331         that is produced at the end of the assembly.  */
00332       if (strcmp (file, _("{standard input}")) == 0
00333          && input_line_pointer != NULL)
00334        {
00335          char *copy;
00336          int len;
00337          int seen_quote = 0;
00338 
00339          for (copy = input_line_pointer - 1;
00340               *copy && (seen_quote
00341                       || (! is_end_of_line [(unsigned char) *copy]));
00342               copy++)
00343            if (*copy == '"' && copy[-1] != '\\')
00344              seen_quote = ! seen_quote;
00345 
00346          len = (copy - input_line_pointer) + 2;
00347 
00348          copy = xmalloc (len);
00349 
00350          if (copy != NULL)
00351            {
00352              char *src = input_line_pointer - 1;
00353              char *dest = copy;
00354 
00355              while (--len)
00356               {
00357                 unsigned char c = *src++;
00358 
00359                 /* Omit control characters in the listing.  */
00360                 if (!ISCNTRL (c))
00361                   *dest++ = c;
00362               }
00363 
00364              *dest = 0;
00365            }
00366 
00367          new->line_contents = copy;
00368        }
00369       else
00370        new->line_contents = NULL;
00371     }
00372   else
00373     {
00374       new = xmalloc (sizeof (list_info_type));
00375       new->line_contents = ps;
00376     }
00377 
00378   last_line = line;
00379   last_file = file;
00380 
00381   new_frag ();
00382 
00383   if (listing_tail)
00384     listing_tail->next = new;
00385   else
00386     head = new;
00387 
00388   listing_tail = new;
00389 
00390   new->frag = frag_now;
00391   new->line = line;
00392   new->file = file_info (file);
00393   new->next = (list_info_type *) NULL;
00394   new->message = (char *) NULL;
00395   new->edict = EDICT_NONE;
00396   new->hll_file = (file_info_type *) NULL;
00397   new->hll_line = 0;
00398   new->debugging = 0;
00399 
00400   new_frag ();
00401 
00402 #ifdef OBJ_ELF
00403   /* In ELF, anything in a section beginning with .debug or .line is
00404      considered to be debugging information.  */
00405   if ((listing & LISTING_NODEBUG) != 0)
00406     {
00407       const char *segname;
00408 
00409       segname = segment_name (now_seg);
00410       if (strncmp (segname, ".debug", sizeof ".debug" - 1) == 0
00411          || strncmp (segname, ".line", sizeof ".line" - 1) == 0)
00412        new->debugging = 1;
00413     }
00414 #endif
00415 }
00416 
00417 /* Attach all current frags to the previous line instead of the
00418    current line.  This is called by the MIPS backend when it discovers
00419    that it needs to add some NOP instructions; the added NOP
00420    instructions should go with the instruction that has the delay, not
00421    with the new instruction.  */
00422 
00423 void
00424 listing_prev_line (void)
00425 {
00426   list_info_type *l;
00427   fragS *f;
00428 
00429   if (head == (list_info_type *) NULL
00430       || head == listing_tail)
00431     return;
00432 
00433   new_frag ();
00434 
00435   for (l = head; l->next != listing_tail; l = l->next)
00436     ;
00437 
00438   for (f = frchain_now->frch_root; f != (fragS *) NULL; f = f->fr_next)
00439     if (f->line == listing_tail)
00440       f->line = l;
00441 
00442   listing_tail->frag = frag_now;
00443   new_frag ();
00444 }
00445 
00446 /* This function returns the next source line from the file supplied,
00447    truncated to size.  It appends a fake line to the end of each input
00448    file to make.  */
00449 
00450 static char *
00451 buffer_line (file_info_type *file, char *line, unsigned int size)
00452 {
00453   unsigned int count = 0;
00454   int c;
00455 
00456   char *p = line;
00457 
00458   /* If we couldn't open the file, return an empty line.  */
00459   if (file->at_end)
00460     return "";
00461 
00462   /* Check the cache and see if we last used this file.  */
00463   if (!last_open_file_info || file != last_open_file_info)
00464     {
00465       if (last_open_file)
00466        {
00467          last_open_file_info->pos = ftell (last_open_file);
00468          fclose (last_open_file);
00469        }
00470 
00471       last_open_file_info = file;
00472       last_open_file = fopen (file->filename, FOPEN_RT);
00473       if (last_open_file == NULL)
00474        {
00475          file->at_end = 1;
00476          return "";
00477        }
00478 
00479       /* Seek to where we were last time this file was open.  */
00480       if (file->pos)
00481        fseek (last_open_file, file->pos, SEEK_SET);
00482     }
00483 
00484   c = fgetc (last_open_file);
00485 
00486   /* Leave room for null.  */
00487   size -= 1;
00488 
00489   while (c != EOF && c != '\n')
00490     {
00491       if (count < size)
00492        *p++ = c;
00493       count++;
00494 
00495       c = fgetc (last_open_file);
00496 
00497     }
00498   if (c == EOF)
00499     {
00500       file->at_end = 1;
00501       if (count + 2 < size)
00502        {
00503          *p++ = '.';
00504          *p++ = '.';
00505          *p++ = '.';
00506        }
00507     }
00508   file->linenum++;
00509   *p++ = 0;
00510   return line;
00511 }
00512 
00513 static const char *fn;
00514 
00515 static unsigned int eject;  /* Eject pending */
00516 static unsigned int page;   /* Current page number */
00517 static char *title;         /* Current title */
00518 static char *subtitle;             /* Current subtitle */
00519 static unsigned int on_page;       /* Number of lines printed on current page */
00520 
00521 static void
00522 listing_page (list_info_type *list)
00523 {
00524   /* Grope around, see if we can see a title or subtitle edict coming up
00525      soon.  (we look down 10 lines of the page and see if it's there)  */
00526   if ((eject || (on_page >= (unsigned int) paper_height))
00527       && paper_height != 0)
00528     {
00529       unsigned int c = 10;
00530       int had_title = 0;
00531       int had_subtitle = 0;
00532 
00533       page++;
00534 
00535       while (c != 0 && list)
00536        {
00537          if (list->edict == EDICT_SBTTL && !had_subtitle)
00538            {
00539              had_subtitle = 1;
00540              subtitle = list->edict_arg;
00541            }
00542          if (list->edict == EDICT_TITLE && !had_title)
00543            {
00544              had_title = 1;
00545              title = list->edict_arg;
00546            }
00547          list = list->next;
00548          c--;
00549        }
00550 
00551       if (page > 1)
00552        {
00553          fprintf (list_file, "\f");
00554        }
00555 
00556       fprintf (list_file, "%s %s \t\t\tpage %d\n", LISTING_HEADER, fn, page);
00557       fprintf (list_file, "%s\n", title);
00558       fprintf (list_file, "%s\n", subtitle);
00559       on_page = 3;
00560       eject = 0;
00561     }
00562 }
00563 
00564 static unsigned int
00565 calc_hex (list_info_type *list)
00566 {
00567   int data_buffer_size;
00568   list_info_type *first = list;
00569   unsigned int address = ~(unsigned int) 0;
00570   fragS *frag;
00571   fragS *frag_ptr;
00572   unsigned int octet_in_frag;
00573 
00574   /* Find first frag which says it belongs to this line.  */
00575   frag = list->frag;
00576   while (frag && frag->line != list)
00577     frag = frag->fr_next;
00578 
00579   frag_ptr = frag;
00580 
00581   data_buffer_size = 0;
00582 
00583   /* Dump all the frags which belong to this line.  */
00584   while (frag_ptr != (fragS *) NULL && frag_ptr->line == first)
00585     {
00586       /* Print as many bytes from the fixed part as is sensible.  */
00587       octet_in_frag = 0;
00588       while ((offsetT) octet_in_frag < frag_ptr->fr_fix
00589             && data_buffer_size < MAX_BYTES - 3)
00590        {
00591          if (address == ~(unsigned int) 0)
00592            address = frag_ptr->fr_address / OCTETS_PER_BYTE;
00593 
00594          sprintf (data_buffer + data_buffer_size,
00595                  "%02X",
00596                  (frag_ptr->fr_literal[octet_in_frag]) & 0xff);
00597          data_buffer_size += 2;
00598          octet_in_frag++;
00599        }
00600       if (frag_ptr->fr_type == rs_fill)
00601        {
00602          unsigned int var_rep_max = octet_in_frag;
00603          unsigned int var_rep_idx = octet_in_frag;
00604 
00605          /* Print as many bytes from the variable part as is sensible.  */
00606          while (((offsetT) octet_in_frag
00607                 < (frag_ptr->fr_fix + frag_ptr->fr_var * frag_ptr->fr_offset))
00608                && data_buffer_size < MAX_BYTES - 3)
00609            {
00610              if (address == ~(unsigned int) 0)
00611               address = frag_ptr->fr_address / OCTETS_PER_BYTE;
00612 
00613              sprintf (data_buffer + data_buffer_size,
00614                      "%02X",
00615                      (frag_ptr->fr_literal[var_rep_idx]) & 0xff);
00616              data_buffer_size += 2;
00617 
00618              var_rep_idx++;
00619              octet_in_frag++;
00620 
00621              if ((offsetT) var_rep_idx >= frag_ptr->fr_fix + frag_ptr->fr_var)
00622               var_rep_idx = var_rep_max;
00623            }
00624        }
00625 
00626       frag_ptr = frag_ptr->fr_next;
00627     }
00628   data_buffer[data_buffer_size] = '\0';
00629   return address;
00630 }
00631 
00632 static void
00633 print_lines (list_info_type *list, unsigned int lineno,
00634             char *string, unsigned int address)
00635 {
00636   unsigned int idx;
00637   unsigned int nchars;
00638   unsigned int lines;
00639   unsigned int octet_in_word = 0;
00640   char *src = data_buffer;
00641   int cur;
00642 
00643   /* Print the stuff on the first line.  */
00644   listing_page (list);
00645   nchars = (LISTING_WORD_SIZE * 2 + 1) * listing_lhs_width;
00646 
00647   /* Print the hex for the first line.  */
00648   if (address == ~(unsigned int) 0)
00649     {
00650       fprintf (list_file, "% 4d     ", lineno);
00651       for (idx = 0; idx < nchars; idx++)
00652        fprintf (list_file, " ");
00653 
00654       fprintf (list_file, "\t%s\n", string ? string : "");
00655 
00656       on_page++;
00657 
00658       listing_page (0);
00659 
00660       return;
00661     }
00662 
00663   if (had_errors ())
00664     fprintf (list_file, "% 4d ???? ", lineno);
00665   else
00666     fprintf (list_file, "% 4d %04x ", lineno, address);
00667 
00668   /* And the data to go along with it.  */
00669   idx = 0;
00670   cur = 0;
00671   while (src[cur] && idx < nchars)
00672     {
00673       int offset;
00674       offset = cur;
00675       fprintf (list_file, "%c%c", src[offset], src[offset + 1]);
00676       cur += 2;
00677       octet_in_word++;
00678 
00679       if (octet_in_word == LISTING_WORD_SIZE)
00680        {
00681          fprintf (list_file, " ");
00682          idx++;
00683          octet_in_word = 0;
00684        }
00685 
00686       idx += 2;
00687     }
00688 
00689   for (; idx < nchars; idx++)
00690     fprintf (list_file, " ");
00691 
00692   fprintf (list_file, "\t%s\n", string ? string : "");
00693   on_page++;
00694   listing_page (list);
00695 
00696   if (list->message)
00697     {
00698       fprintf (list_file, "****  %s\n", list->message);
00699       listing_page (list);
00700       on_page++;
00701     }
00702 
00703   for (lines = 0;
00704        lines < (unsigned int) listing_lhs_cont_lines
00705         && src[cur];
00706        lines++)
00707     {
00708       nchars = ((LISTING_WORD_SIZE * 2) + 1) * listing_lhs_width_second - 1;
00709       idx = 0;
00710 
00711       /* Print any more lines of data, but more compactly.  */
00712       fprintf (list_file, "% 4d      ", lineno);
00713 
00714       while (src[cur] && idx < nchars)
00715        {
00716          int offset;
00717          offset = cur;
00718          fprintf (list_file, "%c%c", src[offset], src[offset + 1]);
00719          cur += 2;
00720          idx += 2;
00721          octet_in_word++;
00722 
00723          if (octet_in_word == LISTING_WORD_SIZE)
00724            {
00725              fprintf (list_file, " ");
00726              idx++;
00727              octet_in_word = 0;
00728            }
00729        }
00730 
00731       fprintf (list_file, "\n");
00732       on_page++;
00733       listing_page (list);
00734     }
00735 }
00736 
00737 static void
00738 list_symbol_table (void)
00739 {
00740   extern symbolS *symbol_rootP;
00741   int got_some = 0;
00742 
00743   symbolS *ptr;
00744   eject = 1;
00745   listing_page (0);
00746 
00747   for (ptr = symbol_rootP; ptr != (symbolS *) NULL; ptr = symbol_next (ptr))
00748     {
00749       if (SEG_NORMAL (S_GET_SEGMENT (ptr))
00750          || S_GET_SEGMENT (ptr) == absolute_section)
00751        {
00752          /* Don't report section symbols.  They are not interesting.  */
00753          if (symbol_section_p (ptr))
00754            continue;
00755 
00756          if (S_GET_NAME (ptr))
00757            {
00758              char buf[30], fmt[8];
00759              valueT val = S_GET_VALUE (ptr);
00760 
00761              /* @@ Note that this is dependent on the compilation options,
00762                not solely on the target characteristics.  */
00763              if (sizeof (val) == 4 && sizeof (int) == 4)
00764               sprintf (buf, "%08lx", (unsigned long) val);
00765              else if (sizeof (val) <= sizeof (unsigned long))
00766               {
00767                 sprintf (fmt, "%%0%lulx",
00768                         (unsigned long) (sizeof (val) * 2));
00769                 sprintf (buf, fmt, (unsigned long) val);
00770               }
00771 #if defined (BFD64)
00772              else if (sizeof (val) > 4)
00773               sprintf_vma (buf, val);
00774 #endif
00775              else
00776               abort ();
00777 
00778              if (!got_some)
00779               {
00780                 fprintf (list_file, "DEFINED SYMBOLS\n");
00781                 on_page++;
00782                 got_some = 1;
00783               }
00784 
00785              if (symbol_get_frag (ptr) && symbol_get_frag (ptr)->line)
00786               {
00787                 fprintf (list_file, "%20s:%-5d  %s:%s %s\n",
00788                         symbol_get_frag (ptr)->line->file->filename,
00789                         symbol_get_frag (ptr)->line->line,
00790                         segment_name (S_GET_SEGMENT (ptr)),
00791                         buf, S_GET_NAME (ptr));
00792               }
00793              else
00794               {
00795                 fprintf (list_file, "%33s:%s %s\n",
00796                         segment_name (S_GET_SEGMENT (ptr)),
00797                         buf, S_GET_NAME (ptr));
00798               }
00799 
00800              on_page++;
00801              listing_page (0);
00802            }
00803        }
00804 
00805     }
00806   if (!got_some)
00807     {
00808       fprintf (list_file, "NO DEFINED SYMBOLS\n");
00809       on_page++;
00810     }
00811   fprintf (list_file, "\n");
00812   on_page++;
00813   listing_page (0);
00814 
00815   got_some = 0;
00816 
00817   for (ptr = symbol_rootP; ptr != (symbolS *) NULL; ptr = symbol_next (ptr))
00818     {
00819       if (S_GET_NAME (ptr) && strlen (S_GET_NAME (ptr)) != 0)
00820        {
00821          if (S_GET_SEGMENT (ptr) == undefined_section)
00822            {
00823              if (!got_some)
00824               {
00825                 got_some = 1;
00826                 fprintf (list_file, "UNDEFINED SYMBOLS\n");
00827                 on_page++;
00828                 listing_page (0);
00829               }
00830              fprintf (list_file, "%s\n", S_GET_NAME (ptr));
00831              on_page++;
00832              listing_page (0);
00833            }
00834        }
00835     }
00836   if (!got_some)
00837     {
00838       fprintf (list_file, "NO UNDEFINED SYMBOLS\n");
00839       on_page++;
00840       listing_page (0);
00841     }
00842 }
00843 
00844 static void
00845 print_source (file_info_type *current_file, list_info_type *list,
00846              char *buffer, unsigned int width)
00847 {
00848   if (!current_file->at_end)
00849     {
00850       while (current_file->linenum < list->hll_line
00851             && !current_file->at_end)
00852        {
00853          char *p = buffer_line (current_file, buffer, width);
00854 
00855          fprintf (list_file, "%4u:%-13s **** %s\n", current_file->linenum,
00856                  current_file->filename, p);
00857          on_page++;
00858          listing_page (list);
00859        }
00860     }
00861 }
00862 
00863 /* Sometimes the user doesn't want to be bothered by the debugging
00864    records inserted by the compiler, see if the line is suspicious.  */
00865 
00866 static int
00867 debugging_pseudo (list_info_type *list, const char *line)
00868 {
00869   static int in_debug;
00870   int was_debug;
00871 
00872   if (list->debugging)
00873     {
00874       in_debug = 1;
00875       return 1;
00876     }
00877 
00878   was_debug = in_debug;
00879   in_debug = 0;
00880 
00881   while (ISSPACE (*line))
00882     line++;
00883 
00884   if (*line != '.')
00885     {
00886 #ifdef OBJ_ELF
00887       /* The ELF compiler sometimes emits blank lines after switching
00888          out of a debugging section.  If the next line drops us back
00889          into debugging information, then don't print the blank line.
00890          This is a hack for a particular compiler behaviour, not a
00891          general case.  */
00892       if (was_debug
00893          && *line == '\0'
00894          && list->next != NULL
00895          && list->next->debugging)
00896        {
00897          in_debug = 1;
00898          return 1;
00899        }
00900 #endif
00901 
00902       return 0;
00903     }
00904 
00905   line++;
00906 
00907   if (strncmp (line, "def", 3) == 0)
00908     return 1;
00909   if (strncmp (line, "val", 3) == 0)
00910     return 1;
00911   if (strncmp (line, "scl", 3) == 0)
00912     return 1;
00913   if (strncmp (line, "line", 4) == 0)
00914     return 1;
00915   if (strncmp (line, "endef", 5) == 0)
00916     return 1;
00917   if (strncmp (line, "ln", 2) == 0)
00918     return 1;
00919   if (strncmp (line, "type", 4) == 0)
00920     return 1;
00921   if (strncmp (line, "size", 4) == 0)
00922     return 1;
00923   if (strncmp (line, "dim", 3) == 0)
00924     return 1;
00925   if (strncmp (line, "tag", 3) == 0)
00926     return 1;
00927   if (strncmp (line, "stabs", 5) == 0)
00928     return 1;
00929   if (strncmp (line, "stabn", 5) == 0)
00930     return 1;
00931 
00932   return 0;
00933 }
00934 
00935 static void
00936 listing_listing (char *name ATTRIBUTE_UNUSED)
00937 {
00938   list_info_type *list = head;
00939   file_info_type *current_hll_file = (file_info_type *) NULL;
00940   char *message;
00941   char *buffer;
00942   char *p;
00943   int show_listing = 1;
00944   unsigned int width;
00945 
00946   buffer = xmalloc (listing_rhs_width);
00947   data_buffer = xmalloc (MAX_BYTES);
00948   eject = 1;
00949   list = head->next;
00950 
00951   while (list)
00952     {
00953       unsigned int list_line;
00954 
00955       width = listing_rhs_width > paper_width ? paper_width :
00956        listing_rhs_width;
00957 
00958       list_line = list->line;
00959       switch (list->edict)
00960        {
00961        case EDICT_LIST:
00962          /* Skip all lines up to the current.  */
00963          list_line--;
00964          break;
00965        case EDICT_NOLIST:
00966          show_listing--;
00967          break;
00968        case EDICT_NOLIST_NEXT:
00969          if (show_listing == 0)
00970            list_line--;
00971          break;
00972        case EDICT_EJECT:
00973          break;
00974        case EDICT_NONE:
00975          break;
00976        case EDICT_TITLE:
00977          title = list->edict_arg;
00978          break;
00979        case EDICT_SBTTL:
00980          subtitle = list->edict_arg;
00981          break;
00982        default:
00983          abort ();
00984        }
00985 
00986       if (show_listing <= 0)
00987        {
00988          while (list->file->linenum < list_line
00989                && !list->file->at_end)
00990            p = buffer_line (list->file, buffer, width);
00991        }
00992 
00993       if (list->edict == EDICT_LIST
00994          || (list->edict == EDICT_NOLIST_NEXT && show_listing == 0))
00995        {
00996          /* Enable listing for the single line that caused the enable.  */
00997          list_line++;
00998          show_listing++;
00999        }
01000 
01001       if (show_listing > 0)
01002        {
01003          /* Scan down the list and print all the stuff which can be done
01004             with this line (or lines).  */
01005          message = 0;
01006 
01007          if (list->hll_file)
01008            current_hll_file = list->hll_file;
01009 
01010          if (current_hll_file && list->hll_line && (listing & LISTING_HLL))
01011            print_source (current_hll_file, list, buffer, width);
01012 
01013          if (list->line_contents)
01014            {
01015              if (!((listing & LISTING_NODEBUG)
01016                   && debugging_pseudo (list, list->line_contents)))
01017               print_lines (list,
01018                           list->file->linenum == 0 ? list->line : list->file->linenum,
01019                           list->line_contents, calc_hex (list));
01020 
01021              free (list->line_contents);
01022              list->line_contents = NULL;
01023            }
01024          else
01025            {
01026              while (list->file->linenum < list_line
01027                    && !list->file->at_end)
01028               {
01029                 unsigned int address;
01030 
01031                 p = buffer_line (list->file, buffer, width);
01032 
01033                 if (list->file->linenum < list_line)
01034                   address = ~(unsigned int) 0;
01035                 else
01036                   address = calc_hex (list);
01037 
01038                 if (!((listing & LISTING_NODEBUG)
01039                      && debugging_pseudo (list, p)))
01040                   print_lines (list, list->file->linenum, p, address);
01041               }
01042            }
01043 
01044          if (list->edict == EDICT_EJECT)
01045            eject = 1;
01046        }
01047 
01048       if (list->edict == EDICT_NOLIST_NEXT && show_listing == 1)
01049        --show_listing;
01050 
01051       list = list->next;
01052     }
01053 
01054   free (buffer);
01055   free (data_buffer);
01056   data_buffer = NULL;
01057 }
01058 
01059 void
01060 listing_print (char *name)
01061 {
01062   int using_stdout;
01063 
01064   title = "";
01065   subtitle = "";
01066 
01067   if (name == NULL)
01068     {
01069       list_file = stdout;
01070       using_stdout = 1;
01071     }
01072   else
01073     {
01074       list_file = fopen (name, FOPEN_WT);
01075       if (list_file != NULL)
01076        using_stdout = 0;
01077       else
01078        {
01079          as_warn (_("can't open %s: %s"), name, xstrerror (errno));
01080          list_file = stdout;
01081          using_stdout = 1;
01082        }
01083     }
01084 
01085   if (listing & LISTING_NOFORM)
01086     paper_height = 0;
01087 
01088   if (listing & LISTING_LISTING)
01089     listing_listing (name);
01090 
01091   if (listing & LISTING_SYMBOLS)
01092     list_symbol_table ();
01093 
01094   if (! using_stdout)
01095     {
01096       if (fclose (list_file) == EOF)
01097        as_warn (_("can't close %s: %s"), name, xstrerror (errno));
01098     }
01099 
01100   if (last_open_file)
01101     fclose (last_open_file);
01102 }
01103 
01104 void
01105 listing_file (const char *name)
01106 {
01107   fn = name;
01108 }
01109 
01110 void
01111 listing_eject (int ignore ATTRIBUTE_UNUSED)
01112 {
01113   if (listing)
01114     listing_tail->edict = EDICT_EJECT;
01115 }
01116 
01117 void
01118 listing_flags (int ignore ATTRIBUTE_UNUSED)
01119 {
01120   while ((*input_line_pointer++) && (*input_line_pointer != '\n'))
01121     input_line_pointer++;
01122 
01123 }
01124 
01125 /* Turn listing on or off.  An argument of 0 means to turn off
01126    listing.  An argument of 1 means to turn on listing.  An argument
01127    of 2 means to turn off listing, but as of the next line; that is,
01128    the current line should be listed, but the next line should not.  */
01129 
01130 void
01131 listing_list (int on)
01132 {
01133   if (listing)
01134     {
01135       switch (on)
01136        {
01137        case 0:
01138          if (listing_tail->edict == EDICT_LIST)
01139            listing_tail->edict = EDICT_NONE;
01140          else
01141            listing_tail->edict = EDICT_NOLIST;
01142          break;
01143        case 1:
01144          if (listing_tail->edict == EDICT_NOLIST
01145              || listing_tail->edict == EDICT_NOLIST_NEXT)
01146            listing_tail->edict = EDICT_NONE;
01147          else
01148            listing_tail->edict = EDICT_LIST;
01149          break;
01150        case 2:
01151          listing_tail->edict = EDICT_NOLIST_NEXT;
01152          break;
01153        default:
01154          abort ();
01155        }
01156     }
01157 }
01158 
01159 void
01160 listing_psize (int width_only)
01161 {
01162   if (! width_only)
01163     {
01164       paper_height = get_absolute_expression ();
01165 
01166       if (paper_height < 0 || paper_height > 1000)
01167        {
01168          paper_height = 0;
01169          as_warn (_("strange paper height, set to no form"));
01170        }
01171 
01172       if (*input_line_pointer != ',')
01173        {
01174          demand_empty_rest_of_line ();
01175          return;
01176        }
01177 
01178       ++input_line_pointer;
01179     }
01180 
01181   paper_width = get_absolute_expression ();
01182 
01183   demand_empty_rest_of_line ();
01184 }
01185 
01186 void
01187 listing_nopage (int ignore ATTRIBUTE_UNUSED)
01188 {
01189   paper_height = 0;
01190 }
01191 
01192 void
01193 listing_title (int depth)
01194 {
01195   int quoted;
01196   char *start;
01197   char *ttl;
01198   unsigned int length;
01199 
01200   SKIP_WHITESPACE ();
01201   if (*input_line_pointer != '\"')
01202     quoted = 0;
01203   else
01204     {
01205       quoted = 1;
01206       ++input_line_pointer;
01207     }
01208 
01209   start = input_line_pointer;
01210 
01211   while (*input_line_pointer)
01212     {
01213       if (quoted
01214          ? *input_line_pointer == '\"'
01215          : is_end_of_line[(unsigned char) *input_line_pointer])
01216        {
01217          if (listing)
01218            {
01219              length = input_line_pointer - start;
01220              ttl = xmalloc (length + 1);
01221              memcpy (ttl, start, length);
01222              ttl[length] = 0;
01223              listing_tail->edict = depth ? EDICT_SBTTL : EDICT_TITLE;
01224              listing_tail->edict_arg = ttl;
01225            }
01226          if (quoted)
01227            input_line_pointer++;
01228          demand_empty_rest_of_line ();
01229          return;
01230        }
01231       else if (*input_line_pointer == '\n')
01232        {
01233          as_bad (_("new line in title"));
01234          demand_empty_rest_of_line ();
01235          return;
01236        }
01237       else
01238        {
01239          input_line_pointer++;
01240        }
01241     }
01242 }
01243 
01244 void
01245 listing_source_line (unsigned int line)
01246 {
01247   if (listing)
01248     {
01249       new_frag ();
01250       listing_tail->hll_line = line;
01251       new_frag ();
01252     }
01253 }
01254 
01255 void
01256 listing_source_file (const char *file)
01257 {
01258   if (listing)
01259     listing_tail->hll_file = file_info (file);
01260 }
01261 
01262 #else
01263 
01264 /* Dummy functions for when compiled without listing enabled.  */
01265 
01266 void
01267 listing_flags (int ignore)
01268 {
01269   s_ignore (0);
01270 }
01271 
01272 void
01273 listing_list (int on)
01274 {
01275   s_ignore (0);
01276 }
01277 
01278 void
01279 listing_eject (int ignore)
01280 {
01281   s_ignore (0);
01282 }
01283 
01284 void
01285 listing_psize (int ignore)
01286 {
01287   s_ignore (0);
01288 }
01289 
01290 void
01291 listing_nopage (int ignore)
01292 {
01293   s_ignore (0);
01294 }
01295 
01296 void
01297 listing_title (int depth)
01298 {
01299   s_ignore (0);
01300 }
01301 
01302 void
01303 listing_file (const char *name)
01304 {
01305 }
01306 
01307 void
01308 listing_newline (char *name)
01309 {
01310 }
01311 
01312 void
01313 listing_source_line (unsigned int n)
01314 {
01315 }
01316 
01317 void
01318 listing_source_file (const char *n)
01319 {
01320 }
01321 
01322 #endif