1/*
2 * DWARF2 debugging format - line information
3 *
4 *  Copyright (C) 2006-2007  Peter Johnson
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the author nor the names of other contributors
15 *    may be used to endorse or promote products derived from this
16 *    software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30#include <util.h>
31
32#include <libyasm.h>
33
34#include "dwarf2-dbgfmt.h"
35
36/* DWARF line number opcodes */
37typedef enum {
38    DW_LNS_extended_op = 0,
39    DW_LNS_copy,
40    DW_LNS_advance_pc,
41    DW_LNS_advance_line,
42    DW_LNS_set_file,
43    DW_LNS_set_column,
44    DW_LNS_negate_stmt,
45    DW_LNS_set_basic_block,
46    DW_LNS_const_add_pc,
47    DW_LNS_fixed_advance_pc,
48#ifdef WITH_DWARF3
49    /* DWARF 3 extensions */
50    DW_LNS_set_prologue_end,
51    DW_LNS_set_epilogue_begin,
52    DW_LNS_set_isa,
53#endif
54    DWARF2_LINE_OPCODE_BASE
55} dwarf_line_number_op;
56
57/* # of LEB128 operands needed for each of the above opcodes */
58static unsigned char line_opcode_num_operands[DWARF2_LINE_OPCODE_BASE-1] = {
59    0,  /* DW_LNS_copy */
60    1,  /* DW_LNS_advance_pc */
61    1,  /* DW_LNS_advance_line */
62    1,  /* DW_LNS_set_file */
63    1,  /* DW_LNS_set_column */
64    0,  /* DW_LNS_negate_stmt */
65    0,  /* DW_LNS_set_basic_block */
66    0,  /* DW_LNS_const_add_pc */
67    1,  /* DW_LNS_fixed_advance_pc */
68#ifdef WITH_DWARF3
69    0,  /* DW_LNS_set_prologue_end */
70    0,  /* DW_LNS_set_epilogue_begin */
71    1   /* DW_LNS_set_isa */
72#endif
73};
74
75/* Line number extended opcodes */
76typedef enum {
77    DW_LNE_end_sequence = 1,
78    DW_LNE_set_address,
79    DW_LNE_define_file,
80    DW_LNE_set_discriminator
81} dwarf_line_number_ext_op;
82
83/* Base and range for line offsets in special opcodes */
84#define DWARF2_LINE_BASE                -5
85#define DWARF2_LINE_RANGE               14
86
87#define DWARF2_MAX_SPECIAL_ADDR_DELTA   \
88    (((255-DWARF2_LINE_OPCODE_BASE)/DWARF2_LINE_RANGE)*\
89     dbgfmt_dwarf2->min_insn_len)
90
91/* Initial value of is_stmt register */
92#define DWARF2_LINE_DEFAULT_IS_STMT     1
93
94/* Line number state machine register state */
95typedef struct dwarf2_line_state {
96    /* static configuration */
97    yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2;
98
99    /* DWARF2 state machine registers */
100    unsigned long address;
101    unsigned long file;
102    unsigned long line;
103    unsigned long column;
104    unsigned long isa;
105    int is_stmt;
106
107    /* other state information */
108    /*@null@*/ yasm_bytecode *precbc;
109} dwarf2_line_state;
110
111typedef struct dwarf2_spp {
112    yasm_bytecode *line_start_prevbc;
113    yasm_bytecode *line_end_prevbc;
114} dwarf2_spp;
115
116typedef struct dwarf2_line_op {
117    dwarf_line_number_op opcode;
118    /*@owned@*/ /*@null@*/ yasm_intnum *operand;
119
120    /* extended opcode */
121    dwarf_line_number_ext_op ext_opcode;
122    /*@null@*/ /*@dependent@*/ yasm_symrec *ext_operand;  /* unsigned */
123    /*@null@*/ /*@dependent@*/ yasm_intnum *ext_operand_int; /* unsigned */
124    unsigned long ext_operandsize;
125} dwarf2_line_op;
126
127/* Bytecode callback function prototypes */
128static void dwarf2_spp_bc_destroy(void *contents);
129static void dwarf2_spp_bc_print(const void *contents, FILE *f,
130                                int indent_level);
131static int dwarf2_spp_bc_calc_len
132    (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
133static int dwarf2_spp_bc_tobytes
134    (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
135     yasm_output_value_func output_value,
136     /*@null@*/ yasm_output_reloc_func output_reloc);
137
138static void dwarf2_line_op_bc_destroy(void *contents);
139static void dwarf2_line_op_bc_print(const void *contents, FILE *f,
140                                    int indent_level);
141static int dwarf2_line_op_bc_calc_len
142    (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
143static int dwarf2_line_op_bc_tobytes
144    (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
145     yasm_output_value_func output_value,
146     /*@null@*/ yasm_output_reloc_func output_reloc);
147
148/* Bytecode callback structures */
149static const yasm_bytecode_callback dwarf2_spp_bc_callback = {
150    dwarf2_spp_bc_destroy,
151    dwarf2_spp_bc_print,
152    yasm_bc_finalize_common,
153    NULL,
154    dwarf2_spp_bc_calc_len,
155    yasm_bc_expand_common,
156    dwarf2_spp_bc_tobytes,
157    0
158};
159
160static const yasm_bytecode_callback dwarf2_line_op_bc_callback = {
161    dwarf2_line_op_bc_destroy,
162    dwarf2_line_op_bc_print,
163    yasm_bc_finalize_common,
164    NULL,
165    dwarf2_line_op_bc_calc_len,
166    yasm_bc_expand_common,
167    dwarf2_line_op_bc_tobytes,
168    0
169};
170
171
172static size_t
173dwarf2_dbgfmt_add_file(yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2, unsigned long filenum,
174                       const char *pathname)
175{
176    size_t dirlen;
177    const char *filename;
178    unsigned long i, dir;
179
180    /* Put the directory into the directory table */
181    dir = 0;
182    dirlen = yasm__splitpath(pathname, &filename);
183    if (dirlen > 0) {
184        /* Look to see if we already have that dir in the table */
185        for (dir=1; dir<dbgfmt_dwarf2->dirs_size+1; dir++) {
186            if (strncmp(dbgfmt_dwarf2->dirs[dir-1], pathname, dirlen) == 0
187                && dbgfmt_dwarf2->dirs[dir-1][dirlen] == '\0')
188                break;
189        }
190        if (dir >= dbgfmt_dwarf2->dirs_size+1) {
191            /* Not found in table, add to end, reallocing if necessary */
192            if (dir >= dbgfmt_dwarf2->dirs_allocated+1) {
193                dbgfmt_dwarf2->dirs_allocated = dir+32;
194                dbgfmt_dwarf2->dirs = yasm_xrealloc(dbgfmt_dwarf2->dirs,
195                    sizeof(char *)*dbgfmt_dwarf2->dirs_allocated);
196            }
197            dbgfmt_dwarf2->dirs[dir-1] = yasm__xstrndup(pathname, dirlen);
198            dbgfmt_dwarf2->dirs_size = dir;
199        }
200    }
201
202    /* Put the filename into the filename table */
203    if (filenum == 0) {
204        /* Look to see if we already have that filename in the table */
205        for (; filenum<dbgfmt_dwarf2->filenames_size; filenum++) {
206            if (!dbgfmt_dwarf2->filenames[filenum].filename ||
207                (dbgfmt_dwarf2->filenames[filenum].dir == dir
208                 && strcmp(dbgfmt_dwarf2->filenames[filenum].filename,
209                           filename) == 0))
210                break;
211        }
212    } else
213        filenum--;      /* array index is 0-based */
214
215    /* Realloc table if necessary */
216    if (filenum >= dbgfmt_dwarf2->filenames_allocated) {
217        unsigned long old_allocated = dbgfmt_dwarf2->filenames_allocated;
218        dbgfmt_dwarf2->filenames_allocated = filenum+32;
219        dbgfmt_dwarf2->filenames = yasm_xrealloc(dbgfmt_dwarf2->filenames,
220            sizeof(dwarf2_filename)*dbgfmt_dwarf2->filenames_allocated);
221        for (i=old_allocated; i<dbgfmt_dwarf2->filenames_allocated; i++) {
222            dbgfmt_dwarf2->filenames[i].pathname = NULL;
223            dbgfmt_dwarf2->filenames[i].filename = NULL;
224            dbgfmt_dwarf2->filenames[i].dir = 0;
225        }
226    }
227
228    /* Actually save in table */
229    if (dbgfmt_dwarf2->filenames[filenum].pathname)
230        yasm_xfree(dbgfmt_dwarf2->filenames[filenum].pathname);
231    if (dbgfmt_dwarf2->filenames[filenum].filename)
232        yasm_xfree(dbgfmt_dwarf2->filenames[filenum].filename);
233    dbgfmt_dwarf2->filenames[filenum].pathname = yasm__xstrdup(pathname);
234    dbgfmt_dwarf2->filenames[filenum].filename = yasm__xstrdup(filename);
235    dbgfmt_dwarf2->filenames[filenum].dir = dir;
236
237    /* Update table size */
238    if (filenum >= dbgfmt_dwarf2->filenames_size)
239        dbgfmt_dwarf2->filenames_size = filenum + 1;
240
241    return filenum;
242}
243
244/* Create and add a new line opcode to a section, updating offset on insertion;
245 * no optimization necessary.
246 */
247static yasm_bytecode *
248dwarf2_dbgfmt_append_line_op(yasm_section *sect, dwarf_line_number_op opcode,
249                             /*@only@*/ /*@null@*/ yasm_intnum *operand)
250{
251    dwarf2_line_op *line_op = yasm_xmalloc(sizeof(dwarf2_line_op));
252    yasm_bytecode *bc;
253
254    line_op->opcode = opcode;
255    line_op->operand = operand;
256    line_op->ext_opcode = 0;
257    line_op->ext_operand = NULL;
258    line_op->ext_operand_int = NULL;
259    line_op->ext_operandsize = 0;
260
261    bc = yasm_bc_create_common(&dwarf2_line_op_bc_callback, line_op, 0);
262    bc->len = 1;
263    if (operand)
264        bc->len += yasm_intnum_size_leb128(operand,
265                                           opcode == DW_LNS_advance_line);
266
267    yasm_dwarf2__append_bc(sect, bc);
268    return bc;
269}
270
271/* Create and add a new extended line opcode to a section, updating offset on
272 * insertion; no optimization necessary.
273 */
274static yasm_bytecode *
275dwarf2_dbgfmt_append_line_ext_op(yasm_section *sect,
276                                 dwarf_line_number_ext_op ext_opcode,
277                                 unsigned long ext_operandsize,
278                                 /*@null@*/ yasm_symrec *ext_operand)
279{
280    dwarf2_line_op *line_op = yasm_xmalloc(sizeof(dwarf2_line_op));
281    yasm_bytecode *bc;
282
283    line_op->opcode = DW_LNS_extended_op;
284    line_op->operand = yasm_intnum_create_uint(ext_operandsize+1);
285    line_op->ext_opcode = ext_opcode;
286    line_op->ext_operand = ext_operand;
287    line_op->ext_operand_int = NULL;
288    line_op->ext_operandsize = ext_operandsize;
289
290    bc = yasm_bc_create_common(&dwarf2_line_op_bc_callback, line_op, 0);
291    bc->len = 2 + yasm_intnum_size_leb128(line_op->operand, 0) +
292        ext_operandsize;
293
294    yasm_dwarf2__append_bc(sect, bc);
295    return bc;
296}
297
298static yasm_bytecode *
299dwarf2_dbgfmt_append_line_ext_op_int(yasm_section *sect,
300                                     dwarf_line_number_ext_op ext_opcode,
301                                     /*@only@*/ yasm_intnum *ext_operand)
302{
303    dwarf2_line_op *line_op = yasm_xmalloc(sizeof(dwarf2_line_op));
304    unsigned long ext_operandsize = yasm_intnum_size_leb128(ext_operand, 0);
305    yasm_bytecode *bc;
306
307    line_op->opcode = DW_LNS_extended_op;
308    line_op->operand = yasm_intnum_create_uint(ext_operandsize+1);
309    line_op->ext_opcode = ext_opcode;
310    line_op->ext_operand = NULL;
311    line_op->ext_operand_int = ext_operand;
312    line_op->ext_operandsize = ext_operandsize;
313
314    bc = yasm_bc_create_common(&dwarf2_line_op_bc_callback, line_op, 0);
315    bc->len = 2 + yasm_intnum_size_leb128(line_op->operand, 0) +
316        ext_operandsize;
317
318    yasm_dwarf2__append_bc(sect, bc);
319    return bc;
320}
321
322static void
323dwarf2_dbgfmt_finalize_locs(yasm_section *sect, dwarf2_section_data *dsd)
324{
325    /*@dependent@*/ yasm_symrec *lastsym = NULL;
326    /*@null@*/ yasm_bytecode *bc;
327    /*@null@*/ dwarf2_loc *loc;
328
329    bc = yasm_section_bcs_first(sect);
330    STAILQ_FOREACH(loc, &dsd->locs, link) {
331        /* Find the first bytecode following this loc by looking at
332         * the virtual line numbers.  XXX: this assumes the source file
333         * order will be the same as the actual section order.  If we ever
334         * implement subsegs this will NOT necessarily be true and this logic
335         * will need to be fixed to handle it!
336         *
337         * Keep track of last symbol seen prior to the loc.
338         */
339        while (bc && bc->line <= loc->vline) {
340            if (bc->symrecs) {
341                int i = 0;
342                while (bc->symrecs[i]) {
343                    lastsym = bc->symrecs[i];
344                    i++;
345                }
346            }
347            bc = yasm_bc__next(bc);
348        }
349        loc->sym = lastsym;
350        loc->bc = bc;
351    }
352}
353
354static int
355dwarf2_dbgfmt_gen_line_op(yasm_section *debug_line, dwarf2_line_state *state,
356                          const dwarf2_loc *loc,
357                          /*@null@*/ const dwarf2_loc *nextloc)
358{
359    unsigned long addr_delta;
360    long line_delta;
361    int opcode1, opcode2;
362    yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = state->dbgfmt_dwarf2;
363
364    if (state->file != loc->file) {
365        state->file = loc->file;
366        dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_set_file,
367                                     yasm_intnum_create_uint(state->file));
368    }
369    if (state->column != loc->column) {
370        state->column = loc->column;
371        dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_set_column,
372                                     yasm_intnum_create_uint(state->column));
373    }
374    if (loc->discriminator != 0) {
375        dwarf2_dbgfmt_append_line_ext_op_int(debug_line,
376            DW_LNE_set_discriminator,
377            yasm_intnum_create_uint(loc->discriminator));
378    }
379#ifdef WITH_DWARF3
380    if (loc->isa_change) {
381        state->isa = loc->isa;
382        dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_set_isa,
383                                     yasm_intnum_create_uint(state->isa));
384    }
385#endif
386    if (state->is_stmt == 0 && loc->is_stmt == IS_STMT_SET) {
387        state->is_stmt = 1;
388        dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_negate_stmt, NULL);
389    } else if (state->is_stmt == 1 && loc->is_stmt == IS_STMT_CLEAR) {
390        state->is_stmt = 0;
391        dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_negate_stmt, NULL);
392    }
393    if (loc->basic_block) {
394        dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_set_basic_block, NULL);
395    }
396#ifdef WITH_DWARF3
397    if (loc->prologue_end) {
398        dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_set_prologue_end, NULL);
399    }
400    if (loc->epilogue_begin) {
401        dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_set_epilogue_begin,
402                                     NULL);
403    }
404#endif
405
406    /* If multiple loc for the same location, use last */
407    if (nextloc && nextloc->bc->offset == loc->bc->offset)
408        return 0;
409
410    if (!state->precbc) {
411        /* Set the starting address for the section */
412        if (!loc->sym) {
413            /* shouldn't happen! */
414            yasm_error_set(YASM_ERROR_GENERAL,
415                           N_("could not find label prior to loc"));
416            return 1;
417        }
418        dwarf2_dbgfmt_append_line_ext_op(debug_line, DW_LNE_set_address,
419            dbgfmt_dwarf2->sizeof_address, loc->sym);
420        addr_delta = 0;
421    } else if (loc->bc) {
422        if (state->precbc->offset > loc->bc->offset)
423            yasm_internal_error(N_("dwarf2 address went backwards?"));
424        addr_delta = loc->bc->offset - state->precbc->offset;
425    } else
426        return 0;       /* ran out of bytecodes!  XXX: do something? */
427
428    /* Generate appropriate opcode(s).  Address can only increment,
429     * whereas line number can go backwards.
430     */
431    line_delta = loc->line - state->line;
432    state->line = loc->line;
433
434    /* First handle the line delta */
435    if (line_delta < DWARF2_LINE_BASE
436        || line_delta >= DWARF2_LINE_BASE+DWARF2_LINE_RANGE) {
437        /* Won't fit in special opcode, use (signed) line advance */
438        dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_advance_line,
439                                     yasm_intnum_create_int(line_delta));
440        line_delta = 0;
441    }
442
443    /* Next handle the address delta */
444    opcode1 = DWARF2_LINE_OPCODE_BASE + line_delta - DWARF2_LINE_BASE +
445        DWARF2_LINE_RANGE * (addr_delta / dbgfmt_dwarf2->min_insn_len);
446    opcode2 = DWARF2_LINE_OPCODE_BASE + line_delta - DWARF2_LINE_BASE +
447        DWARF2_LINE_RANGE * ((addr_delta - DWARF2_MAX_SPECIAL_ADDR_DELTA) /
448                             dbgfmt_dwarf2->min_insn_len);
449    if (line_delta == 0 && addr_delta == 0) {
450        /* Both line and addr deltas are 0: do DW_LNS_copy */
451        dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_copy, NULL);
452    } else if (addr_delta <= DWARF2_MAX_SPECIAL_ADDR_DELTA && opcode1 <= 255) {
453        /* Addr delta in range of special opcode */
454        dwarf2_dbgfmt_append_line_op(debug_line, opcode1, NULL);
455    } else if (addr_delta <= 2*DWARF2_MAX_SPECIAL_ADDR_DELTA
456               && opcode2 <= 255) {
457        /* Addr delta in range of const_add_pc + special */
458        dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_const_add_pc, NULL);
459        dwarf2_dbgfmt_append_line_op(debug_line, opcode2, NULL);
460    } else {
461        /* Need advance_pc */
462        dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_advance_pc,
463                                     yasm_intnum_create_uint(addr_delta));
464        /* Take care of any remaining line_delta and add entry to matrix */
465        if (line_delta == 0)
466            dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_copy, NULL);
467        else {
468            unsigned int opcode;
469            opcode = DWARF2_LINE_OPCODE_BASE + line_delta - DWARF2_LINE_BASE;
470            dwarf2_dbgfmt_append_line_op(debug_line, opcode, NULL);
471        }
472    }
473    state->precbc = loc->bc;
474    return 0;
475}
476
477typedef struct dwarf2_line_bc_info {
478    yasm_section *debug_line;
479    yasm_object *object;
480    yasm_linemap *linemap;
481    yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2;
482    dwarf2_line_state *state;
483    dwarf2_loc loc;
484    unsigned long lastfile;
485} dwarf2_line_bc_info;
486
487static int
488dwarf2_filename_equals(const dwarf2_filename *fn,
489                       char **dirs,
490                       const char *pathname,
491                       unsigned long dirlen,
492                       const char *filename)
493{
494    /* check directory */
495    if (fn->dir == 0) {
496        if (dirlen != 0)
497            return 0;
498    } else {
499        if (strncmp(dirs[fn->dir-1], pathname, dirlen) != 0 ||
500            dirs[fn->dir-1][dirlen] != '\0')
501            return 0;
502    }
503
504    /* check filename */
505    return strcmp(fn->filename, filename) == 0;
506}
507
508static int
509dwarf2_generate_line_bc(yasm_bytecode *bc, /*@null@*/ void *d)
510{
511    dwarf2_line_bc_info *info = (dwarf2_line_bc_info *)d;
512    yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = info->dbgfmt_dwarf2;
513    unsigned long i;
514    size_t dirlen;
515    const char *pathname, *filename;
516    /*@null@*/ yasm_bytecode *nextbc = yasm_bc__next(bc);
517
518    if (nextbc && bc->offset == nextbc->offset)
519        return 0;
520
521    info->loc.vline = bc->line;
522    info->loc.bc = bc;
523
524    /* Keep track of last symbol seen */
525    if (bc->symrecs) {
526        i = 0;
527        while (bc->symrecs[i]) {
528            info->loc.sym = bc->symrecs[i];
529            i++;
530        }
531    }
532
533    yasm_linemap_lookup(info->linemap, bc->line, &pathname, &info->loc.line);
534    dirlen = yasm__splitpath(pathname, &filename);
535
536    /* Find file index; just linear search it unless it was the last used */
537    if (info->lastfile > 0
538        && dwarf2_filename_equals(&dbgfmt_dwarf2->filenames[info->lastfile-1],
539                                  dbgfmt_dwarf2->dirs, pathname, dirlen,
540                                  filename))
541        info->loc.file = info->lastfile;
542    else {
543        for (i=0; i<dbgfmt_dwarf2->filenames_size; i++) {
544            if (dwarf2_filename_equals(&dbgfmt_dwarf2->filenames[i],
545                                       dbgfmt_dwarf2->dirs, pathname, dirlen,
546                                       filename))
547                break;
548        }
549        if (i >= dbgfmt_dwarf2->filenames_size)
550            yasm_internal_error(N_("could not find filename in table"));
551        info->loc.file = i+1;
552        info->lastfile = i+1;
553    }
554    if (dwarf2_dbgfmt_gen_line_op(info->debug_line, info->state, &info->loc,
555                                  NULL))
556        return 1;
557    return 0;
558}
559
560typedef struct dwarf2_line_info {
561    yasm_section *debug_line;   /* section to which line number info goes */
562    yasm_object *object;
563    yasm_linemap *linemap;
564    yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2;
565    yasm_errwarns *errwarns;
566
567    /* Generate based on bytecodes (1) or locs (0)?  Use bytecodes if we're
568     * generating line numbers for the actual assembly source file.
569     */
570    int asm_source;
571
572    /* number of sections line number info generated for */
573    size_t num_sections;
574    /* last section line number info generated for */
575    /*@null@*/ yasm_section *last_code;
576} dwarf2_line_info;
577
578static int
579dwarf2_generate_line_section(yasm_section *sect, /*@null@*/ void *d)
580{
581    dwarf2_line_info *info = (dwarf2_line_info *)d;
582    yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = info->dbgfmt_dwarf2;
583    /*@null@*/ dwarf2_section_data *dsd;
584    /*@null@*/ yasm_bytecode *bc;
585    dwarf2_line_state state;
586    unsigned long addr_delta;
587
588    dsd = yasm_section_get_data(sect, &yasm_dwarf2__section_data_cb);
589    if (!dsd) {
590        if (info->asm_source && yasm_section_is_code(sect)) {
591            /* Create line data for asm code sections */
592            dsd = yasm_xmalloc(sizeof(dwarf2_section_data));
593            STAILQ_INIT(&dsd->locs);
594            yasm_section_add_data(sect, &yasm_dwarf2__section_data_cb, dsd);
595        } else
596            return 0;   /* no line data for this section */
597    }
598
599    info->num_sections++;
600    info->last_code = sect;
601
602    /* initialize state machine registers for each sequence */
603    state.dbgfmt_dwarf2 = dbgfmt_dwarf2;
604    state.address = 0;
605    state.file = 1;
606    state.line = 1;
607    state.column = 0;
608    state.isa = 0;
609    state.is_stmt = DWARF2_LINE_DEFAULT_IS_STMT;
610    state.precbc = NULL;
611
612    if (info->asm_source) {
613        dwarf2_line_bc_info bcinfo;
614
615        bcinfo.debug_line = info->debug_line;
616        bcinfo.object = info->object;
617        bcinfo.linemap = info->linemap;
618        bcinfo.dbgfmt_dwarf2 = dbgfmt_dwarf2;
619        bcinfo.state = &state;
620        bcinfo.lastfile = 0;
621        bcinfo.loc.isa_change = 0;
622        bcinfo.loc.column = 0;
623        bcinfo.loc.discriminator = 0;
624        bcinfo.loc.is_stmt = IS_STMT_NOCHANGE;
625        bcinfo.loc.basic_block = 0;
626        bcinfo.loc.prologue_end = 0;
627        bcinfo.loc.epilogue_begin = 0;
628        bcinfo.loc.sym = NULL;
629
630        /* bcs_traverse() skips first "dummy" bytecode, so look at it
631         * separately to determine the initial symrec.
632         */
633        bc = yasm_section_bcs_first(sect);
634        if (bc->symrecs) {
635            size_t i = 0;
636            while (bc->symrecs[i]) {
637                bcinfo.loc.sym = bc->symrecs[i];
638                i++;
639            }
640        }
641
642        yasm_section_bcs_traverse(sect, info->errwarns, &bcinfo,
643                                  dwarf2_generate_line_bc);
644    } else {
645        /*@null@*/ dwarf2_loc *loc;
646
647        dwarf2_dbgfmt_finalize_locs(sect, dsd);
648
649        STAILQ_FOREACH(loc, &dsd->locs, link) {
650            if (dwarf2_dbgfmt_gen_line_op(info->debug_line, &state, loc,
651                                          STAILQ_NEXT(loc, link)))
652                return 1;
653        }
654    }
655
656    /* End sequence: bring address to end of section, then output end
657     * sequence opcode.  Don't use a special opcode to do this as we don't
658     * want an extra entry in the line matrix.
659     */
660    if (!state.precbc)
661        state.precbc = yasm_section_bcs_first(sect);
662    bc = yasm_section_bcs_last(sect);
663    addr_delta = yasm_bc_next_offset(bc) - state.precbc->offset;
664    if (addr_delta == DWARF2_MAX_SPECIAL_ADDR_DELTA)
665        dwarf2_dbgfmt_append_line_op(info->debug_line, DW_LNS_const_add_pc,
666                                     NULL);
667    else if (addr_delta > 0)
668        dwarf2_dbgfmt_append_line_op(info->debug_line, DW_LNS_advance_pc,
669                                     yasm_intnum_create_uint(addr_delta));
670    dwarf2_dbgfmt_append_line_ext_op(info->debug_line, DW_LNE_end_sequence, 0,
671                                     NULL);
672
673    return 0;
674}
675
676static int
677dwarf2_generate_filename(const char *filename, void *d)
678{
679    yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = (yasm_dbgfmt_dwarf2 *)d;
680    dwarf2_dbgfmt_add_file(dbgfmt_dwarf2, 0, filename);
681    return 0;
682}
683
684yasm_section *
685yasm_dwarf2__generate_line(yasm_object *object, yasm_linemap *linemap,
686                           yasm_errwarns *errwarns, int asm_source,
687                           /*@out@*/ yasm_section **main_code,
688                           /*@out@*/ size_t *num_line_sections)
689{
690    yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = (yasm_dbgfmt_dwarf2 *)object->dbgfmt;
691    dwarf2_line_info info;
692    int new;
693    size_t i;
694    yasm_bytecode *last, *sppbc;
695    dwarf2_spp *spp;
696    dwarf2_head *head;
697
698    if (asm_source) {
699        /* Generate dirs and filenames based on linemap */
700        yasm_linemap_traverse_filenames(linemap, dbgfmt_dwarf2,
701                                        dwarf2_generate_filename);
702    }
703
704    info.num_sections = 0;
705    info.last_code = NULL;
706    info.asm_source = asm_source;
707    info.object = object;
708    info.linemap = linemap;
709    info.dbgfmt_dwarf2 = dbgfmt_dwarf2;
710    info.debug_line = yasm_object_get_general(object, ".debug_line", 1, 0, 0,
711                                              &new, 0);
712    last = yasm_section_bcs_last(info.debug_line);
713
714    /* header */
715    head = yasm_dwarf2__add_head(dbgfmt_dwarf2, info.debug_line, NULL, 0, 0);
716
717    /* statement program prologue */
718    spp = yasm_xmalloc(sizeof(dwarf2_spp));
719    sppbc = yasm_bc_create_common(&dwarf2_spp_bc_callback, spp, 0);
720    sppbc->len = dbgfmt_dwarf2->sizeof_offset + 5 +
721        NELEMS(line_opcode_num_operands);
722
723    /* directory list */
724    for (i=0; i<dbgfmt_dwarf2->dirs_size; i++)
725        sppbc->len += (unsigned long)strlen(dbgfmt_dwarf2->dirs[i])+1;
726    sppbc->len++;
727
728    /* filename list */
729    for (i=0; i<dbgfmt_dwarf2->filenames_size; i++) {
730        if (!dbgfmt_dwarf2->filenames[i].filename) {
731            yasm_error_set(YASM_ERROR_GENERAL,
732                           N_("dwarf2 file number %d unassigned"), i+1);
733            yasm_errwarn_propagate(errwarns, 0);
734            continue;
735        }
736        sppbc->len +=
737            (unsigned long)strlen(dbgfmt_dwarf2->filenames[i].filename) + 1 +
738            yasm_size_uleb128(dbgfmt_dwarf2->filenames[i].dir) + 2;
739    }
740    sppbc->len++;
741    yasm_dwarf2__append_bc(info.debug_line, sppbc);
742
743    /* statement program */
744    yasm_object_sections_traverse(object, (void *)&info,
745                                  dwarf2_generate_line_section);
746
747    /* mark end of line information */
748    yasm_dwarf2__set_head_end(head, yasm_section_bcs_last(info.debug_line));
749
750    *num_line_sections = info.num_sections;
751    if (info.num_sections == 1)
752        *main_code = info.last_code;
753    else
754        *main_code = NULL;
755    return info.debug_line;
756}
757
758static void
759dwarf2_spp_bc_destroy(void *contents)
760{
761    yasm_xfree(contents);
762}
763
764static void
765dwarf2_spp_bc_print(const void *contents, FILE *f, int indent_level)
766{
767    /* TODO */
768}
769
770static int
771dwarf2_spp_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
772                       void *add_span_data)
773{
774    yasm_internal_error(N_("tried to calc_len a dwarf2 spp bytecode"));
775    /*@notreached@*/
776    return 0;
777}
778
779static int
780dwarf2_spp_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp,
781                      unsigned char *bufstart, void *d,
782                      yasm_output_value_func output_value,
783                      yasm_output_reloc_func output_reloc)
784{
785    yasm_object *object = yasm_section_get_object(bc->section);
786    yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = (yasm_dbgfmt_dwarf2 *)object->dbgfmt;
787    unsigned char *buf = *bufp;
788    yasm_intnum *cval;
789    size_t i, len;
790
791    /* Prologue length (following this field) */
792    cval = yasm_intnum_create_uint(bc->len - (unsigned long)(buf-*bufp) -
793                                   dbgfmt_dwarf2->sizeof_offset);
794    yasm_arch_intnum_tobytes(object->arch, cval, buf,
795                             dbgfmt_dwarf2->sizeof_offset,
796                             dbgfmt_dwarf2->sizeof_offset*8, 0, bc, 0);
797    buf += dbgfmt_dwarf2->sizeof_offset;
798
799    YASM_WRITE_8(buf, dbgfmt_dwarf2->min_insn_len);     /* minimum_instr_len */
800    YASM_WRITE_8(buf, DWARF2_LINE_DEFAULT_IS_STMT);     /* default_is_stmt */
801    YASM_WRITE_8(buf, DWARF2_LINE_BASE);                /* line_base */
802    YASM_WRITE_8(buf, DWARF2_LINE_RANGE);               /* line_range */
803    YASM_WRITE_8(buf, DWARF2_LINE_OPCODE_BASE);         /* opcode_base */
804
805    /* Standard opcode # operands array */
806    for (i=0; i<NELEMS(line_opcode_num_operands); i++)
807        YASM_WRITE_8(buf, line_opcode_num_operands[i]);
808
809    /* directory list */
810    for (i=0; i<dbgfmt_dwarf2->dirs_size; i++) {
811        len = strlen(dbgfmt_dwarf2->dirs[i])+1;
812        memcpy(buf, dbgfmt_dwarf2->dirs[i], len);
813        buf += len;
814    }
815    /* finish with single 0 byte */
816    YASM_WRITE_8(buf, 0);
817
818    /* filename list */
819    for (i=0; i<dbgfmt_dwarf2->filenames_size; i++) {
820        len = strlen(dbgfmt_dwarf2->filenames[i].filename)+1;
821        memcpy(buf, dbgfmt_dwarf2->filenames[i].filename, len);
822        buf += len;
823
824        /* dir */
825        buf += yasm_get_uleb128(dbgfmt_dwarf2->filenames[i].dir, buf);
826        YASM_WRITE_8(buf, 0);   /* time */
827        YASM_WRITE_8(buf, 0);   /* length */
828    }
829    /* finish with single 0 byte */
830    YASM_WRITE_8(buf, 0);
831
832    *bufp = buf;
833
834    yasm_intnum_destroy(cval);
835    return 0;
836}
837
838static void
839dwarf2_line_op_bc_destroy(void *contents)
840{
841    dwarf2_line_op *line_op = (dwarf2_line_op *)contents;
842    if (line_op->operand)
843        yasm_intnum_destroy(line_op->operand);
844    if (line_op->ext_operand_int)
845        yasm_intnum_destroy(line_op->ext_operand_int);
846    yasm_xfree(contents);
847}
848
849static void
850dwarf2_line_op_bc_print(const void *contents, FILE *f, int indent_level)
851{
852    /* TODO */
853}
854
855static int
856dwarf2_line_op_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
857                           void *add_span_data)
858{
859    yasm_internal_error(N_("tried to calc_len a dwarf2 line_op bytecode"));
860    /*@notreached@*/
861    return 0;
862}
863
864static int
865dwarf2_line_op_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp,
866                          unsigned char *bufstart, void *d,
867                          yasm_output_value_func output_value,
868                          yasm_output_reloc_func output_reloc)
869{
870    dwarf2_line_op *line_op = (dwarf2_line_op *)bc->contents;
871    unsigned char *buf = *bufp;
872
873    YASM_WRITE_8(buf, line_op->opcode);
874    if (line_op->operand)
875        buf += yasm_intnum_get_leb128(line_op->operand, buf,
876                                      line_op->opcode == DW_LNS_advance_line);
877    if (line_op->ext_opcode > 0) {
878        YASM_WRITE_8(buf, line_op->ext_opcode);
879        if (line_op->ext_operand) {
880            yasm_value value;
881            yasm_value_init_sym(&value, line_op->ext_operand,
882                                line_op->ext_operandsize*8);
883            output_value(&value, buf, line_op->ext_operandsize,
884                         (unsigned long)(buf-bufstart), bc, 0, d);
885            buf += line_op->ext_operandsize;
886        }
887        if (line_op->ext_operand_int) {
888            buf += yasm_intnum_get_leb128(line_op->ext_operand_int, buf, 0);
889        }
890    }
891
892    *bufp = buf;
893    return 0;
894}
895
896void
897yasm_dwarf2__dir_loc(yasm_object *object, yasm_valparamhead *valparams,
898                     yasm_valparamhead *objext_valparams, unsigned long line)
899{
900    yasm_valparam *vp;
901    int in_is_stmt = 0, in_isa = 0, in_discriminator = 0;
902
903    /*@dependent@*/ /*@null@*/ const yasm_intnum *intn;
904    dwarf2_section_data *dsd;
905    dwarf2_loc *loc = yasm_xmalloc(sizeof(dwarf2_loc));
906
907    /* File number (required) */
908    if (!valparams || !(vp = yasm_vps_first(valparams)) ||
909        vp->val || vp->type != YASM_PARAM_EXPR) {
910        yasm_error_set(YASM_ERROR_SYNTAX, N_("file number required"));
911        yasm_xfree(loc);
912        return;
913    }
914    intn = yasm_expr_get_intnum(&vp->param.e, 0);
915    if (!intn) {
916        yasm_error_set(YASM_ERROR_NOT_CONSTANT,
917                       N_("file number is not a constant"));
918        yasm_xfree(loc);
919        return;
920    }
921    if (yasm_intnum_sign(intn) != 1) {
922        yasm_error_set(YASM_ERROR_VALUE, N_("file number less than one"));
923        yasm_xfree(loc);
924        return;
925    }
926    loc->file = yasm_intnum_get_uint(intn);
927
928    /* Line number (required) */
929    vp = yasm_vps_next(vp);
930    if (!vp || vp->val || vp->type != YASM_PARAM_EXPR) {
931        yasm_error_set(YASM_ERROR_SYNTAX, N_("line number required"));
932        yasm_xfree(loc);
933        return;
934    }
935    intn = yasm_expr_get_intnum(&vp->param.e, 0);
936    if (!intn) {
937        yasm_error_set(YASM_ERROR_NOT_CONSTANT,
938                       N_("line number is not a constant"));
939        yasm_xfree(loc);
940        return;
941    }
942    loc->line = yasm_intnum_get_uint(intn);
943
944    /* Generate new section data if it doesn't already exist */
945    if (!object->cur_section) {
946        yasm_error_set(YASM_ERROR_SYNTAX,
947                       N_("[%s] can only be used inside of a section"), "loc");
948        yasm_xfree(loc);
949        return;
950    }
951    dsd = yasm_section_get_data(object->cur_section,
952                                &yasm_dwarf2__section_data_cb);
953    if (!dsd) {
954        dsd = yasm_xmalloc(sizeof(dwarf2_section_data));
955        STAILQ_INIT(&dsd->locs);
956        yasm_section_add_data(object->cur_section,
957                              &yasm_dwarf2__section_data_cb, dsd);
958    }
959
960    /* Defaults for optional settings */
961    loc->column = 0;
962    loc->discriminator = 0;
963    loc->isa_change = 0;
964    loc->isa = 0;
965    loc->is_stmt = IS_STMT_NOCHANGE;
966    loc->basic_block = 0;
967    loc->prologue_end = 0;
968    loc->epilogue_begin = 0;
969
970    /* Optional column number */
971    vp = yasm_vps_next(vp);
972    if (vp && !vp->val && vp->type == YASM_PARAM_EXPR) {
973        intn = yasm_expr_get_intnum(&vp->param.e, 0);
974        if (!intn) {
975            yasm_error_set(YASM_ERROR_NOT_CONSTANT,
976                           N_("column number is not a constant"));
977            yasm_xfree(loc);
978            return;
979        }
980        loc->column = yasm_intnum_get_uint(intn);
981        vp = yasm_vps_next(vp);
982    }
983
984    /* Other options; note for GAS compatibility we need to support both:
985     * is_stmt=1 (NASM) and
986     * is_stmt 1 (GAS)
987     */
988    while (vp) {
989        /*@null@*/ /*@dependent@*/ const char *s;
990        /*@null@*/ /*@only@*/ yasm_expr *e;
991
992restart:
993        if (in_is_stmt) {
994            in_is_stmt = 0;
995            if (!(e = yasm_vp_expr(vp, object->symtab, line)) ||
996                !(intn = yasm_expr_get_intnum(&e, 0))) {
997                yasm_error_set(YASM_ERROR_NOT_CONSTANT,
998                               N_("is_stmt value is not a constant"));
999                yasm_xfree(loc);
1000                if (e)
1001                    yasm_expr_destroy(e);
1002                return;
1003            }
1004            if (yasm_intnum_is_zero(intn))
1005                loc->is_stmt = IS_STMT_SET;
1006            else if (yasm_intnum_is_pos1(intn))
1007                loc->is_stmt = IS_STMT_CLEAR;
1008            else {
1009                yasm_error_set(YASM_ERROR_VALUE,
1010                               N_("is_stmt value not 0 or 1"));
1011                yasm_xfree(loc);
1012                yasm_expr_destroy(e);
1013                return;
1014            }
1015            yasm_expr_destroy(e);
1016        } else if (in_isa) {
1017            in_isa = 0;
1018            if (!(e = yasm_vp_expr(vp, object->symtab, line)) ||
1019                !(intn = yasm_expr_get_intnum(&e, 0))) {
1020                yasm_error_set(YASM_ERROR_NOT_CONSTANT,
1021                               N_("isa value is not a constant"));
1022                yasm_xfree(loc);
1023                if (e)
1024                    yasm_expr_destroy(e);
1025                return;
1026            }
1027            if (yasm_intnum_sign(intn) < 0) {
1028                yasm_error_set(YASM_ERROR_VALUE,
1029                               N_("isa value less than zero"));
1030                yasm_xfree(loc);
1031                yasm_expr_destroy(e);
1032                return;
1033            }
1034            loc->isa_change = 1;
1035            loc->isa = yasm_intnum_get_uint(intn);
1036            yasm_expr_destroy(e);
1037        } else if (in_discriminator) {
1038            in_discriminator = 0;
1039            if (!(e = yasm_vp_expr(vp, object->symtab, line)) ||
1040                !(intn = yasm_expr_get_intnum(&e, 0))) {
1041                yasm_error_set(YASM_ERROR_NOT_CONSTANT,
1042                               N_("discriminator value is not a constant"));
1043                yasm_xfree(loc);
1044                if (e)
1045                    yasm_expr_destroy(e);
1046                return;
1047            }
1048            if (yasm_intnum_sign(intn) < 0) {
1049                yasm_error_set(YASM_ERROR_VALUE,
1050                               N_("discriminator value less than zero"));
1051                yasm_xfree(loc);
1052                yasm_expr_destroy(e);
1053                return;
1054            }
1055            loc->discriminator = yasm_intnum_get_uint(intn);
1056            yasm_expr_destroy(e);
1057        } else if (!vp->val && (s = yasm_vp_id(vp))) {
1058            if (yasm__strcasecmp(s, "is_stmt") == 0)
1059                in_is_stmt = 1;
1060            else if (yasm__strcasecmp(s, "isa") == 0)
1061                in_isa = 1;
1062            else if (yasm__strcasecmp(s, "discriminator") == 0)
1063                in_discriminator = 1;
1064            else if (yasm__strcasecmp(s, "basic_block") == 0)
1065                loc->basic_block = 1;
1066            else if (yasm__strcasecmp(s, "prologue_end") == 0)
1067                loc->prologue_end = 1;
1068            else if (yasm__strcasecmp(s, "epilogue_begin") == 0)
1069                loc->epilogue_begin = 1;
1070            else
1071                yasm_warn_set(YASM_WARN_GENERAL,
1072                              N_("unrecognized loc option `%s'"), s);
1073        } else if (!vp->val) {
1074            yasm_warn_set(YASM_WARN_GENERAL,
1075                          N_("unrecognized numeric qualifier"));
1076        } else if (yasm__strcasecmp(vp->val, "is_stmt") == 0) {
1077            in_is_stmt = 1;
1078            goto restart; /* don't go to the next valparam */
1079        } else if (yasm__strcasecmp(vp->val, "isa") == 0) {
1080            in_isa = 1;
1081            goto restart; /* don't go to the next valparam */
1082        } else if (yasm__strcasecmp(vp->val, "discriminator") == 0) {
1083            in_discriminator = 1;
1084            goto restart; /* don't go to the next valparam */
1085        } else
1086            yasm_warn_set(YASM_WARN_GENERAL,
1087                          N_("unrecognized loc option `%s'"), vp->val);
1088        vp = yasm_vps_next(vp);
1089    }
1090
1091    if (in_is_stmt || in_isa || in_discriminator) {
1092        yasm_error_set(YASM_ERROR_SYNTAX, N_("%s requires value"),
1093                       in_is_stmt ? "is_stmt" :
1094                       (in_isa ? "isa" : "discriminator"));
1095        yasm_xfree(loc);
1096        return;
1097    }
1098
1099    /* Append new location */
1100    loc->vline = line;
1101    loc->bc = NULL;
1102    loc->sym = NULL;
1103    STAILQ_INSERT_TAIL(&dsd->locs, loc, link);
1104}
1105
1106void
1107yasm_dwarf2__dir_file(yasm_object *object, yasm_valparamhead *valparams,
1108                      yasm_valparamhead *objext_valparams, unsigned long line)
1109{
1110    yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = (yasm_dbgfmt_dwarf2 *)object->dbgfmt;
1111    yasm_valparam *vp;
1112    /*@dependent@*/ /*@null@*/ const yasm_intnum *file_intn;
1113    unsigned long filenum;
1114
1115    if (!valparams) {
1116        yasm_error_set(YASM_ERROR_SYNTAX, N_("[%s] requires an argument"),
1117                       "FILE");
1118        return;
1119    }
1120
1121    vp = yasm_vps_first(valparams);
1122    if (yasm_vp_string(vp)) {
1123        /* Just a bare filename */
1124        yasm_object_set_source_fn(object, yasm_vp_string(vp));
1125        return;
1126    }
1127
1128    /* Otherwise.. first vp is the file number */
1129    if (vp->type != YASM_PARAM_EXPR ||
1130        !(file_intn = yasm_expr_get_intnum(&vp->param.e, 0))) {
1131        yasm_error_set(YASM_ERROR_NOT_CONSTANT,
1132                       N_("file number is not a constant"));
1133        return;
1134    }
1135    filenum = yasm_intnum_get_uint(file_intn);
1136
1137    vp = yasm_vps_next(vp);
1138    if (!yasm_vp_string(vp)) {
1139        yasm_error_set(YASM_ERROR_SYNTAX,
1140                       N_("file number given but no filename"));
1141        return;
1142    }
1143
1144    dwarf2_dbgfmt_add_file(dbgfmt_dwarf2, filenum, yasm_vp_string(vp));
1145}
1146