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