/* ".LST" file output for gplink
Copyright 2004, 2005
Craig Franklin
Copyright 2016 Molnár Károly
*/
#include "stdhdr.h"
#include "libgputils.h"
#include "gplink.h"
#include "cod.h"
#ifdef STDC_HEADERS
#include <stdarg.h>
#endif
#define LINESIZ 520
static bool list_enabled;
static const gp_section_t *line_section;
/*------------------------------------------------------------------------------------------------*/
static void _open_source(const char *Name, gp_symbol_t *Symbol) {
bool name_allocated=false;
const char *p;
assert(Name);
list_context_t *pnew = new list_context_t;
pnew->f = fopen(Name, "rt");
if (!pnew->f) {
/* Try searching include pathes. */
for (int i = 0; i < state.num_paths; i++) {
unsigned len = strlen(state.paths[i])
+ strlen(PATH_SEPARATOR_STR)
+ strlen(Name) +1;
char*full_name = new char[len];
snprintf(full_name, len, "%s" PATH_SEPARATOR_STR "%s", state.paths[i], Name);
pnew->f = fopen(full_name, "rb");
if (pnew->f) {
Name = full_name;
name_allocated=true;
break;
}else free(full_name);
}
if (!pnew->f) {
/* The path may belong to a build procedure other than this. */
p = strrchr(Name, PATH_SEPARATOR_CHAR);
if (p) {
for (int i = 0; i < state.num_paths; i++) {
unsigned len = strlen(state.paths[i])
+ strlen(p) + 1;
char*full_name = new char[len];
snprintf(full_name, len, "%s%s", state.paths[i], p);
pnew->f = fopen(full_name, "rb");
if (pnew->f) {
if (name_allocated) free((char*)Name);
Name = full_name;
name_allocated=true;
break;
}
}
}
}
}
if (pnew->f) {
pnew->name = name_allocated ? (char*)Name : GP_Strdup(Name);
pnew->missing_source = false;
}
else {
pnew->missing_source = true;
if (getenv("GPUTILS_WARN_MISSING_SRC")) {
gp_warning("Cannot find source file: \"%s\"", Name);
}
}
pnew->symbol = Symbol;
pnew->line_number = 1;
pnew->prev = state.lst.src;
state.lst.src = pnew;
}
/*------------------------------------------------------------------------------------------------*/
static void _close_source() {
list_context_t *old;
assert(state.lst.src);
old = state.lst.src;
state.lst.src = state.lst.src->prev;
free(old);
}
/*------------------------------------------------------------------------------------------------*/
static void _cdecl _lst_line(const char *Format, ...) {
va_list args;
if (state.lst.f) {
va_start(args, Format);
vfprintf(state.lst.f, Format, args);
va_end(args);
fputc('\n', state.lst.f);
}
}
/*------------------------------------------------------------------------------------------------*/
static const gp_linenum_t* _find_line_number(const gp_symbol_t *Symbol, unsigned Line_number) {
const gp_section_t *section;
const gp_linenum_t *linenum;
section = state.object->section_list.first;
while (section) {
linenum = gp_coffgen_find_linenum(section, Symbol, Line_number);
if (linenum) {
if (section != line_section) {
/* Switching sections, so update was_org with the pnew address. */
state.lst.was_byte_addr = linenum->address;
line_section = section;
}
return linenum;
}
section = section->next;
}
return NULL;
}
/*------------------------------------------------------------------------------------------------*/
static char* _expand_tabs(const char *Buffer) {
static char dest[LINESIZ];
unsigned is;
unsigned id;
char c;
unsigned n;
for (is = 0, id = 0; ((c = Buffer[is]) != '\0') && (id < (sizeof(dest) - 2)); ++is) {
if (c == '\t') {
n = TABULATOR_SIZE - (id % TABULATOR_SIZE);
while ((n-- > 0) && (id < (sizeof(dest) - 2))) {
dest[id++] = ' ';
}
}
else {
dest[id++] = c;
}
}
dest[id] = '\0';
return dest;
}
/*------------------------------------------------------------------------------------------------*/
static void _write_source(bool Last_line) {
char linebuf[LINESIZ];
char dasmbuf[LINESIZ];
char *pc;
const gp_linenum_t *line;
bool first_time;
unsigned org;
unsigned len;
uint8_t byte;
uint16_t word;
int num_bytes;
/* If the source file wasn't found, can't write it to the list file. */
if (state.lst.src->missing_source) {
return;
}
org = 0;
while (true) {
/* When last_line is 0 print all lines, else print to last_line. */
if (Last_line && state.lst.src->line_number > (unsigned)Last_line) {
break;
}
if (fgets(linebuf, LINESIZ, state.lst.src->f) == NULL) {
break;
}
state.lst.was_byte_addr = 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) {
/* Only print the source line the first time. */
linebuf[0] = '\0';
}
state.cod.emitting = true;
org = line->address;
len = gp_mem_b_get_unlisted_size(line_section->data, org);
if (len == 0) {
if (linebuf[0] != '\0') {
_lst_line("%42s %s", "", linebuf);
}
else {
_lst_line("");
}
cod_lst_line(COD_NORMAL_LST_LINE);
}
else {
if ((org & 1) || (len < 2)) {
/* even address or less then two byts to disassemble: disassemble one byte */
if (len != 0) {
gp_mem_b_assert_get(line_section->data, org, &byte, NULL, NULL);
gp_disassemble_byte(line_section->data, org, dasmbuf, sizeof(dasmbuf));
_lst_line("%06lx %02x %-24s %s", gp_processor_insn_from_byte_c(state.pclass, org),
(unsigned)byte, _expand_tabs(dasmbuf), linebuf);
gp_mem_b_set_listed(line_section->data, org, 1);
state.lst.was_byte_addr = org;
cod_lst_line(COD_NORMAL_LST_LINE);
++org;
}
}
else {
state.pclass->i_memory_get(line_section->data, org, &word, NULL, NULL);
num_bytes = gp_disassemble_size(line_section->data, org, state.pclass,
gp_processor_bsr_boundary(state.processor),
state.processor->prog_mem_size, GPDIS_SHOW_ALL_BRANCH,
dasmbuf, sizeof(dasmbuf), len);
_lst_line("%06lx %04x %-24s %s", gp_processor_insn_from_byte_c(state.pclass, org),
word, _expand_tabs(dasmbuf), linebuf);
gp_mem_b_set_listed(line_section->data, org, num_bytes);
state.lst.was_byte_addr = org;
cod_lst_line(COD_NORMAL_LST_LINE);
org += 2;
if (num_bytes > 2) {
state.lst.was_byte_addr = org;
state.pclass->i_memory_get(line_section->data, org, &word, NULL, NULL);
_lst_line("%06lx %04x", gp_processor_insn_from_byte_c(state.pclass, org), word);
cod_lst_line(COD_NORMAL_LST_LINE);
org += 2;
if (line->next) {
/* skip the line number for the other half of this instruction */
line = line->next;
}
}
}
}
first_time = false;
line = line->next;
} /* while (line) */
if (first_time) {
if (linebuf[0] != '\0') {
_lst_line("%42s %s", "", linebuf);
}
else {
_lst_line("");
}
state.cod.emitting = false;
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.lst_file != OUT_NAMED) {
snprintf(state.lst_file_name, sizeof(state.lst_file_name), "%s.lst", state.base_file_name);
}
if (gp_num.errors || state.lst_file == OUT_SUPPRESS) {
state.lst.f = NULL;
state.lst.enabled = false;
unlink(state.lst_file_name);
}
else {
state.lst.f = fopen(state.lst_file_name, "wt");
if (state.lst.f == NULL) {
perror(state.lst_file_name);
exit(1);
}
state.lst.enabled = true;
}
if (!state.lst.enabled) {
return;
}
state.lst.was_byte_addr = 0;
state.cod.emitting = false;
_lst_line("%s", GPLINK_VERSION_STRING);
_lst_line("%s", GPUTILS_COPYRIGHT_STRING);
_lst_line("Listing File Generated: %s", state.start_date);
_lst_line("");
_lst_line("");
_lst_line("Address Value Disassembly Source");
_lst_line("------- ----- ----------- ------");
}
/*------------------------------------------------------------------------------------------------*/
void lst_write() {
const gp_aux_t *aux;
bool first_time;
_lst_init();
if (!state.lst.enabled) {
return;
}
list_enabled = true;
first_time = true;
state.lst.src = NULL;
/* scan through the file symbols */
FOR(gp_symbol_list_t,symbol,state.object->symbol_list) {
if (symbol->pclass == C_FILE) {
/* open a pnew file */
aux = symbol->aux_list.first;
assert(aux);
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);
_write_source(!!aux->_aux_symbol._aux_file.line_number);
}else{
/* it is not an include, so enable listing */
list_enabled = true;
}
_open_source(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->pclass == C_LIST) {
if (strcasecmp(symbol->name, ".list") == 0) {
_write_source(!!symbol->value);
list_enabled = true;
}
else if (strcasecmp(symbol->name, ".nolist") == 0) {
_write_source(!!symbol->value);
list_enabled = false;
}
else {
assert(0);
}
}
else if (symbol->pclass == C_EOF) {
/* print the rest of the current file then, close it */
_write_source(0);
_close_source();
}
}
fclose(state.lst.f);
}
Vorgefundene Kodierung: UTF-8 | 0
|