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