1/* ----------------------------------------------------------------------- *
2 *
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.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following
9 * conditions are met:
10 *
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.
17 *
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.
31 *
32 * ----------------------------------------------------------------------- */
33
34/*
35 * listing.c listing file generator for the Netwide Assembler
36 */
37
38#include "compiler.h"
39
40#include <stdio.h>
41#include <stdlib.h>
42#include <stddef.h>
43#include <string.h>
44#include <ctype.h>
45
46#include "nasm.h"
47#include "nasmlib.h"
48#include "error.h"
49#include "listing.h"
50
51#define LIST_MAX_LEN 256 /* something sensible */
52#define LIST_INDENT 40
53#define LIST_HEXBIT 18
54
55typedef struct MacroInhibit MacroInhibit;
56
57static struct MacroInhibit {
58 MacroInhibit *next;
59 int level;
60 int inhibiting;
61} *mistack;
62
63static char xdigit[] = "0123456789ABCDEF";
64
65#define HEX(a,b) (*(a)=xdigit[((b)>>4)&15],(a)[1]=xdigit[(b)&15]);
66
67static char listline[LIST_MAX_LEN];
68static bool listlinep;
69
70struct list_error {
71 struct list_error *next;
72 char str[1];
73};
74struct list_error *listerr_head, **listerr_tail;
75
76static char listdata[2 * LIST_INDENT]; /* we need less than that actually */
77static int32_t listoffset;
78
79static int32_t listlineno;
80
81static int32_t listp;
82
83static int suppress; /* for INCBIN & TIMES special cases */
84
85static int listlevel, listlevel_e;
86
87static FILE *listfp;
88
89static void list_emit(void)
90{
91 int i;
92 struct list_error *le, *tmp;
93
94 if (listlinep || *listdata) {
95 fprintf(listfp, "%6"PRId32" ", listlineno);
96
97 if (listdata[0])
98 fprintf(listfp, "%08"PRIX32" %-*s", listoffset, LIST_HEXBIT + 1,
99 listdata);
100 else
101 fprintf(listfp, "%*s", LIST_HEXBIT + 10, "");
102
103 if (listlevel_e)
104 fprintf(listfp, "%s<%d>", (listlevel < 10 ? " " : ""),
105 listlevel_e);
106 else if (listlinep)
107 fprintf(listfp, " ");
108
109 if (listlinep)
110 fprintf(listfp, " %s", listline);
111
112 putc('\n', listfp);
113 listlinep = false;
114 listdata[0] = '\0';
115 }
116
117 list_for_each_safe(le, tmp, listerr_head) {
118 fprintf(listfp, "%6"PRId32" ", listlineno);
119 for (i = 0; i < LIST_HEXBIT; i++)
120 putc('*', listfp);
121
122 if (listlevel_e)
123 fprintf(listfp, " %s<%d>", (listlevel < 10 ? " " : ""),
124 listlevel_e);
125 else
126 fprintf(listfp, " ");
127
128 fprintf(listfp, " %s\n", le->str);
129 nasm_free(le);
130 }
131 listerr_head = NULL;
132 listerr_tail = &listerr_head;
133}
134
135static void list_init(const char *fname)
136{
137 if (!fname || fname[0] == '\0') {
138 listfp = NULL;
139 return;
140 }
141
142 listfp = nasm_open_write(fname, NF_TEXT);
143 if (!listfp) {
144 nasm_error(ERR_NONFATAL, "unable to open listing file `%s'",
145 fname);
146 return;
147 }
148
149 *listline = '\0';
150 listlineno = 0;
151 listerr_head = NULL;
152 listerr_tail = &listerr_head;
153 listp = true;
154 listlevel = 0;
155 suppress = 0;
156 mistack = nasm_malloc(sizeof(MacroInhibit));
157 mistack->next = NULL;
158 mistack->level = 0;
159 mistack->inhibiting = true;
160}
161
162static void list_cleanup(void)
163{
164 if (!listp)
165 return;
166
167 while (mistack) {
168 MacroInhibit *temp = mistack;
169 mistack = temp->next;
170 nasm_free(temp);
171 }
172
173 list_emit();
174 fclose(listfp);
175}
176
177static void list_out(int64_t offset, char *str)
178{
179 if (strlen(listdata) + strlen(str) > LIST_HEXBIT) {
180 strcat(listdata, "-");
181 list_emit();
182 }
183 if (!listdata[0])
184 listoffset = offset;
185 strcat(listdata, str);
186}
187
188static void list_address(int64_t offset, const char *brackets,
189 int64_t addr, int size)
190{
191 char q[20];
192 char *r = q;
193
194 nasm_assert(size <= 8);
195
196 *r++ = brackets[0];
197 while (size--) {
198 HEX(r, addr);
199 addr >>= 8;
200 r += 2;
201 }
202 *r++ = brackets[1];
203 *r = '\0';
204 list_out(offset, q);
205}
206
207static void list_output(const struct out_data *data)
208{
209 char q[24];
210 uint64_t size = data->size;
211 uint64_t offset = data->offset;
212 const uint8_t *p = data->data;
213
214
215 if (!listp || suppress || user_nolist)
216 return;
217
218 switch (data->type) {
219 case OUT_ZERODATA:
220 if (size > 16) {
221 snprintf(q, sizeof(q), "<zero %08"PRIX64">", size);
222 list_out(offset, q);
223 break;
224 } else {
225 p = zero_buffer;
226 }
227 /* fall through */
228 case OUT_RAWDATA:
229 {
230 if (size == 0 && !listdata[0])
231 listoffset = data->offset;
232 while (size--) {
233 HEX(q, *p);
234 q[2] = '\0';
235 list_out(offset++, q);
236 p++;
237 }
238 break;
239 }
240 case OUT_ADDRESS:
241 list_address(offset, "[]", data->toffset, size);
242 break;
243 case OUT_SEGMENT:
244 q[0] = '[';
245 memset(q+1, 's', size << 1);
246 q[(size << 1)+1] = ']';
247 q[(size << 1)+2] = '\0';
248 list_out(offset, q);
249 offset += size;
250 break;
251 case OUT_RELADDR:
252 list_address(offset, "()", data->toffset, size);
253 break;
254 case OUT_RESERVE:
255 {
256 snprintf(q, sizeof(q), "<res %08"PRIX64">", size);
257 list_out(offset, q);
258 break;
259 }
260 default:
261 panic();
262 }
263}
264
265static void list_line(int type, char *line)
266{
267 if (!listp)
268 return;
269
270 if (user_nolist)
271 return;
272
273 if (mistack && mistack->inhibiting) {
274 if (type == LIST_MACRO)
275 return;
276 else { /* pop the m i stack */
277 MacroInhibit *temp = mistack;
278 mistack = temp->next;
279 nasm_free(temp);
280 }
281 }
282 list_emit();
283 listlineno = src_get_linnum();
284 listlinep = true;
285 strncpy(listline, line, LIST_MAX_LEN - 1);
286 listline[LIST_MAX_LEN - 1] = '\0';
287 listlevel_e = listlevel;
288}
289
290static void list_uplevel(int type)
291{
292 if (!listp)
293 return;
294 if (type == LIST_INCBIN || type == LIST_TIMES) {
295 suppress |= (type == LIST_INCBIN ? 1 : 2);
296 list_out(listoffset, type == LIST_INCBIN ? "<incbin>" : "<rept>");
297 return;
298 }
299
300 listlevel++;
301
302 if (mistack && mistack->inhibiting && type == LIST_INCLUDE) {
303 MacroInhibit *temp = nasm_malloc(sizeof(MacroInhibit));
304 temp->next = mistack;
305 temp->level = listlevel;
306 temp->inhibiting = false;
307 mistack = temp;
308 } else if (type == LIST_MACRO_NOLIST) {
309 MacroInhibit *temp = nasm_malloc(sizeof(MacroInhibit));
310 temp->next = mistack;
311 temp->level = listlevel;
312 temp->inhibiting = true;
313 mistack = temp;
314 }
315}
316
317static void list_downlevel(int type)
318{
319 if (!listp)
320 return;
321
322 if (type == LIST_INCBIN || type == LIST_TIMES) {
323 suppress &= ~(type == LIST_INCBIN ? 1 : 2);
324 return;
325 }
326
327 listlevel--;
328 while (mistack && mistack->level > listlevel) {
329 MacroInhibit *temp = mistack;
330 mistack = temp->next;
331 nasm_free(temp);
332 }
333}
334
335static void list_error(int severity, const char *fmt, ...)
336{
337 struct list_error *le;
338 va_list ap;
339 int len;
340
341 if (!listfp)
342 return;
343
344 va_start(ap, fmt);
345 len = vsnprintf(NULL, 0, fmt, ap);
346 va_end(ap);
347
348 /* sizeof(*le) already accounts for the final NULL */
349 le = nasm_malloc(sizeof(*le) + len);
350
351 va_start(ap, fmt);
352 vsnprintf(le->str, len+1, fmt, ap);
353 va_end(ap);
354
355 le->next = NULL;
356 *listerr_tail = le;
357 listerr_tail = &le->next;
358
359 if ((severity & ERR_MASK) >= ERR_FATAL)
360 list_emit();
361}
362
363static void list_set_offset(uint64_t offset)
364{
365 listoffset = offset;
366}
367
368static const struct lfmt nasm_list = {
369 list_init,
370 list_cleanup,
371 list_output,
372 list_line,
373 list_uplevel,
374 list_downlevel,
375 list_error,
376 list_set_offset
377};
378
379const struct lfmt *lfmt = &nasm_list;
380