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 | |
55 | typedef struct MacroInhibit MacroInhibit; |
56 | |
57 | static struct MacroInhibit { |
58 | MacroInhibit *next; |
59 | int level; |
60 | int inhibiting; |
61 | } *mistack; |
62 | |
63 | static char xdigit[] = "0123456789ABCDEF" ; |
64 | |
65 | #define HEX(a,b) (*(a)=xdigit[((b)>>4)&15],(a)[1]=xdigit[(b)&15]); |
66 | |
67 | static char listline[LIST_MAX_LEN]; |
68 | static bool listlinep; |
69 | |
70 | struct list_error { |
71 | struct list_error *next; |
72 | char str[1]; |
73 | }; |
74 | struct list_error *listerr_head, **listerr_tail; |
75 | |
76 | static char listdata[2 * LIST_INDENT]; /* we need less than that actually */ |
77 | static int32_t listoffset; |
78 | |
79 | static int32_t listlineno; |
80 | |
81 | static int32_t listp; |
82 | |
83 | static int suppress; /* for INCBIN & TIMES special cases */ |
84 | |
85 | static int listlevel, listlevel_e; |
86 | |
87 | static FILE *listfp; |
88 | |
89 | static 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 | |
135 | static 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 | |
162 | static 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 | |
177 | static 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 | |
188 | static 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 | |
207 | static 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 | |
265 | static 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 | |
290 | static 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 | |
317 | static 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 | |
335 | static 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 | |
363 | static void list_set_offset(uint64_t offset) |
364 | { |
365 | listoffset = offset; |
366 | } |
367 | |
368 | static 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 | |
379 | const struct lfmt *lfmt = &nasm_list; |
380 | |