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
55struct Section {
56 struct Section *next;
57 int32_t number;
58 char *name;
59} *dbgsect;
60
61static unsigned long dbg_max_data_dump = 128;
62static bool section_labels = true;
63static bool subsections_via_symbols = false;
64static int32_t init_seg;
65
66const struct ofmt of_dbg;
67static 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
76static void dbg_reset(void)
77{
78 fprintf(ofile, "*** pass reset: pass0 = %d, passn = %"PRId64"\n",
79 pass0, passn);
80}
81
82static 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
93static 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
134static int32_t dbg_section_names(char *name, int pass, int *bits)
135{
136 return dbg_add_section(name, pass, bits, "section_names");
137}
138
139static 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
158static 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
167static 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
187static 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
204static 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
271static 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
319static 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
325static int32_t dbg_segbase(int32_t segment)
326{
327 return segment;
328}
329
330static enum directive_result
331dbg_directive(enum directive directive, char *value, int pass)
332{
333 switch (directive) {
334 /*
335 * The .obj GROUP directive is nontrivial to emulate in a macro.
336 * It effectively creates a "pseudo-section" containing the first
337 * space-separated argument; the rest we ignore.
338 */
339 case D_GROUP:
340 {
341 int dummy;
342 dbg_add_section(value, pass, &dummy, "directive:group");
343 break;
344 }
345
346 default:
347 break;
348 }
349
350 fprintf(ofile, "directive [%s] value [%s] (pass %d)\n",
351 directive_dname(directive), value, pass);
352 return DIRR_OK;
353}
354
355static enum directive_result
356dbg_pragma(const struct pragma *pragma);
357
358static const struct pragma_facility dbg_pragma_list[] = {
359 { NULL, dbg_pragma }
360};
361
362static enum directive_result
363dbg_pragma(const struct pragma *pragma)
364{
365 fprintf(ofile, "pragma %s(%s) %s[%s] %s\n",
366 pragma->facility_name,
367 pragma->facility->name ? pragma->facility->name : "<default>",
368 pragma->opname, directive_dname(pragma->opcode),
369 pragma->tail);
370
371 if (pragma->facility == &dbg_pragma_list[0]) {
372 switch (pragma->opcode) {
373 case D_MAXDUMP:
374 if (!nasm_stricmp(pragma->tail, "unlimited")) {
375 dbg_max_data_dump = -1UL;
376 } else {
377 char *ep;
378 unsigned long arg;
379
380 errno = 0;
381 arg = strtoul(pragma->tail, &ep, 0);
382 if (errno || *nasm_skip_spaces(ep)) {
383 nasm_error(ERR_WARNING | WARN_BAD_PRAGMA | ERR_PASS2,
384 "invalid %%pragma dbg maxdump argument");
385 return DIRR_ERROR;
386 } else {
387 dbg_max_data_dump = arg;
388 }
389 }
390 break;
391 case D_NOSECLABELS:
392 section_labels = false;
393 break;
394 case D_SUBSECTIONS_VIA_SYMBOLS:
395 subsections_via_symbols = true;
396 break;
397 default:
398 break;
399 }
400 }
401 return DIRR_OK;
402}
403
404static const char * const types[] = {
405 "unknown", "label", "byte", "word", "dword", "float", "qword", "tbyte"
406};
407static void dbgdbg_init(void)
408{
409 fprintf(ofile, " With debug info\n");
410}
411static void dbgdbg_cleanup(void)
412{
413}
414
415static void dbgdbg_linnum(const char *lnfname, int32_t lineno, int32_t segto)
416{
417 fprintf(ofile, "dbglinenum %s(%"PRId32") segment %"PRIx32"\n",
418 lnfname, lineno, segto);
419}
420static void dbgdbg_deflabel(char *name, int32_t segment,
421 int64_t offset, int is_global, char *special)
422{
423 fprintf(ofile, "dbglabel %s := %08"PRIx32":%016"PRIx64" %s (%d)%s%s\n",
424 name,
425 segment, offset,
426 is_global == 2 ? "common" : is_global ? "global" : "local",
427 is_global, special ? ": " : "", special);
428}
429static void dbgdbg_define(const char *type, const char *params)
430{
431 fprintf(ofile, "dbgdirective [%s] value [%s]\n", type, params);
432}
433static void dbgdbg_output(int output_type, void *param)
434{
435 (void)output_type;
436 (void)param;
437}
438static void dbgdbg_typevalue(int32_t type)
439{
440 fprintf(ofile, "new type: %s(%"PRIX32")\n",
441 types[TYM_TYPE(type) >> 3], TYM_ELEMENTS(type));
442}
443
444static const struct pragma_facility dbgdbg_pragma_list[] = {
445 { "dbgdbg", dbg_pragma },
446 { NULL, dbg_pragma } /* Won't trigger, "debug" is a reserved ns */
447};
448
449static const struct dfmt debug_debug_form = {
450 "Trace of all info passed to debug stage",
451 "debug",
452 dbgdbg_init,
453 dbgdbg_linnum,
454 dbgdbg_deflabel,
455 dbgdbg_define,
456 dbgdbg_typevalue,
457 dbgdbg_output,
458 dbgdbg_cleanup,
459 dbgdbg_pragma_list
460};
461
462static const struct dfmt * const debug_debug_arr[3] = {
463 &debug_debug_form,
464 &null_debug_form,
465 NULL
466};
467
468extern macros_t dbg_stdmac[];
469
470const struct ofmt of_dbg = {
471 "Trace of all info passed to output stage",
472 "dbg",
473 ".dbg",
474 OFMT_TEXT,
475 64,
476 debug_debug_arr,
477 &debug_debug_form,
478 dbg_stdmac,
479 dbg_init,
480 dbg_reset,
481 dbg_out,
482 dbg_legacy_out,
483 dbg_deflabel,
484 dbg_section_names,
485 dbg_herelabel,
486 dbg_sectalign,
487 dbg_segbase,
488 dbg_directive,
489 dbg_cleanup,
490 dbg_pragma_list
491};
492
493#endif /* OF_DBG */
494