preproc: BR 2222615: fix segfault on bogus %ifmacro
[nasm.git] / listing.c
blobc71c53d477c8eadb9770ab11cc7929f6a64134e0
1 /* listing.c listing file generator for the Netwide Assembler
3 * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
4 * Julian Hall. All rights reserved. The software is
5 * redistributable under the license given in the file "LICENSE"
6 * distributed in the NASM archive.
8 * initial version 2/vii/97 by Simon Tatham
9 */
11 #include "compiler.h"
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <stddef.h>
16 #include <string.h>
17 #include <ctype.h>
18 #include <inttypes.h>
20 #include "nasm.h"
21 #include "nasmlib.h"
22 #include "listing.h"
24 #define LIST_MAX_LEN 216 /* something sensible */
25 #define LIST_INDENT 40
26 #define LIST_HEXBIT 18
28 typedef struct MacroInhibit MacroInhibit;
30 static struct MacroInhibit {
31 MacroInhibit *next;
32 int level;
33 int inhibiting;
34 } *mistack;
36 static char xdigit[] = "0123456789ABCDEF";
38 #define HEX(a,b) (*(a)=xdigit[((b)>>4)&15],(a)[1]=xdigit[(b)&15]);
40 static char listline[LIST_MAX_LEN];
41 static int listlinep;
43 static char listdata[2 * LIST_INDENT]; /* we need less than that actually */
44 static int32_t listoffset;
46 static int32_t listlineno;
48 static int32_t listp;
50 static int suppress; /* for INCBIN & TIMES special cases */
52 static int listlevel, listlevel_e;
54 static FILE *listfp;
56 static void list_emit(void)
58 if (!listlinep && !listdata[0])
59 return;
61 fprintf(listfp, "%6"PRId32" ", ++listlineno);
63 if (listdata[0])
64 fprintf(listfp, "%08"PRIX32" %-*s", listoffset, LIST_HEXBIT + 1,
65 listdata);
66 else
67 fprintf(listfp, "%*s", LIST_HEXBIT + 10, "");
69 if (listlevel_e)
70 fprintf(listfp, "%s<%d>", (listlevel < 10 ? " " : ""),
71 listlevel_e);
72 else if (listlinep)
73 fprintf(listfp, " ");
75 if (listlinep)
76 fprintf(listfp, " %s", listline);
78 putc('\n', listfp);
79 listlinep = false;
80 listdata[0] = '\0';
83 static void list_init(char *fname, efunc error)
85 listfp = fopen(fname, "w");
86 if (!listfp) {
87 error(ERR_NONFATAL, "unable to open listing file `%s'", fname);
88 return;
91 *listline = '\0';
92 listlineno = 0;
93 listp = true;
94 listlevel = 0;
95 suppress = 0;
96 mistack = nasm_malloc(sizeof(MacroInhibit));
97 mistack->next = NULL;
98 mistack->level = 0;
99 mistack->inhibiting = true;
102 static void list_cleanup(void)
104 if (!listp)
105 return;
107 while (mistack) {
108 MacroInhibit *temp = mistack;
109 mistack = temp->next;
110 nasm_free(temp);
113 list_emit();
114 fclose(listfp);
117 static void list_out(int32_t offset, char *str)
119 if (strlen(listdata) + strlen(str) > LIST_HEXBIT) {
120 strcat(listdata, "-");
121 list_emit();
123 if (!listdata[0])
124 listoffset = offset;
125 strcat(listdata, str);
128 static void list_output(int32_t offset, const void *data,
129 enum out_type type, uint64_t size)
131 if (!listp || suppress || user_nolist) /* fbk - 9/2/00 */
132 return;
134 switch (type) {
135 case OUT_RAWDATA:
137 uint8_t const *p = data;
138 char q[3];
139 if (size == 0 && !listdata[0])
140 listoffset = offset;
141 while (size--) {
142 HEX(q, *p);
143 q[2] = '\0';
144 list_out(offset++, q);
145 p++;
147 break;
149 case OUT_ADDRESS:
151 uint64_t d = *(int64_t *)data;
152 char q[20];
153 uint8_t p[8], *r = p;
154 if (size == 4) {
155 q[0] = '[';
156 q[9] = ']';
157 q[10] = '\0';
158 WRITELONG(r, d);
159 HEX(q + 1, p[0]);
160 HEX(q + 3, p[1]);
161 HEX(q + 5, p[2]);
162 HEX(q + 7, p[3]);
163 list_out(offset, q);
164 } else if (size == 8) {
165 q[0] = '[';
166 q[17] = ']';
167 q[18] = '\0';
168 WRITEDLONG(r, d);
169 HEX(q + 1, p[0]);
170 HEX(q + 3, p[1]);
171 HEX(q + 5, p[2]);
172 HEX(q + 7, p[3]);
173 HEX(q + 9, p[4]);
174 HEX(q + 11, p[5]);
175 HEX(q + 13, p[6]);
176 HEX(q + 15, p[7]);
177 list_out(offset, q);
178 } else {
179 q[0] = '[';
180 q[5] = ']';
181 q[6] = '\0';
182 WRITESHORT(r, d);
183 HEX(q + 1, p[0]);
184 HEX(q + 3, p[1]);
185 list_out(offset, q);
187 break;
189 case OUT_REL2ADR:
191 uint32_t d = *(int32_t *)data;
192 char q[11];
193 uint8_t p[4], *r = p;
194 q[0] = '(';
195 q[5] = ')';
196 q[6] = '\0';
197 WRITESHORT(r, d);
198 HEX(q + 1, p[0]);
199 HEX(q + 3, p[1]);
200 list_out(offset, q);
201 break;
203 case OUT_REL4ADR:
205 uint32_t d = *(int32_t *)data;
206 char q[11];
207 uint8_t p[4], *r = p;
208 q[0] = '(';
209 q[9] = ')';
210 q[10] = '\0';
211 WRITELONG(r, d);
212 HEX(q + 1, p[0]);
213 HEX(q + 3, p[1]);
214 HEX(q + 5, p[2]);
215 HEX(q + 7, p[3]);
216 list_out(offset, q);
217 break;
219 case OUT_REL8ADR:
221 uint64_t d = *(int64_t *)data;
222 char q[19];
223 uint8_t p[8], *r = p;
224 q[0] = '(';
225 q[17] = ')';
226 q[18] = '\0';
227 WRITEDLONG(r, d);
228 HEX(q + 1, p[0]);
229 HEX(q + 3, p[1]);
230 HEX(q + 5, p[2]);
231 HEX(q + 7, p[3]);
232 HEX(q + 9, p[4]);
233 HEX(q + 11, p[5]);
234 HEX(q + 13, p[6]);
235 HEX(q + 15, p[7]);
236 list_out(offset, q);
237 break;
239 case OUT_RESERVE:
241 char q[20];
242 snprintf(q, sizeof(q), "<res %08"PRIX64">", size);
243 list_out(offset, q);
244 break;
249 static void list_line(int type, char *line)
251 if (!listp)
252 return;
253 if (user_nolist) { /* fbk - 9/2/00 */
254 listlineno++;
255 return;
258 if (mistack && mistack->inhibiting) {
259 if (type == LIST_MACRO)
260 return;
261 else { /* pop the m i stack */
262 MacroInhibit *temp = mistack;
263 mistack = temp->next;
264 nasm_free(temp);
267 list_emit();
268 listlinep = true;
269 strncpy(listline, line, LIST_MAX_LEN - 1);
270 listline[LIST_MAX_LEN - 1] = '\0';
271 listlevel_e = listlevel;
274 static void list_uplevel(int type)
276 if (!listp)
277 return;
278 if (type == LIST_INCBIN || type == LIST_TIMES) {
279 suppress |= (type == LIST_INCBIN ? 1 : 2);
280 list_out(listoffset, type == LIST_INCBIN ? "<incbin>" : "<rept>");
281 return;
284 listlevel++;
286 if (mistack && mistack->inhibiting && type == LIST_INCLUDE) {
287 MacroInhibit *temp = nasm_malloc(sizeof(MacroInhibit));
288 temp->next = mistack;
289 temp->level = listlevel;
290 temp->inhibiting = false;
291 mistack = temp;
292 } else if (type == LIST_MACRO_NOLIST) {
293 MacroInhibit *temp = nasm_malloc(sizeof(MacroInhibit));
294 temp->next = mistack;
295 temp->level = listlevel;
296 temp->inhibiting = true;
297 mistack = temp;
301 static void list_downlevel(int type)
303 if (!listp)
304 return;
306 if (type == LIST_INCBIN || type == LIST_TIMES) {
307 suppress &= ~(type == LIST_INCBIN ? 1 : 2);
308 return;
311 listlevel--;
312 while (mistack && mistack->level > listlevel) {
313 MacroInhibit *temp = mistack;
314 mistack = temp->next;
315 nasm_free(temp);
319 ListGen nasmlist = {
320 list_init,
321 list_cleanup,
322 list_output,
323 list_line,
324 list_uplevel,
325 list_downlevel