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  * outdbg.c	output routines for the Netwide Assembler to produce
36  *		a debugging trace
37  */
38 
39 #include "compiler.h"
40 
41 #include "nctype.h"
42 #include <errno.h>
43 
44 #include "nasm.h"
45 #include "nasmlib.h"
46 #include "outform.h"
47 #include "outlib.h"
48 #include "insns.h"
49 
50 #ifdef OF_DBG
51 
52 struct Section {
53     struct Section *next;
54     int32_t number;
55     char *name;
56 } *dbgsect;
57 
58 static unsigned long dbg_max_data_dump = 128;
59 static bool section_labels = true;
60 static bool subsections_via_symbols = false;
61 static int32_t init_seg;
62 
63 const struct ofmt of_dbg;
dbg_init(void)64 static void dbg_init(void)
65 {
66     dbgsect = NULL;
67     fprintf(ofile, "NASM Output format debug dump\n");
68     fprintf(ofile, "input file  = %s\n", inname);
69     fprintf(ofile, "output file = %s\n", outname);
70     init_seg = seg_alloc();
71 }
72 
dbg_reset(void)73 static void dbg_reset(void)
74 {
75     fprintf(ofile, "*** pass reset: pass = %"PRId64" (%s)\n",
76             pass_count(), pass_type_name());
77 }
78 
dbg_cleanup(void)79 static void dbg_cleanup(void)
80 {
81     dfmt->cleanup();
82     while (dbgsect) {
83         struct Section *tmp = dbgsect;
84         dbgsect = dbgsect->next;
85         nasm_free(tmp->name);
86         nasm_free(tmp);
87     }
88 }
89 
dbg_add_section(char * name,int * bits,const char * whatwecallit)90 static int32_t dbg_add_section(char *name, int *bits, const char *whatwecallit)
91 {
92     int seg;
93 
94     /*
95      * We must have an initial default: let's make it 16.
96      */
97     if (!name)
98         *bits = 16;
99 
100     if (!name) {
101         fprintf(ofile, "section_name on init: returning %d\n", init_seg);
102         seg = init_seg;
103     } else {
104         int n = strcspn(name, " \t");
105         char *sname = nasm_strndup(name, n);
106         char *tail = nasm_skip_spaces(name+n);
107         struct Section *s;
108 
109         seg = NO_SEG;
110         for (s = dbgsect; s; s = s->next)
111             if (!strcmp(s->name, sname))
112                 seg = s->number;
113 
114         if (seg == NO_SEG) {
115             s = nasm_malloc(sizeof(*s));
116             s->name = sname;
117             s->number = seg = seg_alloc();
118             s->next = dbgsect;
119             dbgsect = s;
120             fprintf(ofile, "%s %s (%s) pass %"PRId64" (%s) : returning %d\n",
121                     whatwecallit, name, tail, pass_count(), pass_type_name(), seg);
122 
123             if (section_labels)
124                 backend_label(s->name, s->number + 1, 0);
125         }
126     }
127     return seg;
128 }
129 
dbg_section_names(char * name,int * bits)130 static int32_t dbg_section_names(char *name, int *bits)
131 {
132     return dbg_add_section(name, bits, "section_names");
133 }
134 
dbg_herelabel(const char * name,enum label_type type,int32_t oldseg,int32_t * subsection,bool * copyoffset)135 static int32_t dbg_herelabel(const char *name, enum label_type type,
136                              int32_t oldseg, int32_t *subsection,
137                              bool *copyoffset)
138 {
139     int32_t newseg = oldseg;
140 
141     if (subsections_via_symbols && type != LBL_LOCAL) {
142         newseg = *subsection;
143         if (newseg == NO_SEG) {
144             newseg = *subsection = seg_alloc();
145             *copyoffset = true; /* Minic MachO for now */
146         }
147     }
148     fprintf(ofile, "herelabel %s type %d (seg %08x) -> %08x\n",
149             name, type, oldseg, newseg);
150 
151     return newseg;
152 }
153 
dbg_deflabel(char * name,int32_t segment,int64_t offset,int is_global,char * special)154 static void dbg_deflabel(char *name, int32_t segment, int64_t offset,
155                          int is_global, char *special)
156 {
157     fprintf(ofile, "deflabel %s := %08"PRIx32":%016"PRIx64" %s (%d)%s%s\n",
158             name, segment, offset,
159             is_global == 2 ? "common" : is_global ? "global" : "local",
160             is_global, special ? ": " : "", special);
161 }
162 
out_type(enum out_type type)163 static const char *out_type(enum out_type type)
164 {
165     static const char *out_types[] = {
166         "rawdata",
167         "reserve",
168         "zerodata",
169         "address",
170         "reladdr",
171         "segment"
172     };
173     static char invalid_buf[64];
174 
175     if (type >= sizeof(out_types)/sizeof(out_types[0])) {
176         sprintf(invalid_buf, "[invalid type %d]", type);
177         return invalid_buf;
178     }
179 
180     return out_types[type];
181 }
182 
out_sign(enum out_sign sign)183 static const char *out_sign(enum out_sign sign)
184 {
185     static const char *out_signs[] = {
186         "wrap",
187         "signed",
188         "unsigned"
189     };
190     static char invalid_buf[64];
191 
192     if (sign >= sizeof(out_signs)/sizeof(out_signs[0])) {
193         sprintf(invalid_buf, "[invalid sign %d]", sign);
194         return invalid_buf;
195     }
196 
197     return out_signs[sign];
198 }
199 
dbg_out(const struct out_data * data)200 static void dbg_out(const struct out_data *data)
201 {
202     fprintf(ofile,
203             "out to %"PRIx32":%"PRIx64" %s %s bits %d insoffs %d/%d "
204             "size %"PRIu64,
205             data->segment, data->offset,
206             out_type(data->type), out_sign(data->sign),
207             data->bits, data->insoffs, data->inslen, data->size);
208     if (data->itemp) {
209         fprintf(ofile, " ins %s(%d)",
210                 nasm_insn_names[data->itemp->opcode], data->itemp->operands);
211     } else {
212         fprintf(ofile, " no ins (plain data)");
213     }
214 
215     if (data->type == OUT_ADDRESS || data->type == OUT_RELADDR ||
216         data->type == OUT_SEGMENT) {
217         fprintf(ofile, " target %"PRIx32":%"PRIx64,
218                 data->tsegment, data->toffset);
219         if (data->twrt != NO_SEG)
220             fprintf(ofile, " wrt %"PRIx32, data->twrt);
221     }
222     if (data->type == OUT_RELADDR)
223         fprintf(ofile, " relbase %"PRIx64, data->relbase);
224 
225     putc('\n', ofile);
226 
227     if (data->type == OUT_RAWDATA) {
228         if ((size_t)data->size != data->size) {
229             fprintf(ofile, "  data: <error: impossible size>\n");
230         } else if (!data->data) {
231             fprintf(ofile, "  data: <error: null pointer>\n");
232         } else if (dbg_max_data_dump != -1UL &&
233                    data->size > dbg_max_data_dump) {
234             fprintf(ofile, "  data: <%"PRIu64" bytes>\n", data->size);
235         } else {
236             size_t i, j;
237             const uint8_t *bytes = data->data;
238             for (i = 0; i < data->size; i += 16) {
239                 fprintf(ofile, "  data:");
240                 for (j = 0; j < 16; j++) {
241                     if (i+j >= data->size)
242                         fprintf(ofile, "   ");
243                     else
244                         fprintf(ofile, "%c%02x",
245                                 (j == 8) ? '-' : ' ', bytes[i+j]);
246                 }
247                 fprintf(ofile,"    ");
248                 for (j = 0; j < 16; j++) {
249                     if (i+j >= data->size) {
250                         putc(' ', ofile);
251                     } else {
252                         if (bytes[i+j] >= 32 && bytes[i+j] <= 126)
253                             putc(bytes[i+j], ofile);
254                         else
255                             putc('.', ofile);
256                     }
257                 }
258                 putc('\n', ofile);
259             }
260         }
261     }
262 
263     /* This is probably the only place were we'll call this this way... */
264     nasm_do_legacy_output(data);
265 }
266 
dbg_legacy_out(int32_t segto,const void * data,enum out_type type,uint64_t size,int32_t segment,int32_t wrt)267 static void dbg_legacy_out(int32_t segto, const void *data,
268                            enum out_type type, uint64_t size,
269                            int32_t segment, int32_t wrt)
270 {
271     int32_t ldata;
272 
273     if (type == OUT_ADDRESS)
274         fprintf(ofile, "  legacy: out to %"PRIx32", len = %d: ",
275                 segto, (int)abs((int)size));
276     else
277         fprintf(ofile, "  legacy: out to %"PRIx32", len = %"PRId64" (0x%"PRIx64"): ",
278                 segto, (int64_t)size, size);
279 
280     switch (type) {
281     case OUT_RESERVE:
282         fprintf(ofile, "reserved.\n");
283         break;
284     case OUT_RAWDATA:
285         fprintf(ofile, "rawdata\n"); /* Already have a data dump */
286         break;
287     case OUT_ADDRESS:
288 	ldata = *(int64_t *)data;
289         fprintf(ofile, "addr %08"PRIx32" (seg %08"PRIx32", wrt %08"PRIx32")\n",
290                 ldata, segment, wrt);
291         break;
292     case OUT_REL1ADR:
293         fprintf(ofile, "rel1adr %02"PRIx8" (seg %08"PRIx32")\n",
294 		(uint8_t)*(int64_t *)data, segment);
295         break;
296     case OUT_REL2ADR:
297         fprintf(ofile, "rel2adr %04"PRIx16" (seg %08"PRIx32")\n",
298 		(uint16_t)*(int64_t *)data, segment);
299         break;
300     case OUT_REL4ADR:
301         fprintf(ofile, "rel4adr %08"PRIx32" (seg %08"PRIx32")\n",
302 		(uint32_t)*(int64_t *)data,
303                 segment);
304         break;
305     case OUT_REL8ADR:
306         fprintf(ofile, "rel8adr %016"PRIx64" (seg %08"PRIx32")\n",
307 		(uint64_t)*(int64_t *)data, segment);
308         break;
309     default:
310         fprintf(ofile, "unknown\n");
311         break;
312     }
313 }
314 
dbg_sectalign(int32_t seg,unsigned int value)315 static void dbg_sectalign(int32_t seg, unsigned int value)
316 {
317     fprintf(ofile, "set alignment (%d) for segment (%u)\n",
318             seg, value);
319 }
320 
321 static enum directive_result
dbg_directive(enum directive directive,char * value)322 dbg_directive(enum directive directive, char *value)
323 {
324     switch (directive) {
325         /*
326          * The .obj GROUP directive is nontrivial to emulate in a macro.
327          * It effectively creates a "pseudo-section" containing the first
328          * space-separated argument; the rest we ignore.
329          */
330     case D_GROUP:
331     {
332         int dummy;
333         dbg_add_section(value, &dummy, "directive:group");
334         break;
335     }
336 
337     default:
338         break;
339     }
340 
341     fprintf(ofile, "directive [%s] value [%s] pass %"PRId64" (%s)\n",
342             directive_dname(directive), value, pass_count(), pass_type_name());
343     return DIRR_OK;
344 }
345 
346 static enum directive_result
347 dbg_pragma(const struct pragma *pragma);
348 
349 static const struct pragma_facility dbg_pragma_list[] = {
350     { NULL, dbg_pragma }
351 };
352 
353 static enum directive_result
dbg_pragma(const struct pragma * pragma)354 dbg_pragma(const struct pragma *pragma)
355 {
356     fprintf(ofile, "pragma %s(%s) %s[%s] %s\n",
357             pragma->facility_name,
358             pragma->facility->name ? pragma->facility->name : "<default>",
359             pragma->opname, directive_dname(pragma->opcode),
360             pragma->tail);
361 
362     if (pragma->facility == &dbg_pragma_list[0]) {
363         switch (pragma->opcode) {
364         case D_MAXDUMP:
365             if (!nasm_stricmp(pragma->tail, "unlimited")) {
366                 dbg_max_data_dump = -1UL;
367             } else {
368                 char *ep;
369                 unsigned long arg;
370 
371                 errno = 0;
372                 arg = strtoul(pragma->tail, &ep, 0);
373                 if (errno || *nasm_skip_spaces(ep)) {
374                     nasm_warn(WARN_PRAGMA_BAD | ERR_PASS2,
375                                "invalid %%pragma dbg maxdump argument");
376                     return DIRR_ERROR;
377                 } else {
378                     dbg_max_data_dump = arg;
379                 }
380             }
381             break;
382         case D_NOSECLABELS:
383             section_labels = false;
384             break;
385         case D_SUBSECTIONS_VIA_SYMBOLS:
386             subsections_via_symbols = true;
387             break;
388         default:
389             break;
390         }
391     }
392     return DIRR_OK;
393 }
394 
395 static const char * const types[] = {
396     "unknown", "label", "byte", "word", "dword", "float", "qword", "tbyte"
397 };
dbgdbg_init(void)398 static void dbgdbg_init(void)
399 {
400     fprintf(ofile, "   With debug info\n");
401 }
dbgdbg_cleanup(void)402 static void dbgdbg_cleanup(void)
403 {
404 }
405 
dbgdbg_linnum(const char * lnfname,int32_t lineno,int32_t segto)406 static void dbgdbg_linnum(const char *lnfname, int32_t lineno, int32_t segto)
407 {
408     fprintf(ofile, "dbglinenum %s(%"PRId32") segment %"PRIx32"\n",
409 	    lnfname, lineno, segto);
410 }
dbgdbg_deflabel(char * name,int32_t segment,int64_t offset,int is_global,char * special)411 static void dbgdbg_deflabel(char *name, int32_t segment,
412                             int64_t offset, int is_global, char *special)
413 {
414     fprintf(ofile, "dbglabel %s := %08"PRIx32":%016"PRIx64" %s (%d)%s%s\n",
415             name,
416             segment, offset,
417             is_global == 2 ? "common" : is_global ? "global" : "local",
418             is_global, special ? ": " : "", special);
419 }
dbgdbg_define(const char * type,const char * params)420 static void dbgdbg_define(const char *type, const char *params)
421 {
422     fprintf(ofile, "dbgdirective [%s] value [%s]\n", type, params);
423 }
dbgdbg_output(int output_type,void * param)424 static void dbgdbg_output(int output_type, void *param)
425 {
426     (void)output_type;
427     (void)param;
428 }
dbgdbg_typevalue(int32_t type)429 static void dbgdbg_typevalue(int32_t type)
430 {
431     fprintf(ofile, "new type: %s(%"PRIX32")\n",
432             types[TYM_TYPE(type) >> 3], TYM_ELEMENTS(type));
433 }
434 
435 static const struct pragma_facility dbgdbg_pragma_list[] = {
436     { "dbgdbg", dbg_pragma },
437     { NULL, dbg_pragma }        /* Won't trigger, "debug" is a reserved ns */
438 };
439 
440 static const struct dfmt debug_debug_form = {
441     "Trace of all info passed to debug stage",
442     "debug",
443     dbgdbg_init,
444     dbgdbg_linnum,
445     dbgdbg_deflabel,
446     dbgdbg_define,
447     dbgdbg_typevalue,
448     dbgdbg_output,
449     dbgdbg_cleanup,
450     dbgdbg_pragma_list
451 };
452 
453 static const struct dfmt * const debug_debug_arr[3] = {
454     &debug_debug_form,
455     &null_debug_form,
456     NULL
457 };
458 
459 extern macros_t dbg_stdmac[];
460 
461 const struct ofmt of_dbg = {
462     "Trace of all info passed to output stage",
463     "dbg",
464     ".dbg",
465     OFMT_TEXT,
466     64,
467     debug_debug_arr,
468     &debug_debug_form,
469     dbg_stdmac,
470     dbg_init,
471     dbg_reset,
472     dbg_out,
473     dbg_legacy_out,
474     dbg_deflabel,
475     dbg_section_names,
476     dbg_herelabel,
477     dbg_sectalign,
478     null_segbase,
479     dbg_directive,
480     dbg_cleanup,
481     dbg_pragma_list
482 };
483 
484 #endif                          /* OF_DBG */
485