Merge branch 'new-preproc'
[platform/upstream/nasm.git] / listing.c
1 /* ----------------------------------------------------------------------- *
2  *   
3  *   Copyright 1996-2009 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 #include <inttypes.h>
46
47 #include "nasm.h"
48 #include "nasmlib.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
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
129 static void list_init(char *fname, efunc error)
130 {
131     listfp = fopen(fname, "w");
132     if (!listfp) {
133         error(ERR_NONFATAL, "unable to open listing file `%s'",
134               fname);
135         return;
136     }
137
138     *listline = '\0';
139     listlineno = 0;
140     *listerror = '\0';
141     listp = true;
142     listlevel = 0;
143     suppress = 0;
144     mistack = nasm_malloc(sizeof(MacroInhibit));
145     mistack->next = NULL;
146     mistack->level = 0;
147     mistack->inhibiting = true;
148 }
149
150 static void list_cleanup(void)
151 {
152     if (!listp)
153         return;
154
155     while (mistack) {
156         MacroInhibit *temp = mistack;
157         mistack = temp->next;
158         nasm_free(temp);
159     }
160
161     list_emit();
162     fclose(listfp);
163 }
164
165 static void list_out(int32_t offset, char *str)
166 {
167     if (strlen(listdata) + strlen(str) > LIST_HEXBIT) {
168         strcat(listdata, "-");
169         list_emit();
170     }
171     if (!listdata[0])
172         listoffset = offset;
173     strcat(listdata, str);
174 }
175
176 static void list_output(int32_t offset, const void *data,
177                         enum out_type type, uint64_t size)
178 {
179     if (!listp || suppress || user_nolist)      /* fbk - 9/2/00 */
180         return;
181
182     switch (type) {
183     case OUT_RAWDATA:
184     {
185         uint8_t const *p = data;
186         char q[3];
187         if (size == 0 && !listdata[0])
188             listoffset = offset;
189         while (size--) {
190             HEX(q, *p);
191             q[2] = '\0';
192             list_out(offset++, q);
193             p++;
194         }
195         break;
196     }
197     case OUT_ADDRESS:
198     {
199         uint64_t d = *(int64_t *)data;
200         char q[20];
201         uint8_t p[8], *r = p;
202         if (size == 4) {
203             q[0] = '[';
204             q[9] = ']';
205             q[10] = '\0';
206             WRITELONG(r, d);
207             HEX(q + 1, p[0]);
208             HEX(q + 3, p[1]);
209             HEX(q + 5, p[2]);
210             HEX(q + 7, p[3]);
211             list_out(offset, q);
212         } else if (size == 8) {
213             q[0] = '[';
214             q[17] = ']';
215             q[18] = '\0';
216             WRITEDLONG(r, d);
217             HEX(q + 1,  p[0]);
218             HEX(q + 3,  p[1]);
219             HEX(q + 5,  p[2]);
220             HEX(q + 7,  p[3]);
221             HEX(q + 9,  p[4]);
222             HEX(q + 11, p[5]);
223             HEX(q + 13, p[6]);
224             HEX(q + 15, p[7]);
225             list_out(offset, q);
226         } else {
227             q[0] = '[';
228             q[5] = ']';
229             q[6] = '\0';
230             WRITESHORT(r, d);
231             HEX(q + 1, p[0]);
232             HEX(q + 3, p[1]);
233             list_out(offset, q);
234         }
235         break;
236     }
237     case OUT_REL2ADR:
238     {
239         uint32_t d = *(int32_t *)data;
240         char q[11];
241         uint8_t p[4], *r = p;
242         q[0] = '(';
243         q[5] = ')';
244         q[6] = '\0';
245         WRITESHORT(r, d);
246         HEX(q + 1, p[0]);
247         HEX(q + 3, p[1]);
248         list_out(offset, q);
249         break;
250     }
251     case OUT_REL4ADR:
252     {
253         uint32_t d = *(int32_t *)data;
254         char q[11];
255         uint8_t p[4], *r = p;
256         q[0] = '(';
257         q[9] = ')';
258         q[10] = '\0';
259         WRITELONG(r, d);
260         HEX(q + 1, p[0]);
261         HEX(q + 3, p[1]);
262         HEX(q + 5, p[2]);
263         HEX(q + 7, p[3]);
264         list_out(offset, q);
265         break;
266     }
267     case OUT_REL8ADR:
268     {
269         uint64_t d = *(int64_t *)data;
270         char q[19];
271         uint8_t p[8], *r = p;
272         q[0] = '(';
273         q[17] = ')';
274         q[18] = '\0';
275         WRITEDLONG(r, d);
276         HEX(q + 1, p[0]);
277         HEX(q + 3, p[1]);
278         HEX(q + 5, p[2]);
279         HEX(q + 7, p[3]);
280         HEX(q + 9, p[4]);
281         HEX(q + 11, p[5]);
282         HEX(q + 13, p[6]);
283         HEX(q + 15, p[7]);
284         list_out(offset, q);
285         break;
286     }
287     case OUT_RESERVE:
288     {
289         char q[20];
290         snprintf(q, sizeof(q), "<res %08"PRIX64">", size);
291         list_out(offset, q);
292         break;
293     }
294     }
295 }
296
297 static void list_line(int type, char *line)
298 {
299     if (!listp)
300         return;
301     if (user_nolist) {          /* fbk - 9/2/00 */
302         listlineno++;
303         return;
304     }
305
306     if (mistack && mistack->inhibiting) {
307         if (type == LIST_MACRO)
308             return;
309         else {                  /* pop the m i stack */
310             MacroInhibit *temp = mistack;
311             mistack = temp->next;
312             nasm_free(temp);
313         }
314     }
315     list_emit();
316     listlinep = true;
317     strncpy(listline, line, LIST_MAX_LEN - 1);
318     listline[LIST_MAX_LEN - 1] = '\0';
319     listlevel_e = listlevel;
320 }
321
322 static void list_uplevel(int type)
323 {
324     if (!listp)
325         return;
326     if (type == LIST_INCBIN || type == LIST_TIMES) {
327         suppress |= (type == LIST_INCBIN ? 1 : 2);
328         list_out(listoffset, type == LIST_INCBIN ? "<incbin>" : "<rept>");
329         return;
330     }
331
332     listlevel++;
333
334     if (mistack && mistack->inhibiting && type == LIST_INCLUDE) {
335         MacroInhibit *temp = nasm_malloc(sizeof(MacroInhibit));
336         temp->next = mistack;
337         temp->level = listlevel;
338         temp->inhibiting = false;
339         mistack = temp;
340     } else if (type == LIST_MACRO_NOLIST) {
341         MacroInhibit *temp = nasm_malloc(sizeof(MacroInhibit));
342         temp->next = mistack;
343         temp->level = listlevel;
344         temp->inhibiting = true;
345         mistack = temp;
346     }
347 }
348
349 static void list_downlevel(int type)
350 {
351     if (!listp)
352         return;
353
354     if (type == LIST_INCBIN || type == LIST_TIMES) {
355         suppress &= ~(type == LIST_INCBIN ? 1 : 2);
356         return;
357     }
358
359     listlevel--;
360     while (mistack && mistack->level > listlevel) {
361         MacroInhibit *temp = mistack;
362         mistack = temp->next;
363         nasm_free(temp);
364     }
365 }
366
367 static void list_error(int severity, const char *pfx, const char *msg)
368 {
369     if (!listfp)
370         return;
371
372     snprintf(listerror, sizeof listerror, "%s%s", pfx, msg);
373
374     if ((severity & ERR_MASK) >= ERR_FATAL)
375         list_emit();
376 }
377
378
379 ListGen nasmlist = {
380     list_init,
381     list_cleanup,
382     list_output,
383     list_line,
384     list_uplevel,
385     list_downlevel,
386     list_error
387 };