Diagnostics: make debug more dynamic, note -> info, add listmsg level
[nasm.git] / asm / listing.c
blob1831d877f33e4cd32ff1da1db22ad4df3c747d9d
1 /* ----------------------------------------------------------------------- *
3 * Copyright 1996-2018 The NASM Authors - All Rights Reserved
4 * See the file AUTHORS included with the NASM distribution for
5 * the specific copyright holders.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following
9 * conditions are met:
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 * ----------------------------------------------------------------------- */
35 * listing.c listing file generator for the Netwide Assembler
38 #include "compiler.h"
40 #include "nctype.h"
42 #include "nasm.h"
43 #include "nasmlib.h"
44 #include "error.h"
45 #include "strlist.h"
46 #include "listing.h"
48 #define LIST_MAX_LEN 1024 /* something sensible */
49 #define LIST_INDENT 40
50 #define LIST_HEXBIT 18
52 typedef struct MacroInhibit MacroInhibit;
54 static struct MacroInhibit {
55 MacroInhibit *next;
56 int level;
57 int inhibiting;
58 } *mistack;
60 static const char xdigit[] = "0123456789ABCDEF";
62 #define HEX(a,b) (*(a)=xdigit[((b)>>4)&15],(a)[1]=xdigit[(b)&15]);
64 static char listline[LIST_MAX_LEN];
65 static bool listlinep;
67 struct strlist *list_errors;
69 static char listdata[2 * LIST_INDENT]; /* we need less than that actually */
70 static int32_t listoffset;
72 static int32_t listlineno;
74 static int32_t listp;
76 static int suppress; /* for INCBIN & TIMES special cases */
78 static int listlevel, listlevel_e;
80 static FILE *listfp;
82 static void list_emit(void)
84 int i;
85 const struct strlist_entry *e;
87 if (listlinep || *listdata) {
88 fprintf(listfp, "%6"PRId32" ", listlineno);
90 if (listdata[0])
91 fprintf(listfp, "%08"PRIX32" %-*s", listoffset, LIST_HEXBIT + 1,
92 listdata);
93 else
94 fprintf(listfp, "%*s", LIST_HEXBIT + 10, "");
96 if (listlevel_e)
97 fprintf(listfp, "%s<%d>", (listlevel < 10 ? " " : ""),
98 listlevel_e);
99 else if (listlinep)
100 fprintf(listfp, " ");
102 if (listlinep)
103 fprintf(listfp, " %s", listline);
105 putc('\n', listfp);
106 listlinep = false;
107 listdata[0] = '\0';
110 if (list_errors) {
111 strlist_for_each(e, list_errors) {
112 fprintf(listfp, "%6"PRId32" ", listlineno);
113 for (i = 0; i < LIST_HEXBIT; i++)
114 putc('*', listfp);
116 if (listlevel_e)
117 fprintf(listfp, " %s<%d>", (listlevel < 10 ? " " : ""),
118 listlevel_e);
119 else
120 fprintf(listfp, " ");
122 fprintf(listfp, " %s\n", e->str);
125 strlist_free(&list_errors);
129 static void list_init(const char *fname)
131 if (!fname || fname[0] == '\0') {
132 listfp = NULL;
133 return;
136 listfp = nasm_open_write(fname, NF_TEXT);
137 if (!listfp) {
138 nasm_nonfatal("unable to open listing file `%s'", fname);
139 return;
142 *listline = '\0';
143 listlineno = 0;
144 list_errors = NULL;
145 listp = true;
146 listlevel = 0;
147 suppress = 0;
148 mistack = nasm_malloc(sizeof(MacroInhibit));
149 mistack->next = NULL;
150 mistack->level = 0;
151 mistack->inhibiting = true;
154 static void list_cleanup(void)
156 if (!listp)
157 return;
159 while (mistack) {
160 MacroInhibit *temp = mistack;
161 mistack = temp->next;
162 nasm_free(temp);
165 list_emit();
166 fclose(listfp);
169 static void list_out(int64_t offset, char *str)
171 if (strlen(listdata) + strlen(str) > LIST_HEXBIT) {
172 strcat(listdata, "-");
173 list_emit();
175 if (!listdata[0])
176 listoffset = offset;
177 strcat(listdata, str);
180 static void list_address(int64_t offset, const char *brackets,
181 int64_t addr, int size)
183 char q[20];
184 char *r = q;
186 nasm_assert(size <= 8);
188 *r++ = brackets[0];
189 while (size--) {
190 HEX(r, addr);
191 addr >>= 8;
192 r += 2;
194 *r++ = brackets[1];
195 *r = '\0';
196 list_out(offset, q);
199 static void list_output(const struct out_data *data)
201 char q[24];
202 uint64_t size = data->size;
203 uint64_t offset = data->offset;
204 const uint8_t *p = data->data;
207 if (!listp || suppress || user_nolist)
208 return;
210 switch (data->type) {
211 case OUT_ZERODATA:
212 if (size > 16) {
213 snprintf(q, sizeof(q), "<zero %08"PRIX64">", size);
214 list_out(offset, q);
215 break;
216 } else {
217 p = zero_buffer;
219 /* fall through */
220 case OUT_RAWDATA:
222 if (size == 0 && !listdata[0])
223 listoffset = data->offset;
224 while (size--) {
225 HEX(q, *p);
226 q[2] = '\0';
227 list_out(offset++, q);
228 p++;
230 break;
232 case OUT_ADDRESS:
233 list_address(offset, "[]", data->toffset, size);
234 break;
235 case OUT_SEGMENT:
236 q[0] = '[';
237 memset(q+1, 's', size << 1);
238 q[(size << 1)+1] = ']';
239 q[(size << 1)+2] = '\0';
240 list_out(offset, q);
241 offset += size;
242 break;
243 case OUT_RELADDR:
244 list_address(offset, "()", data->toffset, size);
245 break;
246 case OUT_RESERVE:
248 snprintf(q, sizeof(q), "<res %"PRIX64">", size);
249 list_out(offset, q);
250 break;
252 default:
253 panic();
257 static void list_line(int type, char *line)
259 if (!listp)
260 return;
262 if (user_nolist)
263 return;
265 if (mistack && mistack->inhibiting) {
266 if (type == LIST_MACRO)
267 return;
268 else { /* pop the m i stack */
269 MacroInhibit *temp = mistack;
270 mistack = temp->next;
271 nasm_free(temp);
274 list_emit();
275 listlineno = src_get_linnum();
276 listlinep = true;
277 strlcpy(listline, line, LIST_MAX_LEN-3);
278 memcpy(listline + LIST_MAX_LEN-4, "...", 4);
279 listlevel_e = listlevel;
282 static void mistack_push(bool inhibiting)
284 MacroInhibit *temp = nasm_malloc(sizeof(MacroInhibit));
285 temp->next = mistack;
286 temp->level = listlevel;
287 temp->inhibiting = inhibiting;
288 mistack = temp;
291 static void list_uplevel(int type, int64_t size)
293 char str[64];
295 if (!listp)
296 return;
298 switch (type) {
299 case LIST_INCBIN:
300 suppress |= 1;
301 snprintf(str, sizeof str, "<bin %"PRIX64">", size);
302 list_out(listoffset, str);
303 break;
305 case LIST_TIMES:
306 suppress |= 2;
307 snprintf(str, sizeof str, "<rep %"PRIX64">", size);
308 list_out(listoffset, str);
309 break;
311 case LIST_INCLUDE:
312 listlevel++;
313 if (mistack && mistack->inhibiting)
314 mistack_push(false);
315 break;
317 case LIST_MACRO_NOLIST:
318 listlevel++;
319 mistack_push(true);
320 break;
322 default:
323 listlevel++;
324 break;
328 static void list_downlevel(int type)
330 if (!listp)
331 return;
333 switch (type) {
334 case LIST_INCBIN:
335 suppress &= ~1;
336 break;
338 case LIST_TIMES:
339 suppress &= ~2;
340 break;
342 default:
343 listlevel--;
344 while (mistack && mistack->level > listlevel) {
345 MacroInhibit *temp = mistack;
346 mistack = temp->next;
347 nasm_free(temp);
349 break;
353 static void list_error(errflags severity, const char *fmt, ...)
355 va_list ap;
357 if (!listfp)
358 return;
360 if (!list_errors)
361 list_errors = strlist_alloc(false);
363 va_start(ap, fmt);
364 strlist_vprintf(list_errors, fmt, ap);
365 va_end(ap);
367 if ((severity & ERR_MASK) >= ERR_FATAL)
368 list_emit();
371 static void list_set_offset(uint64_t offset)
373 listoffset = offset;
376 static const struct lfmt nasm_list = {
377 list_init,
378 list_cleanup,
379 list_output,
380 list_line,
381 list_uplevel,
382 list_downlevel,
383 list_error,
384 list_set_offset
387 const struct lfmt *lfmt = &nasm_list;