xref: /netbsd/external/gpl3/binutils/dist/gas/listing.c (revision f22f0ef4)
12a6b7db3Sskrll /* listing.c - maintain assembly listings
2*f22f0ef4Schristos    Copyright (C) 1991-2022 Free Software Foundation, Inc.
32a6b7db3Sskrll 
42a6b7db3Sskrll    This file is part of GAS, the GNU Assembler.
52a6b7db3Sskrll 
62a6b7db3Sskrll    GAS is free software; you can redistribute it and/or modify
72a6b7db3Sskrll    it under the terms of the GNU General Public License as published by
82a6b7db3Sskrll    the Free Software Foundation; either version 3, or (at your option)
92a6b7db3Sskrll    any later version.
102a6b7db3Sskrll 
112a6b7db3Sskrll    GAS is distributed in the hope that it will be useful,
122a6b7db3Sskrll    but WITHOUT ANY WARRANTY; without even the implied warranty of
132a6b7db3Sskrll    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
142a6b7db3Sskrll    GNU General Public License for more details.
152a6b7db3Sskrll 
162a6b7db3Sskrll    You should have received a copy of the GNU General Public License
172a6b7db3Sskrll    along with GAS; see the file COPYING.  If not, write to the Free
182a6b7db3Sskrll    Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
192a6b7db3Sskrll    02110-1301, USA.  */
202a6b7db3Sskrll 
212a6b7db3Sskrll /* Contributed by Steve Chamberlain <sac@cygnus.com>
222a6b7db3Sskrll 
232a6b7db3Sskrll  A listing page looks like:
242a6b7db3Sskrll 
252a6b7db3Sskrll  LISTING_HEADER  sourcefilename pagenumber
262a6b7db3Sskrll  TITLE LINE
272a6b7db3Sskrll  SUBTITLE LINE
282a6b7db3Sskrll  linenumber address data  source
292a6b7db3Sskrll  linenumber address data  source
302a6b7db3Sskrll  linenumber address data  source
312a6b7db3Sskrll  linenumber address data  source
322a6b7db3Sskrll 
332a6b7db3Sskrll  If not overridden, the listing commands are:
342a6b7db3Sskrll 
352a6b7db3Sskrll  .title  "stuff"
362a6b7db3Sskrll  	Put "stuff" onto the title line
372a6b7db3Sskrll  .sbttl  "stuff"
382a6b7db3Sskrll         Put stuff onto the subtitle line
392a6b7db3Sskrll 
402a6b7db3Sskrll   If these commands come within 10 lines of the top of the page, they
412a6b7db3Sskrll   will affect the page they are on, as well as any subsequent page
422a6b7db3Sskrll 
432a6b7db3Sskrll  .eject
4498f124a6Schristos  	Throw a page
452a6b7db3Sskrll  .list
462a6b7db3Sskrll  	Increment the enable listing counter
472a6b7db3Sskrll  .nolist
482a6b7db3Sskrll  	Decrement the enable listing counter
492a6b7db3Sskrll 
502a6b7db3Sskrll  .psize Y[,X]
512a6b7db3Sskrll  	Set the paper size to X wide and Y high. Setting a psize Y of
522a6b7db3Sskrll 	zero will suppress form feeds except where demanded by .eject
532a6b7db3Sskrll 
542a6b7db3Sskrll  If the counter goes below zero, listing is suppressed.
552a6b7db3Sskrll 
562a6b7db3Sskrll  Listings are a maintained by read calling various listing_<foo>
572a6b7db3Sskrll  functions.  What happens most is that the macro NO_LISTING is not
582a6b7db3Sskrll  defined (from the Makefile), then the macro LISTING_NEWLINE expands
592a6b7db3Sskrll  into a call to listing_newline.  The call is done from read.c, every
602a6b7db3Sskrll  time it sees a newline, and -l is on the command line.
612a6b7db3Sskrll 
622a6b7db3Sskrll  The function listing_newline remembers the frag associated with the
632a6b7db3Sskrll  newline, and creates a new frag - note that this is wasteful, but not
642a6b7db3Sskrll  a big deal, since listing slows things down a lot anyway.  The
652a6b7db3Sskrll  function also remembers when the filename changes.
662a6b7db3Sskrll 
672a6b7db3Sskrll  When all the input has finished, and gas has had a chance to settle
682a6b7db3Sskrll  down, the listing is output. This is done by running down the list of
692a6b7db3Sskrll  frag/source file records, and opening the files as needed and printing
702a6b7db3Sskrll  out the bytes and chars associated with them.
712a6b7db3Sskrll 
722a6b7db3Sskrll  The only things which the architecture can change about the listing
732a6b7db3Sskrll  are defined in these macros:
742a6b7db3Sskrll 
752a6b7db3Sskrll  LISTING_HEADER		The name of the architecture
762a6b7db3Sskrll  LISTING_WORD_SIZE      The make of the number of bytes in a word, this determines
772a6b7db3Sskrll  			the clumping of the output data. eg a value of
782a6b7db3Sskrll 			2 makes words look like 1234 5678, whilst 1
792a6b7db3Sskrll 			would make the same value look like 12 34 56
802a6b7db3Sskrll 			78
812a6b7db3Sskrll  LISTING_LHS_WIDTH      Number of words of above size for the lhs
822a6b7db3Sskrll 
832a6b7db3Sskrll  LISTING_LHS_WIDTH_SECOND   Number of words for the data on the lhs
842a6b7db3Sskrll  			for the second line
852a6b7db3Sskrll 
862a6b7db3Sskrll  LISTING_LHS_CONT_LINES	Max number of lines to use up for a continuation
872a6b7db3Sskrll  LISTING_RHS_WIDTH      Number of chars from the input file to print
882a6b7db3Sskrll                         on a line.  */
892a6b7db3Sskrll 
902a6b7db3Sskrll #include "as.h"
9105caefcfSchristos #include "filenames.h"
922a6b7db3Sskrll #include "safe-ctype.h"
932a6b7db3Sskrll #include "input-file.h"
942a6b7db3Sskrll #include "subsegs.h"
952a6b7db3Sskrll #include "bfdver.h"
962a6b7db3Sskrll #include <time.h>
97b075ecf2Schristos #include <stdarg.h>
982a6b7db3Sskrll 
992a6b7db3Sskrll #ifndef NO_LISTING
1002a6b7db3Sskrll 
1012a6b7db3Sskrll #ifndef LISTING_HEADER
1022a6b7db3Sskrll #define LISTING_HEADER "GAS LISTING"
1032a6b7db3Sskrll #endif
1042a6b7db3Sskrll #ifndef LISTING_WORD_SIZE
1052a6b7db3Sskrll #define LISTING_WORD_SIZE 4
1062a6b7db3Sskrll #endif
1072a6b7db3Sskrll #ifndef LISTING_LHS_WIDTH
1082a6b7db3Sskrll #define LISTING_LHS_WIDTH ((LISTING_WORD_SIZE) > 4 ? 1 : 4 / (LISTING_WORD_SIZE))
1092a6b7db3Sskrll #endif
1102a6b7db3Sskrll #ifndef LISTING_LHS_WIDTH_SECOND
1112a6b7db3Sskrll #define LISTING_LHS_WIDTH_SECOND LISTING_LHS_WIDTH
1122a6b7db3Sskrll #endif
1132a6b7db3Sskrll #ifndef LISTING_RHS_WIDTH
1142a6b7db3Sskrll #define LISTING_RHS_WIDTH 100
1152a6b7db3Sskrll #endif
1162a6b7db3Sskrll #ifndef LISTING_LHS_CONT_LINES
1172a6b7db3Sskrll #define LISTING_LHS_CONT_LINES 4
1182a6b7db3Sskrll #endif
1192a6b7db3Sskrll #define MAX_DATELEN 30
1202a6b7db3Sskrll 
1212a6b7db3Sskrll /* This structure remembers which .s were used.  */
1222a6b7db3Sskrll typedef struct file_info_struct
1232a6b7db3Sskrll {
1242a6b7db3Sskrll   struct file_info_struct * next;
1252a6b7db3Sskrll   char *                    filename;
1262a6b7db3Sskrll   long                      pos;
1272a6b7db3Sskrll   unsigned int              linenum;
1282a6b7db3Sskrll   int                       at_end;
1292a6b7db3Sskrll } file_info_type;
1302a6b7db3Sskrll 
131b075ecf2Schristos enum edict_enum
132b075ecf2Schristos {
133b075ecf2Schristos   EDICT_NONE,
134b075ecf2Schristos   EDICT_SBTTL,
135b075ecf2Schristos   EDICT_TITLE,
136b075ecf2Schristos   EDICT_NOLIST,
137b075ecf2Schristos   EDICT_LIST,
138b075ecf2Schristos   EDICT_NOLIST_NEXT,
139b075ecf2Schristos   EDICT_EJECT
140b075ecf2Schristos };
141b075ecf2Schristos 
142b075ecf2Schristos 
14305caefcfSchristos struct list_message
14405caefcfSchristos {
14505caefcfSchristos   char *message;
14605caefcfSchristos   struct list_message *next;
14705caefcfSchristos };
14805caefcfSchristos 
1492a6b7db3Sskrll /* This structure remembers which line from which file goes into which
1502a6b7db3Sskrll    frag.  */
1512a6b7db3Sskrll struct list_info_struct
1522a6b7db3Sskrll {
1532a6b7db3Sskrll   /* Frag which this line of source is nearest to.  */
1542a6b7db3Sskrll   fragS *frag;
1552a6b7db3Sskrll 
1562a6b7db3Sskrll   /* The actual line in the source file.  */
1572a6b7db3Sskrll   unsigned int line;
1582a6b7db3Sskrll 
1592a6b7db3Sskrll   /* Pointer to the file info struct for the file which this line
1602a6b7db3Sskrll      belongs to.  */
1612a6b7db3Sskrll   file_info_type *file;
1622a6b7db3Sskrll 
1632a6b7db3Sskrll   /* The expanded text of any macro that may have been executing.  */
1642a6b7db3Sskrll   char *line_contents;
1652a6b7db3Sskrll 
1662a6b7db3Sskrll   /* Next in list.  */
1672a6b7db3Sskrll   struct list_info_struct *next;
1682a6b7db3Sskrll 
1692a6b7db3Sskrll   /* Pointer to the file info struct for the high level language
1702a6b7db3Sskrll      source line that belongs here.  */
1712a6b7db3Sskrll   file_info_type *hll_file;
1722a6b7db3Sskrll 
1732a6b7db3Sskrll   /* High level language source line.  */
1742a6b7db3Sskrll   unsigned int hll_line;
1752a6b7db3Sskrll 
17605caefcfSchristos   /* Pointers to linked list of messages associated with this line.  */
17705caefcfSchristos   struct list_message *messages, *last_message;
1782a6b7db3Sskrll 
179b075ecf2Schristos   enum edict_enum edict;
1802a6b7db3Sskrll   char *edict_arg;
1812a6b7db3Sskrll 
1822a6b7db3Sskrll   /* Nonzero if this line is to be omitted because it contains
1832a6b7db3Sskrll      debugging information.  This can become a flags field if we come
1842a6b7db3Sskrll      up with more information to store here.  */
1852a6b7db3Sskrll   int debugging;
1862a6b7db3Sskrll };
1872a6b7db3Sskrll 
1882a6b7db3Sskrll typedef struct list_info_struct list_info_type;
1892a6b7db3Sskrll 
1902a6b7db3Sskrll int listing_lhs_width        = LISTING_LHS_WIDTH;
1912a6b7db3Sskrll int listing_lhs_width_second = LISTING_LHS_WIDTH_SECOND;
1922a6b7db3Sskrll int listing_lhs_cont_lines   = LISTING_LHS_CONT_LINES;
1932a6b7db3Sskrll int listing_rhs_width        = LISTING_RHS_WIDTH;
1942a6b7db3Sskrll 
1952a6b7db3Sskrll struct list_info_struct *        listing_tail;
1962a6b7db3Sskrll 
1972a6b7db3Sskrll static file_info_type *          file_info_head;
1982a6b7db3Sskrll static file_info_type *          last_open_file_info;
1992a6b7db3Sskrll static FILE *                    last_open_file;
2002a6b7db3Sskrll static struct list_info_struct * head;
2012a6b7db3Sskrll static int                       paper_width = 200;
2022a6b7db3Sskrll static int                       paper_height = 60;
2032a6b7db3Sskrll 
2042a6b7db3Sskrll extern int                       listing;
2052a6b7db3Sskrll 
2062a6b7db3Sskrll /* File to output listings to.  */
2072a6b7db3Sskrll static FILE *list_file;
2082a6b7db3Sskrll 
2092a6b7db3Sskrll /* This static array is used to keep the text of data to be printed
2102a6b7db3Sskrll    before the start of the line.  */
2112a6b7db3Sskrll 
2122a6b7db3Sskrll #define MAX_BYTES							\
2132a6b7db3Sskrll   (((LISTING_WORD_SIZE * 2) + 1) * listing_lhs_width			\
2142a6b7db3Sskrll    + ((((LISTING_WORD_SIZE * 2) + 1) * listing_lhs_width_second)	\
2152a6b7db3Sskrll       * listing_lhs_cont_lines)						\
2162a6b7db3Sskrll    + 20)
2172a6b7db3Sskrll 
2182a6b7db3Sskrll static char *data_buffer;
2192a6b7db3Sskrll 
2202a6b7db3Sskrll /* Prototypes.  */
2212a6b7db3Sskrll static void listing_message (const char *, const char *);
2222a6b7db3Sskrll static file_info_type *file_info (const char *);
2232a6b7db3Sskrll static void new_frag (void);
2242a6b7db3Sskrll static void listing_page (list_info_type *);
2252a6b7db3Sskrll static unsigned int calc_hex (list_info_type *);
22675f9f1baSchristos static void print_lines (list_info_type *, unsigned int, const char *,
22775f9f1baSchristos 			 unsigned int);
2282a6b7db3Sskrll static void list_symbol_table (void);
2292a6b7db3Sskrll static int debugging_pseudo (list_info_type *, const char *);
2302a6b7db3Sskrll static void listing_listing (char *);
2312a6b7db3Sskrll 
2322a6b7db3Sskrll static void
listing_message(const char * name,const char * message)2332a6b7db3Sskrll listing_message (const char *name, const char *message)
2342a6b7db3Sskrll {
2352a6b7db3Sskrll   if (listing_tail != (list_info_type *) NULL)
2362a6b7db3Sskrll     {
23775f9f1baSchristos       char *n = concat (name, message, (char *) NULL);
23875f9f1baSchristos       struct list_message *lm = XNEW (struct list_message);
23905caefcfSchristos       lm->message = n;
24005caefcfSchristos       lm->next = NULL;
24105caefcfSchristos 
24205caefcfSchristos       if (listing_tail->last_message)
24305caefcfSchristos 	listing_tail->last_message->next = lm;
24405caefcfSchristos       else
24505caefcfSchristos 	listing_tail->messages = lm;
24605caefcfSchristos       listing_tail->last_message = lm;
2472a6b7db3Sskrll     }
2482a6b7db3Sskrll }
2492a6b7db3Sskrll 
2502a6b7db3Sskrll void
listing_warning(const char * message)2512a6b7db3Sskrll listing_warning (const char *message)
2522a6b7db3Sskrll {
2532a6b7db3Sskrll   listing_message (_("Warning: "), message);
2542a6b7db3Sskrll }
2552a6b7db3Sskrll 
2562a6b7db3Sskrll void
listing_error(const char * message)2572a6b7db3Sskrll listing_error (const char *message)
2582a6b7db3Sskrll {
2592a6b7db3Sskrll   listing_message (_("Error: "), message);
2602a6b7db3Sskrll }
2612a6b7db3Sskrll 
2622a6b7db3Sskrll static file_info_type *
file_info(const char * file_name)2632a6b7db3Sskrll file_info (const char *file_name)
2642a6b7db3Sskrll {
2652a6b7db3Sskrll   /* Find an entry with this file name.  */
2662a6b7db3Sskrll   file_info_type *p = file_info_head;
2672a6b7db3Sskrll 
2682a6b7db3Sskrll   while (p != (file_info_type *) NULL)
2692a6b7db3Sskrll     {
27005caefcfSchristos       if (filename_cmp (p->filename, file_name) == 0)
2712a6b7db3Sskrll 	return p;
2722a6b7db3Sskrll       p = p->next;
2732a6b7db3Sskrll     }
2742a6b7db3Sskrll 
2752a6b7db3Sskrll   /* Make new entry.  */
27675f9f1baSchristos   p = XNEW (file_info_type);
2772a6b7db3Sskrll   p->next = file_info_head;
2782a6b7db3Sskrll   file_info_head = p;
2792a6b7db3Sskrll   p->filename = xstrdup (file_name);
2802a6b7db3Sskrll   p->pos = 0;
2812a6b7db3Sskrll   p->linenum = 0;
2822a6b7db3Sskrll   p->at_end = 0;
2832a6b7db3Sskrll 
2842a6b7db3Sskrll   return p;
2852a6b7db3Sskrll }
2862a6b7db3Sskrll 
2872a6b7db3Sskrll static void
new_frag(void)2882a6b7db3Sskrll new_frag (void)
2892a6b7db3Sskrll {
2902a6b7db3Sskrll   frag_wane (frag_now);
2912a6b7db3Sskrll   frag_new (0);
2922a6b7db3Sskrll }
2932a6b7db3Sskrll 
2942a6b7db3Sskrll void
listing_newline(char * ps)2952a6b7db3Sskrll listing_newline (char *ps)
2962a6b7db3Sskrll {
29775f9f1baSchristos   const char *file;
2982a6b7db3Sskrll   unsigned int line;
2992a6b7db3Sskrll   static unsigned int last_line = 0xffff;
30075f9f1baSchristos   static const char *last_file = NULL;
301b075ecf2Schristos   list_info_type *new_i = NULL;
3022a6b7db3Sskrll 
3032a6b7db3Sskrll   if (listing == 0)
3042a6b7db3Sskrll     return;
3052a6b7db3Sskrll 
3062a6b7db3Sskrll   if (now_seg == absolute_section)
3072a6b7db3Sskrll     return;
3082a6b7db3Sskrll 
3092a6b7db3Sskrll #ifdef OBJ_ELF
3102a6b7db3Sskrll   /* In ELF, anything in a section beginning with .debug or .line is
3112a6b7db3Sskrll      considered to be debugging information.  This includes the
3122a6b7db3Sskrll      statement which switches us into the debugging section, which we
3132a6b7db3Sskrll      can only set after we are already in the debugging section.  */
3142a6b7db3Sskrll   if ((listing & LISTING_NODEBUG) != 0
3152a6b7db3Sskrll       && listing_tail != NULL
3162a6b7db3Sskrll       && ! listing_tail->debugging)
3172a6b7db3Sskrll     {
3182a6b7db3Sskrll       const char *segname;
3192a6b7db3Sskrll 
3202a6b7db3Sskrll       segname = segment_name (now_seg);
321*f22f0ef4Schristos       if (startswith (segname, ".debug")
322*f22f0ef4Schristos 	  || startswith (segname, ".line"))
3232a6b7db3Sskrll 	listing_tail->debugging = 1;
3242a6b7db3Sskrll     }
3252a6b7db3Sskrll #endif
3262a6b7db3Sskrll 
32798f124a6Schristos   /* PR 21977 - use the physical file name not the logical one unless high
32898f124a6Schristos      level source files are being included in the listing.  */
32998f124a6Schristos   if (listing & LISTING_HLL)
33075f9f1baSchristos     file = as_where (&line);
33198f124a6Schristos   else
33298f124a6Schristos     file = as_where_physical (&line);
33398f124a6Schristos 
3342a6b7db3Sskrll   if (ps == NULL)
3352a6b7db3Sskrll     {
3362a6b7db3Sskrll       if (line == last_line
33705caefcfSchristos 	  && !(last_file && file && filename_cmp (file, last_file)))
3382a6b7db3Sskrll 	return;
3392a6b7db3Sskrll 
34075f9f1baSchristos       new_i = XNEW (list_info_type);
3412a6b7db3Sskrll 
3422a6b7db3Sskrll       /* Detect if we are reading from stdin by examining the file
3432a6b7db3Sskrll 	 name returned by as_where().
3442a6b7db3Sskrll 
3452a6b7db3Sskrll 	 [FIXME: We rely upon the name in the strcmp below being the
3462a6b7db3Sskrll 	 same as the one used by input_scrub_new_file(), if that is
3472a6b7db3Sskrll 	 not true, then this code will fail].
3482a6b7db3Sskrll 
3492a6b7db3Sskrll 	 If we are reading from stdin, then we need to save each input
3502a6b7db3Sskrll 	 line here (assuming of course that we actually have a line of
3512a6b7db3Sskrll 	 input to read), so that it can be displayed in the listing
3522a6b7db3Sskrll 	 that is produced at the end of the assembly.  */
3532a6b7db3Sskrll       if (strcmp (file, _("{standard input}")) == 0
3542a6b7db3Sskrll 	  && input_line_pointer != NULL)
3552a6b7db3Sskrll 	{
35675f9f1baSchristos 	  char *copy, *src, *dest;
3572a6b7db3Sskrll 	  int len;
3582a6b7db3Sskrll 	  int seen_quote = 0;
359b075ecf2Schristos 	  int seen_slash = 0;
3602a6b7db3Sskrll 
361b075ecf2Schristos 	  for (copy = input_line_pointer;
3622a6b7db3Sskrll 	       *copy && (seen_quote
363b075ecf2Schristos 			 || is_end_of_line [(unsigned char) *copy] != 1);
3642a6b7db3Sskrll 	       copy++)
365b075ecf2Schristos 	    {
366b075ecf2Schristos 	      if (seen_slash)
367b075ecf2Schristos 		seen_slash = 0;
368b075ecf2Schristos 	      else if (*copy == '\\')
369b075ecf2Schristos 		seen_slash = 1;
370b075ecf2Schristos 	      else if (*copy == '"')
3712a6b7db3Sskrll 		seen_quote = !seen_quote;
372b075ecf2Schristos 	    }
3732a6b7db3Sskrll 
374b075ecf2Schristos 	  len = copy - input_line_pointer + 1;
3752a6b7db3Sskrll 
37675f9f1baSchristos 	  copy = XNEWVEC (char, len);
3772a6b7db3Sskrll 
37875f9f1baSchristos 	  src = input_line_pointer;
37975f9f1baSchristos 	  dest = copy;
3802a6b7db3Sskrll 
3812a6b7db3Sskrll 	  while (--len)
3822a6b7db3Sskrll 	    {
3832a6b7db3Sskrll 	      unsigned char c = *src++;
3842a6b7db3Sskrll 
3852a6b7db3Sskrll 	      /* Omit control characters in the listing.  */
3862a6b7db3Sskrll 	      if (!ISCNTRL (c))
3872a6b7db3Sskrll 		*dest++ = c;
3882a6b7db3Sskrll 	    }
3892a6b7db3Sskrll 
3902a6b7db3Sskrll 	  *dest = 0;
3912a6b7db3Sskrll 
392b075ecf2Schristos 	  new_i->line_contents = copy;
3932a6b7db3Sskrll 	}
3942a6b7db3Sskrll       else
395b075ecf2Schristos 	new_i->line_contents = NULL;
3962a6b7db3Sskrll     }
3972a6b7db3Sskrll   else
3982a6b7db3Sskrll     {
39975f9f1baSchristos       new_i = XNEW (list_info_type);
400b075ecf2Schristos       new_i->line_contents = ps;
4012a6b7db3Sskrll     }
4022a6b7db3Sskrll 
4032a6b7db3Sskrll   last_line = line;
4042a6b7db3Sskrll   last_file = file;
4052a6b7db3Sskrll 
4062a6b7db3Sskrll   new_frag ();
4072a6b7db3Sskrll 
4082a6b7db3Sskrll   if (listing_tail)
409b075ecf2Schristos     listing_tail->next = new_i;
4102a6b7db3Sskrll   else
411b075ecf2Schristos     head = new_i;
4122a6b7db3Sskrll 
413b075ecf2Schristos   listing_tail = new_i;
4142a6b7db3Sskrll 
415b075ecf2Schristos   new_i->frag = frag_now;
416b075ecf2Schristos   new_i->line = line;
417b075ecf2Schristos   new_i->file = file_info (file);
418b075ecf2Schristos   new_i->next = (list_info_type *) NULL;
41905caefcfSchristos   new_i->messages = NULL;
42005caefcfSchristos   new_i->last_message = NULL;
421b075ecf2Schristos   new_i->edict = EDICT_NONE;
422b075ecf2Schristos   new_i->hll_file = (file_info_type *) NULL;
423b075ecf2Schristos   new_i->hll_line = 0;
424b075ecf2Schristos   new_i->debugging = 0;
4252a6b7db3Sskrll 
4262a6b7db3Sskrll   new_frag ();
4272a6b7db3Sskrll 
4282a6b7db3Sskrll #ifdef OBJ_ELF
4292a6b7db3Sskrll   /* In ELF, anything in a section beginning with .debug or .line is
4302a6b7db3Sskrll      considered to be debugging information.  */
4312a6b7db3Sskrll   if ((listing & LISTING_NODEBUG) != 0)
4322a6b7db3Sskrll     {
4332a6b7db3Sskrll       const char *segname;
4342a6b7db3Sskrll 
4352a6b7db3Sskrll       segname = segment_name (now_seg);
436*f22f0ef4Schristos       if (startswith (segname, ".debug")
437*f22f0ef4Schristos 	  || startswith (segname, ".line"))
438b075ecf2Schristos 	new_i->debugging = 1;
4392a6b7db3Sskrll     }
4402a6b7db3Sskrll #endif
4412a6b7db3Sskrll }
4422a6b7db3Sskrll 
4432a6b7db3Sskrll /* Attach all current frags to the previous line instead of the
4442a6b7db3Sskrll    current line.  This is called by the MIPS backend when it discovers
4452a6b7db3Sskrll    that it needs to add some NOP instructions; the added NOP
4462a6b7db3Sskrll    instructions should go with the instruction that has the delay, not
4472a6b7db3Sskrll    with the new instruction.  */
4482a6b7db3Sskrll 
4492a6b7db3Sskrll void
listing_prev_line(void)4502a6b7db3Sskrll listing_prev_line (void)
4512a6b7db3Sskrll {
4522a6b7db3Sskrll   list_info_type *l;
4532a6b7db3Sskrll   fragS *f;
4542a6b7db3Sskrll 
4552a6b7db3Sskrll   if (head == (list_info_type *) NULL
4562a6b7db3Sskrll       || head == listing_tail)
4572a6b7db3Sskrll     return;
4582a6b7db3Sskrll 
4592a6b7db3Sskrll   new_frag ();
4602a6b7db3Sskrll 
4612a6b7db3Sskrll   for (l = head; l->next != listing_tail; l = l->next)
4622a6b7db3Sskrll     ;
4632a6b7db3Sskrll 
4642a6b7db3Sskrll   for (f = frchain_now->frch_root; f != (fragS *) NULL; f = f->fr_next)
4652a6b7db3Sskrll     if (f->line == listing_tail)
4662a6b7db3Sskrll       f->line = l;
4672a6b7db3Sskrll 
4682a6b7db3Sskrll   listing_tail->frag = frag_now;
4692a6b7db3Sskrll   new_frag ();
4702a6b7db3Sskrll }
4712a6b7db3Sskrll 
4722a6b7db3Sskrll /* This function returns the next source line from the file supplied,
4732a6b7db3Sskrll    truncated to size.  It appends a fake line to the end of each input
474b075ecf2Schristos    file to make using the returned buffer simpler.  */
4752a6b7db3Sskrll 
47675f9f1baSchristos static const char *
buffer_line(file_info_type * file,char * line,unsigned int size)4772a6b7db3Sskrll buffer_line (file_info_type *file, char *line, unsigned int size)
4782a6b7db3Sskrll {
4792a6b7db3Sskrll   unsigned int count = 0;
4802a6b7db3Sskrll   int c;
4812a6b7db3Sskrll   char *p = line;
4822a6b7db3Sskrll 
4832a6b7db3Sskrll   /* If we couldn't open the file, return an empty line.  */
4842a6b7db3Sskrll   if (file->at_end)
4852a6b7db3Sskrll     return "";
4862a6b7db3Sskrll 
4872a6b7db3Sskrll   /* Check the cache and see if we last used this file.  */
4882a6b7db3Sskrll   if (!last_open_file_info || file != last_open_file_info)
4892a6b7db3Sskrll     {
4902a6b7db3Sskrll       if (last_open_file)
4912a6b7db3Sskrll 	{
4922a6b7db3Sskrll 	  last_open_file_info->pos = ftell (last_open_file);
4932a6b7db3Sskrll 	  fclose (last_open_file);
4942a6b7db3Sskrll 	}
4952a6b7db3Sskrll 
496b075ecf2Schristos       /* Open the file in the binary mode so that ftell above can
497b075ecf2Schristos 	 return a reliable value that we can feed to fseek below.  */
4982a6b7db3Sskrll       last_open_file_info = file;
499b075ecf2Schristos       last_open_file = fopen (file->filename, FOPEN_RB);
5002a6b7db3Sskrll       if (last_open_file == NULL)
5012a6b7db3Sskrll 	{
5022a6b7db3Sskrll 	  file->at_end = 1;
5032a6b7db3Sskrll 	  return "";
5042a6b7db3Sskrll 	}
5052a6b7db3Sskrll 
5062a6b7db3Sskrll       /* Seek to where we were last time this file was open.  */
5072a6b7db3Sskrll       if (file->pos)
5082a6b7db3Sskrll 	fseek (last_open_file, file->pos, SEEK_SET);
5092a6b7db3Sskrll     }
5102a6b7db3Sskrll 
511b075ecf2Schristos   c = fgetc (last_open_file);
512b075ecf2Schristos 
513b075ecf2Schristos   while (c != EOF && c != '\n' && c != '\r')
5142a6b7db3Sskrll     {
515*f22f0ef4Schristos       if (++count < size)
5162a6b7db3Sskrll 	*p++ = c;
5172a6b7db3Sskrll       c = fgetc (last_open_file);
5182a6b7db3Sskrll     }
519b075ecf2Schristos 
520b075ecf2Schristos   /* If '\r' is followed by '\n', swallow that.  Likewise, if '\n'
521b075ecf2Schristos      is followed by '\r', swallow that as well.  */
522b075ecf2Schristos   if (c == '\r' || c == '\n')
523b075ecf2Schristos     {
524b075ecf2Schristos       int next = fgetc (last_open_file);
525b075ecf2Schristos 
526b075ecf2Schristos       if ((c == '\r' && next != '\n')
527b075ecf2Schristos 	  || (c == '\n' && next != '\r'))
528b075ecf2Schristos 	ungetc (next, last_open_file);
529b075ecf2Schristos     }
530b075ecf2Schristos 
5312a6b7db3Sskrll   if (c == EOF)
5322a6b7db3Sskrll     {
5332a6b7db3Sskrll       file->at_end = 1;
534*f22f0ef4Schristos       if (count + 3 < size)
5352a6b7db3Sskrll 	{
5362a6b7db3Sskrll 	  *p++ = '.';
5372a6b7db3Sskrll 	  *p++ = '.';
5382a6b7db3Sskrll 	  *p++ = '.';
5392a6b7db3Sskrll 	}
5402a6b7db3Sskrll     }
5412a6b7db3Sskrll   file->linenum++;
5422a6b7db3Sskrll   *p++ = 0;
5432a6b7db3Sskrll   return line;
5442a6b7db3Sskrll }
5452a6b7db3Sskrll 
546b075ecf2Schristos 
547b075ecf2Schristos /* This function rewinds the requested file back to the line requested,
548b075ecf2Schristos    reads it in again into the buffer provided and then restores the file
54975f9f1baSchristos    back to its original location.  */
550b075ecf2Schristos 
55175f9f1baSchristos static void
rebuffer_line(file_info_type * file,unsigned int linenum,char * buffer,unsigned int size)552b075ecf2Schristos rebuffer_line (file_info_type *  file,
553b075ecf2Schristos 	       unsigned int      linenum,
554b075ecf2Schristos 	       char *            buffer,
555b075ecf2Schristos 	       unsigned int      size)
556b075ecf2Schristos {
557b075ecf2Schristos   unsigned int count = 0;
5585ba6b03cSchristos   unsigned int current_line;
559b075ecf2Schristos   char * p = buffer;
560b075ecf2Schristos   long pos;
5615ba6b03cSchristos   long pos2;
562b075ecf2Schristos   int c;
563*f22f0ef4Schristos   bool found = false;
564b075ecf2Schristos 
565b075ecf2Schristos   /* Sanity checks.  */
5665ba6b03cSchristos   if (file == NULL || buffer == NULL || size <= 1 || file->linenum <= linenum)
56775f9f1baSchristos     return;
568b075ecf2Schristos 
569b075ecf2Schristos   /* Check the cache and see if we last used this file.  */
570b075ecf2Schristos   if (last_open_file_info == NULL || file != last_open_file_info)
571b075ecf2Schristos     {
572b075ecf2Schristos       if (last_open_file)
573b075ecf2Schristos 	{
574b075ecf2Schristos 	  last_open_file_info->pos = ftell (last_open_file);
575b075ecf2Schristos 	  fclose (last_open_file);
576b075ecf2Schristos 	}
577b075ecf2Schristos 
578b075ecf2Schristos       /* Open the file in the binary mode so that ftell above can
579b075ecf2Schristos 	 return a reliable value that we can feed to fseek below.  */
580b075ecf2Schristos       last_open_file_info = file;
581b075ecf2Schristos       last_open_file = fopen (file->filename, FOPEN_RB);
582b075ecf2Schristos       if (last_open_file == NULL)
583b075ecf2Schristos 	{
584b075ecf2Schristos 	  file->at_end = 1;
58575f9f1baSchristos 	  return;
586b075ecf2Schristos 	}
587b075ecf2Schristos 
588b075ecf2Schristos       /* Seek to where we were last time this file was open.  */
589b075ecf2Schristos       if (file->pos)
590b075ecf2Schristos 	fseek (last_open_file, file->pos, SEEK_SET);
591b075ecf2Schristos     }
592b075ecf2Schristos 
593b075ecf2Schristos   /* Remember where we are in the current file.  */
5945ba6b03cSchristos   pos2 = pos = ftell (last_open_file);
5955ba6b03cSchristos   if (pos < 3)
59675f9f1baSchristos     return;
5975ba6b03cSchristos   current_line = file->linenum;
598b075ecf2Schristos 
599b075ecf2Schristos   /* Leave room for the nul at the end of the buffer.  */
600b075ecf2Schristos   size -= 1;
6015ba6b03cSchristos   buffer[size] = 0;
6025ba6b03cSchristos 
6035ba6b03cSchristos   /* Increment the current line count by one.
6045ba6b03cSchristos      This is to allow for the fact that we are searching for the
6055ba6b03cSchristos      start of a previous line, but we do this by detecting end-of-line
6065ba6b03cSchristos      character(s) not start-of-line characters.  */
6075ba6b03cSchristos   ++ current_line;
6085ba6b03cSchristos 
6095ba6b03cSchristos   while (pos2 > 0 && ! found)
6105ba6b03cSchristos     {
6115ba6b03cSchristos       char * ptr;
6125ba6b03cSchristos 
6135ba6b03cSchristos       /* Move backwards through the file, looking for earlier lines.  */
6145ba6b03cSchristos       pos2 = (long) size > pos2 ? 0 : pos2 - size;
6155ba6b03cSchristos       fseek (last_open_file, pos2, SEEK_SET);
6165ba6b03cSchristos 
6175ba6b03cSchristos       /* Our caller has kindly provided us with a buffer, so we use it.  */
6185ba6b03cSchristos       if (fread (buffer, 1, size, last_open_file) != size)
6195ba6b03cSchristos 	{
6205ba6b03cSchristos 	  as_warn (_("unable to rebuffer file: %s\n"), file->filename);
62175f9f1baSchristos 	  return;
6225ba6b03cSchristos 	}
6235ba6b03cSchristos 
6245ba6b03cSchristos       for (ptr = buffer + size; ptr >= buffer; -- ptr)
6255ba6b03cSchristos 	{
6265ba6b03cSchristos 	  if (*ptr == '\n')
6275ba6b03cSchristos 	    {
6285ba6b03cSchristos 	      -- current_line;
6295ba6b03cSchristos 
6305ba6b03cSchristos 	      if (current_line == linenum)
6315ba6b03cSchristos 		{
6325ba6b03cSchristos 		  /* We have found the start of the line we seek.  */
633*f22f0ef4Schristos 		  found = true;
6345ba6b03cSchristos 
6355ba6b03cSchristos 		  /* FIXME: We could skip the read-in-the-line code
6365ba6b03cSchristos 		     below if we know that we already have the whole
6375ba6b03cSchristos 		     line in the buffer.  */
6385ba6b03cSchristos 
6395ba6b03cSchristos 		  /* Advance pos2 to the newline character we have just located.  */
6405ba6b03cSchristos 		  pos2 += (ptr - buffer);
6415ba6b03cSchristos 
6425ba6b03cSchristos 		  /* Skip the newline and, if present, the carriage return.  */
6435ba6b03cSchristos 		  if (ptr + 1 == buffer + size)
6445ba6b03cSchristos 		    {
6455ba6b03cSchristos 		      ++pos2;
6465ba6b03cSchristos 		      if (fgetc (last_open_file) == '\r')
6475ba6b03cSchristos 			++ pos2;
6485ba6b03cSchristos 		    }
6495ba6b03cSchristos 		  else
6505ba6b03cSchristos 		    pos2 += (ptr[1] == '\r' ? 2 : 1);
6515ba6b03cSchristos 
6525ba6b03cSchristos 		  /* Move the file pointer to this location.  */
6535ba6b03cSchristos 		  fseek (last_open_file, pos2, SEEK_SET);
6545ba6b03cSchristos 		  break;
6555ba6b03cSchristos 		}
6565ba6b03cSchristos 	    }
6575ba6b03cSchristos 	}
6585ba6b03cSchristos     }
659b075ecf2Schristos 
660b075ecf2Schristos   /* Read in the line.  */
661b075ecf2Schristos   c = fgetc (last_open_file);
662b075ecf2Schristos 
663b075ecf2Schristos   while (c != EOF && c != '\n' && c != '\r')
664b075ecf2Schristos     {
665b075ecf2Schristos       if (count < size)
666b075ecf2Schristos 	*p++ = c;
667b075ecf2Schristos       count++;
668b075ecf2Schristos 
669b075ecf2Schristos       c = fgetc (last_open_file);
670b075ecf2Schristos     }
671b075ecf2Schristos 
672b075ecf2Schristos   /* If '\r' is followed by '\n', swallow that.  Likewise, if '\n'
673b075ecf2Schristos      is followed by '\r', swallow that as well.  */
674b075ecf2Schristos   if (c == '\r' || c == '\n')
675b075ecf2Schristos     {
676b075ecf2Schristos       int next = fgetc (last_open_file);
677b075ecf2Schristos 
678b075ecf2Schristos       if ((c == '\r' && next != '\n')
679b075ecf2Schristos 	  || (c == '\n' && next != '\r'))
680b075ecf2Schristos 	ungetc (next, last_open_file);
681b075ecf2Schristos     }
682b075ecf2Schristos 
683b075ecf2Schristos   /* Terminate the line.  */
684b075ecf2Schristos   *p++ = 0;
685b075ecf2Schristos 
686b075ecf2Schristos   /* Reset the file position.  */
687b075ecf2Schristos   fseek (last_open_file, pos, SEEK_SET);
688b075ecf2Schristos }
689b075ecf2Schristos 
6902a6b7db3Sskrll static const char *fn;
69175f9f1baSchristos static unsigned int eject;	/* Eject pending.  */
69275f9f1baSchristos static unsigned int page;	/* Current page number.  */
69375f9f1baSchristos static const char *title;	/* Current title.  */
69475f9f1baSchristos static const char *subtitle;	/* Current subtitle.  */
69575f9f1baSchristos static unsigned int on_page;	/* Number of lines printed on current page.  */
6962a6b7db3Sskrll 
6972a6b7db3Sskrll static void
listing_page(list_info_type * list)6982a6b7db3Sskrll listing_page (list_info_type *list)
6992a6b7db3Sskrll {
7002a6b7db3Sskrll   /* Grope around, see if we can see a title or subtitle edict coming up
7012a6b7db3Sskrll      soon.  (we look down 10 lines of the page and see if it's there)  */
7022a6b7db3Sskrll   if ((eject || (on_page >= (unsigned int) paper_height))
7032a6b7db3Sskrll       && paper_height != 0)
7042a6b7db3Sskrll     {
7052a6b7db3Sskrll       unsigned int c = 10;
7062a6b7db3Sskrll       int had_title = 0;
7072a6b7db3Sskrll       int had_subtitle = 0;
7082a6b7db3Sskrll 
7092a6b7db3Sskrll       page++;
7102a6b7db3Sskrll 
7112a6b7db3Sskrll       while (c != 0 && list)
7122a6b7db3Sskrll 	{
7132a6b7db3Sskrll 	  if (list->edict == EDICT_SBTTL && !had_subtitle)
7142a6b7db3Sskrll 	    {
7152a6b7db3Sskrll 	      had_subtitle = 1;
7162a6b7db3Sskrll 	      subtitle = list->edict_arg;
7172a6b7db3Sskrll 	    }
7182a6b7db3Sskrll 	  if (list->edict == EDICT_TITLE && !had_title)
7192a6b7db3Sskrll 	    {
7202a6b7db3Sskrll 	      had_title = 1;
7212a6b7db3Sskrll 	      title = list->edict_arg;
7222a6b7db3Sskrll 	    }
7232a6b7db3Sskrll 	  list = list->next;
7242a6b7db3Sskrll 	  c--;
7252a6b7db3Sskrll 	}
7262a6b7db3Sskrll 
7272a6b7db3Sskrll       if (page > 1)
7282a6b7db3Sskrll 	{
7292a6b7db3Sskrll 	  fprintf (list_file, "\f");
7302a6b7db3Sskrll 	}
7312a6b7db3Sskrll 
7322a6b7db3Sskrll       fprintf (list_file, "%s %s \t\t\tpage %d\n", LISTING_HEADER, fn, page);
7332a6b7db3Sskrll       fprintf (list_file, "%s\n", title);
7342a6b7db3Sskrll       fprintf (list_file, "%s\n", subtitle);
7352a6b7db3Sskrll       on_page = 3;
7362a6b7db3Sskrll       eject = 0;
7372a6b7db3Sskrll     }
7382a6b7db3Sskrll }
7392a6b7db3Sskrll 
740b075ecf2Schristos /* Print a line into the list_file.  Update the line count
741b075ecf2Schristos    and if necessary start a new page.  */
742b075ecf2Schristos 
743b075ecf2Schristos static void
emit_line(list_info_type * list,const char * format,...)744b075ecf2Schristos emit_line (list_info_type * list, const char * format, ...)
745b075ecf2Schristos {
746b075ecf2Schristos   va_list args;
747b075ecf2Schristos 
748b075ecf2Schristos   va_start (args, format);
749b075ecf2Schristos 
750b075ecf2Schristos   vfprintf (list_file, format, args);
751b075ecf2Schristos   on_page++;
752b075ecf2Schristos   listing_page (list);
753b075ecf2Schristos 
754b075ecf2Schristos   va_end (args);
755b075ecf2Schristos }
756b075ecf2Schristos 
7572a6b7db3Sskrll static unsigned int
calc_hex(list_info_type * list)7582a6b7db3Sskrll calc_hex (list_info_type *list)
7592a6b7db3Sskrll {
7602a6b7db3Sskrll   int data_buffer_size;
7612a6b7db3Sskrll   list_info_type *first = list;
7622a6b7db3Sskrll   unsigned int address = ~(unsigned int) 0;
7632a6b7db3Sskrll   fragS *frag;
7642a6b7db3Sskrll   fragS *frag_ptr;
7652a6b7db3Sskrll   unsigned int octet_in_frag;
7662a6b7db3Sskrll 
7672a6b7db3Sskrll   /* Find first frag which says it belongs to this line.  */
7682a6b7db3Sskrll   frag = list->frag;
7692a6b7db3Sskrll   while (frag && frag->line != list)
7702a6b7db3Sskrll     frag = frag->fr_next;
7712a6b7db3Sskrll 
7722a6b7db3Sskrll   frag_ptr = frag;
7732a6b7db3Sskrll 
7742a6b7db3Sskrll   data_buffer_size = 0;
7752a6b7db3Sskrll 
7762a6b7db3Sskrll   /* Dump all the frags which belong to this line.  */
7772a6b7db3Sskrll   while (frag_ptr != (fragS *) NULL && frag_ptr->line == first)
7782a6b7db3Sskrll     {
7792a6b7db3Sskrll       /* Print as many bytes from the fixed part as is sensible.  */
7802a6b7db3Sskrll       octet_in_frag = 0;
781f7172901Schristos       while (octet_in_frag < frag_ptr->fr_fix
7822a6b7db3Sskrll 	     && data_buffer_size < MAX_BYTES - 3)
7832a6b7db3Sskrll 	{
7842a6b7db3Sskrll 	  if (address == ~(unsigned int) 0)
7852a6b7db3Sskrll 	    address = frag_ptr->fr_address / OCTETS_PER_BYTE;
7862a6b7db3Sskrll 
7872a6b7db3Sskrll 	  sprintf (data_buffer + data_buffer_size,
7882a6b7db3Sskrll 		   "%02X",
7892a6b7db3Sskrll 		   (frag_ptr->fr_literal[octet_in_frag]) & 0xff);
7902a6b7db3Sskrll 	  data_buffer_size += 2;
7912a6b7db3Sskrll 	  octet_in_frag++;
7922a6b7db3Sskrll 	}
7932a6b7db3Sskrll       if (frag_ptr->fr_type == rs_fill)
7942a6b7db3Sskrll 	{
7952a6b7db3Sskrll 	  unsigned int var_rep_max = octet_in_frag;
7962a6b7db3Sskrll 	  unsigned int var_rep_idx = octet_in_frag;
7972a6b7db3Sskrll 
7982a6b7db3Sskrll 	  /* Print as many bytes from the variable part as is sensible.  */
799f7172901Schristos 	  while ((octet_in_frag
800f7172901Schristos 		  < frag_ptr->fr_fix + frag_ptr->fr_var * frag_ptr->fr_offset)
8012a6b7db3Sskrll 		 && data_buffer_size < MAX_BYTES - 3)
8022a6b7db3Sskrll 	    {
8032a6b7db3Sskrll 	      if (address == ~(unsigned int) 0)
8042a6b7db3Sskrll 		address = frag_ptr->fr_address / OCTETS_PER_BYTE;
8052a6b7db3Sskrll 
8062a6b7db3Sskrll 	      sprintf (data_buffer + data_buffer_size,
8072a6b7db3Sskrll 		       "%02X",
8082a6b7db3Sskrll 		       (frag_ptr->fr_literal[var_rep_idx]) & 0xff);
8092a6b7db3Sskrll 	      data_buffer_size += 2;
8102a6b7db3Sskrll 
8112a6b7db3Sskrll 	      var_rep_idx++;
8122a6b7db3Sskrll 	      octet_in_frag++;
8132a6b7db3Sskrll 
814f7172901Schristos 	      if (var_rep_idx >= frag_ptr->fr_fix + frag_ptr->fr_var)
8152a6b7db3Sskrll 		var_rep_idx = var_rep_max;
8162a6b7db3Sskrll 	    }
8172a6b7db3Sskrll 	}
8182a6b7db3Sskrll 
8192a6b7db3Sskrll       frag_ptr = frag_ptr->fr_next;
8202a6b7db3Sskrll     }
8212a6b7db3Sskrll   data_buffer[data_buffer_size] = '\0';
8222a6b7db3Sskrll   return address;
8232a6b7db3Sskrll }
8242a6b7db3Sskrll 
8252a6b7db3Sskrll static void
print_lines(list_info_type * list,unsigned int lineno,const char * string,unsigned int address)8262a6b7db3Sskrll print_lines (list_info_type *list, unsigned int lineno,
82775f9f1baSchristos 	     const char *string, unsigned int address)
8282a6b7db3Sskrll {
8292a6b7db3Sskrll   unsigned int idx;
8302a6b7db3Sskrll   unsigned int nchars;
8312a6b7db3Sskrll   unsigned int lines;
8322a6b7db3Sskrll   unsigned int octet_in_word = 0;
8332a6b7db3Sskrll   char *src = data_buffer;
8342a6b7db3Sskrll   int cur;
83505caefcfSchristos   struct list_message *msg;
8362a6b7db3Sskrll 
8372a6b7db3Sskrll   /* Print the stuff on the first line.  */
8382a6b7db3Sskrll   listing_page (list);
8392a6b7db3Sskrll   nchars = (LISTING_WORD_SIZE * 2 + 1) * listing_lhs_width;
8402a6b7db3Sskrll 
8412a6b7db3Sskrll   /* Print the hex for the first line.  */
8422a6b7db3Sskrll   if (address == ~(unsigned int) 0)
8432a6b7db3Sskrll     {
8442a6b7db3Sskrll       fprintf (list_file, "% 4d     ", lineno);
8452a6b7db3Sskrll       for (idx = 0; idx < nchars; idx++)
8462a6b7db3Sskrll 	fprintf (list_file, " ");
8472a6b7db3Sskrll 
848b075ecf2Schristos       emit_line (NULL, "\t%s\n", string ? string : "");
8492a6b7db3Sskrll       return;
8502a6b7db3Sskrll     }
8512a6b7db3Sskrll 
8522a6b7db3Sskrll   if (had_errors ())
8532a6b7db3Sskrll     fprintf (list_file, "% 4d ???? ", lineno);
8542a6b7db3Sskrll   else
8552a6b7db3Sskrll     fprintf (list_file, "% 4d %04x ", lineno, address);
8562a6b7db3Sskrll 
8572a6b7db3Sskrll   /* And the data to go along with it.  */
8582a6b7db3Sskrll   idx = 0;
8592a6b7db3Sskrll   cur = 0;
8602a6b7db3Sskrll   while (src[cur] && idx < nchars)
8612a6b7db3Sskrll     {
8622a6b7db3Sskrll       int offset;
8632a6b7db3Sskrll       offset = cur;
8642a6b7db3Sskrll       fprintf (list_file, "%c%c", src[offset], src[offset + 1]);
8652a6b7db3Sskrll       cur += 2;
8662a6b7db3Sskrll       octet_in_word++;
8672a6b7db3Sskrll 
8682a6b7db3Sskrll       if (octet_in_word == LISTING_WORD_SIZE)
8692a6b7db3Sskrll 	{
8702a6b7db3Sskrll 	  fprintf (list_file, " ");
8712a6b7db3Sskrll 	  idx++;
8722a6b7db3Sskrll 	  octet_in_word = 0;
8732a6b7db3Sskrll 	}
8742a6b7db3Sskrll 
8752a6b7db3Sskrll       idx += 2;
8762a6b7db3Sskrll     }
8772a6b7db3Sskrll 
8782a6b7db3Sskrll   for (; idx < nchars; idx++)
8792a6b7db3Sskrll     fprintf (list_file, " ");
8802a6b7db3Sskrll 
881b075ecf2Schristos   emit_line (list, "\t%s\n", string ? string : "");
8822a6b7db3Sskrll 
88305caefcfSchristos   for (msg = list->messages; msg; msg = msg->next)
88405caefcfSchristos     emit_line (list, "****  %s\n", msg->message);
8852a6b7db3Sskrll 
8862a6b7db3Sskrll   for (lines = 0;
8872a6b7db3Sskrll        lines < (unsigned int) listing_lhs_cont_lines
8882a6b7db3Sskrll 	 && src[cur];
8892a6b7db3Sskrll        lines++)
8902a6b7db3Sskrll     {
8912a6b7db3Sskrll       nchars = ((LISTING_WORD_SIZE * 2) + 1) * listing_lhs_width_second - 1;
8922a6b7db3Sskrll       idx = 0;
8932a6b7db3Sskrll 
8942a6b7db3Sskrll       /* Print any more lines of data, but more compactly.  */
8952a6b7db3Sskrll       fprintf (list_file, "% 4d      ", lineno);
8962a6b7db3Sskrll 
8972a6b7db3Sskrll       while (src[cur] && idx < nchars)
8982a6b7db3Sskrll 	{
8992a6b7db3Sskrll 	  int offset;
9002a6b7db3Sskrll 	  offset = cur;
9012a6b7db3Sskrll 	  fprintf (list_file, "%c%c", src[offset], src[offset + 1]);
9022a6b7db3Sskrll 	  cur += 2;
9032a6b7db3Sskrll 	  idx += 2;
9042a6b7db3Sskrll 	  octet_in_word++;
9052a6b7db3Sskrll 
9062a6b7db3Sskrll 	  if (octet_in_word == LISTING_WORD_SIZE)
9072a6b7db3Sskrll 	    {
9082a6b7db3Sskrll 	      fprintf (list_file, " ");
9092a6b7db3Sskrll 	      idx++;
9102a6b7db3Sskrll 	      octet_in_word = 0;
9112a6b7db3Sskrll 	    }
9122a6b7db3Sskrll 	}
9132a6b7db3Sskrll 
914b075ecf2Schristos       emit_line (list, "\n");
9152a6b7db3Sskrll     }
9162a6b7db3Sskrll }
9172a6b7db3Sskrll 
9182a6b7db3Sskrll static void
list_symbol_table(void)9192a6b7db3Sskrll list_symbol_table (void)
9202a6b7db3Sskrll {
9212a6b7db3Sskrll   extern symbolS *symbol_rootP;
9222a6b7db3Sskrll   int got_some = 0;
9232a6b7db3Sskrll 
9242a6b7db3Sskrll   symbolS *ptr;
9252a6b7db3Sskrll   eject = 1;
926b075ecf2Schristos   listing_page (NULL);
9272a6b7db3Sskrll 
9282a6b7db3Sskrll   for (ptr = symbol_rootP; ptr != (symbolS *) NULL; ptr = symbol_next (ptr))
9292a6b7db3Sskrll     {
9302a6b7db3Sskrll       if (SEG_NORMAL (S_GET_SEGMENT (ptr))
9312a6b7db3Sskrll 	  || S_GET_SEGMENT (ptr) == absolute_section)
9322a6b7db3Sskrll 	{
9332a6b7db3Sskrll 	  /* Don't report section symbols.  They are not interesting.  */
9342a6b7db3Sskrll 	  if (symbol_section_p (ptr))
9352a6b7db3Sskrll 	    continue;
9362a6b7db3Sskrll 
9372a6b7db3Sskrll 	  if (S_GET_NAME (ptr))
9382a6b7db3Sskrll 	    {
9392a6b7db3Sskrll 	      char buf[30], fmt[8];
9402a6b7db3Sskrll 	      valueT val = S_GET_VALUE (ptr);
9412a6b7db3Sskrll 
9422a6b7db3Sskrll 	      /* @@ Note that this is dependent on the compilation options,
9432a6b7db3Sskrll 		 not solely on the target characteristics.  */
9442a6b7db3Sskrll 	      if (sizeof (val) == 4 && sizeof (int) == 4)
9452a6b7db3Sskrll 		sprintf (buf, "%08lx", (unsigned long) val);
9462a6b7db3Sskrll 	      else if (sizeof (val) <= sizeof (unsigned long))
9472a6b7db3Sskrll 		{
9482a6b7db3Sskrll 		  sprintf (fmt, "%%0%lulx",
9492a6b7db3Sskrll 			   (unsigned long) (sizeof (val) * 2));
9502a6b7db3Sskrll 		  sprintf (buf, fmt, (unsigned long) val);
9512a6b7db3Sskrll 		}
9522a6b7db3Sskrll #if defined (BFD64)
9532a6b7db3Sskrll 	      else if (sizeof (val) > 4)
9542a6b7db3Sskrll 		sprintf_vma (buf, val);
9552a6b7db3Sskrll #endif
9562a6b7db3Sskrll 	      else
9572a6b7db3Sskrll 		abort ();
9582a6b7db3Sskrll 
9592a6b7db3Sskrll 	      if (!got_some)
9602a6b7db3Sskrll 		{
9612a6b7db3Sskrll 		  fprintf (list_file, "DEFINED SYMBOLS\n");
9622a6b7db3Sskrll 		  on_page++;
9632a6b7db3Sskrll 		  got_some = 1;
9642a6b7db3Sskrll 		}
9652a6b7db3Sskrll 
9662a6b7db3Sskrll 	      if (symbol_get_frag (ptr) && symbol_get_frag (ptr)->line)
9672a6b7db3Sskrll 		{
9682a6b7db3Sskrll 		  fprintf (list_file, "%20s:%-5d  %s:%s %s\n",
9692a6b7db3Sskrll 			   symbol_get_frag (ptr)->line->file->filename,
9702a6b7db3Sskrll 			   symbol_get_frag (ptr)->line->line,
9712a6b7db3Sskrll 			   segment_name (S_GET_SEGMENT (ptr)),
9722a6b7db3Sskrll 			   buf, S_GET_NAME (ptr));
9732a6b7db3Sskrll 		}
9742a6b7db3Sskrll 	      else
9752a6b7db3Sskrll 		{
9762a6b7db3Sskrll 		  fprintf (list_file, "%33s:%s %s\n",
9772a6b7db3Sskrll 			   segment_name (S_GET_SEGMENT (ptr)),
9782a6b7db3Sskrll 			   buf, S_GET_NAME (ptr));
9792a6b7db3Sskrll 		}
9802a6b7db3Sskrll 
9812a6b7db3Sskrll 	      on_page++;
982b075ecf2Schristos 	      listing_page (NULL);
9832a6b7db3Sskrll 	    }
9842a6b7db3Sskrll 	}
9852a6b7db3Sskrll 
9862a6b7db3Sskrll     }
9872a6b7db3Sskrll   if (!got_some)
9882a6b7db3Sskrll     {
9892a6b7db3Sskrll       fprintf (list_file, "NO DEFINED SYMBOLS\n");
9902a6b7db3Sskrll       on_page++;
9912a6b7db3Sskrll     }
992b075ecf2Schristos   emit_line (NULL, "\n");
9932a6b7db3Sskrll 
9942a6b7db3Sskrll   got_some = 0;
9952a6b7db3Sskrll 
9962a6b7db3Sskrll   for (ptr = symbol_rootP; ptr != (symbolS *) NULL; ptr = symbol_next (ptr))
9972a6b7db3Sskrll     {
9982a6b7db3Sskrll       if (S_GET_NAME (ptr) && strlen (S_GET_NAME (ptr)) != 0)
9992a6b7db3Sskrll 	{
10002a6b7db3Sskrll 	  if (S_GET_SEGMENT (ptr) == undefined_section)
10012a6b7db3Sskrll 	    {
10022a6b7db3Sskrll 	      if (!got_some)
10032a6b7db3Sskrll 		{
10042a6b7db3Sskrll 		  got_some = 1;
1005b075ecf2Schristos 
1006b075ecf2Schristos 		  emit_line (NULL, "UNDEFINED SYMBOLS\n");
10072a6b7db3Sskrll 		}
1008b075ecf2Schristos 
1009b075ecf2Schristos 	      emit_line (NULL, "%s\n", S_GET_NAME (ptr));
10102a6b7db3Sskrll 	    }
10112a6b7db3Sskrll 	}
10122a6b7db3Sskrll     }
10132a6b7db3Sskrll 
1014b075ecf2Schristos   if (!got_some)
1015b075ecf2Schristos     emit_line (NULL, "NO UNDEFINED SYMBOLS\n");
1016b075ecf2Schristos }
1017b075ecf2Schristos 
1018b075ecf2Schristos typedef struct cached_line
10192a6b7db3Sskrll {
1020b075ecf2Schristos   file_info_type * file;
1021b075ecf2Schristos   unsigned int     line;
1022b075ecf2Schristos   char             buffer [LISTING_RHS_WIDTH];
1023b075ecf2Schristos } cached_line;
1024b075ecf2Schristos 
1025b075ecf2Schristos static void
print_source(file_info_type * current_file,list_info_type * list,unsigned int width)1026b075ecf2Schristos print_source (file_info_type *  current_file,
1027b075ecf2Schristos 	      list_info_type *  list,
1028b075ecf2Schristos 	      unsigned int      width)
1029b075ecf2Schristos {
1030b075ecf2Schristos #define NUM_CACHE_LINES  3
1031b075ecf2Schristos   static cached_line cached_lines[NUM_CACHE_LINES];
1032b075ecf2Schristos   static int next_free_line = 0;
1033b075ecf2Schristos   cached_line * cache = NULL;
1034b075ecf2Schristos 
1035b075ecf2Schristos   if (current_file->linenum > list->hll_line
1036b075ecf2Schristos       && list->hll_line > 0)
1037b075ecf2Schristos     {
1038b075ecf2Schristos       /* This can happen with modern optimizing compilers.  The source
1039b075ecf2Schristos 	 lines from the high level language input program are split up
1040b075ecf2Schristos 	 and interleaved, meaning the line number we want to display
1041b075ecf2Schristos 	 (list->hll_line) can have already been displayed.  We have
1042b075ecf2Schristos 	 three choices:
1043b075ecf2Schristos 
1044b075ecf2Schristos 	   a. Do nothing, since we have already displayed the source
1045b075ecf2Schristos 	      line.  This was the old behaviour.
1046b075ecf2Schristos 
1047b075ecf2Schristos 	   b. Display the particular line requested again, but only
1048b075ecf2Schristos 	      that line.  This is the new behaviour.
1049b075ecf2Schristos 
1050b075ecf2Schristos 	   c. Display the particular line requested again and reset
1051b075ecf2Schristos 	      the current_file->line_num value so that we redisplay
1052b075ecf2Schristos 	      all the following lines as well the next time we
1053b075ecf2Schristos 	      encounter a larger line number.  */
1054b075ecf2Schristos       int i;
1055b075ecf2Schristos 
1056b075ecf2Schristos       /* Check the cache, maybe we already have the line saved.  */
1057b075ecf2Schristos       for (i = 0; i < NUM_CACHE_LINES; i++)
1058b075ecf2Schristos 	if (cached_lines[i].file == current_file
1059b075ecf2Schristos 	    && cached_lines[i].line == list->hll_line)
1060b075ecf2Schristos 	  {
1061b075ecf2Schristos 	    cache = cached_lines + i;
1062b075ecf2Schristos 	    break;
1063b075ecf2Schristos 	  }
1064b075ecf2Schristos 
1065b075ecf2Schristos       if (i == NUM_CACHE_LINES)
1066b075ecf2Schristos 	{
1067b075ecf2Schristos 	  cache = cached_lines + next_free_line;
1068b075ecf2Schristos 	  next_free_line ++;
1069b075ecf2Schristos 	  if (next_free_line == NUM_CACHE_LINES)
1070b075ecf2Schristos 	    next_free_line = 0;
1071b075ecf2Schristos 
1072b075ecf2Schristos 	  cache->file = current_file;
1073b075ecf2Schristos 	  cache->line = list->hll_line;
1074b075ecf2Schristos 	  cache->buffer[0] = 0;
1075b075ecf2Schristos 	  rebuffer_line (current_file, cache->line, cache->buffer, width);
1076b075ecf2Schristos 	}
1077b075ecf2Schristos 
1078b075ecf2Schristos       emit_line (list, "%4u:%-13s **** %s\n",
1079b075ecf2Schristos 		 cache->line, cache->file->filename, cache->buffer);
1080b075ecf2Schristos       return;
1081b075ecf2Schristos     }
1082b075ecf2Schristos 
10832a6b7db3Sskrll   if (!current_file->at_end)
10842a6b7db3Sskrll     {
1085b075ecf2Schristos       int num_lines_shown = 0;
1086b075ecf2Schristos 
10872a6b7db3Sskrll       while (current_file->linenum < list->hll_line
10882a6b7db3Sskrll 	     && !current_file->at_end)
10892a6b7db3Sskrll 	{
109075f9f1baSchristos 	  const char *p;
10912a6b7db3Sskrll 
1092b075ecf2Schristos 	  cache = cached_lines + next_free_line;
1093b075ecf2Schristos 	  cache->file = current_file;
1094b075ecf2Schristos 	  cache->line = current_file->linenum + 1;
1095b075ecf2Schristos 	  cache->buffer[0] = 0;
1096b075ecf2Schristos 	  p = buffer_line (current_file, cache->buffer, width);
1097b075ecf2Schristos 
1098b075ecf2Schristos 	  /* Cache optimization:  If printing a group of lines
1099b075ecf2Schristos 	     cache the first and last lines in the group.  */
1100b075ecf2Schristos 	  if (num_lines_shown == 0)
1101b075ecf2Schristos 	    {
1102b075ecf2Schristos 	      next_free_line ++;
1103b075ecf2Schristos 	      if (next_free_line == NUM_CACHE_LINES)
1104b075ecf2Schristos 		next_free_line = 0;
1105b075ecf2Schristos 	    }
1106b075ecf2Schristos 
1107b075ecf2Schristos 	  emit_line (list, "%4u:%-13s **** %s\n",
1108b075ecf2Schristos 		     cache->line, cache->file->filename, p);
1109b075ecf2Schristos 	  num_lines_shown ++;
11102a6b7db3Sskrll 	}
11112a6b7db3Sskrll     }
11122a6b7db3Sskrll }
11132a6b7db3Sskrll 
11142a6b7db3Sskrll /* Sometimes the user doesn't want to be bothered by the debugging
11152a6b7db3Sskrll    records inserted by the compiler, see if the line is suspicious.  */
11162a6b7db3Sskrll 
11172a6b7db3Sskrll static int
debugging_pseudo(list_info_type * list,const char * line)11182a6b7db3Sskrll debugging_pseudo (list_info_type *list, const char *line)
11192a6b7db3Sskrll {
1120b075ecf2Schristos #ifdef OBJ_ELF
11212a6b7db3Sskrll   static int in_debug;
11222a6b7db3Sskrll   int was_debug;
1123b075ecf2Schristos #endif
11242a6b7db3Sskrll 
11252a6b7db3Sskrll   if (list->debugging)
11262a6b7db3Sskrll     {
1127b075ecf2Schristos #ifdef OBJ_ELF
11282a6b7db3Sskrll       in_debug = 1;
1129b075ecf2Schristos #endif
11302a6b7db3Sskrll       return 1;
11312a6b7db3Sskrll     }
1132b075ecf2Schristos #ifdef OBJ_ELF
11332a6b7db3Sskrll   was_debug = in_debug;
11342a6b7db3Sskrll   in_debug = 0;
1135b075ecf2Schristos #endif
11362a6b7db3Sskrll 
11372a6b7db3Sskrll   while (ISSPACE (*line))
11382a6b7db3Sskrll     line++;
11392a6b7db3Sskrll 
11402a6b7db3Sskrll   if (*line != '.')
11412a6b7db3Sskrll     {
11422a6b7db3Sskrll #ifdef OBJ_ELF
11432a6b7db3Sskrll       /* The ELF compiler sometimes emits blank lines after switching
11442a6b7db3Sskrll          out of a debugging section.  If the next line drops us back
11452a6b7db3Sskrll          into debugging information, then don't print the blank line.
11462a6b7db3Sskrll          This is a hack for a particular compiler behaviour, not a
11472a6b7db3Sskrll          general case.  */
11482a6b7db3Sskrll       if (was_debug
11492a6b7db3Sskrll 	  && *line == '\0'
11502a6b7db3Sskrll 	  && list->next != NULL
11512a6b7db3Sskrll 	  && list->next->debugging)
11522a6b7db3Sskrll 	{
11532a6b7db3Sskrll 	  in_debug = 1;
11542a6b7db3Sskrll 	  return 1;
11552a6b7db3Sskrll 	}
11562a6b7db3Sskrll #endif
11572a6b7db3Sskrll 
11582a6b7db3Sskrll       return 0;
11592a6b7db3Sskrll     }
11602a6b7db3Sskrll 
11612a6b7db3Sskrll   line++;
11622a6b7db3Sskrll 
1163*f22f0ef4Schristos   if (startswith (line, "def"))
11642a6b7db3Sskrll     return 1;
1165*f22f0ef4Schristos   if (startswith (line, "val"))
11662a6b7db3Sskrll     return 1;
1167*f22f0ef4Schristos   if (startswith (line, "scl"))
11682a6b7db3Sskrll     return 1;
1169*f22f0ef4Schristos   if (startswith (line, "line"))
11702a6b7db3Sskrll     return 1;
1171*f22f0ef4Schristos   if (startswith (line, "endef"))
11722a6b7db3Sskrll     return 1;
1173*f22f0ef4Schristos   if (startswith (line, "ln"))
11742a6b7db3Sskrll     return 1;
1175*f22f0ef4Schristos   if (startswith (line, "type"))
11762a6b7db3Sskrll     return 1;
1177*f22f0ef4Schristos   if (startswith (line, "size"))
11782a6b7db3Sskrll     return 1;
1179*f22f0ef4Schristos   if (startswith (line, "dim"))
11802a6b7db3Sskrll     return 1;
1181*f22f0ef4Schristos   if (startswith (line, "tag"))
11822a6b7db3Sskrll     return 1;
1183*f22f0ef4Schristos   if (startswith (line, "stabs"))
11842a6b7db3Sskrll     return 1;
1185*f22f0ef4Schristos   if (startswith (line, "stabn"))
11862a6b7db3Sskrll     return 1;
11872a6b7db3Sskrll 
11882a6b7db3Sskrll   return 0;
11892a6b7db3Sskrll }
11902a6b7db3Sskrll 
11912a6b7db3Sskrll static void
listing_listing(char * name ATTRIBUTE_UNUSED)11922a6b7db3Sskrll listing_listing (char *name ATTRIBUTE_UNUSED)
11932a6b7db3Sskrll {
11942a6b7db3Sskrll   list_info_type *list = head;
11952a6b7db3Sskrll   file_info_type *current_hll_file = (file_info_type *) NULL;
11962a6b7db3Sskrll   char *buffer;
119775f9f1baSchristos   const char *p;
11982a6b7db3Sskrll   int show_listing = 1;
11992a6b7db3Sskrll   unsigned int width;
12002a6b7db3Sskrll 
120175f9f1baSchristos   buffer = XNEWVEC (char, listing_rhs_width);
120275f9f1baSchristos   data_buffer = XNEWVEC (char, MAX_BYTES);
12032a6b7db3Sskrll   eject = 1;
12042a6b7db3Sskrll   list = head->next;
12052a6b7db3Sskrll 
12062a6b7db3Sskrll   while (list)
12072a6b7db3Sskrll     {
12082a6b7db3Sskrll       unsigned int list_line;
12092a6b7db3Sskrll 
12102a6b7db3Sskrll       width = listing_rhs_width > paper_width ? paper_width :
12112a6b7db3Sskrll 	listing_rhs_width;
12122a6b7db3Sskrll 
12132a6b7db3Sskrll       list_line = list->line;
12142a6b7db3Sskrll       switch (list->edict)
12152a6b7db3Sskrll 	{
12162a6b7db3Sskrll 	case EDICT_LIST:
12172a6b7db3Sskrll 	  /* Skip all lines up to the current.  */
12182a6b7db3Sskrll 	  list_line--;
12192a6b7db3Sskrll 	  break;
12202a6b7db3Sskrll 	case EDICT_NOLIST:
12212a6b7db3Sskrll 	  show_listing--;
12222a6b7db3Sskrll 	  break;
12232a6b7db3Sskrll 	case EDICT_NOLIST_NEXT:
12242a6b7db3Sskrll 	  if (show_listing == 0)
12252a6b7db3Sskrll 	    list_line--;
12262a6b7db3Sskrll 	  break;
12272a6b7db3Sskrll 	case EDICT_EJECT:
12282a6b7db3Sskrll 	  break;
12292a6b7db3Sskrll 	case EDICT_NONE:
12302a6b7db3Sskrll 	  break;
12312a6b7db3Sskrll 	case EDICT_TITLE:
12322a6b7db3Sskrll 	  title = list->edict_arg;
12332a6b7db3Sskrll 	  break;
12342a6b7db3Sskrll 	case EDICT_SBTTL:
12352a6b7db3Sskrll 	  subtitle = list->edict_arg;
12362a6b7db3Sskrll 	  break;
12372a6b7db3Sskrll 	default:
12382a6b7db3Sskrll 	  abort ();
12392a6b7db3Sskrll 	}
12402a6b7db3Sskrll 
12412a6b7db3Sskrll       if (show_listing <= 0)
12422a6b7db3Sskrll 	{
12432a6b7db3Sskrll 	  while (list->file->linenum < list_line
12442a6b7db3Sskrll 		 && !list->file->at_end)
12452a6b7db3Sskrll 	    p = buffer_line (list->file, buffer, width);
12462a6b7db3Sskrll 	}
12472a6b7db3Sskrll 
12482a6b7db3Sskrll       if (list->edict == EDICT_LIST
12492a6b7db3Sskrll 	  || (list->edict == EDICT_NOLIST_NEXT && show_listing == 0))
12502a6b7db3Sskrll 	{
12512a6b7db3Sskrll 	  /* Enable listing for the single line that caused the enable.  */
12522a6b7db3Sskrll 	  list_line++;
12532a6b7db3Sskrll 	  show_listing++;
12542a6b7db3Sskrll 	}
12552a6b7db3Sskrll 
12562a6b7db3Sskrll       if (show_listing > 0)
12572a6b7db3Sskrll 	{
12582a6b7db3Sskrll 	  /* Scan down the list and print all the stuff which can be done
12592a6b7db3Sskrll 	     with this line (or lines).  */
12602a6b7db3Sskrll 	  if (list->hll_file)
12612a6b7db3Sskrll 	    current_hll_file = list->hll_file;
12622a6b7db3Sskrll 
12632a6b7db3Sskrll 	  if (current_hll_file && list->hll_line && (listing & LISTING_HLL))
1264b075ecf2Schristos 	    print_source (current_hll_file, list, width);
12652a6b7db3Sskrll 
12662a6b7db3Sskrll 	  if (list->line_contents)
12672a6b7db3Sskrll 	    {
12682a6b7db3Sskrll 	      if (!((listing & LISTING_NODEBUG)
12692a6b7db3Sskrll 		    && debugging_pseudo (list, list->line_contents)))
12702a6b7db3Sskrll 		print_lines (list,
12712a6b7db3Sskrll 			     list->file->linenum == 0 ? list->line : list->file->linenum,
12722a6b7db3Sskrll 			     list->line_contents, calc_hex (list));
12732a6b7db3Sskrll 
12742a6b7db3Sskrll 	      free (list->line_contents);
12752a6b7db3Sskrll 	      list->line_contents = NULL;
12762a6b7db3Sskrll 	    }
12772a6b7db3Sskrll 	  else
12782a6b7db3Sskrll 	    {
12792a6b7db3Sskrll 	      while (list->file->linenum < list_line
12802a6b7db3Sskrll 		     && !list->file->at_end)
12812a6b7db3Sskrll 		{
12822a6b7db3Sskrll 		  unsigned int address;
12832a6b7db3Sskrll 
12842a6b7db3Sskrll 		  p = buffer_line (list->file, buffer, width);
12852a6b7db3Sskrll 
12862a6b7db3Sskrll 		  if (list->file->linenum < list_line)
12872a6b7db3Sskrll 		    address = ~(unsigned int) 0;
12882a6b7db3Sskrll 		  else
12892a6b7db3Sskrll 		    address = calc_hex (list);
12902a6b7db3Sskrll 
12912a6b7db3Sskrll 		  if (!((listing & LISTING_NODEBUG)
12922a6b7db3Sskrll 			&& debugging_pseudo (list, p)))
12932a6b7db3Sskrll 		    print_lines (list, list->file->linenum, p, address);
12942a6b7db3Sskrll 		}
12952a6b7db3Sskrll 	    }
12962a6b7db3Sskrll 
12972a6b7db3Sskrll 	  if (list->edict == EDICT_EJECT)
12982a6b7db3Sskrll 	    eject = 1;
12992a6b7db3Sskrll 	}
13002a6b7db3Sskrll 
13012a6b7db3Sskrll       if (list->edict == EDICT_NOLIST_NEXT && show_listing == 1)
13022a6b7db3Sskrll 	--show_listing;
13032a6b7db3Sskrll 
13042a6b7db3Sskrll       list = list->next;
13052a6b7db3Sskrll     }
13062a6b7db3Sskrll 
13072a6b7db3Sskrll   free (buffer);
13082a6b7db3Sskrll   free (data_buffer);
13092a6b7db3Sskrll   data_buffer = NULL;
13102a6b7db3Sskrll }
13112a6b7db3Sskrll 
13122a6b7db3Sskrll /* Print time stamp in ISO format:  yyyy-mm-ddThh:mm:ss.ss+/-zzzz.  */
13132a6b7db3Sskrll 
13142a6b7db3Sskrll static void
print_timestamp(void)13152a6b7db3Sskrll print_timestamp (void)
13162a6b7db3Sskrll {
13172a6b7db3Sskrll   const time_t now = time (NULL);
13182a6b7db3Sskrll   struct tm * timestamp;
13192a6b7db3Sskrll   char stampstr[MAX_DATELEN];
13202a6b7db3Sskrll 
13212a6b7db3Sskrll   /* Any portable way to obtain subsecond values???  */
13222a6b7db3Sskrll   timestamp = localtime (&now);
13232a6b7db3Sskrll   strftime (stampstr, MAX_DATELEN, "%Y-%m-%dT%H:%M:%S.000%z", timestamp);
13242a6b7db3Sskrll   fprintf (list_file, _("\n time stamp    \t: %s\n\n"), stampstr);
13252a6b7db3Sskrll }
13262a6b7db3Sskrll 
13272a6b7db3Sskrll static void
print_single_option(char * opt,int * pos)13282a6b7db3Sskrll print_single_option (char * opt, int *pos)
13292a6b7db3Sskrll {
13302a6b7db3Sskrll   int opt_len = strlen (opt);
13312a6b7db3Sskrll 
13322a6b7db3Sskrll    if ((*pos + opt_len) < paper_width)
13332a6b7db3Sskrll      {
13342a6b7db3Sskrll         fprintf (list_file, _("%s "), opt);
13352a6b7db3Sskrll         *pos = *pos + opt_len;
13362a6b7db3Sskrll      }
13372a6b7db3Sskrll    else
13382a6b7db3Sskrll      {
13392a6b7db3Sskrll         fprintf (list_file, _("\n\t%s "), opt);
13402a6b7db3Sskrll         *pos = opt_len;
13412a6b7db3Sskrll      }
13422a6b7db3Sskrll }
13432a6b7db3Sskrll 
13442a6b7db3Sskrll /* Print options passed to as.  */
13452a6b7db3Sskrll 
13462a6b7db3Sskrll static void
print_options(char ** argv)13472a6b7db3Sskrll print_options (char ** argv)
13482a6b7db3Sskrll {
13492a6b7db3Sskrll   const char *field_name = _("\n options passed\t: ");
13502a6b7db3Sskrll   int pos = strlen (field_name);
13512a6b7db3Sskrll   char **p;
13522a6b7db3Sskrll 
13532a6b7db3Sskrll   fputs (field_name, list_file);
13542a6b7db3Sskrll   for (p = &argv[1]; *p != NULL; p++)
13552a6b7db3Sskrll     if (**p == '-')
13562a6b7db3Sskrll       {
13572a6b7db3Sskrll         /* Ignore these.  */
13582a6b7db3Sskrll         if (strcmp (*p, "-o") == 0)
13592a6b7db3Sskrll           {
13602a6b7db3Sskrll             if (p[1] != NULL)
13612a6b7db3Sskrll               p++;
13622a6b7db3Sskrll             continue;
13632a6b7db3Sskrll           }
13642a6b7db3Sskrll         if (strcmp (*p, "-v") == 0)
13652a6b7db3Sskrll           continue;
13662a6b7db3Sskrll 
13672a6b7db3Sskrll         print_single_option (*p, &pos);
13682a6b7db3Sskrll       }
13692a6b7db3Sskrll }
13702a6b7db3Sskrll 
13712a6b7db3Sskrll /* Print a first section with basic info like file names, as version,
13722a6b7db3Sskrll    options passed, target, and timestamp.
13732a6b7db3Sskrll    The format of this section is as follows:
13742a6b7db3Sskrll 
13752a6b7db3Sskrll    AS VERSION
13762a6b7db3Sskrll 
13772a6b7db3Sskrll    fieldname TAB ':' fieldcontents
13782a6b7db3Sskrll   { TAB fieldcontents-cont }  */
13792a6b7db3Sskrll 
13802a6b7db3Sskrll static void
listing_general_info(char ** argv)13812a6b7db3Sskrll listing_general_info (char ** argv)
13822a6b7db3Sskrll {
13832a6b7db3Sskrll   /* Print the stuff on the first line.  */
13842a6b7db3Sskrll   eject = 1;
1385b075ecf2Schristos   listing_page (NULL);
13862a6b7db3Sskrll 
13872a6b7db3Sskrll   fprintf (list_file,
13882a6b7db3Sskrll            _(" GNU assembler version %s (%s)\n\t using BFD version %s."),
13892a6b7db3Sskrll            VERSION, TARGET_ALIAS, BFD_VERSION_STRING);
13902a6b7db3Sskrll   print_options (argv);
13912a6b7db3Sskrll   fprintf (list_file, _("\n input file    \t: %s"), fn);
13922a6b7db3Sskrll   fprintf (list_file, _("\n output file   \t: %s"), out_file_name);
13932a6b7db3Sskrll   fprintf (list_file, _("\n target        \t: %s"), TARGET_CANONICAL);
13942a6b7db3Sskrll   print_timestamp ();
13952a6b7db3Sskrll }
13962a6b7db3Sskrll 
13972a6b7db3Sskrll void
listing_print(char * name,char ** argv)13982a6b7db3Sskrll listing_print (char *name, char **argv)
13992a6b7db3Sskrll {
14002a6b7db3Sskrll   int using_stdout;
14012a6b7db3Sskrll 
14022a6b7db3Sskrll   title = "";
14032a6b7db3Sskrll   subtitle = "";
14042a6b7db3Sskrll 
14052a6b7db3Sskrll   if (name == NULL)
14062a6b7db3Sskrll     {
14072a6b7db3Sskrll       list_file = stdout;
14082a6b7db3Sskrll       using_stdout = 1;
14092a6b7db3Sskrll     }
14102a6b7db3Sskrll   else
14112a6b7db3Sskrll     {
14122a6b7db3Sskrll       list_file = fopen (name, FOPEN_WT);
14132a6b7db3Sskrll       if (list_file != NULL)
14142a6b7db3Sskrll 	using_stdout = 0;
14152a6b7db3Sskrll       else
14162a6b7db3Sskrll 	{
14172a6b7db3Sskrll 	  as_warn (_("can't open %s: %s"), name, xstrerror (errno));
14182a6b7db3Sskrll 	  list_file = stdout;
14192a6b7db3Sskrll 	  using_stdout = 1;
14202a6b7db3Sskrll 	}
14212a6b7db3Sskrll     }
14222a6b7db3Sskrll 
14232a6b7db3Sskrll   if (listing & LISTING_NOFORM)
14242a6b7db3Sskrll     paper_height = 0;
14252a6b7db3Sskrll 
14262a6b7db3Sskrll   if (listing & LISTING_GENERAL)
14272a6b7db3Sskrll     listing_general_info (argv);
14282a6b7db3Sskrll 
14292a6b7db3Sskrll   if (listing & LISTING_LISTING)
14302a6b7db3Sskrll     listing_listing (name);
14312a6b7db3Sskrll 
14322a6b7db3Sskrll   if (listing & LISTING_SYMBOLS)
14332a6b7db3Sskrll     list_symbol_table ();
14342a6b7db3Sskrll 
14352a6b7db3Sskrll   if (! using_stdout)
14362a6b7db3Sskrll     {
14372a6b7db3Sskrll       if (fclose (list_file) == EOF)
14382a6b7db3Sskrll 	as_warn (_("can't close %s: %s"), name, xstrerror (errno));
14392a6b7db3Sskrll     }
14402a6b7db3Sskrll 
14412a6b7db3Sskrll   if (last_open_file)
14422a6b7db3Sskrll     fclose (last_open_file);
14432a6b7db3Sskrll }
14442a6b7db3Sskrll 
14452a6b7db3Sskrll void
listing_file(const char * name)14462a6b7db3Sskrll listing_file (const char *name)
14472a6b7db3Sskrll {
14482a6b7db3Sskrll   fn = name;
14492a6b7db3Sskrll }
14502a6b7db3Sskrll 
14512a6b7db3Sskrll void
listing_eject(int ignore ATTRIBUTE_UNUSED)14522a6b7db3Sskrll listing_eject (int ignore ATTRIBUTE_UNUSED)
14532a6b7db3Sskrll {
14542a6b7db3Sskrll   if (listing)
14552a6b7db3Sskrll     listing_tail->edict = EDICT_EJECT;
14562a6b7db3Sskrll }
14572a6b7db3Sskrll 
14582a6b7db3Sskrll /* Turn listing on or off.  An argument of 0 means to turn off
14592a6b7db3Sskrll    listing.  An argument of 1 means to turn on listing.  An argument
14602a6b7db3Sskrll    of 2 means to turn off listing, but as of the next line; that is,
14612a6b7db3Sskrll    the current line should be listed, but the next line should not.  */
14622a6b7db3Sskrll 
14632a6b7db3Sskrll void
listing_list(int on)14642a6b7db3Sskrll listing_list (int on)
14652a6b7db3Sskrll {
14662a6b7db3Sskrll   if (listing)
14672a6b7db3Sskrll     {
14682a6b7db3Sskrll       switch (on)
14692a6b7db3Sskrll 	{
14702a6b7db3Sskrll 	case 0:
14712a6b7db3Sskrll 	  if (listing_tail->edict == EDICT_LIST)
14722a6b7db3Sskrll 	    listing_tail->edict = EDICT_NONE;
14732a6b7db3Sskrll 	  else
14742a6b7db3Sskrll 	    listing_tail->edict = EDICT_NOLIST;
14752a6b7db3Sskrll 	  break;
14762a6b7db3Sskrll 	case 1:
14772a6b7db3Sskrll 	  if (listing_tail->edict == EDICT_NOLIST
14782a6b7db3Sskrll 	      || listing_tail->edict == EDICT_NOLIST_NEXT)
14792a6b7db3Sskrll 	    listing_tail->edict = EDICT_NONE;
14802a6b7db3Sskrll 	  else
14812a6b7db3Sskrll 	    listing_tail->edict = EDICT_LIST;
14822a6b7db3Sskrll 	  break;
14832a6b7db3Sskrll 	case 2:
14842a6b7db3Sskrll 	  listing_tail->edict = EDICT_NOLIST_NEXT;
14852a6b7db3Sskrll 	  break;
14862a6b7db3Sskrll 	default:
14872a6b7db3Sskrll 	  abort ();
14882a6b7db3Sskrll 	}
14892a6b7db3Sskrll     }
14902a6b7db3Sskrll }
14912a6b7db3Sskrll 
14922a6b7db3Sskrll void
listing_psize(int width_only)14932a6b7db3Sskrll listing_psize (int width_only)
14942a6b7db3Sskrll {
14952a6b7db3Sskrll   if (! width_only)
14962a6b7db3Sskrll     {
14972a6b7db3Sskrll       paper_height = get_absolute_expression ();
14982a6b7db3Sskrll 
14992a6b7db3Sskrll       if (paper_height < 0 || paper_height > 1000)
15002a6b7db3Sskrll 	{
15012a6b7db3Sskrll 	  paper_height = 0;
15022a6b7db3Sskrll 	  as_warn (_("strange paper height, set to no form"));
15032a6b7db3Sskrll 	}
15042a6b7db3Sskrll 
15052a6b7db3Sskrll       if (*input_line_pointer != ',')
15062a6b7db3Sskrll 	{
15072a6b7db3Sskrll 	  demand_empty_rest_of_line ();
15082a6b7db3Sskrll 	  return;
15092a6b7db3Sskrll 	}
15102a6b7db3Sskrll 
15112a6b7db3Sskrll       ++input_line_pointer;
15122a6b7db3Sskrll     }
15132a6b7db3Sskrll 
1514*f22f0ef4Schristos   {
1515*f22f0ef4Schristos     expressionS exp;
1516*f22f0ef4Schristos 
1517*f22f0ef4Schristos     (void) expression_and_evaluate (& exp);
1518*f22f0ef4Schristos 
1519*f22f0ef4Schristos     if (exp.X_op == O_constant)
1520*f22f0ef4Schristos       {
1521*f22f0ef4Schristos 	offsetT new_width = exp.X_add_number;
1522*f22f0ef4Schristos 
1523*f22f0ef4Schristos 	if (new_width > 7)
1524*f22f0ef4Schristos 	  paper_width = new_width;
1525*f22f0ef4Schristos 	else
1526*f22f0ef4Schristos 	  as_bad (_("new paper width is too small"));
1527*f22f0ef4Schristos       }
1528*f22f0ef4Schristos     else if (exp.X_op != O_absent)
1529*f22f0ef4Schristos       as_bad (_("bad or irreducible expression for paper width"));
1530*f22f0ef4Schristos     else
1531*f22f0ef4Schristos       as_bad (_("missing expression for paper width"));
1532*f22f0ef4Schristos   }
15332a6b7db3Sskrll 
15342a6b7db3Sskrll   demand_empty_rest_of_line ();
15352a6b7db3Sskrll }
15362a6b7db3Sskrll 
15372a6b7db3Sskrll void
listing_nopage(int ignore ATTRIBUTE_UNUSED)15382a6b7db3Sskrll listing_nopage (int ignore ATTRIBUTE_UNUSED)
15392a6b7db3Sskrll {
15402a6b7db3Sskrll   paper_height = 0;
15412a6b7db3Sskrll }
15422a6b7db3Sskrll 
15432a6b7db3Sskrll void
listing_title(int depth)15442a6b7db3Sskrll listing_title (int depth)
15452a6b7db3Sskrll {
15462a6b7db3Sskrll   int quoted;
15472a6b7db3Sskrll   char *start;
15482a6b7db3Sskrll   char *ttl;
15492a6b7db3Sskrll   unsigned int length;
15502a6b7db3Sskrll 
15512a6b7db3Sskrll   SKIP_WHITESPACE ();
15522a6b7db3Sskrll   if (*input_line_pointer != '\"')
15532a6b7db3Sskrll     quoted = 0;
15542a6b7db3Sskrll   else
15552a6b7db3Sskrll     {
15562a6b7db3Sskrll       quoted = 1;
15572a6b7db3Sskrll       ++input_line_pointer;
15582a6b7db3Sskrll     }
15592a6b7db3Sskrll 
15602a6b7db3Sskrll   start = input_line_pointer;
15612a6b7db3Sskrll 
15622a6b7db3Sskrll   while (*input_line_pointer)
15632a6b7db3Sskrll     {
15642a6b7db3Sskrll       if (quoted
15652a6b7db3Sskrll 	  ? *input_line_pointer == '\"'
15662a6b7db3Sskrll 	  : is_end_of_line[(unsigned char) *input_line_pointer])
15672a6b7db3Sskrll 	{
15682a6b7db3Sskrll 	  if (listing)
15692a6b7db3Sskrll 	    {
15702a6b7db3Sskrll 	      length = input_line_pointer - start;
157175f9f1baSchristos 	      ttl = xmemdup0 (start, length);
15722a6b7db3Sskrll 	      listing_tail->edict = depth ? EDICT_SBTTL : EDICT_TITLE;
15732a6b7db3Sskrll 	      listing_tail->edict_arg = ttl;
15742a6b7db3Sskrll 	    }
15752a6b7db3Sskrll 	  if (quoted)
15762a6b7db3Sskrll 	    input_line_pointer++;
15772a6b7db3Sskrll 	  demand_empty_rest_of_line ();
15782a6b7db3Sskrll 	  return;
15792a6b7db3Sskrll 	}
15802a6b7db3Sskrll       else if (*input_line_pointer == '\n')
15812a6b7db3Sskrll 	{
15822a6b7db3Sskrll 	  as_bad (_("new line in title"));
15832a6b7db3Sskrll 	  demand_empty_rest_of_line ();
15842a6b7db3Sskrll 	  return;
15852a6b7db3Sskrll 	}
15862a6b7db3Sskrll       else
15872a6b7db3Sskrll 	{
15882a6b7db3Sskrll 	  input_line_pointer++;
15892a6b7db3Sskrll 	}
15902a6b7db3Sskrll     }
15912a6b7db3Sskrll }
15922a6b7db3Sskrll 
15932a6b7db3Sskrll void
listing_source_line(unsigned int line)15942a6b7db3Sskrll listing_source_line (unsigned int line)
15952a6b7db3Sskrll {
15962a6b7db3Sskrll   if (listing)
15972a6b7db3Sskrll     {
15982a6b7db3Sskrll       new_frag ();
15992a6b7db3Sskrll       listing_tail->hll_line = line;
16002a6b7db3Sskrll       new_frag ();
16012a6b7db3Sskrll     }
16022a6b7db3Sskrll }
16032a6b7db3Sskrll 
16042a6b7db3Sskrll void
listing_source_file(const char * file)16052a6b7db3Sskrll listing_source_file (const char *file)
16062a6b7db3Sskrll {
16072a6b7db3Sskrll   if (listing)
16082a6b7db3Sskrll     listing_tail->hll_file = file_info (file);
16092a6b7db3Sskrll }
16102a6b7db3Sskrll 
16112a6b7db3Sskrll #else
16122a6b7db3Sskrll 
16132a6b7db3Sskrll /* Dummy functions for when compiled without listing enabled.  */
16142a6b7db3Sskrll 
16152a6b7db3Sskrll void
listing_list(int on)16162a6b7db3Sskrll listing_list (int on)
16172a6b7db3Sskrll {
16182a6b7db3Sskrll   s_ignore (0);
16192a6b7db3Sskrll }
16202a6b7db3Sskrll 
16212a6b7db3Sskrll void
listing_eject(int ignore)16222a6b7db3Sskrll listing_eject (int ignore)
16232a6b7db3Sskrll {
16242a6b7db3Sskrll   s_ignore (0);
16252a6b7db3Sskrll }
16262a6b7db3Sskrll 
16272a6b7db3Sskrll void
listing_psize(int ignore)16282a6b7db3Sskrll listing_psize (int ignore)
16292a6b7db3Sskrll {
16302a6b7db3Sskrll   s_ignore (0);
16312a6b7db3Sskrll }
16322a6b7db3Sskrll 
16332a6b7db3Sskrll void
listing_nopage(int ignore)16342a6b7db3Sskrll listing_nopage (int ignore)
16352a6b7db3Sskrll {
16362a6b7db3Sskrll   s_ignore (0);
16372a6b7db3Sskrll }
16382a6b7db3Sskrll 
16392a6b7db3Sskrll void
listing_title(int depth)16402a6b7db3Sskrll listing_title (int depth)
16412a6b7db3Sskrll {
16422a6b7db3Sskrll   s_ignore (0);
16432a6b7db3Sskrll }
16442a6b7db3Sskrll 
16452a6b7db3Sskrll void
listing_file(const char * name)16462a6b7db3Sskrll listing_file (const char *name)
16472a6b7db3Sskrll {
16482a6b7db3Sskrll }
16492a6b7db3Sskrll 
16502a6b7db3Sskrll void
listing_newline(char * name)16512a6b7db3Sskrll listing_newline (char *name)
16522a6b7db3Sskrll {
16532a6b7db3Sskrll }
16542a6b7db3Sskrll 
16552a6b7db3Sskrll void
listing_source_line(unsigned int n)16562a6b7db3Sskrll listing_source_line (unsigned int n)
16572a6b7db3Sskrll {
16582a6b7db3Sskrll }
16592a6b7db3Sskrll 
16602a6b7db3Sskrll void
listing_source_file(const char * n)16612a6b7db3Sskrll listing_source_file (const char *n)
16622a6b7db3Sskrll {
16632a6b7db3Sskrll }
16642a6b7db3Sskrll 
16652a6b7db3Sskrll #endif
1666