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 216        /* 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 static char listerror[LIST_MAX_LEN];
71 
72 static char listdata[2 * LIST_INDENT];  /* we need less than that actually */
73 static int32_t listoffset;
74 
75 static int32_t listlineno;
76 
77 static int32_t listp;
78 
79 static int suppress;            /* for INCBIN & TIMES special cases */
80 
81 static int listlevel, listlevel_e;
82 
83 static FILE *listfp;
84 
list_emit(void)85 static void list_emit(void)
86 {
87     int i;
88 
89     if (!listlinep && !listdata[0])
90         return;
91 
92     fprintf(listfp, "%6"PRId32" ", listlineno);
93 
94     if (listdata[0])
95         fprintf(listfp, "%08"PRIX32" %-*s", listoffset, LIST_HEXBIT + 1,
96                 listdata);
97     else
98         fprintf(listfp, "%*s", LIST_HEXBIT + 10, "");
99 
100     if (listlevel_e)
101         fprintf(listfp, "%s<%d>", (listlevel < 10 ? " " : ""),
102                 listlevel_e);
103     else if (listlinep)
104         fprintf(listfp, "    ");
105 
106     if (listlinep)
107         fprintf(listfp, " %s", listline);
108 
109     putc('\n', listfp);
110     listlinep = false;
111     listdata[0] = '\0';
112 
113     if (listerror[0]) {
114 	fprintf(listfp, "%6"PRId32"          ", listlineno);
115 	for (i = 0; i < LIST_HEXBIT; i++)
116 	    putc('*', listfp);
117 
118 	if (listlevel_e)
119 	    fprintf(listfp, " %s<%d>", (listlevel < 10 ? " " : ""),
120 		    listlevel_e);
121 	else
122 	    fprintf(listfp, "     ");
123 
124 	fprintf(listfp, "  %s\n", listerror);
125 	listerror[0] = '\0';
126     }
127 }
128 
list_init(const char * fname)129 static void list_init(const char *fname)
130 {
131     if (!fname || fname[0] == '\0') {
132 	listfp = NULL;
133 	return;
134     }
135 
136     listfp = nasm_open_write(fname, NF_TEXT);
137     if (!listfp) {
138 	nasm_error(ERR_NONFATAL, "unable to open listing file `%s'",
139 		   fname);
140         return;
141     }
142 
143     *listline = '\0';
144     listlineno = 0;
145     *listerror = '\0';
146     listp = true;
147     listlevel = 0;
148     suppress = 0;
149     mistack = nasm_malloc(sizeof(MacroInhibit));
150     mistack->next = NULL;
151     mistack->level = 0;
152     mistack->inhibiting = true;
153 }
154 
list_cleanup(void)155 static void list_cleanup(void)
156 {
157     if (!listp)
158         return;
159 
160     while (mistack) {
161         MacroInhibit *temp = mistack;
162         mistack = temp->next;
163         nasm_free(temp);
164     }
165 
166     list_emit();
167     fclose(listfp);
168 }
169 
list_out(int64_t offset,char * str)170 static void list_out(int64_t offset, char *str)
171 {
172     if (strlen(listdata) + strlen(str) > LIST_HEXBIT) {
173         strcat(listdata, "-");
174         list_emit();
175     }
176     if (!listdata[0])
177         listoffset = offset;
178     strcat(listdata, str);
179 }
180 
list_address(int64_t offset,const char * brackets,int64_t addr,int size)181 static void list_address(int64_t offset, const char *brackets,
182 			 int64_t addr, int size)
183 {
184     char q[20];
185     char *r = q;
186 
187     nasm_assert(size <= 8);
188 
189     *r++ = brackets[0];
190     while (size--) {
191 	HEX(r, addr);
192 	addr >>= 8;
193 	r += 2;
194     }
195     *r++ = brackets[1];
196     *r = '\0';
197     list_out(offset, q);
198 }
199 
list_output(const struct out_data * data)200 static void list_output(const struct out_data *data)
201 {
202     char q[24];
203     uint64_t size = data->size;
204     uint64_t offset = data->offset;
205     const uint8_t *p = data->data;
206 
207 
208     if (!listp || suppress || user_nolist)
209         return;
210 
211     switch (data->type) {
212     case OUT_ZERODATA:
213         if (size > 16) {
214             snprintf(q, sizeof(q), "<zero %08"PRIX64">", size);
215             list_out(offset, q);
216             break;
217         } else {
218             p = zero_buffer;
219         }
220         /* fall through */
221     case OUT_RAWDATA:
222     {
223 	if (size == 0 && !listdata[0])
224 	    listoffset = data->offset;
225         while (size--) {
226             HEX(q, *p);
227             q[2] = '\0';
228             list_out(offset++, q);
229             p++;
230         }
231 	break;
232     }
233     case OUT_ADDRESS:
234         list_address(offset, "[]", data->toffset, size);
235 	break;
236     case OUT_SEGMENT:
237         q[0] = '[';
238         memset(q+1, 's', size << 1);
239         q[(size << 1)+1] = ']';
240         q[(size << 1)+2] = '\0';
241         list_out(offset, q);
242         offset += size;
243         break;
244     case OUT_RELADDR:
245 	list_address(offset, "()", data->toffset, size);
246 	break;
247     case OUT_RESERVE:
248     {
249         snprintf(q, sizeof(q), "<res %08"PRIX64">", size);
250         list_out(offset, q);
251 	break;
252     }
253     default:
254         panic();
255     }
256 }
257 
list_line(int type,char * line)258 static void list_line(int type, char *line)
259 {
260     if (!listp)
261         return;
262 
263     if (user_nolist)
264       return;
265 
266     if (mistack && mistack->inhibiting) {
267         if (type == LIST_MACRO)
268             return;
269         else {                  /* pop the m i stack */
270             MacroInhibit *temp = mistack;
271             mistack = temp->next;
272             nasm_free(temp);
273         }
274     }
275     list_emit();
276     listlineno = src_get_linnum();
277     listlinep = true;
278     strncpy(listline, line, LIST_MAX_LEN - 1);
279     listline[LIST_MAX_LEN - 1] = '\0';
280     listlevel_e = listlevel;
281 }
282 
list_uplevel(int type)283 static void list_uplevel(int type)
284 {
285     if (!listp)
286         return;
287     if (type == LIST_INCBIN || type == LIST_TIMES) {
288         suppress |= (type == LIST_INCBIN ? 1 : 2);
289         list_out(listoffset, type == LIST_INCBIN ? "<incbin>" : "<rept>");
290         return;
291     }
292 
293     listlevel++;
294 
295     if (mistack && mistack->inhibiting && type == LIST_INCLUDE) {
296         MacroInhibit *temp = nasm_malloc(sizeof(MacroInhibit));
297         temp->next = mistack;
298         temp->level = listlevel;
299         temp->inhibiting = false;
300         mistack = temp;
301     } else if (type == LIST_MACRO_NOLIST) {
302         MacroInhibit *temp = nasm_malloc(sizeof(MacroInhibit));
303         temp->next = mistack;
304         temp->level = listlevel;
305         temp->inhibiting = true;
306         mistack = temp;
307     }
308 }
309 
list_downlevel(int type)310 static void list_downlevel(int type)
311 {
312     if (!listp)
313         return;
314 
315     if (type == LIST_INCBIN || type == LIST_TIMES) {
316         suppress &= ~(type == LIST_INCBIN ? 1 : 2);
317         return;
318     }
319 
320     listlevel--;
321     while (mistack && mistack->level > listlevel) {
322         MacroInhibit *temp = mistack;
323         mistack = temp->next;
324         nasm_free(temp);
325     }
326 }
327 
list_error(int severity,const char * pfx,const char * msg)328 static void list_error(int severity, const char *pfx, const char *msg)
329 {
330     if (!listfp)
331 	return;
332 
333     snprintf(listerror, sizeof listerror, "%s%s", pfx, msg);
334 
335     if ((severity & ERR_MASK) >= ERR_FATAL)
336 	list_emit();
337 }
338 
list_set_offset(uint64_t offset)339 static void list_set_offset(uint64_t offset)
340 {
341     listoffset = offset;
342 }
343 
344 static const struct lfmt nasm_list = {
345     list_init,
346     list_cleanup,
347     list_output,
348     list_line,
349     list_uplevel,
350     list_downlevel,
351     list_error,
352     list_set_offset
353 };
354 
355 const struct lfmt *lfmt = &nasm_list;
356