#include "as.h"
#include "obstack.h"
#include "safe-ctype.h"
#include "input-file.h"
#include "subsegs.h"
#ifndef NO_LISTING
#ifndef LISTING_HEADER
#define LISTING_HEADER "GAS LISTING"
#endif
#ifndef LISTING_WORD_SIZE
#define LISTING_WORD_SIZE 4
#endif
#ifndef LISTING_LHS_WIDTH
#define LISTING_LHS_WIDTH ((LISTING_WORD_SIZE) > 4 ? 1 : 4 / (LISTING_WORD_SIZE))
#endif
#ifndef LISTING_LHS_WIDTH_SECOND
#define LISTING_LHS_WIDTH_SECOND LISTING_LHS_WIDTH
#endif
#ifndef LISTING_RHS_WIDTH
#define LISTING_RHS_WIDTH 100
#endif
#ifndef LISTING_LHS_CONT_LINES
#define LISTING_LHS_CONT_LINES 4
#endif
typedef struct file_info_struct
{
struct file_info_struct * next;
char * filename;
long pos;
unsigned int linenum;
int at_end;
} file_info_type;
struct list_info_struct
{
fragS *frag;
unsigned int line;
file_info_type *file;
char *line_contents;
struct list_info_struct *next;
file_info_type *hll_file;
unsigned int hll_line;
char *message;
enum
{
EDICT_NONE,
EDICT_SBTTL,
EDICT_TITLE,
EDICT_NOLIST,
EDICT_LIST,
EDICT_NOLIST_NEXT,
EDICT_EJECT
} edict;
char *edict_arg;
int debugging;
};
typedef struct list_info_struct list_info_type;
int listing_lhs_width = LISTING_LHS_WIDTH;
int listing_lhs_width_second = LISTING_LHS_WIDTH_SECOND;
int listing_lhs_cont_lines = LISTING_LHS_CONT_LINES;
int listing_rhs_width = LISTING_RHS_WIDTH;
struct list_info_struct * listing_tail;
static file_info_type * file_info_head;
static file_info_type * last_open_file_info;
static FILE * last_open_file;
static struct list_info_struct * head;
static int paper_width = 200;
static int paper_height = 60;
extern int listing;
static FILE *list_file;
#define MAX_BYTES \
(((LISTING_WORD_SIZE * 2) + 1) * listing_lhs_width \
+ ((((LISTING_WORD_SIZE * 2) + 1) * listing_lhs_width_second) \
* listing_lhs_cont_lines) \
+ 20)
static char *data_buffer;
static void listing_message (const char *, const char *);
static file_info_type *file_info (const char *);
static void new_frag (void);
static char *buffer_line (file_info_type *, char *, unsigned int);
static void listing_page (list_info_type *);
static unsigned int calc_hex (list_info_type *);
static void print_lines (list_info_type *, unsigned int, char *, unsigned int);
static void list_symbol_table (void);
static void print_source (file_info_type *, list_info_type *, char *, unsigned int);
static int debugging_pseudo (list_info_type *, const char *);
static void listing_listing (char *);
static void
listing_message (const char *name, const char *message)
{
if (listing_tail != (list_info_type *) NULL)
{
unsigned int l = strlen (name) + strlen (message) + 1;
char *n = (char *) xmalloc (l);
strcpy (n, name);
strcat (n, message);
listing_tail->message = n;
}
}
void
listing_warning (const char *message)
{
listing_message (_("Warning:"), message);
}
void
listing_error (const char *message)
{
listing_message (_("Error:"), message);
}
static file_info_type *
file_info (const char *file_name)
{
file_info_type *p = file_info_head;
while (p != (file_info_type *) NULL)
{
if (strcmp (p->filename, file_name) == 0)
return p;
p = p->next;
}
p = xmalloc (sizeof (file_info_type));
p->next = file_info_head;
file_info_head = p;
p->filename = xstrdup (file_name);
p->pos = 0;
p->linenum = 0;
p->at_end = 0;
return p;
}
static void
new_frag (void)
{
frag_wane (frag_now);
frag_new (0);
}
void
listing_newline (char *ps)
{
char *file;
unsigned int line;
static unsigned int last_line = 0xffff;
static char *last_file = NULL;
list_info_type *new = NULL;
if (listing == 0)
return;
if (now_seg == absolute_section)
return;
#ifdef OBJ_ELF
if ((listing & LISTING_NODEBUG) != 0
&& listing_tail != NULL
&& ! listing_tail->debugging)
{
const char *segname;
segname = segment_name (now_seg);
if (strncmp (segname, ".debug", sizeof ".debug" - 1) == 0
|| strncmp (segname, ".line", sizeof ".line" - 1) == 0)
listing_tail->debugging = 1;
}
#endif
as_where (&file, &line);
if (ps == NULL)
{
if (line == last_line
&& !(last_file && file && strcmp (file, last_file)))
return;
new = (list_info_type *) xmalloc (sizeof (list_info_type));
if (strcmp (file, _("{standard input}")) == 0
&& input_line_pointer != NULL)
{
char *copy;
int len;
int seen_quote = 0;
for (copy = input_line_pointer - 1;
*copy && (seen_quote
|| (! is_end_of_line [(unsigned char) *copy]));
copy++)
if (*copy == '"' && copy[-1] != '\\')
seen_quote = ! seen_quote;
len = (copy - input_line_pointer) + 2;
copy = xmalloc (len);
if (copy != NULL)
{
char *src = input_line_pointer - 1;
char *dest = copy;
while (--len)
{
unsigned char c = *src++;
if (!ISCNTRL (c))
*dest++ = c;
}
*dest = 0;
}
new->line_contents = copy;
}
else
new->line_contents = NULL;
}
else
{
new = xmalloc (sizeof (list_info_type));
new->line_contents = ps;
}
last_line = line;
last_file = file;
new_frag ();
if (listing_tail)
listing_tail->next = new;
else
head = new;
listing_tail = new;
new->frag = frag_now;
new->line = line;
new->file = file_info (file);
new->next = (list_info_type *) NULL;
new->message = (char *) NULL;
new->edict = EDICT_NONE;
new->hll_file = (file_info_type *) NULL;
new->hll_line = 0;
new->debugging = 0;
new_frag ();
#ifdef OBJ_ELF
if ((listing & LISTING_NODEBUG) != 0)
{
const char *segname;
segname = segment_name (now_seg);
if (strncmp (segname, ".debug", sizeof ".debug" - 1) == 0
|| strncmp (segname, ".line", sizeof ".line" - 1) == 0)
new->debugging = 1;
}
#endif
}
void
listing_prev_line (void)
{
list_info_type *l;
fragS *f;
if (head == (list_info_type *) NULL
|| head == listing_tail)
return;
new_frag ();
for (l = head; l->next != listing_tail; l = l->next)
;
for (f = frchain_now->frch_root; f != (fragS *) NULL; f = f->fr_next)
if (f->line == listing_tail)
f->line = l;
listing_tail->frag = frag_now;
new_frag ();
}
static char *
buffer_line (file_info_type *file, char *line, unsigned int size)
{
unsigned int count = 0;
int c;
char *p = line;
if (file->at_end)
return "";
if (!last_open_file_info || file != last_open_file_info)
{
if (last_open_file)
{
last_open_file_info->pos = ftell (last_open_file);
fclose (last_open_file);
}
last_open_file_info = file;
last_open_file = fopen (file->filename, FOPEN_RT);
if (last_open_file == NULL)
{
file->at_end = 1;
return "";
}
if (file->pos)
fseek (last_open_file, file->pos, SEEK_SET);
}
c = fgetc (last_open_file);
size -= 1;
while (c != EOF && c != '\n')
{
if (count < size)
*p++ = c;
count++;
c = fgetc (last_open_file);
}
if (c == EOF)
{
file->at_end = 1;
if (count + 2 < size)
{
*p++ = '.';
*p++ = '.';
*p++ = '.';
}
}
file->linenum++;
*p++ = 0;
return line;
}
static const char *fn;
static unsigned int eject;
static unsigned int page;
static char *title;
static char *subtitle;
static unsigned int on_page;
static void
listing_page (list_info_type *list)
{
if ((eject || (on_page >= (unsigned int) paper_height))
&& paper_height != 0)
{
unsigned int c = 10;
int had_title = 0;
int had_subtitle = 0;
page++;
while (c != 0 && list)
{
if (list->edict == EDICT_SBTTL && !had_subtitle)
{
had_subtitle = 1;
subtitle = list->edict_arg;
}
if (list->edict == EDICT_TITLE && !had_title)
{
had_title = 1;
title = list->edict_arg;
}
list = list->next;
c--;
}
if (page > 1)
{
fprintf (list_file, "\f");
}
fprintf (list_file, "%s %s \t\t\tpage %d\n", LISTING_HEADER, fn, page);
fprintf (list_file, "%s\n", title);
fprintf (list_file, "%s\n", subtitle);
on_page = 3;
eject = 0;
}
}
static unsigned int
calc_hex (list_info_type *list)
{
int data_buffer_size;
list_info_type *first = list;
unsigned int address = ~(unsigned int) 0;
fragS *frag;
fragS *frag_ptr;
unsigned int octet_in_frag;
frag = list->frag;
while (frag && frag->line != list)
frag = frag->fr_next;
frag_ptr = frag;
data_buffer_size = 0;
while (frag_ptr != (fragS *) NULL && frag_ptr->line == first)
{
octet_in_frag = 0;
while ((offsetT) octet_in_frag < frag_ptr->fr_fix
&& data_buffer_size < MAX_BYTES - 3)
{
if (address == ~(unsigned int) 0)
address = frag_ptr->fr_address / OCTETS_PER_BYTE;
sprintf (data_buffer + data_buffer_size,
"%02X",
(frag_ptr->fr_literal[octet_in_frag]) & 0xff);
data_buffer_size += 2;
octet_in_frag++;
}
if (frag_ptr->fr_type == rs_fill)
{
unsigned int var_rep_max = octet_in_frag;
unsigned int var_rep_idx = octet_in_frag;
while (((offsetT) octet_in_frag
< (frag_ptr->fr_fix + frag_ptr->fr_var * frag_ptr->fr_offset))
&& data_buffer_size < MAX_BYTES - 3)
{
if (address == ~(unsigned int) 0)
address = frag_ptr->fr_address / OCTETS_PER_BYTE;
sprintf (data_buffer + data_buffer_size,
"%02X",
(frag_ptr->fr_literal[var_rep_idx]) & 0xff);
#if 0
data_buffer[data_buffer_size++] = '*';
data_buffer[data_buffer_size++] = '*';
#endif
data_buffer_size += 2;
var_rep_idx++;
octet_in_frag++;
if ((offsetT) var_rep_idx >= frag_ptr->fr_fix + frag_ptr->fr_var)
var_rep_idx = var_rep_max;
}
}
frag_ptr = frag_ptr->fr_next;
}
data_buffer[data_buffer_size] = '\0';
return address;
}
static void
print_lines (list_info_type *list, unsigned int lineno,
char *string, unsigned int address)
{
unsigned int idx;
unsigned int nchars;
unsigned int lines;
unsigned int octet_in_word = 0;
char *src = data_buffer;
int cur;
listing_page (list);
nchars = (LISTING_WORD_SIZE * 2 + 1) * listing_lhs_width;
if (address == ~(unsigned int) 0)
{
fprintf (list_file, "% 4d ", lineno);
for (idx = 0; idx < nchars; idx++)
fprintf (list_file, " ");
fprintf (list_file, "\t%s\n", string ? string : "");
on_page++;
listing_page (0);
return;
}
if (had_errors ())
fprintf (list_file, "% 4d ???? ", lineno);
else
fprintf (list_file, "% 4d %04x ", lineno, address);
idx = 0;
cur = 0;
while (src[cur] && idx < nchars)
{
int offset;
offset = cur;
fprintf (list_file, "%c%c", src[offset], src[offset + 1]);
cur += 2;
octet_in_word++;
if (octet_in_word == LISTING_WORD_SIZE)
{
fprintf (list_file, " ");
idx++;
octet_in_word = 0;
}
idx += 2;
}
for (; idx < nchars; idx++)
fprintf (list_file, " ");
fprintf (list_file, "\t%s\n", string ? string : "");
on_page++;
listing_page (list);
if (list->message)
{
fprintf (list_file, "**** %s\n", list->message);
listing_page (list);
on_page++;
}
for (lines = 0;
lines < (unsigned int) listing_lhs_cont_lines
&& src[cur];
lines++)
{
nchars = ((LISTING_WORD_SIZE * 2) + 1) * listing_lhs_width_second - 1;
idx = 0;
fprintf (list_file, "% 4d ", lineno);
while (src[cur] && idx < nchars)
{
int offset;
offset = cur;
fprintf (list_file, "%c%c", src[offset], src[offset + 1]);
cur += 2;
idx += 2;
octet_in_word++;
if (octet_in_word == LISTING_WORD_SIZE)
{
fprintf (list_file, " ");
idx++;
octet_in_word = 0;
}
}
fprintf (list_file, "\n");
on_page++;
listing_page (list);
}
}
static void
list_symbol_table (void)
{
extern symbolS *symbol_rootP;
int got_some = 0;
symbolS *ptr;
eject = 1;
listing_page (0);
for (ptr = symbol_rootP; ptr != (symbolS *) NULL; ptr = symbol_next (ptr))
{
if (SEG_NORMAL (S_GET_SEGMENT (ptr))
|| S_GET_SEGMENT (ptr) == absolute_section)
{
#ifdef BFD_ASSEMBLER
if (symbol_section_p (ptr))
continue;
#endif
if (S_GET_NAME (ptr))
{
char buf[30], fmt[8];
valueT val = S_GET_VALUE (ptr);
if (sizeof (val) == 4 && sizeof (int) == 4)
sprintf (buf, "%08lx", (unsigned long) val);
else if (sizeof (val) <= sizeof (unsigned long))
{
sprintf (fmt, "%%0%lulx",
(unsigned long) (sizeof (val) * 2));
sprintf (buf, fmt, (unsigned long) val);
}
#if defined (BFD64)
else if (sizeof (val) > 4)
sprintf_vma (buf, val);
#endif
else
abort ();
if (!got_some)
{
fprintf (list_file, "DEFINED SYMBOLS\n");
on_page++;
got_some = 1;
}
if (symbol_get_frag (ptr) && symbol_get_frag (ptr)->line)
{
fprintf (list_file, "%20s:%-5d %s:%s %s\n",
symbol_get_frag (ptr)->line->file->filename,
symbol_get_frag (ptr)->line->line,
segment_name (S_GET_SEGMENT (ptr)),
buf, S_GET_NAME (ptr));
}
else
{
fprintf (list_file, "%33s:%s %s\n",
segment_name (S_GET_SEGMENT (ptr)),
buf, S_GET_NAME (ptr));
}
on_page++;
listing_page (0);
}
}
}
if (!got_some)
{
fprintf (list_file, "NO DEFINED SYMBOLS\n");
on_page++;
}
fprintf (list_file, "\n");
on_page++;
listing_page (0);
got_some = 0;
for (ptr = symbol_rootP; ptr != (symbolS *) NULL; ptr = symbol_next (ptr))
{
if (S_GET_NAME (ptr) && strlen (S_GET_NAME (ptr)) != 0)
{
if (S_GET_SEGMENT (ptr) == undefined_section)
{
if (!got_some)
{
got_some = 1;
fprintf (list_file, "UNDEFINED SYMBOLS\n");
on_page++;
listing_page (0);
}
fprintf (list_file, "%s\n", S_GET_NAME (ptr));
on_page++;
listing_page (0);
}
}
}
if (!got_some)
{
fprintf (list_file, "NO UNDEFINED SYMBOLS\n");
on_page++;
listing_page (0);
}
}
static void
print_source (file_info_type *current_file, list_info_type *list,
char *buffer, unsigned int width)
{
if (!current_file->at_end)
{
while (current_file->linenum < list->hll_line
&& !current_file->at_end)
{
char *p = buffer_line (current_file, buffer, width);
fprintf (list_file, "%4u:%-13s **** %s\n", current_file->linenum,
current_file->filename, p);
on_page++;
listing_page (list);
}
}
}
static int
debugging_pseudo (list_info_type *list, const char *line)
{
static int in_debug;
int was_debug;
if (list->debugging)
{
in_debug = 1;
return 1;
}
was_debug = in_debug;
in_debug = 0;
while (ISSPACE (*line))
line++;
if (*line != '.')
{
#ifdef OBJ_ELF
if (was_debug
&& *line == '\0'
&& list->next != NULL
&& list->next->debugging)
{
in_debug = 1;
return 1;
}
#endif
return 0;
}
line++;
if (strncmp (line, "def", 3) == 0)
return 1;
if (strncmp (line, "val", 3) == 0)
return 1;
if (strncmp (line, "scl", 3) == 0)
return 1;
if (strncmp (line, "line", 4) == 0)
return 1;
if (strncmp (line, "endef", 5) == 0)
return 1;
if (strncmp (line, "ln", 2) == 0)
return 1;
if (strncmp (line, "type", 4) == 0)
return 1;
if (strncmp (line, "size", 4) == 0)
return 1;
if (strncmp (line, "dim", 3) == 0)
return 1;
if (strncmp (line, "tag", 3) == 0)
return 1;
if (strncmp (line, "stabs", 5) == 0)
return 1;
if (strncmp (line, "stabn", 5) == 0)
return 1;
return 0;
}
static void
listing_listing (char *name ATTRIBUTE_UNUSED)
{
list_info_type *list = head;
file_info_type *current_hll_file = (file_info_type *) NULL;
char *message;
char *buffer;
char *p;
int show_listing = 1;
unsigned int width;
buffer = xmalloc (listing_rhs_width);
data_buffer = xmalloc (MAX_BYTES);
eject = 1;
list = head;
while (list != (list_info_type *) NULL && 0)
{
if (list->next)
list->frag = list->next->frag;
list = list->next;
}
list = head->next;
while (list)
{
unsigned int list_line;
width = listing_rhs_width > paper_width ? paper_width :
listing_rhs_width;
list_line = list->line;
switch (list->edict)
{
case EDICT_LIST:
list_line--;
break;
case EDICT_NOLIST:
show_listing--;
break;
case EDICT_NOLIST_NEXT:
if (show_listing == 0)
list_line--;
break;
case EDICT_EJECT:
break;
case EDICT_NONE:
break;
case EDICT_TITLE:
title = list->edict_arg;
break;
case EDICT_SBTTL:
subtitle = list->edict_arg;
break;
default:
abort ();
}
if (show_listing <= 0)
{
while (list->file->linenum < list_line
&& !list->file->at_end)
p = buffer_line (list->file, buffer, width);
}
if (list->edict == EDICT_LIST
|| (list->edict == EDICT_NOLIST_NEXT && show_listing == 0))
{
list_line++;
show_listing++;
}
if (show_listing > 0)
{
message = 0;
if (list->hll_file)
current_hll_file = list->hll_file;
if (current_hll_file && list->hll_line && (listing & LISTING_HLL))
print_source (current_hll_file, list, buffer, width);
if (list->line_contents)
{
if (!((listing & LISTING_NODEBUG)
&& debugging_pseudo (list, list->line_contents)))
print_lines (list,
list->file->linenum == 0 ? list->line : list->file->linenum,
list->line_contents, calc_hex (list));
free (list->line_contents);
list->line_contents = NULL;
}
else
{
while (list->file->linenum < list_line
&& !list->file->at_end)
{
unsigned int address;
p = buffer_line (list->file, buffer, width);
if (list->file->linenum < list_line)
address = ~(unsigned int) 0;
else
address = calc_hex (list);
if (!((listing & LISTING_NODEBUG)
&& debugging_pseudo (list, p)))
print_lines (list, list->file->linenum, p, address);
}
}
if (list->edict == EDICT_EJECT)
eject = 1;
}
if (list->edict == EDICT_NOLIST_NEXT && show_listing == 1)
--show_listing;
list = list->next;
}
free (buffer);
free (data_buffer);
data_buffer = NULL;
}
void
listing_print (char *name)
{
int using_stdout;
title = "";
subtitle = "";
if (name == NULL)
{
list_file = stdout;
using_stdout = 1;
}
else
{
list_file = fopen (name, FOPEN_WT);
if (list_file != NULL)
using_stdout = 0;
else
{
#ifdef BFD_ASSEMBLER
bfd_set_error (bfd_error_system_call);
#endif
as_perror (_("can't open list file: %s"), name);
list_file = stdout;
using_stdout = 1;
}
}
if (listing & LISTING_NOFORM)
paper_height = 0;
if (listing & LISTING_LISTING)
listing_listing (name);
if (listing & LISTING_SYMBOLS)
list_symbol_table ();
if (! using_stdout)
{
if (fclose (list_file) == EOF)
{
#ifdef BFD_ASSEMBLER
bfd_set_error (bfd_error_system_call);
#endif
as_perror (_("error closing list file: %s"), name);
}
}
if (last_open_file)
fclose (last_open_file);
}
void
listing_file (const char *name)
{
fn = name;
}
void
listing_eject (int ignore ATTRIBUTE_UNUSED)
{
if (listing)
listing_tail->edict = EDICT_EJECT;
}
void
listing_flags (int ignore ATTRIBUTE_UNUSED)
{
while ((*input_line_pointer++) && (*input_line_pointer != '\n'))
input_line_pointer++;
}
void
listing_list (int on)
{
if (listing)
{
switch (on)
{
case 0:
if (listing_tail->edict == EDICT_LIST)
listing_tail->edict = EDICT_NONE;
else
listing_tail->edict = EDICT_NOLIST;
break;
case 1:
if (listing_tail->edict == EDICT_NOLIST
|| listing_tail->edict == EDICT_NOLIST_NEXT)
listing_tail->edict = EDICT_NONE;
else
listing_tail->edict = EDICT_LIST;
break;
case 2:
listing_tail->edict = EDICT_NOLIST_NEXT;
break;
default:
abort ();
}
}
}
void
listing_psize (int width_only)
{
if (! width_only)
{
paper_height = get_absolute_expression ();
if (paper_height < 0 || paper_height > 1000)
{
paper_height = 0;
as_warn (_("strange paper height, set to no form"));
}
if (*input_line_pointer != ',')
{
demand_empty_rest_of_line ();
return;
}
++input_line_pointer;
}
paper_width = get_absolute_expression ();
demand_empty_rest_of_line ();
}
void
listing_nopage (int ignore ATTRIBUTE_UNUSED)
{
paper_height = 0;
}
void
listing_title (int depth)
{
int quoted;
char *start;
char *ttl;
unsigned int length;
SKIP_WHITESPACE ();
if (*input_line_pointer != '\"')
quoted = 0;
else
{
quoted = 1;
++input_line_pointer;
}
start = input_line_pointer;
while (*input_line_pointer)
{
if (quoted
? *input_line_pointer == '\"'
: is_end_of_line[(unsigned char) *input_line_pointer])
{
if (listing)
{
length = input_line_pointer - start;
ttl = xmalloc (length + 1);
memcpy (ttl, start, length);
ttl[length] = 0;
listing_tail->edict = depth ? EDICT_SBTTL : EDICT_TITLE;
listing_tail->edict_arg = ttl;
}
if (quoted)
input_line_pointer++;
demand_empty_rest_of_line ();
return;
}
else if (*input_line_pointer == '\n')
{
as_bad (_("new line in title"));
demand_empty_rest_of_line ();
return;
}
else
{
input_line_pointer++;
}
}
}
void
listing_source_line (unsigned int line)
{
if (listing)
{
new_frag ();
listing_tail->hll_line = line;
new_frag ();
}
}
void
listing_source_file (const char *file)
{
if (listing)
listing_tail->hll_file = file_info (file);
}
#else
void
listing_flags (int ignore)
{
s_ignore (0);
}
void
listing_list (int on)
{
s_ignore (0);
}
void
listing_eject (int ignore)
{
s_ignore (0);
}
void
listing_psize (int ignore)
{
s_ignore (0);
}
void
listing_nopage (int ignore)
{
s_ignore (0);
}
void
listing_title (int depth)
{
s_ignore (0);
}
void
listing_file (const char *name)
{
}
void
listing_newline (char *name)
{
}
void
listing_source_line (unsigned int n)
{
}
void
listing_source_file (const char *n)
{
}
#endif