diff options
Diffstat (limited to 'vere/ext/nasm/asm/listing.c')
-rw-r--r-- | vere/ext/nasm/asm/listing.c | 415 |
1 files changed, 415 insertions, 0 deletions
diff --git a/vere/ext/nasm/asm/listing.c b/vere/ext/nasm/asm/listing.c new file mode 100644 index 0000000..186b8b4 --- /dev/null +++ b/vere/ext/nasm/asm/listing.c @@ -0,0 +1,415 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 1996-2020 The NASM Authors - All Rights Reserved + * See the file AUTHORS included with the NASM distribution for + * the specific copyright holders. + * + * 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. + * + * 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 + */ + +#include "compiler.h" + +#include "nctype.h" + +#include "nasm.h" +#include "nasmlib.h" +#include "error.h" +#include "strlist.h" +#include "listing.h" + +#define LIST_MAX_LEN 1024 /* something sensible */ +#define LIST_INDENT 40 +#define LIST_HEXBIT 18 + +static const char xdigit[] = "0123456789ABCDEF"; + +#define HEX(a,b) (*(a)=xdigit[((b)>>4)&15],(a)[1]=xdigit[(b)&15]); + +uint64_t list_options, active_list_options; + +static char listline[LIST_MAX_LEN]; +static bool listlinep; + +static struct strlist *list_errors; + +static char listdata[2 * LIST_INDENT]; /* we need less than that actually */ +static int32_t listoffset; + +static int32_t listlineno; + +static int suppress; /* for INCBIN & TIMES special cases */ + +static int listlevel, listlevel_e; + +static FILE *listfp; + +static void list_emit(void) +{ + int i; + const struct strlist_entry *e; + + if (listlinep || *listdata) { + fprintf(listfp, "%6"PRId32" ", listlineno); + + if (listdata[0]) + fprintf(listfp, "%08"PRIX32" %-*s", listoffset, LIST_HEXBIT + 1, + listdata); + else + fprintf(listfp, "%*s", LIST_HEXBIT + 10, ""); + + if (listlevel_e) + fprintf(listfp, "%s<%d>", (listlevel < 10 ? " " : ""), + listlevel_e); + else if (listlinep) + fprintf(listfp, " "); + + if (listlinep) + fprintf(listfp, " %s", listline); + + putc('\n', listfp); + listlinep = false; + listdata[0] = '\0'; + } + + if (list_errors) { + static const char fillchars[] = " --***XX"; + char fillchar; + + strlist_for_each(e, list_errors) { + fprintf(listfp, "%6"PRId32" ", listlineno); + fillchar = fillchars[e->pvt.u & ERR_MASK]; + for (i = 0; i < LIST_HEXBIT; i++) + putc(fillchar, listfp); + + if (listlevel_e) + fprintf(listfp, " %s<%d>", (listlevel < 10 ? " " : ""), + listlevel_e); + else + fprintf(listfp, " "); + + fprintf(listfp, " %s\n", e->str); + } + + strlist_free(&list_errors); + } +} + +static void list_cleanup(void) +{ + if (!listfp) + return; + + list_emit(); + fclose(listfp); + listfp = NULL; + active_list_options = 0; +} + +static void list_init(const char *fname) +{ + enum file_flags flags = NF_TEXT; + + if (listfp) + list_cleanup(); + + if (!fname || fname[0] == '\0') { + listfp = NULL; + return; + } + + if (list_option('w')) + flags |= NF_IOLBF; + + listfp = nasm_open_write(fname, flags); + if (!listfp) { + nasm_nonfatal("unable to open listing file `%s'", fname); + return; + } + + active_list_options = list_options | 1; + + *listline = '\0'; + listlineno = 0; + list_errors = NULL; + listlevel = 0; + suppress = 0; +} + +static void list_out(int64_t offset, char *str) +{ + if (strlen(listdata) + strlen(str) > LIST_HEXBIT) { + strcat(listdata, "-"); + list_emit(); + } + if (!listdata[0]) + listoffset = offset; + strcat(listdata, str); +} + +static void list_address(int64_t offset, const char *brackets, + 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); +} + +static void list_size(int64_t offset, const char *tag, uint64_t size) +{ + char buf[64]; + const char *fmt; + + if (list_option('d')) + fmt = "<%s %"PRIu64">"; + else + fmt = "<%s %"PRIX64"h>"; + + snprintf(buf, sizeof buf, fmt, tag, size); + list_out(offset, buf); +} + +static void list_output(const struct out_data *data) +{ + char q[24]; + uint64_t size = data->size; + uint64_t offset = data->offset; + const uint8_t *p = data->data; + + + if (!listfp || suppress || user_nolist) + return; + + switch (data->type) { + case OUT_ZERODATA: + if (size > 16) { + list_size(offset, "zero", size); + break; + } else { + p = zero_buffer; + } + /* fall through */ + case OUT_RAWDATA: + { + if (size == 0) { + if (!listdata[0]) + listoffset = data->offset; + } else if (p) { + while (size--) { + HEX(q, *p); + q[2] = '\0'; + list_out(offset++, q); + p++; + } + } else { + /* Used for listing on non-code generation passes with -Lp */ + list_size(offset, "len", size); + } + break; + } + case OUT_ADDRESS: + list_address(offset, "[]", data->toffset, size); + break; + 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; + case OUT_RELADDR: + list_address(offset, "()", data->toffset, size); + break; + case OUT_RESERVE: + { + if (size > 8) { + list_size(offset, "res", size); + } else { + memset(q, '?', size << 1); + q[size << 1] = '\0'; + list_out(offset, q); + } + break; + } + default: + panic(); + } +} + +static void list_line(int type, int32_t lineno, const char *line) +{ + (void)type; + + if (!listfp) + return; + + if (user_nolist) + return; + + list_emit(); + if (lineno >= 0) + listlineno = lineno; + listlinep = true; + strlcpy(listline, line, LIST_MAX_LEN-3); + memcpy(listline + LIST_MAX_LEN-4, "...", 4); + listlevel_e = listlevel; +} + +static void list_uplevel(int type, int64_t size) +{ + if (!listfp) + return; + + switch (type) { + case LIST_INCBIN: + suppress |= 1; + list_size(listoffset, "bin", size); + break; + + case LIST_TIMES: + suppress |= 2; + list_size(listoffset, "rep", size); + break; + + case LIST_INCLUDE: + listlevel++; + break; + + default: + listlevel++; + break; + } +} + +static void list_downlevel(int type) +{ + if (!listfp) + return; + + switch (type) { + case LIST_INCBIN: + suppress &= ~1; + break; + + case LIST_TIMES: + suppress &= ~2; + break; + + default: + listlevel--; + break; + } +} + +static void printf_func(2, 3) list_error(errflags severity, const char *fmt, ...) +{ + va_list ap; + + if (!listfp) + return; + + if (!list_errors) + list_errors = strlist_alloc(false); + + va_start(ap, fmt); + strlist_vprintf(list_errors, fmt, ap); + va_end(ap); + strlist_tail(list_errors)->pvt.u = severity; + + if ((severity & ERR_MASK) >= ERR_FATAL) + list_emit(); +} + +static void list_set_offset(uint64_t offset) +{ + listoffset = offset; +} + +static void list_update_options(const char *str) +{ + bool state = true; + unsigned char c; + uint64_t mask; + + while ((c = *str++)) { + switch (c) { + case '+': + state = true; + break; + case '-': + state = false; + break; + default: + mask = list_option_mask(c); + if (state) + list_options |= mask; + else + list_options &= ~mask; + break; + } + } +} + +enum directive_result list_pragma(const struct pragma *pragma) +{ + switch (pragma->opcode) { + case D_OPTIONS: + list_update_options(pragma->tail); + return DIRR_OK; + + default: + return DIRR_UNKNOWN; + } +} + +static const struct lfmt nasm_list = { + list_init, + list_cleanup, + list_output, + list_line, + list_uplevel, + list_downlevel, + list_error, + list_set_offset +}; + +const struct lfmt *lfmt = &nasm_list; |