2009-06-29 08:13:04 +08:00
|
|
|
/* ----------------------------------------------------------------------- *
|
2017-05-04 08:32:02 +08:00
|
|
|
*
|
2018-05-09 03:45:00 +08:00
|
|
|
* Copyright 1996-2018 The NASM Authors - All Rights Reserved
|
2009-06-29 08:13:04 +08:00
|
|
|
* See the file AUTHORS included with the NASM distribution for
|
|
|
|
* the specific copyright holders.
|
2002-05-01 04:52:26 +08:00
|
|
|
*
|
2009-06-29 08:13:04 +08:00
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following
|
|
|
|
* conditions are met:
|
|
|
|
*
|
|
|
|
* * Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* * Redistributions in binary form must reproduce the above
|
|
|
|
* copyright notice, this list of conditions and the following
|
|
|
|
* disclaimer in the documentation and/or other materials provided
|
|
|
|
* with the distribution.
|
2017-05-04 08:32:02 +08:00
|
|
|
*
|
2009-06-29 08:13:04 +08:00
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
|
|
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
|
|
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
|
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
|
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*
|
|
|
|
* ----------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* listing.c listing file generator for the Netwide Assembler
|
2002-05-01 04:52:26 +08:00
|
|
|
*/
|
|
|
|
|
2007-10-03 12:53:51 +08:00
|
|
|
#include "compiler.h"
|
|
|
|
|
2002-05-01 04:52:26 +08:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
|
|
#include "nasm.h"
|
|
|
|
#include "nasmlib.h"
|
2017-03-08 11:23:03 +08:00
|
|
|
#include "error.h"
|
2018-12-14 15:06:05 +08:00
|
|
|
#include "strlist.h"
|
2002-05-01 04:52:26 +08:00
|
|
|
#include "listing.h"
|
|
|
|
|
2018-12-13 08:47:04 +08:00
|
|
|
#define LIST_MAX_LEN 256 /* something sensible */
|
2002-05-01 04:52:26 +08:00
|
|
|
#define LIST_INDENT 40
|
|
|
|
#define LIST_HEXBIT 18
|
|
|
|
|
|
|
|
typedef struct MacroInhibit MacroInhibit;
|
|
|
|
|
|
|
|
static struct MacroInhibit {
|
|
|
|
MacroInhibit *next;
|
|
|
|
int level;
|
|
|
|
int inhibiting;
|
|
|
|
} *mistack;
|
|
|
|
|
2007-04-14 00:47:53 +08:00
|
|
|
static char xdigit[] = "0123456789ABCDEF";
|
2002-05-01 04:52:26 +08:00
|
|
|
|
|
|
|
#define HEX(a,b) (*(a)=xdigit[((b)>>4)&15],(a)[1]=xdigit[(b)&15]);
|
|
|
|
|
2007-04-14 00:47:53 +08:00
|
|
|
static char listline[LIST_MAX_LEN];
|
2009-07-08 03:04:12 +08:00
|
|
|
static bool listlinep;
|
|
|
|
|
2018-12-14 15:06:05 +08:00
|
|
|
struct strlist *list_errors;
|
2002-05-01 04:52:26 +08:00
|
|
|
|
2007-04-14 00:47:53 +08:00
|
|
|
static char listdata[2 * LIST_INDENT]; /* we need less than that actually */
|
2007-04-12 10:40:54 +08:00
|
|
|
static int32_t listoffset;
|
2002-05-01 04:52:26 +08:00
|
|
|
|
2007-04-12 10:40:54 +08:00
|
|
|
static int32_t listlineno;
|
2002-05-01 04:52:26 +08:00
|
|
|
|
2007-04-12 10:40:54 +08:00
|
|
|
static int32_t listp;
|
2002-05-01 04:52:26 +08:00
|
|
|
|
2005-01-16 06:15:51 +08:00
|
|
|
static int suppress; /* for INCBIN & TIMES special cases */
|
2002-05-01 04:52:26 +08:00
|
|
|
|
|
|
|
static int listlevel, listlevel_e;
|
|
|
|
|
|
|
|
static FILE *listfp;
|
|
|
|
|
2005-01-16 06:15:51 +08:00
|
|
|
static void list_emit(void)
|
2002-05-01 04:53:55 +08:00
|
|
|
{
|
2009-07-08 03:04:12 +08:00
|
|
|
int i;
|
2018-12-14 15:06:05 +08:00
|
|
|
const struct strlist_entry *e;
|
2009-07-08 03:04:12 +08:00
|
|
|
|
2018-12-13 08:47:04 +08:00
|
|
|
if (listlinep || *listdata) {
|
|
|
|
fprintf(listfp, "%6"PRId32" ", listlineno);
|
2002-05-01 04:53:55 +08:00
|
|
|
|
2018-12-13 08:47:04 +08:00
|
|
|
if (listdata[0])
|
|
|
|
fprintf(listfp, "%08"PRIX32" %-*s", listoffset, LIST_HEXBIT + 1,
|
|
|
|
listdata);
|
|
|
|
else
|
|
|
|
fprintf(listfp, "%*s", LIST_HEXBIT + 10, "");
|
2002-05-01 04:53:55 +08:00
|
|
|
|
2018-12-13 08:47:04 +08:00
|
|
|
if (listlevel_e)
|
|
|
|
fprintf(listfp, "%s<%d>", (listlevel < 10 ? " " : ""),
|
|
|
|
listlevel_e);
|
|
|
|
else if (listlinep)
|
|
|
|
fprintf(listfp, " ");
|
2002-05-01 04:53:55 +08:00
|
|
|
|
2018-12-13 08:47:04 +08:00
|
|
|
if (listlinep)
|
|
|
|
fprintf(listfp, " %s", listline);
|
2002-05-01 04:53:55 +08:00
|
|
|
|
2018-12-13 08:47:04 +08:00
|
|
|
putc('\n', listfp);
|
|
|
|
listlinep = false;
|
|
|
|
listdata[0] = '\0';
|
|
|
|
}
|
2009-07-08 03:04:12 +08:00
|
|
|
|
2018-12-14 15:06:05 +08:00
|
|
|
if (list_errors) {
|
|
|
|
strlist_for_each(e, list_errors) {
|
|
|
|
fprintf(listfp, "%6"PRId32" ", listlineno);
|
|
|
|
for (i = 0; i < LIST_HEXBIT; i++)
|
|
|
|
putc('*', listfp);
|
|
|
|
|
|
|
|
if (listlevel_e)
|
|
|
|
fprintf(listfp, " %s<%d>", (listlevel < 10 ? " " : ""),
|
|
|
|
listlevel_e);
|
|
|
|
else
|
|
|
|
fprintf(listfp, " ");
|
2017-05-04 08:32:02 +08:00
|
|
|
|
2018-12-14 15:06:05 +08:00
|
|
|
fprintf(listfp, " %s\n", e->str);
|
|
|
|
}
|
2009-07-08 03:04:12 +08:00
|
|
|
|
2018-12-14 15:06:05 +08:00
|
|
|
strlist_free(list_errors);
|
|
|
|
list_errors = NULL;
|
2009-07-08 03:04:12 +08:00
|
|
|
}
|
2002-05-01 04:52:26 +08:00
|
|
|
}
|
|
|
|
|
2016-02-18 12:27:41 +08:00
|
|
|
static void list_init(const char *fname)
|
2002-05-01 04:53:55 +08:00
|
|
|
{
|
2016-03-05 01:44:42 +08:00
|
|
|
if (!fname || fname[0] == '\0') {
|
2016-02-18 12:27:41 +08:00
|
|
|
listfp = NULL;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-05-25 19:28:46 +08:00
|
|
|
listfp = nasm_open_write(fname, NF_TEXT);
|
2002-05-01 04:52:26 +08:00
|
|
|
if (!listfp) {
|
2018-12-02 01:04:53 +08:00
|
|
|
nasm_nonfatal("unable to open listing file `%s'", fname);
|
2005-01-16 06:15:51 +08:00
|
|
|
return;
|
2002-05-01 04:52:26 +08:00
|
|
|
}
|
2002-05-01 04:53:55 +08:00
|
|
|
|
2002-05-01 04:52:26 +08:00
|
|
|
*listline = '\0';
|
|
|
|
listlineno = 0;
|
2018-12-14 15:06:05 +08:00
|
|
|
list_errors = NULL;
|
2007-10-11 05:58:45 +08:00
|
|
|
listp = true;
|
2002-05-01 04:52:26 +08:00
|
|
|
listlevel = 0;
|
|
|
|
suppress = 0;
|
|
|
|
mistack = nasm_malloc(sizeof(MacroInhibit));
|
|
|
|
mistack->next = NULL;
|
|
|
|
mistack->level = 0;
|
2007-10-11 05:58:45 +08:00
|
|
|
mistack->inhibiting = true;
|
2002-05-01 04:52:26 +08:00
|
|
|
}
|
|
|
|
|
2005-01-16 06:15:51 +08:00
|
|
|
static void list_cleanup(void)
|
2002-05-01 04:53:55 +08:00
|
|
|
{
|
2002-05-01 04:52:26 +08:00
|
|
|
if (!listp)
|
2005-01-16 06:15:51 +08:00
|
|
|
return;
|
2002-05-01 04:53:55 +08:00
|
|
|
|
2002-05-01 04:52:26 +08:00
|
|
|
while (mistack) {
|
2005-01-16 06:15:51 +08:00
|
|
|
MacroInhibit *temp = mistack;
|
|
|
|
mistack = temp->next;
|
|
|
|
nasm_free(temp);
|
2002-05-01 04:52:26 +08:00
|
|
|
}
|
2002-05-01 04:53:55 +08:00
|
|
|
|
2002-05-01 04:52:26 +08:00
|
|
|
list_emit();
|
2005-01-16 06:15:51 +08:00
|
|
|
fclose(listfp);
|
2002-05-01 04:52:26 +08:00
|
|
|
}
|
|
|
|
|
2016-09-21 05:04:33 +08:00
|
|
|
static void list_out(int64_t offset, char *str)
|
2002-05-01 04:53:55 +08:00
|
|
|
{
|
2002-05-01 04:52:26 +08:00
|
|
|
if (strlen(listdata) + strlen(str) > LIST_HEXBIT) {
|
2005-01-16 06:15:51 +08:00
|
|
|
strcat(listdata, "-");
|
|
|
|
list_emit();
|
2002-05-01 04:52:26 +08:00
|
|
|
}
|
|
|
|
if (!listdata[0])
|
2005-01-16 06:15:51 +08:00
|
|
|
listoffset = offset;
|
2002-05-01 04:52:26 +08:00
|
|
|
strcat(listdata, str);
|
|
|
|
}
|
|
|
|
|
2016-09-21 05:04:33 +08:00
|
|
|
static void list_address(int64_t offset, const char *brackets,
|
2010-05-07 06:25:43 +08:00
|
|
|
int64_t addr, int size)
|
|
|
|
{
|
|
|
|
char q[20];
|
|
|
|
char *r = q;
|
|
|
|
|
|
|
|
nasm_assert(size <= 8);
|
|
|
|
|
|
|
|
*r++ = brackets[0];
|
|
|
|
while (size--) {
|
|
|
|
HEX(r, addr);
|
|
|
|
addr >>= 8;
|
|
|
|
r += 2;
|
|
|
|
}
|
|
|
|
*r++ = brackets[1];
|
|
|
|
*r = '\0';
|
|
|
|
list_out(offset, q);
|
|
|
|
}
|
|
|
|
|
2016-09-21 05:04:33 +08:00
|
|
|
static void list_output(const struct out_data *data)
|
2002-05-01 04:53:55 +08:00
|
|
|
{
|
2018-06-03 14:48:16 +08:00
|
|
|
char q[24];
|
2016-09-21 05:04:33 +08:00
|
|
|
uint64_t size = data->size;
|
|
|
|
uint64_t offset = data->offset;
|
2017-05-04 08:32:02 +08:00
|
|
|
const uint8_t *p = data->data;
|
|
|
|
|
2010-05-07 06:25:43 +08:00
|
|
|
|
2016-02-18 12:27:41 +08:00
|
|
|
if (!listp || suppress || user_nolist)
|
2005-01-16 06:15:51 +08:00
|
|
|
return;
|
2002-05-01 04:52:26 +08:00
|
|
|
|
2016-09-21 05:04:33 +08:00
|
|
|
switch (data->type) {
|
2017-05-04 08:32:02 +08:00
|
|
|
case OUT_ZERODATA:
|
|
|
|
if (size > 16) {
|
|
|
|
snprintf(q, sizeof(q), "<zero %08"PRIX64">", size);
|
|
|
|
list_out(offset, q);
|
2018-05-09 03:45:00 +08:00
|
|
|
break;
|
2017-05-04 08:32:02 +08:00
|
|
|
} else {
|
|
|
|
p = zero_buffer;
|
|
|
|
}
|
2018-05-09 03:45:00 +08:00
|
|
|
/* fall through */
|
2007-11-10 06:44:02 +08:00
|
|
|
case OUT_RAWDATA:
|
|
|
|
{
|
2007-11-20 03:53:18 +08:00
|
|
|
if (size == 0 && !listdata[0])
|
2016-09-21 05:04:33 +08:00
|
|
|
listoffset = data->offset;
|
2005-01-16 06:15:51 +08:00
|
|
|
while (size--) {
|
|
|
|
HEX(q, *p);
|
|
|
|
q[2] = '\0';
|
|
|
|
list_out(offset++, q);
|
|
|
|
p++;
|
|
|
|
}
|
2007-11-10 06:44:02 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case OUT_ADDRESS:
|
2017-05-02 06:32:37 +08:00
|
|
|
list_address(offset, "[]", data->toffset, size);
|
2010-05-07 06:25:43 +08:00
|
|
|
break;
|
2017-05-02 06:32:37 +08:00
|
|
|
case OUT_SEGMENT:
|
|
|
|
q[0] = '[';
|
|
|
|
memset(q+1, 's', size << 1);
|
|
|
|
q[(size << 1)+1] = ']';
|
|
|
|
q[(size << 1)+2] = '\0';
|
|
|
|
list_out(offset, q);
|
|
|
|
offset += size;
|
|
|
|
break;
|
2016-09-21 05:04:33 +08:00
|
|
|
case OUT_RELADDR:
|
|
|
|
list_address(offset, "()", data->toffset, size);
|
2007-11-10 06:44:02 +08:00
|
|
|
break;
|
|
|
|
case OUT_RESERVE:
|
|
|
|
{
|
2007-11-07 13:48:12 +08:00
|
|
|
snprintf(q, sizeof(q), "<res %08"PRIX64">", size);
|
2005-01-16 06:15:51 +08:00
|
|
|
list_out(offset, q);
|
2007-11-10 06:44:02 +08:00
|
|
|
break;
|
|
|
|
}
|
2016-09-21 05:04:33 +08:00
|
|
|
default:
|
|
|
|
panic();
|
2002-05-01 04:52:26 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-04-14 00:47:53 +08:00
|
|
|
static void list_line(int type, char *line)
|
2002-05-01 04:53:55 +08:00
|
|
|
{
|
2002-05-01 04:52:26 +08:00
|
|
|
if (!listp)
|
2005-01-16 06:15:51 +08:00
|
|
|
return;
|
2016-02-18 07:35:06 +08:00
|
|
|
|
|
|
|
if (user_nolist)
|
|
|
|
return;
|
2002-05-01 04:53:55 +08:00
|
|
|
|
2005-01-16 06:15:51 +08:00
|
|
|
if (mistack && mistack->inhibiting) {
|
|
|
|
if (type == LIST_MACRO)
|
|
|
|
return;
|
|
|
|
else { /* pop the m i stack */
|
|
|
|
MacroInhibit *temp = mistack;
|
|
|
|
mistack = temp->next;
|
|
|
|
nasm_free(temp);
|
|
|
|
}
|
2002-05-01 04:52:26 +08:00
|
|
|
}
|
|
|
|
list_emit();
|
2016-02-18 07:35:06 +08:00
|
|
|
listlineno = src_get_linnum();
|
2007-10-11 05:58:45 +08:00
|
|
|
listlinep = true;
|
2005-01-16 06:15:51 +08:00
|
|
|
strncpy(listline, line, LIST_MAX_LEN - 1);
|
|
|
|
listline[LIST_MAX_LEN - 1] = '\0';
|
2002-05-01 04:52:26 +08:00
|
|
|
listlevel_e = listlevel;
|
|
|
|
}
|
|
|
|
|
2005-01-16 06:15:51 +08:00
|
|
|
static void list_uplevel(int type)
|
2002-05-01 04:53:55 +08:00
|
|
|
{
|
2002-05-01 04:52:26 +08:00
|
|
|
if (!listp)
|
2005-01-16 06:15:51 +08:00
|
|
|
return;
|
|
|
|
if (type == LIST_INCBIN || type == LIST_TIMES) {
|
|
|
|
suppress |= (type == LIST_INCBIN ? 1 : 2);
|
|
|
|
list_out(listoffset, type == LIST_INCBIN ? "<incbin>" : "<rept>");
|
|
|
|
return;
|
2002-05-01 04:52:26 +08:00
|
|
|
}
|
2002-05-01 04:53:55 +08:00
|
|
|
|
2002-05-01 04:52:26 +08:00
|
|
|
listlevel++;
|
2002-05-01 04:53:55 +08:00
|
|
|
|
2005-01-16 06:15:51 +08:00
|
|
|
if (mistack && mistack->inhibiting && type == LIST_INCLUDE) {
|
|
|
|
MacroInhibit *temp = nasm_malloc(sizeof(MacroInhibit));
|
|
|
|
temp->next = mistack;
|
|
|
|
temp->level = listlevel;
|
2007-10-11 05:58:45 +08:00
|
|
|
temp->inhibiting = false;
|
2005-01-16 06:15:51 +08:00
|
|
|
mistack = temp;
|
|
|
|
} else if (type == LIST_MACRO_NOLIST) {
|
|
|
|
MacroInhibit *temp = nasm_malloc(sizeof(MacroInhibit));
|
|
|
|
temp->next = mistack;
|
|
|
|
temp->level = listlevel;
|
2007-10-11 05:58:45 +08:00
|
|
|
temp->inhibiting = true;
|
2005-01-16 06:15:51 +08:00
|
|
|
mistack = temp;
|
2002-05-01 04:52:26 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-01-16 06:15:51 +08:00
|
|
|
static void list_downlevel(int type)
|
2002-05-01 04:53:55 +08:00
|
|
|
{
|
2002-05-01 04:52:26 +08:00
|
|
|
if (!listp)
|
2005-01-16 06:15:51 +08:00
|
|
|
return;
|
2002-05-01 04:53:55 +08:00
|
|
|
|
2005-01-16 06:15:51 +08:00
|
|
|
if (type == LIST_INCBIN || type == LIST_TIMES) {
|
|
|
|
suppress &= ~(type == LIST_INCBIN ? 1 : 2);
|
|
|
|
return;
|
2002-05-01 04:52:26 +08:00
|
|
|
}
|
2002-05-01 04:53:55 +08:00
|
|
|
|
2002-05-01 04:52:26 +08:00
|
|
|
listlevel--;
|
2005-01-16 06:15:51 +08:00
|
|
|
while (mistack && mistack->level > listlevel) {
|
|
|
|
MacroInhibit *temp = mistack;
|
|
|
|
mistack = temp->next;
|
|
|
|
nasm_free(temp);
|
2002-05-01 04:52:26 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-14 11:39:41 +08:00
|
|
|
static void list_error(errflags severity, const char *fmt, ...)
|
2009-07-08 03:04:12 +08:00
|
|
|
{
|
2018-12-11 16:06:29 +08:00
|
|
|
va_list ap;
|
|
|
|
|
2009-07-08 03:04:12 +08:00
|
|
|
if (!listfp)
|
|
|
|
return;
|
|
|
|
|
2018-12-14 15:06:05 +08:00
|
|
|
if (!list_errors)
|
|
|
|
list_errors = strlist_alloc(false);
|
2018-12-13 08:47:04 +08:00
|
|
|
|
2018-12-11 16:06:29 +08:00
|
|
|
va_start(ap, fmt);
|
2018-12-14 15:06:05 +08:00
|
|
|
strlist_vprintf(list_errors, fmt, ap);
|
2018-12-11 16:06:29 +08:00
|
|
|
va_end(ap);
|
2018-12-13 08:47:04 +08:00
|
|
|
|
2009-07-08 03:04:12 +08:00
|
|
|
if ((severity & ERR_MASK) >= ERR_FATAL)
|
|
|
|
list_emit();
|
|
|
|
}
|
|
|
|
|
2016-09-21 05:04:33 +08:00
|
|
|
static void list_set_offset(uint64_t offset)
|
|
|
|
{
|
|
|
|
listoffset = offset;
|
|
|
|
}
|
2009-07-08 03:04:12 +08:00
|
|
|
|
2016-02-18 17:16:18 +08:00
|
|
|
static const struct lfmt nasm_list = {
|
2002-05-01 04:52:26 +08:00
|
|
|
list_init,
|
|
|
|
list_cleanup,
|
|
|
|
list_output,
|
|
|
|
list_line,
|
|
|
|
list_uplevel,
|
2009-07-08 03:04:12 +08:00
|
|
|
list_downlevel,
|
2016-09-21 05:04:33 +08:00
|
|
|
list_error,
|
|
|
|
list_set_offset
|
2002-05-01 04:52:26 +08:00
|
|
|
};
|
2016-02-18 12:27:41 +08:00
|
|
|
|
2016-02-18 17:16:18 +08:00
|
|
|
const struct lfmt *lfmt = &nasm_list;
|