Merge remote-tracking branch 'github/nasm-2.15.xx'
[nasm.git] / asm / listing.c
blobf6ef6d1b688aa8a3534ea9753334ef33232506d6
1 /* ----------------------------------------------------------------------- *
3 * Copyright 1996-2020 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 static const char xdigit[] = "0123456789ABCDEF";
54 #define HEX(a,b) (*(a)=xdigit[((b)>>4)&15],(a)[1]=xdigit[(b)&15]);
56 uint64_t list_options, active_list_options;
58 static char listline[LIST_MAX_LEN];
59 static bool listlinep;
61 static struct strlist *list_errors;
63 static char listdata[2 * LIST_INDENT]; /* we need less than that actually */
64 static int32_t listoffset;
66 static int32_t listlineno;
68 static int suppress; /* for INCBIN & TIMES special cases */
70 static int listlevel, listlevel_e;
72 static FILE *listfp;
74 static void list_emit(void)
76 int i;
77 const struct strlist_entry *e;
79 if (listlinep || *listdata) {
80 fprintf(listfp, "%6"PRId32" ", listlineno);
82 if (listdata[0])
83 fprintf(listfp, "%08"PRIX32" %-*s", listoffset, LIST_HEXBIT + 1,
84 listdata);
85 else
86 fprintf(listfp, "%*s", LIST_HEXBIT + 10, "");
88 if (listlevel_e)
89 fprintf(listfp, "%s<%d>", (listlevel < 10 ? " " : ""),
90 listlevel_e);
91 else if (listlinep)
92 fprintf(listfp, " ");
94 if (listlinep)
95 fprintf(listfp, " %s", listline);
97 putc('\n', listfp);
98 listlinep = false;
99 listdata[0] = '\0';
102 if (list_errors) {
103 static const char fillchars[] = " --***XX";
104 char fillchar;
106 strlist_for_each(e, list_errors) {
107 fprintf(listfp, "%6"PRId32" ", listlineno);
108 fillchar = fillchars[e->pvt.u & ERR_MASK];
109 for (i = 0; i < LIST_HEXBIT; i++)
110 putc(fillchar, listfp);
112 if (listlevel_e)
113 fprintf(listfp, " %s<%d>", (listlevel < 10 ? " " : ""),
114 listlevel_e);
115 else
116 fprintf(listfp, " ");
118 fprintf(listfp, " %s\n", e->str);
121 strlist_free(&list_errors);
125 static void list_cleanup(void)
127 if (!listfp)
128 return;
130 list_emit();
131 fclose(listfp);
132 listfp = NULL;
135 static void list_init(const char *fname)
137 enum file_flags flags = NF_TEXT;
139 if (listfp)
140 list_cleanup();
142 if (!fname || fname[0] == '\0') {
143 listfp = NULL;
144 return;
147 if (list_option('w'))
148 flags |= NF_IOLBF;
150 listfp = nasm_open_write(fname, flags);
151 if (!listfp) {
152 nasm_nonfatal("unable to open listing file `%s'", fname);
153 return;
156 *listline = '\0';
157 listlineno = 0;
158 list_errors = NULL;
159 listlevel = 0;
160 suppress = 0;
163 static void list_out(int64_t offset, char *str)
165 if (strlen(listdata) + strlen(str) > LIST_HEXBIT) {
166 strcat(listdata, "-");
167 list_emit();
169 if (!listdata[0])
170 listoffset = offset;
171 strcat(listdata, str);
174 static void list_address(int64_t offset, const char *brackets,
175 int64_t addr, int size)
177 char q[20];
178 char *r = q;
180 nasm_assert(size <= 8);
182 *r++ = brackets[0];
183 while (size--) {
184 HEX(r, addr);
185 addr >>= 8;
186 r += 2;
188 *r++ = brackets[1];
189 *r = '\0';
190 list_out(offset, q);
193 static void list_size(int64_t offset, const char *tag, uint64_t size)
195 char buf[64];
196 const char *fmt;
198 if (list_option('d'))
199 fmt = "<%s %"PRIu64">";
200 else
201 fmt = "<%s %"PRIX64"h>";
203 snprintf(buf, sizeof buf, fmt, tag, size);
204 list_out(offset, buf);
207 static void list_output(const struct out_data *data)
209 char q[24];
210 uint64_t size = data->size;
211 uint64_t offset = data->offset;
212 const uint8_t *p = data->data;
215 if (!listfp || suppress || user_nolist)
216 return;
218 switch (data->type) {
219 case OUT_ZERODATA:
220 if (size > 16) {
221 list_size(offset, "zero", size);
222 break;
223 } else {
224 p = zero_buffer;
226 /* fall through */
227 case OUT_RAWDATA:
229 if (size == 0) {
230 if (!listdata[0])
231 listoffset = data->offset;
232 } else if (p) {
233 while (size--) {
234 HEX(q, *p);
235 q[2] = '\0';
236 list_out(offset++, q);
237 p++;
239 } else {
240 /* Used for listing on non-code generation passes with -Lp */
241 list_size(offset, "len", size);
243 break;
245 case OUT_ADDRESS:
246 list_address(offset, "[]", data->toffset, size);
247 break;
248 case OUT_SEGMENT:
249 q[0] = '[';
250 memset(q+1, 's', size << 1);
251 q[(size << 1)+1] = ']';
252 q[(size << 1)+2] = '\0';
253 list_out(offset, q);
254 offset += size;
255 break;
256 case OUT_RELADDR:
257 list_address(offset, "()", data->toffset, size);
258 break;
259 case OUT_RESERVE:
261 if (size > 8) {
262 list_size(offset, "res", size);
263 } else {
264 memset(q, '?', size << 1);
265 q[size << 1] = '\0';
266 list_out(offset, q);
268 break;
270 default:
271 panic();
275 static void list_line(int type, int32_t lineno, const char *line)
277 (void)type;
279 if (!listfp)
280 return;
282 if (user_nolist)
283 return;
285 list_emit();
286 if (lineno >= 0)
287 listlineno = lineno;
288 listlinep = true;
289 strlcpy(listline, line, LIST_MAX_LEN-3);
290 memcpy(listline + LIST_MAX_LEN-4, "...", 4);
291 listlevel_e = listlevel;
294 static void list_uplevel(int type, int64_t size)
296 if (!listfp)
297 return;
299 switch (type) {
300 case LIST_INCBIN:
301 suppress |= 1;
302 list_size(listoffset, "bin", size);
303 break;
305 case LIST_TIMES:
306 suppress |= 2;
307 list_size(listoffset, "rep", size);
308 break;
310 case LIST_INCLUDE:
311 listlevel++;
312 break;
314 default:
315 listlevel++;
316 break;
320 static void list_downlevel(int type)
322 if (!listfp)
323 return;
325 switch (type) {
326 case LIST_INCBIN:
327 suppress &= ~1;
328 break;
330 case LIST_TIMES:
331 suppress &= ~2;
332 break;
334 default:
335 listlevel--;
336 break;
340 static void list_error(errflags severity, const char *fmt, ...)
342 va_list ap;
344 if (!listfp)
345 return;
347 if (!list_errors)
348 list_errors = strlist_alloc(false);
350 va_start(ap, fmt);
351 strlist_vprintf(list_errors, fmt, ap);
352 va_end(ap);
353 strlist_tail(list_errors)->pvt.u = severity;
355 if ((severity & ERR_MASK) >= ERR_FATAL)
356 list_emit();
359 static void list_set_offset(uint64_t offset)
361 listoffset = offset;
364 static void list_update_options(const char *str)
366 bool state = true;
367 unsigned char c;
368 uint64_t mask;
370 while ((c = *str++)) {
371 switch (c) {
372 case '+':
373 state = true;
374 break;
375 case '-':
376 state = false;
377 break;
378 default:
379 mask = list_option_mask(c);
380 if (state)
381 list_options |= mask;
382 else
383 list_options &= ~mask;
384 break;
389 enum directive_result list_pragma(const struct pragma *pragma)
391 switch (pragma->opcode) {
392 case D_OPTIONS:
393 list_update_options(pragma->tail);
394 return DIRR_OK;
396 default:
397 return DIRR_UNKNOWN;
401 static const struct lfmt nasm_list = {
402 list_init,
403 list_cleanup,
404 list_output,
405 list_line,
406 list_uplevel,
407 list_downlevel,
408 list_error,
409 list_set_offset
412 const struct lfmt *lfmt = &nasm_list;