/* ".LST" file output for gplink
Copyright (C) 2004, 2005
Craig Franklin
This file is part of gputils.
gputils is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
gputils is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with gputils; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "stdhdr.h"
#include "libgputils.h"
#include "gplink.h"
#include "cod.h"
#ifdef STDC_HEADERS
#include <stdarg.h>
#endif
static gp_boolean list_enabled;
static gp_section_type *line_section;
static void
open_src(char *name, gp_symbol_type *symbol)
{
struct list_context *new = malloc(sizeof(*new));
assert(name != NULL);
new->f = fopen(name, "rt");
if(new->f) {
new->name = strdup(name);
new->missing_source = false;
} else {
new->missing_source = true;
}
new->symbol = symbol;
new->line_number = 1;
new->prev = state.lst.src;
state.lst.src = new;
}
static void
close_src(void)
{
struct list_context *old;
assert(state.lst.src != NULL);
old = state.lst.src;
state.lst.src = state.lst.src->prev;
free(old);
}
static void
lst_line(const char *format, ...)
{
va_list args;
char buffer[BUFSIZ];
if (state.lst.f == NULL)
return;
va_start(args, format);
vsnprintf(buffer, sizeof(buffer), format, args);
va_end(args);
fprintf(state.lst.f, "%s\n", buffer);
return;
}
gp_linenum_type *
find_line_number(gp_symbol_type *symbol, int line_number)
{
gp_section_type *section;
gp_linenum_type *line = NULL;
section = state.object->sections;
/* FIXME: This too slow. */
while (section != NULL) {
line = section->line_numbers;
while (line != NULL) {
if ((line->symbol == symbol) &&
(line->line_number == line_number)) {
if (section != line_section) {
/* switching sections, so update was_org with the new section
address */
state.lst.was_org = section->address >> state.byte_addr;
line_section = section;
}
return line;
}
line = line->next;
}
section = section->next;
}
return NULL;
}
static void
write_src(int last_line)
{
#define LINESIZ 520
char linebuf[LINESIZ];
char dasmbuf[LINESIZ];
char *pc;
gp_linenum_type *line = NULL;
gp_boolean first_time;
int org = 0;
int data;
int num_words;
/* if the source file wasn't found, can't write it to the list file */
if (state.lst.src->missing_source)
return;
while (1) {
/* when last_line is 0 print all lines, else print to last_line */
if ((last_line) && (state.lst.src->line_number > last_line))
break;
if (fgets(linebuf, LINESIZ, state.lst.src->f) == NULL)
break;
state.lst.was_org = org;
if (list_enabled) {
/* Eat the trailing newline */
pc = strrchr(linebuf, '\n');
if (pc)
*pc = 0;
first_time = true;
line = find_line_number(state.lst.src->symbol,
state.lst.src->line_number);
while (line) {
/* print all instructions generated by this line of the source */
if (line->line_number != state.lst.src->line_number)
break;
if (first_time == false) {
/* only print the source line the first time */
linebuf[0] = '\0';
}
state.cod.emitting = 1;
org = line->address >> state.byte_addr;
data = i_memory_get(line_section->data, org);
assert(data & MEM_USED_MASK);
num_words = gp_disassemble(line_section->data,
org,
state.class,
dasmbuf,
sizeof(dasmbuf));
lst_line("%06lx %04x %-24s %s",
line->address,
data & 0xffff,
dasmbuf,
linebuf);
cod_lst_line(COD_NORMAL_LST_LINE);
org++;
if (num_words != 1) {
state.lst.was_org = org;
data = i_memory_get(line_section->data, org);
assert(data & MEM_USED_MASK);
lst_line("%06lx %04x",
org << state.byte_addr,
data & 0xffff);
cod_lst_line(COD_NORMAL_LST_LINE);
org++;
if (line->next) {
/* skip the line number for the other half of this instruction */
line = line->next;
}
}
first_time = false;
line = line->next;
}
if (first_time) {
lst_line("%42s %s", " ", linebuf);
state.cod.emitting = 0;
cod_lst_line(COD_NORMAL_LST_LINE);
}
}
state.lst.src->line_number++;
}
}
/*
* lst_init - initialize the lst file
*/
static void
lst_init(void)
{
if (state.lstfile != named) {
strncpy(state.lstfilename, state.basefilename, sizeof(state.lstfilename));
strncat(state.lstfilename, ".lst", sizeof(state.lstfilename));
}
if ((gp_num_errors) || (state.lstfile == suppress)) {
state.lst.f = NULL;
state.lst.enabled = false;
unlink(state.lstfilename);
} else {
state.lst.f = fopen(state.lstfilename, "wt");
if (state.lst.f == NULL) {
perror(state.lstfilename);
exit(1);
}
state.lst.enabled = true;
}
if(!state.lst.enabled)
return;
state.lst.was_org = 0;
state.cod.emitting = 0;
lst_line("%s", GPLINK_VERSION_STRING);
lst_line("%s", GPUTILS_COPYRIGHT_STRING);
lst_line("Listing File Generated: %s", state.startdate);
lst_line(" ");
lst_line(" ");
lst_line("Address Value Disassembly Source");
lst_line("------- ----- ----------- ------");
}
void
write_lst(void)
{
gp_symbol_type *symbol = state.object->symbols;
gp_aux_type *aux;
gp_boolean first_time = true;
lst_init();
if(!state.lst.enabled)
return;
list_enabled = true;
state.lst.src = NULL;
/* scan through the file symbols */
while (symbol != NULL) {
if (symbol->class == C_FILE) {
/* open a new file */
aux = symbol->aux_list;
assert(aux != NULL);
if (aux->_aux_symbol._aux_file.line_number) {
/* it is an include file, so print the current file
until the line number is reached */
assert(state.lst.src != NULL);
write_src(aux->_aux_symbol._aux_file.line_number);
} else {
/* it is not an include, so enable listing */
list_enabled = true;
}
open_src(aux->_aux_symbol._aux_file.filename, symbol);
if (first_time) {
/* write the line numbers for the lst file header */
cod_lst_line(COD_FIRST_LST_LINE);
cod_lst_line(COD_NORMAL_LST_LINE);
cod_lst_line(COD_NORMAL_LST_LINE);
cod_lst_line(COD_NORMAL_LST_LINE);
cod_lst_line(COD_NORMAL_LST_LINE);
cod_lst_line(COD_NORMAL_LST_LINE);
cod_lst_line(COD_NORMAL_LST_LINE);
first_time = false;
}
} else if (symbol->class == C_EOF) {
/* print the rest of the current file then, close it */
write_src(0);
close_src();
} else if (symbol->class == C_LIST) {
if (strcasecmp(symbol->name, ".list") == 0) {
write_src(symbol->value);
list_enabled = true;
} else if (strcasecmp(symbol->name, ".nolist") == 0) {
write_src(symbol->value);
list_enabled = false;
} else {
assert(0);
}
}
symbol = symbol->next;
}
fclose(state.lst.f);
}
syntax highlighted by Code2HTML, v. 0.9.1