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