From b2e43e41d37cf858eca4d638c70a70d11c0b7fd5 Mon Sep 17 00:00:00 2001 From: Peter Johnson Date: Sat, 11 Feb 2006 21:58:35 +0000 Subject: [PATCH] Generate DWARF2 information from asm source, closing #43. Asm-level source debug information is generated if no file/loc directives are used. Also will generate basic DWARF2 info/abbrev/aranges if not specified in source. What's not handled is multiple code sections; I need to figure out how DWARF2 expects these to be generated. The implementation of this refactors all the line generation into dwarf2-line.c and makes dwarf2-dbgfmt.c contain only the core DWARF2 functions. One challenge yet to be taken care of is how to test the automatic generation, as the current working directory is saved into the output object file. * dwarf64_2loc: Update so built-in info generation doesn't happen. svn path=/trunk/yasm/; revision=1376 --- modules/dbgfmts/dwarf2/Makefile.inc | 3 + modules/dbgfmts/dwarf2/dwarf2-aranges.c | 127 +++ modules/dbgfmts/dwarf2/dwarf2-dbgfmt.c | 967 +++-------------- modules/dbgfmts/dwarf2/dwarf2-dbgfmt.h | 131 +++ modules/dbgfmts/dwarf2/dwarf2-info.c | 519 ++++++++++ modules/dbgfmts/dwarf2/dwarf2-line.c | 979 ++++++++++++++++++ .../dwarf2/tests/pass64/dwarf64_2loc.asm | 2 + .../dwarf2/tests/pass64/dwarf64_2loc.hex | 156 ++- 8 files changed, 2044 insertions(+), 840 deletions(-) create mode 100644 modules/dbgfmts/dwarf2/dwarf2-aranges.c create mode 100644 modules/dbgfmts/dwarf2/dwarf2-dbgfmt.h create mode 100644 modules/dbgfmts/dwarf2/dwarf2-info.c create mode 100644 modules/dbgfmts/dwarf2/dwarf2-line.c diff --git a/modules/dbgfmts/dwarf2/Makefile.inc b/modules/dbgfmts/dwarf2/Makefile.inc index b477d970..7dc6ec92 100644 --- a/modules/dbgfmts/dwarf2/Makefile.inc +++ b/modules/dbgfmts/dwarf2/Makefile.inc @@ -1,6 +1,9 @@ # $Id$ libyasm_a_SOURCES += modules/dbgfmts/dwarf2/dwarf2-dbgfmt.c +libyasm_a_SOURCES += modules/dbgfmts/dwarf2/dwarf2-line.c +libyasm_a_SOURCES += modules/dbgfmts/dwarf2/dwarf2-aranges.c +libyasm_a_SOURCES += modules/dbgfmts/dwarf2/dwarf2-info.c YASM_MODULES += dbgfmt_dwarf2 diff --git a/modules/dbgfmts/dwarf2/dwarf2-aranges.c b/modules/dbgfmts/dwarf2/dwarf2-aranges.c new file mode 100644 index 00000000..680912fa --- /dev/null +++ b/modules/dbgfmts/dwarf2/dwarf2-aranges.c @@ -0,0 +1,127 @@ +/* + * DWARF2 debugging format - address range table + * + * Copyright (C) 2006 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include +/*@unused@*/ RCSID("$Id$"); + +#define YASM_LIB_INTERNAL +#define YASM_BC_INTERNAL +#include + +#include "dwarf2-dbgfmt.h" + + +static void +dwarf2_append_arange(yasm_section *debug_aranges, /*@only@*/ yasm_expr *start, + /*@only@*/ yasm_expr *length, size_t sizeof_address) +{ + yasm_datavalhead dvs; + yasm_bytecode *bc; + + yasm_dvs_initialize(&dvs); + yasm_dvs_append(&dvs, yasm_dv_create_expr(start)); + yasm_dvs_append(&dvs, yasm_dv_create_expr(length)); + bc = yasm_bc_create_data(&dvs, sizeof_address, 0, 0); + yasm_bc_finalize(bc, yasm_dwarf2__append_bc(debug_aranges, bc)); + yasm_bc_resolve(bc, 0, NULL); +} + +typedef struct dwarf2_aranges_info { + yasm_section *debug_aranges; /* section to which address ranges go */ + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2; +} dwarf2_aranges_info; + +static int +dwarf2_generate_aranges_section(yasm_section *sect, /*@null@*/ void *d) +{ + dwarf2_aranges_info *info = (dwarf2_aranges_info *)d; + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = info->dbgfmt_dwarf2; + /*@null@*/ dwarf2_section_data *dsd; + /*@dependent@*/ yasm_symrec *ssym, *esym; + /*@only@*/ yasm_expr *start, *length; + + dsd = yasm_section_get_data(sect, &yasm_dwarf2__section_data_cb); + if (!dsd) + return 0; /* no line data for this section */ + + /* Create address range descriptor */ + ssym = yasm_symtab_define_label(dbgfmt_dwarf2->symtab, "start", + yasm_section_bcs_first(sect), 0, 0); + esym = yasm_symtab_define_label(dbgfmt_dwarf2->symtab, "end", + yasm_section_bcs_last(sect), 0, 0); + start = yasm_expr_create_ident(yasm_expr_sym(ssym), 0); + length = yasm_expr_create(YASM_EXPR_SUB, yasm_expr_sym(esym), + yasm_expr_sym(ssym), 0); + dwarf2_append_arange(info->debug_aranges, start, length, + dbgfmt_dwarf2->sizeof_address); + + return 0; +} + +yasm_section * +yasm_dwarf2__generate_aranges(yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2, + yasm_section *debug_info) +{ + int new; + yasm_section *debug_aranges; + yasm_bytecode *bc; + dwarf2_head *head; + dwarf2_aranges_info info; + + debug_aranges = + yasm_object_get_general(dbgfmt_dwarf2->object, ".debug_aranges", 0, + 2*dbgfmt_dwarf2->sizeof_address, 0, 0, &new, + 0); + + /* header */ + head = yasm_dwarf2__add_head(dbgfmt_dwarf2, debug_aranges, debug_info, 1, + 1); + + /* align ranges to 2x address size (range size) */ + bc = yasm_bc_create_align( + yasm_expr_create_ident(yasm_expr_int( + yasm_intnum_create_uint(dbgfmt_dwarf2->sizeof_address*2)), 0), + NULL, NULL, NULL, 0); + yasm_bc_finalize(bc, yasm_dwarf2__append_bc(debug_aranges, bc)); + yasm_bc_resolve(bc, 0, NULL); + + info.debug_aranges = debug_aranges; + info.dbgfmt_dwarf2 = dbgfmt_dwarf2; + yasm_object_sections_traverse(dbgfmt_dwarf2->object, (void *)&info, + dwarf2_generate_aranges_section); + + /* Terminate with empty address range descriptor */ + dwarf2_append_arange(debug_aranges, + yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(0)), 0), + yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(0)), 0), + dbgfmt_dwarf2->sizeof_address); + + /* mark end of aranges information */ + yasm_dwarf2__set_head_end(head, yasm_section_bcs_last(debug_aranges)); + + return debug_aranges; +} + diff --git a/modules/dbgfmts/dwarf2/dwarf2-dbgfmt.c b/modules/dbgfmts/dwarf2/dwarf2-dbgfmt.c index 44d36dbd..3cd717ea 100644 --- a/modules/dbgfmts/dwarf2/dwarf2-dbgfmt.c +++ b/modules/dbgfmts/dwarf2/dwarf2-dbgfmt.c @@ -11,9 +11,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the author nor the names of other contributors - * may be used to endorse or promote products derived from this - * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -34,216 +31,45 @@ #define YASM_BC_INTERNAL #include -#define WITH_DWARF3 1 +#include "dwarf2-dbgfmt.h" -/* DWARF line number opcodes */ -typedef enum { - DW_LNS_extended_op = 0, - DW_LNS_copy, - DW_LNS_advance_pc, - DW_LNS_advance_line, - DW_LNS_set_file, - DW_LNS_set_column, - DW_LNS_negate_stmt, - DW_LNS_set_basic_block, - DW_LNS_const_add_pc, - DW_LNS_fixed_advance_pc, -#ifdef WITH_DWARF3 - /* DWARF 3 extensions */ - DW_LNS_set_prologue_end, - DW_LNS_set_epilogue_begin, - DW_LNS_set_isa, -#endif - DWARF2_LINE_OPCODE_BASE -} dwarf_line_number_op; - -/* # of LEB128 operands needed for each of the above opcodes */ -static unsigned char line_opcode_num_operands[DWARF2_LINE_OPCODE_BASE-1] = { - 0, /* DW_LNS_copy */ - 1, /* DW_LNS_advance_pc */ - 1, /* DW_LNS_advance_line */ - 1, /* DW_LNS_set_file */ - 1, /* DW_LNS_set_column */ - 0, /* DW_LNS_negate_stmt */ - 0, /* DW_LNS_set_basic_block */ - 0, /* DW_LNS_const_add_pc */ - 1, /* DW_LNS_fixed_advance_pc */ -#ifdef WITH_DWARF3 - 0, /* DW_LNS_set_prologue_end */ - 0, /* DW_LNS_set_epilogue_begin */ - 1 /* DW_LNS_set_isa */ -#endif -}; - -/* Line number extended opcodes */ -typedef enum { - DW_LNE_end_sequence = 1, - DW_LNE_set_address, - DW_LNE_define_file -} dwarf_line_number_ext_op; - -/* Base and range for line offsets in special opcodes */ -#define DWARF2_LINE_BASE -5 -#define DWARF2_LINE_RANGE 14 - -#define DWARF2_MAX_SPECIAL_ADDR_DELTA \ - (((255-DWARF2_LINE_OPCODE_BASE)/DWARF2_LINE_RANGE)*\ - dbgfmt_dwarf2->min_insn_len) - -/* Initial value of is_stmt register */ -#define DWARF2_LINE_DEFAULT_IS_STMT 1 - -typedef struct { - char *filename; /* basename of full filename */ - size_t dir; /* index into directories array for relative path; - * 0 for current directory. */ -} dwarf2_filename; - -/* Global data */ -typedef struct yasm_dbgfmt_dwarf2 { - yasm_dbgfmt_base dbgfmt; /* base structure */ - - yasm_object *object; - yasm_symtab *symtab; - yasm_linemap *linemap; - yasm_arch *arch; - - char **dirs; - size_t dirs_size; - size_t dirs_allocated; - - dwarf2_filename *filenames; - size_t filenames_size; - size_t filenames_allocated; - - enum { - DWARF2_FORMAT_32BIT, - DWARF2_FORMAT_64BIT - } format; - - size_t sizeof_address, sizeof_offset, min_insn_len; -} yasm_dbgfmt_dwarf2; - -/* .loc directive data */ -typedef struct dwarf2_loc { - /*@reldef@*/ STAILQ_ENTRY(dwarf2_loc) link; - - unsigned long vline; /* virtual line number of .loc directive */ - - /* source information */ - unsigned long file; /* index into table of filenames */ - unsigned long line; /* source line number */ - unsigned long column; /* source column */ - int isa_change; - unsigned long isa; - enum { - IS_STMT_NOCHANGE = 0, - IS_STMT_SET, - IS_STMT_CLEAR - } is_stmt; - int basic_block; - int prologue_end; - int epilogue_begin; - - yasm_bytecode *bc; /* first bytecode following */ - yasm_symrec *sym; /* last symbol preceding */ -} dwarf2_loc; - -/* Line number state machine register state */ -typedef struct dwarf2_line_state { - /* static configuration */ - yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2; - - /* DWARF2 state machine registers */ - unsigned long address; - unsigned long file; - unsigned long line; - unsigned long column; - unsigned long isa; - int is_stmt; - - /* other state information */ - /*@null@*/ yasm_bytecode *precbc; -} dwarf2_line_state; - -/* Per-section data */ -typedef struct dwarf2_section_data { - /* The locations set by the .loc directives in this section, in assembly - * source order. - */ - /*@reldef@*/ STAILQ_HEAD(dwarf2_lochead, dwarf2_loc) locs; -} dwarf2_section_data; - -/* Temporary information used during generate phase */ -typedef struct dwarf2_info { - yasm_section *debug_line; /* section to which line number info goes */ - yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2; -} dwarf2_info; - -typedef struct dwarf2_spp { +struct dwarf2_head { yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2; - yasm_bytecode *line_start_prevbc; - yasm_bytecode *line_end_prevbc; -} dwarf2_spp; - -typedef struct dwarf2_line_op { - dwarf_line_number_op opcode; - /*@owned@*/ /*@null@*/ yasm_intnum *operand; - - /* extended opcode */ - dwarf_line_number_ext_op ext_opcode; - /*@owned@*/ /*@null@*/ yasm_expr *ext_operand; /* unsigned */ - unsigned long ext_operandsize; -} dwarf2_line_op; - -/* Section data callback function prototypes */ -static void dwarf2_section_data_destroy(void *data); -static void dwarf2_section_data_print(void *data, FILE *f, int indent_level); + yasm_bytecode *start_prevbc; + yasm_bytecode *end_prevbc; + /*@null@*/ yasm_expr *debug_ptr; + int with_address; + int with_segment; +}; /* Bytecode callback function prototypes */ - -static void dwarf2_line_op_bc_destroy(void *contents); -static void dwarf2_line_op_bc_print(const void *contents, FILE *f, int - indent_level); -static yasm_bc_resolve_flags dwarf2_line_op_bc_resolve +static void dwarf2_head_bc_destroy(void *contents); +static void dwarf2_head_bc_print(const void *contents, FILE *f, + int indent_level); +static yasm_bc_resolve_flags dwarf2_head_bc_resolve (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist); -static int dwarf2_line_op_bc_tobytes +static int dwarf2_head_bc_tobytes (yasm_bytecode *bc, unsigned char **bufp, void *d, yasm_output_expr_func output_expr, /*@null@*/ yasm_output_reloc_func output_reloc); -static void dwarf2_spp_bc_destroy(void *contents); -static void dwarf2_spp_bc_print(const void *contents, FILE *f, int - indent_level); -static yasm_bc_resolve_flags dwarf2_spp_bc_resolve - (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist); -static int dwarf2_spp_bc_tobytes - (yasm_bytecode *bc, unsigned char **bufp, void *d, - yasm_output_expr_func output_expr, - /*@null@*/ yasm_output_reloc_func output_reloc); - -/* Section data callback */ -static const yasm_assoc_data_callback dwarf2_section_data_cb = { - dwarf2_section_data_destroy, - dwarf2_section_data_print -}; - /* Bytecode callback structures */ - -static const yasm_bytecode_callback dwarf2_line_op_bc_callback = { - dwarf2_line_op_bc_destroy, - dwarf2_line_op_bc_print, +static const yasm_bytecode_callback dwarf2_head_bc_callback = { + dwarf2_head_bc_destroy, + dwarf2_head_bc_print, yasm_bc_finalize_common, - dwarf2_line_op_bc_resolve, - dwarf2_line_op_bc_tobytes + dwarf2_head_bc_resolve, + dwarf2_head_bc_tobytes }; -static const yasm_bytecode_callback dwarf2_spp_bc_callback = { - dwarf2_spp_bc_destroy, - dwarf2_spp_bc_print, - yasm_bc_finalize_common, - dwarf2_spp_bc_resolve, - dwarf2_spp_bc_tobytes +/* Section data callback function prototypes */ +static void dwarf2_section_data_destroy(void *data); +static void dwarf2_section_data_print(void *data, FILE *f, int indent_level); + +/* Section data callback */ +const yasm_assoc_data_callback yasm_dwarf2__section_data_cb = { + dwarf2_section_data_destroy, + dwarf2_section_data_print }; yasm_dbgfmt_module yasm_dwarf2_LTX_dbgfmt; @@ -273,6 +99,7 @@ dwarf2_dbgfmt_create(yasm_object *object, yasm_objfmt *of, yasm_arch *a) dbgfmt_dwarf2->filenames = yasm_xmalloc(sizeof(dwarf2_filename)*dbgfmt_dwarf2->filenames_allocated); for (i=0; ifilenames_allocated; i++) { + dbgfmt_dwarf2->filenames[i].pathname = NULL; dbgfmt_dwarf2->filenames[i].filename = NULL; dbgfmt_dwarf2->filenames[i].dir = 0; } @@ -302,9 +129,12 @@ dwarf2_dbgfmt_destroy(/*@only@*/ yasm_dbgfmt *dbgfmt) if (dbgfmt_dwarf2->dirs[i]) yasm_xfree(dbgfmt_dwarf2->dirs[i]); yasm_xfree(dbgfmt_dwarf2->dirs); - for (i=0; ifilenames_size; i++) + for (i=0; ifilenames_size; i++) { + if (dbgfmt_dwarf2->filenames[i].pathname) + yasm_xfree(dbgfmt_dwarf2->filenames[i].pathname); if (dbgfmt_dwarf2->filenames[i].filename) yasm_xfree(dbgfmt_dwarf2->filenames[i].filename); + } yasm_xfree(dbgfmt_dwarf2->filenames); yasm_xfree(dbgfmt); } @@ -312,372 +142,130 @@ dwarf2_dbgfmt_destroy(/*@only@*/ yasm_dbgfmt *dbgfmt) /* Add a bytecode to a section, updating offset on insertion; * no optimization necessary. */ -static void -dwarf2_dbgfmt_append_bc(yasm_section *sect, yasm_bytecode *bc) +yasm_bytecode * +yasm_dwarf2__append_bc(yasm_section *sect, yasm_bytecode *bc) { yasm_bytecode *precbc = yasm_section_bcs_last(sect); bc->offset = precbc ? precbc->offset + precbc->len : 0; yasm_section_bcs_append(sect, bc); -} - -/* Create and add a new line opcode to a section, updating offset on insertion; - * no optimization necessary. - */ -static yasm_bytecode * -dwarf2_dbgfmt_append_line_op(yasm_section *sect, dwarf_line_number_op opcode, - /*@only@*/ /*@null@*/ yasm_intnum *operand) -{ - dwarf2_line_op *line_op = yasm_xmalloc(sizeof(dwarf2_line_op)); - yasm_bytecode *bc; - - line_op->opcode = opcode; - line_op->operand = operand; - line_op->ext_opcode = 0; - line_op->ext_operand = NULL; - line_op->ext_operandsize = 0; - - bc = yasm_bc_create_common(&dwarf2_line_op_bc_callback, line_op, 0); - bc->len = 1; - if (operand) - bc->len += yasm_intnum_size_leb128(operand, - opcode == DW_LNS_advance_line); - - dwarf2_dbgfmt_append_bc(sect, bc); - return bc; -} - -/* Create and add a new extended line opcode to a section, updating offset on - * insertion; no optimization necessary. - */ -static yasm_bytecode * -dwarf2_dbgfmt_append_line_ext_op(yasm_section *sect, - dwarf_line_number_ext_op ext_opcode, - unsigned long ext_operandsize, - /*@only@*/ /*@null@*/ yasm_expr *ext_operand) -{ - dwarf2_line_op *line_op = yasm_xmalloc(sizeof(dwarf2_line_op)); - yasm_bytecode *bc; - - line_op->opcode = DW_LNS_extended_op; - line_op->operand = yasm_intnum_create_uint(ext_operandsize+1); - line_op->ext_opcode = ext_opcode; - line_op->ext_operand = ext_operand; - line_op->ext_operandsize = ext_operandsize; - - bc = yasm_bc_create_common(&dwarf2_line_op_bc_callback, line_op, 0); - bc->len = 2 + yasm_intnum_size_leb128(line_op->operand, 0) + - ext_operandsize; - - dwarf2_dbgfmt_append_bc(sect, bc); - return bc; + return precbc; } static void -dwarf2_dbgfmt_finalize_locs(yasm_section *sect, dwarf2_section_data *dsd) -{ - /*@dependent@*/ yasm_symrec *lastsym = NULL; - /*@null@*/ yasm_bytecode *bc; - /*@null@*/ dwarf2_loc *loc; - - bc = yasm_section_bcs_first(sect); - STAILQ_FOREACH(loc, &dsd->locs, link) { - /* Find the first bytecode following this loc by looking at - * the virtual line numbers. XXX: this assumes the source file - * order will be the same as the actual section order. If we ever - * implement subsegs this will NOT necessarily be true and this logic - * will need to be fixed to handle it! - * - * Keep track of last symbol seen prior to the loc. - */ - while (bc && bc->line <= loc->vline) { - if (bc->symrecs) { - int i = 0; - while (bc->symrecs[i]) { - lastsym = bc->symrecs[i]; - i++; - } - } - bc = yasm_bc__next(bc); - } - loc->sym = lastsym; - loc->bc = bc; - } -} - -static int -dwarf2_dbgfmt_gen_line_op(yasm_section *debug_line, dwarf2_line_state *state, - dwarf2_loc *loc, /*@null@*/ dwarf2_loc *nextloc) +dwarf2_dbgfmt_generate(yasm_dbgfmt *dbgfmt) { - unsigned long addr_delta; - long line_delta; - int opcode1, opcode2; - yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = state->dbgfmt_dwarf2; - - if (state->file != loc->file) { - state->file = loc->file; - dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_set_file, - yasm_intnum_create_uint(state->file)); - } - if (state->column != loc->column) { - state->column = loc->column; - dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_set_column, - yasm_intnum_create_uint(state->column)); - } -#ifdef WITH_DWARF3 - if (loc->isa_change) { - state->isa = loc->isa; - dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_set_isa, - yasm_intnum_create_uint(state->isa)); - } -#endif - if (state->is_stmt == 0 && loc->is_stmt == IS_STMT_SET) { - state->is_stmt = 1; - dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_negate_stmt, NULL); - } else if (state->is_stmt == 1 && loc->is_stmt == IS_STMT_CLEAR) { - state->is_stmt = 0; - dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_negate_stmt, NULL); - } - if (loc->basic_block) { - dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_set_basic_block, NULL); - } -#ifdef WITH_DWARF3 - if (loc->prologue_end) { - dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_set_prologue_end, NULL); - } - if (loc->epilogue_begin) { - dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_set_epilogue_begin, - NULL); - } -#endif - - /* If multiple loc for the same location, use last */ - if (nextloc && nextloc->bc->offset == loc->bc->offset) - return 0; - - if (!state->precbc) { - /* Set the starting address for the section */ - if (!loc->sym) { - /* shouldn't happen! */ - yasm__error(loc->line, N_("could not find label prior to loc")); - return 1; - } - dwarf2_dbgfmt_append_line_ext_op(debug_line, DW_LNE_set_address, - dbgfmt_dwarf2->sizeof_address, - yasm_expr_create_ident(yasm_expr_sym(loc->sym), loc->line)); - addr_delta = 0; - } else if (loc->bc) { - if (state->precbc->offset > loc->bc->offset) - yasm_internal_error(N_("dwarf2 address went backwards?")); - addr_delta = loc->bc->offset - state->precbc->offset; - } else - return 0; /* ran out of bytecodes! XXX: do something? */ + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = (yasm_dbgfmt_dwarf2 *)dbgfmt; + int new; + size_t num_line_sections; + /*@null@*/ yasm_section *debug_info, *debug_line, *main_code; - /* Generate appropriate opcode(s). Address can only increment, - * whereas line number can go backwards. + /* If we don't have any .file directives, generate line information + * based on the asm source. */ - line_delta = loc->line - state->line; - state->line = loc->line; + debug_line = yasm_dwarf2__generate_line(dbgfmt_dwarf2, + dbgfmt_dwarf2->filenames_size == 0, + &main_code, &num_line_sections); - /* First handle the line delta */ - if (line_delta < DWARF2_LINE_BASE - || line_delta >= DWARF2_LINE_BASE+DWARF2_LINE_RANGE) { - /* Won't fit in special opcode, use (signed) line advance */ - dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_advance_line, - yasm_intnum_create_int(line_delta)); - line_delta = 0; - } - - /* Next handle the address delta */ - opcode1 = DWARF2_LINE_OPCODE_BASE + line_delta - DWARF2_LINE_BASE + - DWARF2_LINE_RANGE * (addr_delta / dbgfmt_dwarf2->min_insn_len); - opcode2 = DWARF2_LINE_OPCODE_BASE + line_delta - DWARF2_LINE_BASE + - DWARF2_LINE_RANGE * ((addr_delta - DWARF2_MAX_SPECIAL_ADDR_DELTA) / - dbgfmt_dwarf2->min_insn_len); - if (line_delta == 0 && addr_delta == 0) { - /* Both line and addr deltas are 0: do DW_LNS_copy */ - dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_copy, NULL); - } else if (addr_delta <= DWARF2_MAX_SPECIAL_ADDR_DELTA && opcode1 <= 255) { - /* Addr delta in range of special opcode */ - dwarf2_dbgfmt_append_line_op(debug_line, opcode1, NULL); - } else if (addr_delta <= 2*DWARF2_MAX_SPECIAL_ADDR_DELTA - && opcode2 <= 255) { - /* Addr delta in range of const_add_pc + special */ - dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_const_add_pc, NULL); - dwarf2_dbgfmt_append_line_op(debug_line, opcode2, NULL); - } else { - /* Need advance_pc */ - dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_advance_pc, - yasm_intnum_create_uint(addr_delta)); - /* Take care of any remaining line_delta and add entry to matrix */ - if (line_delta == 0) - dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_copy, NULL); - else { - unsigned int opcode; - opcode = DWARF2_LINE_OPCODE_BASE + line_delta - DWARF2_LINE_BASE; - dwarf2_dbgfmt_append_line_op(debug_line, opcode, NULL); - } + /* If we don't have a .debug_info (or it's empty), generate the minimal + * set of .debug_info, .debug_aranges, and .debug_abbrev so that the + * .debug_line we're generating is actually useful. + */ + debug_info = yasm_object_find_general(dbgfmt_dwarf2->object, ".debug_info"); + if (num_line_sections > 0 && + (!debug_info || yasm_section_bcs_first(debug_info) + == yasm_section_bcs_last(debug_info))) { + debug_info = yasm_dwarf2__generate_info(dbgfmt_dwarf2, debug_line, + main_code); + yasm_dwarf2__generate_aranges(dbgfmt_dwarf2, debug_info); + /*yasm_dwarf2__generate_pubnames(dbgfmt_dwarf2, debug_info);*/ } - state->precbc = loc->bc; - return 0; } -static int -dwarf2_dbgfmt_generate_section(yasm_section *sect, /*@null@*/ void *d) +yasm_expr * +yasm_dwarf2__bc_sym(yasm_symtab *symtab, yasm_bytecode *bc) { - dwarf2_info *info = (dwarf2_info *)d; - yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = info->dbgfmt_dwarf2; - /*@null@*/ dwarf2_section_data *dsd; - /*@null@*/ dwarf2_loc *loc; - /*@null@*/ yasm_bytecode *bc; - dwarf2_line_state state; - unsigned long addr_delta; - - dsd = yasm_section_get_data(sect, &dwarf2_section_data_cb); - if (!dsd) - return 0; /* no line data for this section */ - - /* initialize state machine registers for each sequence */ - state.dbgfmt_dwarf2 = dbgfmt_dwarf2; - state.address = 0; - state.file = 1; - state.line = 1; - state.column = 0; - state.isa = 0; - state.is_stmt = DWARF2_LINE_DEFAULT_IS_STMT; - state.precbc = NULL; - - dwarf2_dbgfmt_finalize_locs(sect, dsd); - - STAILQ_FOREACH(loc, &dsd->locs, link) { - if (dwarf2_dbgfmt_gen_line_op(info->debug_line, &state, loc, - STAILQ_NEXT(loc, link))) - return 1; - } - - /* End sequence: bring address to end of section, then output end - * sequence opcode. Don't use a special opcode to do this as we don't - * want an extra entry in the line matrix. - */ - bc = yasm_section_bcs_last(sect); - addr_delta = bc->offset + bc->len - state.precbc->offset; - if (addr_delta == DWARF2_MAX_SPECIAL_ADDR_DELTA) - dwarf2_dbgfmt_append_line_op(info->debug_line, DW_LNS_const_add_pc, - NULL); - else if (addr_delta > 0) - dwarf2_dbgfmt_append_line_op(info->debug_line, DW_LNS_advance_pc, - yasm_intnum_create_uint(addr_delta)); - dwarf2_dbgfmt_append_line_ext_op(info->debug_line, DW_LNE_end_sequence, 0, - NULL); - - return 0; + /*@dependent@*/ yasm_symrec *sym; + if (bc->symrecs && bc->symrecs[0]) + sym = bc->symrecs[0]; + else + sym = yasm_symtab_define_label(symtab, ".bcsym", bc, 0, 0); + return yasm_expr_create_ident(yasm_expr_sym(sym), 0); } -static void -dwarf2_dbgfmt_generate(yasm_dbgfmt *dbgfmt) +dwarf2_head * +yasm_dwarf2__add_head + (yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2, yasm_section *sect, + /*@null@*/ yasm_section *debug_ptr, int with_address, int with_segment) { - yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = (yasm_dbgfmt_dwarf2 *)dbgfmt; - dwarf2_info info; - int new; - size_t i; - yasm_bytecode *last, *sppbc; - dwarf2_spp *spp; - yasm_intnum *cval; - - /* Only generate line info for now */ + dwarf2_head *head; + yasm_bytecode *bc; - info.dbgfmt_dwarf2 = dbgfmt_dwarf2; - info.debug_line = yasm_object_get_general(dbgfmt_dwarf2->object, - ".debug_line", 0, 4, 0, 0, &new, - 0); - yasm_section_set_align(info.debug_line, 0, 0); - last = yasm_section_bcs_last(info.debug_line); + head = yasm_xmalloc(sizeof(dwarf2_head)); + head->dbgfmt_dwarf2 = dbgfmt_dwarf2; + head->start_prevbc = yasm_section_bcs_last(sect); - /* statement program prologue */ - spp = yasm_xmalloc(sizeof(dwarf2_spp)); - spp->dbgfmt_dwarf2 = dbgfmt_dwarf2; - spp->line_start_prevbc = last; - sppbc = yasm_bc_create_common(&dwarf2_spp_bc_callback, spp, 0); - sppbc->offset = last->offset + last->len; - sppbc->len = dbgfmt_dwarf2->sizeof_offset*2 + 2 + 5 + - NELEMS(line_opcode_num_operands); + bc = yasm_bc_create_common(&dwarf2_head_bc_callback, head, 0); + bc->len = dbgfmt_dwarf2->sizeof_offset + 2; if (dbgfmt_dwarf2->format == DWARF2_FORMAT_64BIT) - sppbc->len += 4; - /* directory list */ - for (i=0; idirs_size; i++) - sppbc->len += strlen(dbgfmt_dwarf2->dirs[i])+1; - sppbc->len++; - /* filename list */ - cval = yasm_intnum_create_uint(0); - for (i=0; ifilenames_size; i++) { - if (!dbgfmt_dwarf2->filenames[i].filename) - yasm__error(0, N_("dwarf2 file number %d unassigned"), i+1); - yasm_intnum_set_uint(cval, dbgfmt_dwarf2->filenames[i].dir); - sppbc->len += strlen(dbgfmt_dwarf2->filenames[i].filename) + 1 + - yasm_intnum_size_leb128(cval, 0) + 2; - } - yasm_intnum_destroy(cval); - sppbc->len++; - yasm_section_bcs_append(info.debug_line, sppbc); - - /* statement program */ - yasm_object_sections_traverse(dbgfmt_dwarf2->object, (void *)&info, - dwarf2_dbgfmt_generate_section); - - /* fill initial pseudo-stab's fields */ - spp->line_end_prevbc = yasm_section_bcs_last(info.debug_line); -} - -static void -dwarf2_section_data_destroy(void *data) -{ - dwarf2_section_data *dsd = data; - dwarf2_loc *n1, *n2; + bc->len += 4; - /* Delete locations */ - n1 = STAILQ_FIRST(&dsd->locs); - while (n1) { - n2 = STAILQ_NEXT(n1, link); - yasm_xfree(n1); - n1 = n2; - } - - yasm_xfree(data); + if (debug_ptr) { + head->debug_ptr = + yasm_dwarf2__bc_sym(dbgfmt_dwarf2->symtab, + yasm_section_bcs_first(debug_ptr)); + bc->len += dbgfmt_dwarf2->sizeof_offset; + } else + head->debug_ptr = NULL; + + head->with_address = with_address; + head->with_segment = with_segment; + if (with_address) + bc->len++; + if (with_segment) + bc->len++; + + head->end_prevbc = bc; + yasm_dwarf2__append_bc(sect, bc); + return head; } -static void -dwarf2_section_data_print(void *data, FILE *f, int indent_level) +void +yasm_dwarf2__set_head_end(dwarf2_head *head, yasm_bytecode *end_prevbc) { - /* TODO */ + head->end_prevbc = end_prevbc; } static void -dwarf2_spp_bc_destroy(void *contents) +dwarf2_head_bc_destroy(void *contents) { + dwarf2_head *head = (dwarf2_head *)contents; + if (head->debug_ptr) + yasm_expr_destroy(head->debug_ptr); yasm_xfree(contents); } static void -dwarf2_spp_bc_print(const void *contents, FILE *f, int indent_level) +dwarf2_head_bc_print(const void *contents, FILE *f, int indent_level) { /* TODO */ } static yasm_bc_resolve_flags -dwarf2_spp_bc_resolve(yasm_bytecode *bc, int save, - yasm_calc_bc_dist_func calc_bc_dist) +dwarf2_head_bc_resolve(yasm_bytecode *bc, int save, + yasm_calc_bc_dist_func calc_bc_dist) { - yasm_internal_error(N_("tried to resolve a dwarf2 spp bytecode")); + yasm_internal_error(N_("tried to resolve a dwarf2 head bytecode")); /*@notreached@*/ return YASM_BC_RESOLVE_MIN_LEN; } static int -dwarf2_spp_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, - yasm_output_expr_func output_expr, - yasm_output_reloc_func output_reloc) +dwarf2_head_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_expr_func output_expr, + yasm_output_reloc_func output_reloc) { - dwarf2_spp *spp = (dwarf2_spp *)bc->contents; - yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = spp->dbgfmt_dwarf2; + dwarf2_head *head = (dwarf2_head *)bc->contents; + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = head->dbgfmt_dwarf2; unsigned char *buf = *bufp; yasm_intnum *intn, *cval; size_t i, len; @@ -688,10 +276,10 @@ dwarf2_spp_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, YASM_WRITE_8(buf, 0xff); YASM_WRITE_8(buf, 0xff); } - /* Total length of statement info (following this field) */ + + /* Total length of aranges info (following this field) */ cval = yasm_intnum_create_uint(dbgfmt_dwarf2->sizeof_offset); - intn = yasm_common_calc_bc_dist(spp->line_start_prevbc, - spp->line_end_prevbc); + intn = yasm_common_calc_bc_dist(head->start_prevbc, head->end_prevbc); yasm_intnum_calc(intn, YASM_EXPR_SUB, cval, bc->line); yasm_arch_intnum_tobytes(dbgfmt_dwarf2->arch, intn, buf, dbgfmt_dwarf2->sizeof_offset, @@ -705,48 +293,21 @@ dwarf2_spp_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, 0); buf += 2; - /* Prologue length (following this field) */ - cval = yasm_intnum_create_uint(bc->len - (buf-*bufp) - - dbgfmt_dwarf2->sizeof_offset); - yasm_arch_intnum_tobytes(dbgfmt_dwarf2->arch, cval, buf, - dbgfmt_dwarf2->sizeof_offset, - dbgfmt_dwarf2->sizeof_offset*8, 0, bc, - 0, 0); - buf += dbgfmt_dwarf2->sizeof_offset; - - YASM_WRITE_8(buf, dbgfmt_dwarf2->min_insn_len); /* minimum_instr_len */ - YASM_WRITE_8(buf, DWARF2_LINE_DEFAULT_IS_STMT); /* default_is_stmt */ - YASM_WRITE_8(buf, DWARF2_LINE_BASE); /* line_base */ - YASM_WRITE_8(buf, DWARF2_LINE_RANGE); /* line_range */ - YASM_WRITE_8(buf, DWARF2_LINE_OPCODE_BASE); /* opcode_base */ - - /* Standard opcode # operands array */ - for (i=0; idirs_size; i++) { - len = strlen(dbgfmt_dwarf2->dirs[i])+1; - memcpy(buf, dbgfmt_dwarf2->dirs[i], len); - buf += len; + /* Pointer to another debug section */ + if (head->debug_ptr) { + output_expr(&head->debug_ptr, buf, dbgfmt_dwarf2->sizeof_offset, + dbgfmt_dwarf2->sizeof_offset*8, 0, + (unsigned long)(buf-*bufp), bc, 0, 0, d); + buf += dbgfmt_dwarf2->sizeof_offset; } - /* finish with single 0 byte */ - YASM_WRITE_8(buf, 0); - /* filename list */ - for (i=0; ifilenames_size; i++) { - len = strlen(dbgfmt_dwarf2->filenames[i].filename)+1; - memcpy(buf, dbgfmt_dwarf2->filenames[i].filename, len); - buf += len; + /* Size of the offset portion of the address */ + if (head->with_address) + YASM_WRITE_8(buf, dbgfmt_dwarf2->sizeof_address); - /* dir */ - yasm_intnum_set_uint(cval, dbgfmt_dwarf2->filenames[i].dir); - buf += yasm_intnum_get_leb128(cval, buf, 0); - YASM_WRITE_8(buf, 0); /* time */ - YASM_WRITE_8(buf, 0); /* length */ - } - /* finish with single 0 byte */ - YASM_WRITE_8(buf, 0); + /* Size of a segment descriptor. 0 = flat address space */ + if (head->with_segment) + YASM_WRITE_8(buf, 0); *bufp = buf; @@ -755,54 +316,26 @@ dwarf2_spp_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, } static void -dwarf2_line_op_bc_destroy(void *contents) +dwarf2_section_data_destroy(void *data) { - dwarf2_line_op *line_op = (dwarf2_line_op *)contents; - if (line_op->operand) - yasm_intnum_destroy(line_op->operand); - if (line_op->ext_operand) - yasm_expr_destroy(line_op->ext_operand); - yasm_xfree(contents); -} + dwarf2_section_data *dsd = data; + dwarf2_loc *n1, *n2; -static void -dwarf2_line_op_bc_print(const void *contents, FILE *f, int indent_level) -{ -} + /* Delete locations */ + n1 = STAILQ_FIRST(&dsd->locs); + while (n1) { + n2 = STAILQ_NEXT(n1, link); + yasm_xfree(n1); + n1 = n2; + } -static yasm_bc_resolve_flags -dwarf2_line_op_bc_resolve(yasm_bytecode *bc, int save, - yasm_calc_bc_dist_func calc_bc_dist) -{ - yasm_internal_error(N_("tried to resolve a dwarf2 line_op bytecode")); - /*@notreached@*/ - return YASM_BC_RESOLVE_MIN_LEN; + yasm_xfree(data); } -static int -dwarf2_line_op_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, - yasm_output_expr_func output_expr, - yasm_output_reloc_func output_reloc) +static void +dwarf2_section_data_print(void *data, FILE *f, int indent_level) { - dwarf2_line_op *line_op = (dwarf2_line_op *)bc->contents; - unsigned char *buf = *bufp; - - YASM_WRITE_8(buf, line_op->opcode); - if (line_op->operand) - buf += yasm_intnum_get_leb128(line_op->operand, buf, - line_op->opcode == DW_LNS_advance_line); - if (line_op->ext_opcode > 0) { - YASM_WRITE_8(buf, line_op->ext_opcode); - if (line_op->ext_operand) { - output_expr(&line_op->ext_operand, buf, line_op->ext_operandsize, - line_op->ext_operandsize*8, 0, - (unsigned long)(buf-*bufp), bc, 0, 0, d); - buf += line_op->ext_operandsize; - } - } - - *bufp = buf; - return 0; + /* TODO */ } static int @@ -811,226 +344,8 @@ dwarf2_dbgfmt_directive(yasm_dbgfmt *dbgfmt, const char *name, unsigned long line) { yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = (yasm_dbgfmt_dwarf2 *)dbgfmt; - - if (yasm__strcasecmp(name, "loc") == 0) { - /*@dependent@*/ /*@null@*/ const yasm_intnum *intn; - dwarf2_section_data *dsd; - dwarf2_loc *loc = yasm_xmalloc(sizeof(dwarf2_loc)); - - /* File number (required) */ - yasm_valparam *vp = yasm_vps_first(valparams); - if (!vp || !vp->param) { - yasm__error(line, N_("file number required")); - yasm_xfree(loc); - return 0; - } - intn = yasm_expr_get_intnum(&vp->param, NULL); - if (!intn) { - yasm__error(line, N_("file number is not a constant")); - yasm_xfree(loc); - return 0; - } - if (yasm_intnum_sign(intn) != 1) { - yasm__error(line, N_("file number less than one")); - yasm_xfree(loc); - return 0; - } - loc->file = yasm_intnum_get_uint(intn); - - /* Line number (required) */ - vp = yasm_vps_next(vp); - if (!vp || !vp->param) { - yasm__error(line, N_("line number required")); - yasm_xfree(loc); - return 0; - } - intn = yasm_expr_get_intnum(&vp->param, NULL); - if (!intn) { - yasm__error(line, N_("file number is not a constant")); - yasm_xfree(loc); - return 0; - } - loc->line = yasm_intnum_get_uint(intn); - - /* Generate new section data if it doesn't already exist */ - dsd = yasm_section_get_data(sect, &dwarf2_section_data_cb); - if (!dsd) { - dsd = yasm_xmalloc(sizeof(dwarf2_section_data)); - STAILQ_INIT(&dsd->locs); - yasm_section_add_data(sect, &dwarf2_section_data_cb, dsd); - } - - /* Defaults for optional settings */ - loc->column = 0; - loc->isa_change = 0; - loc->isa = 0; - loc->is_stmt = IS_STMT_NOCHANGE; - loc->basic_block = 0; - loc->prologue_end = 0; - loc->epilogue_begin = 0; - - /* Optional column number */ - vp = yasm_vps_next(vp); - if (vp && vp->param) { - intn = yasm_expr_get_intnum(&vp->param, NULL); - if (!intn) { - yasm__error(line, N_("column number is not a constant")); - yasm_xfree(loc); - return 0; - } - loc->column = yasm_intnum_get_uint(intn); - vp = yasm_vps_next(vp); - } - - /* Other options */ - while (vp && vp->val) { - if (yasm__strcasecmp(vp->val, "basic_block") == 0) - loc->basic_block = 1; - else if (yasm__strcasecmp(vp->val, "prologue_end") == 0) - loc->prologue_end = 1; - else if (yasm__strcasecmp(vp->val, "epilogue_begin") == 0) - loc->epilogue_begin = 1; - else if (yasm__strcasecmp(vp->val, "is_stmt") == 0) { - if (!vp->param) { - yasm__error(line, N_("is_stmt requires value")); - yasm_xfree(loc); - return 0; - } - intn = yasm_expr_get_intnum(&vp->param, NULL); - if (!intn) { - yasm__error(line, N_("is_stmt value is not a constant")); - yasm_xfree(loc); - return 0; - } - if (yasm_intnum_is_zero(intn)) - loc->is_stmt = IS_STMT_SET; - else if (yasm_intnum_is_pos1(intn)) - loc->is_stmt = IS_STMT_CLEAR; - else { - yasm__error(line, N_("is_stmt value not 0 or 1")); - yasm_xfree(loc); - return 0; - } - } else if (yasm__strcasecmp(vp->val, "isa") == 0) { - if (!vp->param) { - yasm__error(line, N_("isa requires value")); - yasm_xfree(loc); - return 0; - } - intn = yasm_expr_get_intnum(&vp->param, NULL); - if (!intn) { - yasm__error(line, N_("isa value is not a constant")); - yasm_xfree(loc); - return 0; - } - if (yasm_intnum_sign(intn) < 0) { - yasm__error(line, N_("isa value less than zero")); - yasm_xfree(loc); - return 0; - } - loc->isa_change = 1; - loc->isa = yasm_intnum_get_uint(intn); - } else - yasm__warning(YASM_WARN_GENERAL, line, - N_("unrecognized loc option `%s'"), vp->val); - } - - /* Append new location */ - loc->vline = line; - loc->bc = NULL; - loc->sym = NULL; - STAILQ_INSERT_TAIL(&dsd->locs, loc, link); - - return 0; - } else if (yasm__strcasecmp(name, "file") == 0) { - /*@dependent@*/ /*@null@*/ const yasm_intnum *file_intn; - size_t filenum; - size_t dirlen; - const char *filename; - size_t i, dir; - - yasm_valparam *vp = yasm_vps_first(valparams); - - if (vp->val) { - /* Just a bare filename */ - yasm_object_set_source_fn(dbgfmt_dwarf2->object, vp->val); - return 0; - } - - /* Otherwise.. first vp is the file number */ - file_intn = yasm_expr_get_intnum(&vp->param, NULL); - if (!file_intn) { - yasm__error(line, N_("file number is not a constant")); - return 0; - } - filenum = (size_t)yasm_intnum_get_uint(file_intn); - - vp = yasm_vps_next(vp); - if (!vp || !vp->val) { - yasm__error(line, N_("file number given but no filename")); - return 0; - } - - /* Put the directory into the directory table */ - dir = 0; - dirlen = yasm__splitpath(vp->val, &filename); - if (dirlen > 0) { - /* Look to see if we already have that dir in the table */ - for (dir=1; dirdirs_size+1; dir++) { - if (strncmp(dbgfmt_dwarf2->dirs[dir-1], vp->val, dirlen) == 0 - && dbgfmt_dwarf2->dirs[dir-1][dirlen] == '\0') - break; - } - if (dir >= dbgfmt_dwarf2->dirs_size+1) { - /* Not found in table, add to end, reallocing if necessary */ - if (dir >= dbgfmt_dwarf2->dirs_allocated+1) { - dbgfmt_dwarf2->dirs_allocated = dir+32; - dbgfmt_dwarf2->dirs = yasm_xrealloc(dbgfmt_dwarf2->dirs, - sizeof(char *)*dbgfmt_dwarf2->dirs_allocated); - } - dbgfmt_dwarf2->dirs[dir-1] = yasm__xstrndup(vp->val, dirlen); - dbgfmt_dwarf2->dirs_size = dir; - } - } - - /* Put the filename into the filename table */ - if (filenum == 0) { - /* Look to see if we already have that filename in the table */ - for (; filenumfilenames_size; filenum++) { - if (!dbgfmt_dwarf2->filenames[filenum].filename || - (dbgfmt_dwarf2->filenames[filenum].dir == dir - && strcmp(dbgfmt_dwarf2->filenames[filenum].filename, - filename) == 0)) - break; - } - } else - filenum--; /* array index is 0-based */ - - /* Realloc table if necessary */ - if (filenum >= dbgfmt_dwarf2->filenames_allocated) { - size_t old_allocated = dbgfmt_dwarf2->filenames_allocated; - dbgfmt_dwarf2->filenames_allocated = filenum+32; - dbgfmt_dwarf2->filenames = yasm_xrealloc(dbgfmt_dwarf2->filenames, - sizeof(dwarf2_filename)*dbgfmt_dwarf2->filenames_allocated); - for (i=old_allocated; ifilenames_allocated; i++) { - dbgfmt_dwarf2->filenames[i].filename = NULL; - dbgfmt_dwarf2->filenames[i].dir = 0; - } - } - - /* Actually save in table */ - if (dbgfmt_dwarf2->filenames[filenum].filename) - yasm_xfree(dbgfmt_dwarf2->filenames[filenum].filename); - dbgfmt_dwarf2->filenames[filenum].filename = yasm__xstrdup(filename); - dbgfmt_dwarf2->filenames[filenum].dir = dir; - - /* Update table size */ - if (filenum >= dbgfmt_dwarf2->filenames_size) - dbgfmt_dwarf2->filenames_size = filenum + 1; - - return 0; - } - return 1; + return yasm_dwarf2__line_directive(dbgfmt_dwarf2, name, sect, valparams, + line); } /* Define dbgfmt structure -- see dbgfmt.h for details */ diff --git a/modules/dbgfmts/dwarf2/dwarf2-dbgfmt.h b/modules/dbgfmts/dwarf2/dwarf2-dbgfmt.h new file mode 100644 index 00000000..1874298d --- /dev/null +++ b/modules/dbgfmts/dwarf2/dwarf2-dbgfmt.h @@ -0,0 +1,131 @@ +/* $Id$ + * DWARF2 debugging format + * + * Copyright (C) 2006 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef YASM_DWARF2_DBGFMT_H +#define YASM_DWARF2_DBGFMT_H + +#define WITH_DWARF3 1 + +typedef struct { + char *pathname; /* full filename */ + char *filename; /* basename of full filename */ + size_t dir; /* index into directories array for relative path; + * 0 for current directory. */ +} dwarf2_filename; + +/* Global data */ +typedef struct yasm_dbgfmt_dwarf2 { + yasm_dbgfmt_base dbgfmt; /* base structure */ + + yasm_object *object; + yasm_symtab *symtab; + yasm_linemap *linemap; + yasm_arch *arch; + + char **dirs; + size_t dirs_size; + size_t dirs_allocated; + + dwarf2_filename *filenames; + size_t filenames_size; + size_t filenames_allocated; + + enum { + DWARF2_FORMAT_32BIT, + DWARF2_FORMAT_64BIT + } format; + + size_t sizeof_address, sizeof_offset, min_insn_len; +} yasm_dbgfmt_dwarf2; + +/* .loc directive data */ +typedef struct dwarf2_loc { + /*@reldef@*/ STAILQ_ENTRY(dwarf2_loc) link; + + unsigned long vline; /* virtual line number of .loc directive */ + + /* source information */ + unsigned long file; /* index into table of filenames */ + unsigned long line; /* source line number */ + unsigned long column; /* source column */ + int isa_change; + unsigned long isa; + enum { + IS_STMT_NOCHANGE = 0, + IS_STMT_SET, + IS_STMT_CLEAR + } is_stmt; + int basic_block; + int prologue_end; + int epilogue_begin; + + yasm_bytecode *bc; /* first bytecode following */ + yasm_symrec *sym; /* last symbol preceding */ +} dwarf2_loc; + +/* Per-section data */ +typedef struct dwarf2_section_data { + /* The locations set by the .loc directives in this section, in assembly + * source order. + */ + /*@reldef@*/ STAILQ_HEAD(dwarf2_lochead, dwarf2_loc) locs; +} dwarf2_section_data; + +extern const yasm_assoc_data_callback yasm_dwarf2__section_data_cb; + +yasm_bytecode *yasm_dwarf2__append_bc(yasm_section *sect, yasm_bytecode *bc); + +/*@only@*/ yasm_expr *yasm_dwarf2__bc_sym(yasm_symtab *symtab, + yasm_bytecode *bc); + +typedef struct dwarf2_head dwarf2_head; +dwarf2_head *yasm_dwarf2__add_head + (yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2, yasm_section *sect, + /*@null@*/ yasm_section *debug_ptr, int with_address, int with_segment); +void yasm_dwarf2__set_head_end(dwarf2_head *head, yasm_bytecode *end_prevbc); + +/* Line number functions */ +yasm_section *yasm_dwarf2__generate_line + (yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2, int asm_source, + /*@out@*/ yasm_section **main_code, /*@out@*/ size_t *num_line_sections); +int yasm_dwarf2__line_directive + (yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2, const char *name, yasm_section *sect, + yasm_valparamhead *valparams, unsigned long line); + +/* Address range table functions */ +yasm_section *yasm_dwarf2__generate_aranges(yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2, + yasm_section *debug_info); + +/* Name lookup table functions */ +yasm_section *yasm_dwarf2__generate_pubnames(yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2, + yasm_section *debug_info); + +/* Information functions */ +yasm_section *yasm_dwarf2__generate_info + (yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2, yasm_section *debug_line, + /*@null@*/ yasm_section *main_code); + +#endif diff --git a/modules/dbgfmts/dwarf2/dwarf2-info.c b/modules/dbgfmts/dwarf2/dwarf2-info.c new file mode 100644 index 00000000..039021df --- /dev/null +++ b/modules/dbgfmts/dwarf2/dwarf2-info.c @@ -0,0 +1,519 @@ +/* + * DWARF2 debugging format - info and abbreviation tables + * + * Copyright (C) 2006 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include +/*@unused@*/ RCSID("$Id$"); + +/* Need either unistd.h or direct.h (on Windows) to prototype getcwd() */ +#ifdef HAVE_UNISTD_H +#include +#elif defined(WIN32) || defined(_WIN32) +#include +#endif + +#define YASM_LIB_INTERNAL +#define YASM_BC_INTERNAL +#include + +#include "dwarf2-dbgfmt.h" + +#define DW_LANG_Mips_Assembler 0x8001 + +/* Tag encodings */ +typedef enum { + DW_TAG_padding = 0x00, + DW_TAG_array_type = 0x01, + DW_TAG_class_type = 0x02, + DW_TAG_entry_point = 0x03, + DW_TAG_enumeration_type = 0x04, + DW_TAG_formal_parameter = 0x05, + DW_TAG_imported_declaration = 0x08, + DW_TAG_label = 0x0a, + DW_TAG_lexical_block = 0x0b, + DW_TAG_member = 0x0d, + DW_TAG_pointer_type = 0x0f, + DW_TAG_reference_type = 0x10, + DW_TAG_compile_unit = 0x11, + DW_TAG_string_type = 0x12, + DW_TAG_structure_type = 0x13, + DW_TAG_subroutine_type = 0x15, + DW_TAG_typedef = 0x16, + DW_TAG_union_type = 0x17, + DW_TAG_unspecified_parameters = 0x18, + DW_TAG_variant = 0x19, + DW_TAG_common_block = 0x1a, + DW_TAG_common_inclusion = 0x1b, + DW_TAG_inheritance = 0x1c, + DW_TAG_inlined_subroutine = 0x1d, + DW_TAG_module = 0x1e, + DW_TAG_ptr_to_member_type = 0x1f, + DW_TAG_set_type = 0x20, + DW_TAG_subrange_type = 0x21, + DW_TAG_with_stmt = 0x22, + DW_TAG_access_declaration = 0x23, + DW_TAG_base_type = 0x24, + DW_TAG_catch_block = 0x25, + DW_TAG_const_type = 0x26, + DW_TAG_constant = 0x27, + DW_TAG_enumerator = 0x28, + DW_TAG_file_type = 0x29, + DW_TAG_friend = 0x2a, + DW_TAG_namelist = 0x2b, + DW_TAG_namelist_item = 0x2c, + DW_TAG_packed_type = 0x2d, + DW_TAG_subprogram = 0x2e, + DW_TAG_template_type_param = 0x2f, + DW_TAG_template_value_param = 0x30, + DW_TAG_thrown_type = 0x31, + DW_TAG_try_block = 0x32, + DW_TAG_variant_part = 0x33, + DW_TAG_variable = 0x34, + DW_TAG_volatile_type = 0x35 +} dwarf_tag; + +/* Attribute form encodings */ +typedef enum { + DW_FORM_addr = 0x01, + DW_FORM_block2 = 0x03, + DW_FORM_block4 = 0x04, + DW_FORM_data2 = 0x05, + DW_FORM_data4 = 0x06, + DW_FORM_data8 = 0x07, + DW_FORM_string = 0x08, + DW_FORM_block = 0x09, + DW_FORM_block1 = 0x0a, + DW_FORM_data1 = 0x0b, + DW_FORM_flag = 0x0c, + DW_FORM_sdata = 0x0d, + DW_FORM_strp = 0x0e, + DW_FORM_udata = 0x0f, + DW_FORM_ref_addr = 0x10, + DW_FORM_ref1 = 0x11, + DW_FORM_ref2 = 0x12, + DW_FORM_ref4 = 0x13, + DW_FORM_ref8 = 0x14, + DW_FORM_ref_udata = 0x15, + DW_FORM_indirect = 0x16 +} dwarf_form; + +/* Attribute encodings */ +typedef enum { + DW_AT_sibling = 0x01, + DW_AT_location = 0x02, + DW_AT_name = 0x03, + DW_AT_ordering = 0x09, + DW_AT_subscr_data = 0x0a, + DW_AT_byte_size = 0x0b, + DW_AT_bit_offset = 0x0c, + DW_AT_bit_size = 0x0d, + DW_AT_element_list = 0x0f, + DW_AT_stmt_list = 0x10, + DW_AT_low_pc = 0x11, + DW_AT_high_pc = 0x12, + DW_AT_language = 0x13, + DW_AT_member = 0x14, + DW_AT_discr = 0x15, + DW_AT_discr_value = 0x16, + DW_AT_visibility = 0x17, + DW_AT_import = 0x18, + DW_AT_string_length = 0x19, + DW_AT_common_reference = 0x1a, + DW_AT_comp_dir = 0x1b, + DW_AT_const_value = 0x1c, + DW_AT_containing_type = 0x1d, + DW_AT_default_value = 0x1e, + DW_AT_inline = 0x20, + DW_AT_is_optional = 0x21, + DW_AT_lower_bound = 0x22, + DW_AT_producer = 0x25, + DW_AT_prototyped = 0x27, + DW_AT_return_addr = 0x2a, + DW_AT_start_scope = 0x2c, + DW_AT_stride_size = 0x2e, + DW_AT_upper_bound = 0x2f, + DW_AT_abstract_origin = 0x31, + DW_AT_accessibility = 0x32, + DW_AT_address_class = 0x33, + DW_AT_artificial = 0x34, + DW_AT_base_types = 0x35, + DW_AT_calling_convention = 0x36, + DW_AT_count = 0x37, + DW_AT_data_member_location = 0x38, + DW_AT_decl_column = 0x39, + DW_AT_decl_file = 0x3a, + DW_AT_decl_line = 0x3b, + DW_AT_declaration = 0x3c, + DW_AT_discr_list = 0x3d, + DW_AT_encoding = 0x3e, + DW_AT_external = 0x3f, + DW_AT_frame_base = 0x40, + DW_AT_friend = 0x41, + DW_AT_identifier_case = 0x42, + DW_AT_macro_info = 0x43, + DW_AT_namelist_items = 0x44, + DW_AT_priority = 0x45, + DW_AT_segment = 0x46, + DW_AT_specification = 0x47, + DW_AT_static_link = 0x48, + DW_AT_type = 0x49, + DW_AT_use_location = 0x4a, + DW_AT_variable_parameter = 0x4b, + DW_AT_virtuality = 0x4c, + DW_AT_vtable_elem_location = 0x4d +} dwarf_attribute; + +typedef struct dwarf2_info_head { + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2; + yasm_bytecode *info_start_prevbc; + yasm_bytecode *info_end_prevbc; + /*@owned@*/ yasm_expr *debug_abbrev_expr; /* points to debug_abbrev */ +} dwarf2_info_head; + +typedef struct dwarf2_abbrev_attr { + STAILQ_ENTRY(dwarf2_abbrev_attr) link; + dwarf_attribute name; + dwarf_form form; +} dwarf2_abbrev_attr; + +typedef struct dwarf2_abbrev { + unsigned long id; + dwarf_tag tag; + int has_children; + STAILQ_HEAD(dwarf2_abbrev_attrhead, dwarf2_abbrev_attr) attrs; +} dwarf2_abbrev; + +/* Bytecode callback function prototypes */ + +static void dwarf2_info_head_bc_destroy(void *contents); +static void dwarf2_info_head_bc_print(const void *contents, FILE *f, + int indent_level); +static yasm_bc_resolve_flags dwarf2_info_head_bc_resolve + (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist); +static int dwarf2_info_head_bc_tobytes + (yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_expr_func output_expr, + /*@null@*/ yasm_output_reloc_func output_reloc); + +static void dwarf2_abbrev_bc_destroy(void *contents); +static void dwarf2_abbrev_bc_print(const void *contents, FILE *f, + int indent_level); +static yasm_bc_resolve_flags dwarf2_abbrev_bc_resolve + (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist); +static int dwarf2_abbrev_bc_tobytes + (yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_expr_func output_expr, + /*@null@*/ yasm_output_reloc_func output_reloc); + +/* Bytecode callback structures */ + +static const yasm_bytecode_callback dwarf2_info_head_bc_callback = { + dwarf2_info_head_bc_destroy, + dwarf2_info_head_bc_print, + yasm_bc_finalize_common, + dwarf2_info_head_bc_resolve, + dwarf2_info_head_bc_tobytes +}; + +static const yasm_bytecode_callback dwarf2_abbrev_bc_callback = { + dwarf2_abbrev_bc_destroy, + dwarf2_abbrev_bc_print, + yasm_bc_finalize_common, + dwarf2_abbrev_bc_resolve, + dwarf2_abbrev_bc_tobytes +}; + + +static unsigned long +dwarf2_add_abbrev_attr(dwarf2_abbrev *abbrev, dwarf_attribute name, + dwarf_form form) +{ + dwarf2_abbrev_attr *attr = yasm_xmalloc(sizeof(dwarf2_abbrev_attr)); + attr->name = name; + attr->form = form; + STAILQ_INSERT_TAIL(&abbrev->attrs, attr, link); + return yasm_size_uleb128(name) + yasm_size_uleb128(form); +} + +static void +dwarf2_append_expr(yasm_section *sect, /*@only@*/ yasm_expr *expr, size_t size, + int leb) +{ + yasm_datavalhead dvs; + yasm_bytecode *bc; + + yasm_dvs_initialize(&dvs); + yasm_dvs_append(&dvs, yasm_dv_create_expr(expr)); + if (leb == 0) + bc = yasm_bc_create_data(&dvs, size, 0, 0); + else + bc = yasm_bc_create_leb128(&dvs, leb<0, 0); + yasm_bc_finalize(bc, yasm_dwarf2__append_bc(sect, bc)); + yasm_bc_resolve(bc, 0, NULL); +} + +static void +dwarf2_append_str(yasm_section *sect, const char *str) +{ + yasm_datavalhead dvs; + yasm_bytecode *bc; + + yasm_dvs_initialize(&dvs); + yasm_dvs_append(&dvs, yasm_dv_create_string(yasm__xstrdup(str), + strlen(str))); + bc = yasm_bc_create_data(&dvs, 1, 1, 0); + yasm_bc_finalize(bc, yasm_dwarf2__append_bc(sect, bc)); + yasm_bc_resolve(bc, 0, NULL); +} + +yasm_section * +yasm_dwarf2__generate_info(yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2, + yasm_section *debug_line, yasm_section *main_code) +{ + int new; + yasm_bytecode *abc; + dwarf2_abbrev *abbrev; + dwarf2_head *head; + char *buf; + yasm_section *debug_abbrev = + yasm_object_get_general(dbgfmt_dwarf2->object, ".debug_abbrev", 0, + 4, 0, 0, &new, 0); + yasm_section *debug_info = + yasm_object_get_general(dbgfmt_dwarf2->object, ".debug_info", 0, 4, 0, + 0, &new, 0); + + /* Create abbreviation table entry for compilation unit */ + abbrev = yasm_xmalloc(sizeof(dwarf2_abbrev)); + abc = yasm_bc_create_common(&dwarf2_abbrev_bc_callback, abbrev, 0); + abbrev->id = 1; + abbrev->tag = DW_TAG_compile_unit; + abbrev->has_children = 0; + abc->len = yasm_size_uleb128(abbrev->id) + yasm_size_uleb128(abbrev->tag) + + 3; + STAILQ_INIT(&abbrev->attrs); + yasm_dwarf2__append_bc(debug_abbrev, abc); + + /* info header */ + head = yasm_dwarf2__add_head(dbgfmt_dwarf2, debug_info, debug_abbrev, 1, 0); + + /* Generate abbreviations at the same time as info (since they're linked + * and we're only generating one piece of info). + */ + + /* generating info using abbrev 1 */ + dwarf2_append_expr(debug_info, + yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(1)), 0), + 0, 1); + + /* statement list (line numbers) */ + abc->len += dwarf2_add_abbrev_attr(abbrev, DW_AT_stmt_list, DW_FORM_data4); + dwarf2_append_expr(debug_info, + yasm_dwarf2__bc_sym(dbgfmt_dwarf2->symtab, + yasm_section_bcs_first(debug_line)), + dbgfmt_dwarf2->sizeof_offset, 0); + + if (main_code) { + /* All code is contiguous in one section */ + abc->len += dwarf2_add_abbrev_attr(abbrev, DW_AT_low_pc, DW_FORM_addr); + dwarf2_append_expr(debug_info, + yasm_dwarf2__bc_sym(dbgfmt_dwarf2->symtab, + yasm_section_bcs_first(main_code)), + dbgfmt_dwarf2->sizeof_address, 0); + + abc->len += dwarf2_add_abbrev_attr(abbrev, DW_AT_high_pc, DW_FORM_addr); + dwarf2_append_expr(debug_info, + yasm_dwarf2__bc_sym(dbgfmt_dwarf2->symtab, + yasm_section_bcs_last(main_code)), + dbgfmt_dwarf2->sizeof_address, 0); + } + + /* input filename */ + abc->len += dwarf2_add_abbrev_attr(abbrev, DW_AT_name, DW_FORM_string); + dwarf2_append_str(debug_info, + yasm_object_get_source_fn(dbgfmt_dwarf2->object)); + + /* compile directory (current working directory) */ + abc->len += dwarf2_add_abbrev_attr(abbrev, DW_AT_comp_dir, DW_FORM_string); + buf = getcwd(NULL, 0); + dwarf2_append_str(debug_info, buf); + free(buf); + + /* producer - assembler name */ + abc->len += dwarf2_add_abbrev_attr(abbrev, DW_AT_producer, DW_FORM_string); + dwarf2_append_str(debug_info, PACKAGE " " VERSION); + + /* language - no standard code for assembler, use MIPS as a substitute */ + abc->len += dwarf2_add_abbrev_attr(abbrev, DW_AT_language, DW_FORM_data2); + dwarf2_append_expr(debug_info, + yasm_expr_create_ident(yasm_expr_int( + yasm_intnum_create_uint(DW_LANG_Mips_Assembler)), 0), 2, 0); + + /* Terminate list of abbreviations */ + abbrev = yasm_xmalloc(sizeof(dwarf2_abbrev)); + abc = yasm_bc_create_common(&dwarf2_abbrev_bc_callback, abbrev, 0); + abbrev->id = 0; + abc->len = 1; + yasm_dwarf2__append_bc(debug_abbrev, abc); + + /* mark end of info */ + yasm_dwarf2__set_head_end(head, yasm_section_bcs_last(debug_info)); + + return debug_info; +} + +static void +dwarf2_info_head_bc_destroy(void *contents) +{ + dwarf2_info_head *ih = (dwarf2_info_head *)contents; + yasm_xfree(contents); +} + +static void +dwarf2_info_head_bc_print(const void *contents, FILE *f, int indent_level) +{ + /* TODO */ +} + +static yasm_bc_resolve_flags +dwarf2_info_head_bc_resolve(yasm_bytecode *bc, int save, + yasm_calc_bc_dist_func calc_bc_dist) +{ + yasm_internal_error(N_("tried to resolve a dwarf2 info head bytecode")); + /*@notreached@*/ + return YASM_BC_RESOLVE_MIN_LEN; +} + +static int +dwarf2_info_head_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_expr_func output_expr, + yasm_output_reloc_func output_reloc) +{ + dwarf2_info_head *ih = (dwarf2_info_head *)bc->contents; + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = ih->dbgfmt_dwarf2; + unsigned char *buf = *bufp; + yasm_intnum *intn, *cval; + size_t i, len; + + if (dbgfmt_dwarf2->format == DWARF2_FORMAT_64BIT) { + YASM_WRITE_8(buf, 0xff); + YASM_WRITE_8(buf, 0xff); + YASM_WRITE_8(buf, 0xff); + YASM_WRITE_8(buf, 0xff); + } + + /* Total length of info (following this field) */ + cval = yasm_intnum_create_uint(dbgfmt_dwarf2->sizeof_offset); + intn = yasm_common_calc_bc_dist(ih->info_start_prevbc, ih->info_end_prevbc); + yasm_intnum_calc(intn, YASM_EXPR_SUB, cval, bc->line); + yasm_arch_intnum_tobytes(dbgfmt_dwarf2->arch, intn, buf, + dbgfmt_dwarf2->sizeof_offset, + dbgfmt_dwarf2->sizeof_offset*8, 0, bc, 0, 0); + buf += dbgfmt_dwarf2->sizeof_offset; + yasm_intnum_destroy(intn); + + /* DWARF version */ + yasm_intnum_set_uint(cval, 2); + yasm_arch_intnum_tobytes(dbgfmt_dwarf2->arch, cval, buf, 2, 16, 0, bc, 0, + 0); + buf += 2; + + /* Pointer to our debug_abbrev */ + output_expr(&ih->debug_abbrev_expr, buf, dbgfmt_dwarf2->sizeof_offset, + dbgfmt_dwarf2->sizeof_offset*8, 0, (unsigned long)(buf-*bufp), + bc, 0, 0, d); + buf += dbgfmt_dwarf2->sizeof_offset; + + /* Size of the offset portion of the address */ + YASM_WRITE_8(buf, dbgfmt_dwarf2->sizeof_address); + + *bufp = buf; + + yasm_intnum_destroy(cval); + return 0; +} + +static void +dwarf2_abbrev_bc_destroy(void *contents) +{ + dwarf2_abbrev *abbrev = (dwarf2_abbrev *)contents; + dwarf2_abbrev_attr *n1, *n2; + + /* Delete attributes */ + n1 = STAILQ_FIRST(&abbrev->attrs); + while (n1) { + n2 = STAILQ_NEXT(n1, link); + yasm_xfree(n1); + n1 = n2; + } + + yasm_xfree(contents); +} + +static void +dwarf2_abbrev_bc_print(const void *contents, FILE *f, int indent_level) +{ + /* TODO */ +} + +static yasm_bc_resolve_flags +dwarf2_abbrev_bc_resolve(yasm_bytecode *bc, int save, + yasm_calc_bc_dist_func calc_bc_dist) +{ + yasm_internal_error(N_("tried to resolve a dwarf2 aranges head bytecode")); + /*@notreached@*/ + return YASM_BC_RESOLVE_MIN_LEN; +} + +static int +dwarf2_abbrev_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_expr_func output_expr, + yasm_output_reloc_func output_reloc) +{ + dwarf2_abbrev *abbrev = (dwarf2_abbrev *)bc->contents; + unsigned char *buf = *bufp; + dwarf2_abbrev_attr *attr; + + if (abbrev->id == 0) { + YASM_WRITE_8(buf, 0); + *bufp = buf; + return 0; + } + + buf += yasm_get_uleb128(abbrev->id, buf); + buf += yasm_get_uleb128(abbrev->tag, buf); + YASM_WRITE_8(buf, abbrev->has_children); + + STAILQ_FOREACH(attr, &abbrev->attrs, link) { + buf += yasm_get_uleb128(attr->name, buf); + buf += yasm_get_uleb128(attr->form, buf); + } + + YASM_WRITE_8(buf, 0); + YASM_WRITE_8(buf, 0); + + *bufp = buf; + return 0; +} + diff --git a/modules/dbgfmts/dwarf2/dwarf2-line.c b/modules/dbgfmts/dwarf2/dwarf2-line.c new file mode 100644 index 00000000..a8a11e6d --- /dev/null +++ b/modules/dbgfmts/dwarf2/dwarf2-line.c @@ -0,0 +1,979 @@ +/* + * DWARF2 debugging format - line information + * + * Copyright (C) 2006 Peter Johnson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of other contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include +/*@unused@*/ RCSID("$Id$"); + +#define YASM_LIB_INTERNAL +#define YASM_BC_INTERNAL +#include + +#include "dwarf2-dbgfmt.h" + +/* DWARF line number opcodes */ +typedef enum { + DW_LNS_extended_op = 0, + DW_LNS_copy, + DW_LNS_advance_pc, + DW_LNS_advance_line, + DW_LNS_set_file, + DW_LNS_set_column, + DW_LNS_negate_stmt, + DW_LNS_set_basic_block, + DW_LNS_const_add_pc, + DW_LNS_fixed_advance_pc, +#ifdef WITH_DWARF3 + /* DWARF 3 extensions */ + DW_LNS_set_prologue_end, + DW_LNS_set_epilogue_begin, + DW_LNS_set_isa, +#endif + DWARF2_LINE_OPCODE_BASE +} dwarf_line_number_op; + +/* # of LEB128 operands needed for each of the above opcodes */ +static unsigned char line_opcode_num_operands[DWARF2_LINE_OPCODE_BASE-1] = { + 0, /* DW_LNS_copy */ + 1, /* DW_LNS_advance_pc */ + 1, /* DW_LNS_advance_line */ + 1, /* DW_LNS_set_file */ + 1, /* DW_LNS_set_column */ + 0, /* DW_LNS_negate_stmt */ + 0, /* DW_LNS_set_basic_block */ + 0, /* DW_LNS_const_add_pc */ + 1, /* DW_LNS_fixed_advance_pc */ +#ifdef WITH_DWARF3 + 0, /* DW_LNS_set_prologue_end */ + 0, /* DW_LNS_set_epilogue_begin */ + 1 /* DW_LNS_set_isa */ +#endif +}; + +/* Line number extended opcodes */ +typedef enum { + DW_LNE_end_sequence = 1, + DW_LNE_set_address, + DW_LNE_define_file +} dwarf_line_number_ext_op; + +/* Base and range for line offsets in special opcodes */ +#define DWARF2_LINE_BASE -5 +#define DWARF2_LINE_RANGE 14 + +#define DWARF2_MAX_SPECIAL_ADDR_DELTA \ + (((255-DWARF2_LINE_OPCODE_BASE)/DWARF2_LINE_RANGE)*\ + dbgfmt_dwarf2->min_insn_len) + +/* Initial value of is_stmt register */ +#define DWARF2_LINE_DEFAULT_IS_STMT 1 + +/* Line number state machine register state */ +typedef struct dwarf2_line_state { + /* static configuration */ + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2; + + /* DWARF2 state machine registers */ + unsigned long address; + unsigned long file; + unsigned long line; + unsigned long column; + unsigned long isa; + int is_stmt; + + /* other state information */ + /*@null@*/ yasm_bytecode *precbc; +} dwarf2_line_state; + +typedef struct dwarf2_spp { + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2; + yasm_bytecode *line_start_prevbc; + yasm_bytecode *line_end_prevbc; +} dwarf2_spp; + +typedef struct dwarf2_line_op { + dwarf_line_number_op opcode; + /*@owned@*/ /*@null@*/ yasm_intnum *operand; + + /* extended opcode */ + dwarf_line_number_ext_op ext_opcode; + /*@owned@*/ /*@null@*/ yasm_expr *ext_operand; /* unsigned */ + unsigned long ext_operandsize; +} dwarf2_line_op; + +/* Bytecode callback function prototypes */ +static void dwarf2_spp_bc_destroy(void *contents); +static void dwarf2_spp_bc_print(const void *contents, FILE *f, + int indent_level); +static yasm_bc_resolve_flags dwarf2_spp_bc_resolve + (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist); +static int dwarf2_spp_bc_tobytes + (yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_expr_func output_expr, + /*@null@*/ yasm_output_reloc_func output_reloc); + +static void dwarf2_line_op_bc_destroy(void *contents); +static void dwarf2_line_op_bc_print(const void *contents, FILE *f, + int indent_level); +static yasm_bc_resolve_flags dwarf2_line_op_bc_resolve + (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist); +static int dwarf2_line_op_bc_tobytes + (yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_expr_func output_expr, + /*@null@*/ yasm_output_reloc_func output_reloc); + +/* Bytecode callback structures */ +static const yasm_bytecode_callback dwarf2_spp_bc_callback = { + dwarf2_spp_bc_destroy, + dwarf2_spp_bc_print, + yasm_bc_finalize_common, + dwarf2_spp_bc_resolve, + dwarf2_spp_bc_tobytes +}; + +static const yasm_bytecode_callback dwarf2_line_op_bc_callback = { + dwarf2_line_op_bc_destroy, + dwarf2_line_op_bc_print, + yasm_bc_finalize_common, + dwarf2_line_op_bc_resolve, + dwarf2_line_op_bc_tobytes +}; + + +static size_t +dwarf2_dbgfmt_add_file(yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2, size_t filenum, + const char *pathname) +{ + size_t dirlen; + const char *filename; + size_t i, dir; + + /* Put the directory into the directory table */ + dir = 0; + dirlen = yasm__splitpath(pathname, &filename); + if (dirlen > 0) { + /* Look to see if we already have that dir in the table */ + for (dir=1; dirdirs_size+1; dir++) { + if (strncmp(dbgfmt_dwarf2->dirs[dir-1], pathname, dirlen) == 0 + && dbgfmt_dwarf2->dirs[dir-1][dirlen] == '\0') + break; + } + if (dir >= dbgfmt_dwarf2->dirs_size+1) { + /* Not found in table, add to end, reallocing if necessary */ + if (dir >= dbgfmt_dwarf2->dirs_allocated+1) { + dbgfmt_dwarf2->dirs_allocated = dir+32; + dbgfmt_dwarf2->dirs = yasm_xrealloc(dbgfmt_dwarf2->dirs, + sizeof(char *)*dbgfmt_dwarf2->dirs_allocated); + } + dbgfmt_dwarf2->dirs[dir-1] = yasm__xstrndup(pathname, dirlen); + dbgfmt_dwarf2->dirs_size = dir; + } + } + + /* Put the filename into the filename table */ + if (filenum == 0) { + /* Look to see if we already have that filename in the table */ + for (; filenumfilenames_size; filenum++) { + if (!dbgfmt_dwarf2->filenames[filenum].filename || + (dbgfmt_dwarf2->filenames[filenum].dir == dir + && strcmp(dbgfmt_dwarf2->filenames[filenum].filename, + filename) == 0)) + break; + } + } else + filenum--; /* array index is 0-based */ + + /* Realloc table if necessary */ + if (filenum >= dbgfmt_dwarf2->filenames_allocated) { + size_t old_allocated = dbgfmt_dwarf2->filenames_allocated; + dbgfmt_dwarf2->filenames_allocated = filenum+32; + dbgfmt_dwarf2->filenames = yasm_xrealloc(dbgfmt_dwarf2->filenames, + sizeof(dwarf2_filename)*dbgfmt_dwarf2->filenames_allocated); + for (i=old_allocated; ifilenames_allocated; i++) { + dbgfmt_dwarf2->filenames[i].pathname = NULL; + dbgfmt_dwarf2->filenames[i].filename = NULL; + dbgfmt_dwarf2->filenames[i].dir = 0; + } + } + + /* Actually save in table */ + if (dbgfmt_dwarf2->filenames[filenum].pathname) + yasm_xfree(dbgfmt_dwarf2->filenames[filenum].pathname); + if (dbgfmt_dwarf2->filenames[filenum].filename) + yasm_xfree(dbgfmt_dwarf2->filenames[filenum].filename); + dbgfmt_dwarf2->filenames[filenum].pathname = yasm__xstrdup(pathname); + dbgfmt_dwarf2->filenames[filenum].filename = yasm__xstrdup(filename); + dbgfmt_dwarf2->filenames[filenum].dir = dir; + + /* Update table size */ + if (filenum >= dbgfmt_dwarf2->filenames_size) + dbgfmt_dwarf2->filenames_size = filenum + 1; + + return filenum; +} + +/* Create and add a new line opcode to a section, updating offset on insertion; + * no optimization necessary. + */ +static yasm_bytecode * +dwarf2_dbgfmt_append_line_op(yasm_section *sect, dwarf_line_number_op opcode, + /*@only@*/ /*@null@*/ yasm_intnum *operand) +{ + dwarf2_line_op *line_op = yasm_xmalloc(sizeof(dwarf2_line_op)); + yasm_bytecode *bc; + + line_op->opcode = opcode; + line_op->operand = operand; + line_op->ext_opcode = 0; + line_op->ext_operand = NULL; + line_op->ext_operandsize = 0; + + bc = yasm_bc_create_common(&dwarf2_line_op_bc_callback, line_op, 0); + bc->len = 1; + if (operand) + bc->len += yasm_intnum_size_leb128(operand, + opcode == DW_LNS_advance_line); + + yasm_dwarf2__append_bc(sect, bc); + return bc; +} + +/* Create and add a new extended line opcode to a section, updating offset on + * insertion; no optimization necessary. + */ +static yasm_bytecode * +dwarf2_dbgfmt_append_line_ext_op(yasm_section *sect, + dwarf_line_number_ext_op ext_opcode, + unsigned long ext_operandsize, + /*@only@*/ /*@null@*/ yasm_expr *ext_operand) +{ + dwarf2_line_op *line_op = yasm_xmalloc(sizeof(dwarf2_line_op)); + yasm_bytecode *bc; + + line_op->opcode = DW_LNS_extended_op; + line_op->operand = yasm_intnum_create_uint(ext_operandsize+1); + line_op->ext_opcode = ext_opcode; + line_op->ext_operand = ext_operand; + line_op->ext_operandsize = ext_operandsize; + + bc = yasm_bc_create_common(&dwarf2_line_op_bc_callback, line_op, 0); + bc->len = 2 + yasm_intnum_size_leb128(line_op->operand, 0) + + ext_operandsize; + + yasm_dwarf2__append_bc(sect, bc); + return bc; +} + +static void +dwarf2_dbgfmt_finalize_locs(yasm_section *sect, dwarf2_section_data *dsd) +{ + /*@dependent@*/ yasm_symrec *lastsym = NULL; + /*@null@*/ yasm_bytecode *bc; + /*@null@*/ dwarf2_loc *loc; + + bc = yasm_section_bcs_first(sect); + STAILQ_FOREACH(loc, &dsd->locs, link) { + /* Find the first bytecode following this loc by looking at + * the virtual line numbers. XXX: this assumes the source file + * order will be the same as the actual section order. If we ever + * implement subsegs this will NOT necessarily be true and this logic + * will need to be fixed to handle it! + * + * Keep track of last symbol seen prior to the loc. + */ + while (bc && bc->line <= loc->vline) { + if (bc->symrecs) { + int i = 0; + while (bc->symrecs[i]) { + lastsym = bc->symrecs[i]; + i++; + } + } + bc = yasm_bc__next(bc); + } + loc->sym = lastsym; + loc->bc = bc; + } +} + +static int +dwarf2_dbgfmt_gen_line_op(yasm_section *debug_line, dwarf2_line_state *state, + const dwarf2_loc *loc, + /*@null@*/ const dwarf2_loc *nextloc) +{ + unsigned long addr_delta; + long line_delta; + int opcode1, opcode2; + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = state->dbgfmt_dwarf2; + + if (state->file != loc->file) { + state->file = loc->file; + dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_set_file, + yasm_intnum_create_uint(state->file)); + } + if (state->column != loc->column) { + state->column = loc->column; + dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_set_column, + yasm_intnum_create_uint(state->column)); + } +#ifdef WITH_DWARF3 + if (loc->isa_change) { + state->isa = loc->isa; + dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_set_isa, + yasm_intnum_create_uint(state->isa)); + } +#endif + if (state->is_stmt == 0 && loc->is_stmt == IS_STMT_SET) { + state->is_stmt = 1; + dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_negate_stmt, NULL); + } else if (state->is_stmt == 1 && loc->is_stmt == IS_STMT_CLEAR) { + state->is_stmt = 0; + dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_negate_stmt, NULL); + } + if (loc->basic_block) { + dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_set_basic_block, NULL); + } +#ifdef WITH_DWARF3 + if (loc->prologue_end) { + dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_set_prologue_end, NULL); + } + if (loc->epilogue_begin) { + dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_set_epilogue_begin, + NULL); + } +#endif + + /* If multiple loc for the same location, use last */ + if (nextloc && nextloc->bc->offset == loc->bc->offset) + return 0; + + if (!state->precbc) { + /* Set the starting address for the section */ + if (!loc->sym) { + /* shouldn't happen! */ + yasm__error(loc->line, N_("could not find label prior to loc")); + return 1; + } + dwarf2_dbgfmt_append_line_ext_op(debug_line, DW_LNE_set_address, + dbgfmt_dwarf2->sizeof_address, + yasm_expr_create_ident(yasm_expr_sym(loc->sym), loc->line)); + addr_delta = 0; + } else if (loc->bc) { + if (state->precbc->offset > loc->bc->offset) + yasm_internal_error(N_("dwarf2 address went backwards?")); + addr_delta = loc->bc->offset - state->precbc->offset; + } else + return 0; /* ran out of bytecodes! XXX: do something? */ + + /* Generate appropriate opcode(s). Address can only increment, + * whereas line number can go backwards. + */ + line_delta = loc->line - state->line; + state->line = loc->line; + + /* First handle the line delta */ + if (line_delta < DWARF2_LINE_BASE + || line_delta >= DWARF2_LINE_BASE+DWARF2_LINE_RANGE) { + /* Won't fit in special opcode, use (signed) line advance */ + dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_advance_line, + yasm_intnum_create_int(line_delta)); + line_delta = 0; + } + + /* Next handle the address delta */ + opcode1 = DWARF2_LINE_OPCODE_BASE + line_delta - DWARF2_LINE_BASE + + DWARF2_LINE_RANGE * (addr_delta / dbgfmt_dwarf2->min_insn_len); + opcode2 = DWARF2_LINE_OPCODE_BASE + line_delta - DWARF2_LINE_BASE + + DWARF2_LINE_RANGE * ((addr_delta - DWARF2_MAX_SPECIAL_ADDR_DELTA) / + dbgfmt_dwarf2->min_insn_len); + if (line_delta == 0 && addr_delta == 0) { + /* Both line and addr deltas are 0: do DW_LNS_copy */ + dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_copy, NULL); + } else if (addr_delta <= DWARF2_MAX_SPECIAL_ADDR_DELTA && opcode1 <= 255) { + /* Addr delta in range of special opcode */ + dwarf2_dbgfmt_append_line_op(debug_line, opcode1, NULL); + } else if (addr_delta <= 2*DWARF2_MAX_SPECIAL_ADDR_DELTA + && opcode2 <= 255) { + /* Addr delta in range of const_add_pc + special */ + dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_const_add_pc, NULL); + dwarf2_dbgfmt_append_line_op(debug_line, opcode2, NULL); + } else { + /* Need advance_pc */ + dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_advance_pc, + yasm_intnum_create_uint(addr_delta)); + /* Take care of any remaining line_delta and add entry to matrix */ + if (line_delta == 0) + dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_copy, NULL); + else { + unsigned int opcode; + opcode = DWARF2_LINE_OPCODE_BASE + line_delta - DWARF2_LINE_BASE; + dwarf2_dbgfmt_append_line_op(debug_line, opcode, NULL); + } + } + state->precbc = loc->bc; + return 0; +} + +typedef struct dwarf2_line_bc_info { + yasm_section *debug_line; + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2; + dwarf2_line_state *state; + dwarf2_loc loc; + size_t lastfile; +} dwarf2_line_bc_info; + +static int +dwarf2_generate_line_bc(yasm_bytecode *bc, /*@null@*/ void *d) +{ + dwarf2_line_bc_info *info = (dwarf2_line_bc_info *)d; + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = info->dbgfmt_dwarf2; + size_t i; + const char *filename; + /*@null@*/ yasm_bytecode *nextbc = yasm_bc__next(bc); + + if (nextbc && bc->offset == nextbc->offset) + return 0; + + info->loc.vline = bc->line; + info->loc.bc = bc; + + /* Keep track of last symbol seen */ + if (bc->symrecs) { + i = 0; + while (bc->symrecs[i]) { + info->loc.sym = bc->symrecs[i]; + i++; + } + } + + yasm_linemap_lookup(dbgfmt_dwarf2->linemap, bc->line, &filename, + &info->loc.line); + /* Find file index; just linear search it unless it was the last used */ + if (info->lastfile > 0 + && strcmp(filename, dbgfmt_dwarf2->filenames[info->lastfile-1].pathname) + == 0) + info->loc.file = info->lastfile; + else { + for (i=0; ifilenames_size; i++) { + if (strcmp(filename, dbgfmt_dwarf2->filenames[i].pathname) == 0) + break; + } + if (i >= dbgfmt_dwarf2->filenames_size) + yasm_internal_error(N_("could not find filename in table")); + info->loc.file = i+1; + info->lastfile = i+1; + } + if (dwarf2_dbgfmt_gen_line_op(info->debug_line, info->state, &info->loc, + NULL)) + return 1; + return 0; +} + +typedef struct dwarf2_line_info { + yasm_section *debug_line; /* section to which line number info goes */ + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2; + + /* Generate based on bytecodes (1) or locs (0)? Use bytecodes if we're + * generating line numbers for the actual assembly source file. + */ + int asm_source; + + /* number of sections line number info generated for */ + size_t num_sections; + /* last section line number info generated for */ + /*@null@*/ yasm_section *last_code; +} dwarf2_line_info; + +static int +dwarf2_generate_line_section(yasm_section *sect, /*@null@*/ void *d) +{ + dwarf2_line_info *info = (dwarf2_line_info *)d; + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = info->dbgfmt_dwarf2; + /*@null@*/ dwarf2_section_data *dsd; + /*@null@*/ yasm_bytecode *bc; + dwarf2_line_state state; + unsigned long addr_delta; + + dsd = yasm_section_get_data(sect, &yasm_dwarf2__section_data_cb); + if (!dsd) { + if (info->asm_source && yasm_section_is_code(sect)) { + /* Create line data for asm code sections */ + dsd = yasm_xmalloc(sizeof(dwarf2_section_data)); + STAILQ_INIT(&dsd->locs); + yasm_section_add_data(sect, &yasm_dwarf2__section_data_cb, dsd); + } else + return 0; /* no line data for this section */ + } + + info->num_sections++; + info->last_code = sect; + + /* initialize state machine registers for each sequence */ + state.dbgfmt_dwarf2 = dbgfmt_dwarf2; + state.address = 0; + state.file = 1; + state.line = 1; + state.column = 0; + state.isa = 0; + state.is_stmt = DWARF2_LINE_DEFAULT_IS_STMT; + state.precbc = NULL; + + if (info->asm_source) { + dwarf2_line_bc_info bcinfo; + + bcinfo.debug_line = info->debug_line; + bcinfo.dbgfmt_dwarf2 = dbgfmt_dwarf2; + bcinfo.state = &state; + bcinfo.lastfile = 0; + bcinfo.loc.isa_change = 0; + bcinfo.loc.column = 0; + bcinfo.loc.is_stmt = IS_STMT_NOCHANGE; + bcinfo.loc.basic_block = 0; + bcinfo.loc.prologue_end = 0; + bcinfo.loc.epilogue_begin = 0; + bcinfo.loc.sym = NULL; + + /* bcs_traverse() skips first "dummy" bytecode, so look at it + * separately to determine the initial symrec. + */ + bc = yasm_section_bcs_first(sect); + if (bc->symrecs) { + size_t i = 0; + while (bc->symrecs[i]) { + bcinfo.loc.sym = bc->symrecs[i]; + i++; + } + } + + yasm_section_bcs_traverse(sect, &bcinfo, dwarf2_generate_line_bc); + } else { + /*@null@*/ dwarf2_loc *loc; + + dwarf2_dbgfmt_finalize_locs(sect, dsd); + + STAILQ_FOREACH(loc, &dsd->locs, link) { + if (dwarf2_dbgfmt_gen_line_op(info->debug_line, &state, loc, + STAILQ_NEXT(loc, link))) + return 1; + } + } + + /* End sequence: bring address to end of section, then output end + * sequence opcode. Don't use a special opcode to do this as we don't + * want an extra entry in the line matrix. + */ + if (!state.precbc) + state.precbc = yasm_section_bcs_first(sect); + bc = yasm_section_bcs_last(sect); + addr_delta = bc->offset + bc->len - state.precbc->offset; + if (addr_delta == DWARF2_MAX_SPECIAL_ADDR_DELTA) + dwarf2_dbgfmt_append_line_op(info->debug_line, DW_LNS_const_add_pc, + NULL); + else if (addr_delta > 0) + dwarf2_dbgfmt_append_line_op(info->debug_line, DW_LNS_advance_pc, + yasm_intnum_create_uint(addr_delta)); + dwarf2_dbgfmt_append_line_ext_op(info->debug_line, DW_LNE_end_sequence, 0, + NULL); + + return 0; +} + +static int +dwarf2_generate_filename(const char *filename, void *d) +{ + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = (yasm_dbgfmt_dwarf2 *)d; + dwarf2_dbgfmt_add_file(dbgfmt_dwarf2, 0, filename); + return 0; +} + +yasm_section * +yasm_dwarf2__generate_line(yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2, int asm_source, + /*@out@*/ yasm_section **main_code, + /*@out@*/ size_t *num_line_sections) +{ + dwarf2_line_info info; + int new; + size_t i; + yasm_bytecode *last, *sppbc; + dwarf2_spp *spp; + dwarf2_head *head; + + if (asm_source) { + /* Generate dirs and filenames based on linemap */ + yasm_linemap_traverse_filenames(dbgfmt_dwarf2->linemap, dbgfmt_dwarf2, + dwarf2_generate_filename); + } + + info.num_sections = 0; + info.last_code = NULL; + info.asm_source = asm_source; + info.dbgfmt_dwarf2 = dbgfmt_dwarf2; + info.debug_line = yasm_object_get_general(dbgfmt_dwarf2->object, + ".debug_line", 0, 4, 0, 0, &new, + 0); + yasm_section_set_align(info.debug_line, 0, 0); + last = yasm_section_bcs_last(info.debug_line); + + /* header */ + head = yasm_dwarf2__add_head(dbgfmt_dwarf2, info.debug_line, NULL, 0, 0); + + /* statement program prologue */ + spp = yasm_xmalloc(sizeof(dwarf2_spp)); + spp->dbgfmt_dwarf2 = dbgfmt_dwarf2; + sppbc = yasm_bc_create_common(&dwarf2_spp_bc_callback, spp, 0); + sppbc->len = dbgfmt_dwarf2->sizeof_offset + 5 + + NELEMS(line_opcode_num_operands); + + /* directory list */ + for (i=0; idirs_size; i++) + sppbc->len += strlen(dbgfmt_dwarf2->dirs[i])+1; + sppbc->len++; + + /* filename list */ + for (i=0; ifilenames_size; i++) { + if (!dbgfmt_dwarf2->filenames[i].filename) + yasm__error(0, N_("dwarf2 file number %d unassigned"), i+1); + sppbc->len += strlen(dbgfmt_dwarf2->filenames[i].filename) + 1 + + yasm_size_uleb128(dbgfmt_dwarf2->filenames[i].dir) + 2; + } + sppbc->len++; + yasm_dwarf2__append_bc(info.debug_line, sppbc); + + /* statement program */ + yasm_object_sections_traverse(dbgfmt_dwarf2->object, (void *)&info, + dwarf2_generate_line_section); + + /* mark end of line information */ + yasm_dwarf2__set_head_end(head, yasm_section_bcs_last(info.debug_line)); + + *num_line_sections = info.num_sections; + if (info.num_sections == 1) + *main_code = info.last_code; + else + *main_code = NULL; + return info.debug_line; +} + +static void +dwarf2_spp_bc_destroy(void *contents) +{ + yasm_xfree(contents); +} + +static void +dwarf2_spp_bc_print(const void *contents, FILE *f, int indent_level) +{ + /* TODO */ +} + +static yasm_bc_resolve_flags +dwarf2_spp_bc_resolve(yasm_bytecode *bc, int save, + yasm_calc_bc_dist_func calc_bc_dist) +{ + yasm_internal_error(N_("tried to resolve a dwarf2 spp bytecode")); + /*@notreached@*/ + return YASM_BC_RESOLVE_MIN_LEN; +} + +static int +dwarf2_spp_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_expr_func output_expr, + yasm_output_reloc_func output_reloc) +{ + dwarf2_spp *spp = (dwarf2_spp *)bc->contents; + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = spp->dbgfmt_dwarf2; + unsigned char *buf = *bufp; + yasm_intnum *intn, *cval; + size_t i, len; + + /* Prologue length (following this field) */ + cval = yasm_intnum_create_uint(bc->len - (buf-*bufp) - + dbgfmt_dwarf2->sizeof_offset); + yasm_arch_intnum_tobytes(dbgfmt_dwarf2->arch, cval, buf, + dbgfmt_dwarf2->sizeof_offset, + dbgfmt_dwarf2->sizeof_offset*8, 0, bc, 0, 0); + buf += dbgfmt_dwarf2->sizeof_offset; + + YASM_WRITE_8(buf, dbgfmt_dwarf2->min_insn_len); /* minimum_instr_len */ + YASM_WRITE_8(buf, DWARF2_LINE_DEFAULT_IS_STMT); /* default_is_stmt */ + YASM_WRITE_8(buf, DWARF2_LINE_BASE); /* line_base */ + YASM_WRITE_8(buf, DWARF2_LINE_RANGE); /* line_range */ + YASM_WRITE_8(buf, DWARF2_LINE_OPCODE_BASE); /* opcode_base */ + + /* Standard opcode # operands array */ + for (i=0; idirs_size; i++) { + len = strlen(dbgfmt_dwarf2->dirs[i])+1; + memcpy(buf, dbgfmt_dwarf2->dirs[i], len); + buf += len; + } + /* finish with single 0 byte */ + YASM_WRITE_8(buf, 0); + + /* filename list */ + for (i=0; ifilenames_size; i++) { + len = strlen(dbgfmt_dwarf2->filenames[i].filename)+1; + memcpy(buf, dbgfmt_dwarf2->filenames[i].filename, len); + buf += len; + + /* dir */ + buf += yasm_get_uleb128(dbgfmt_dwarf2->filenames[i].dir, buf); + YASM_WRITE_8(buf, 0); /* time */ + YASM_WRITE_8(buf, 0); /* length */ + } + /* finish with single 0 byte */ + YASM_WRITE_8(buf, 0); + + *bufp = buf; + + yasm_intnum_destroy(cval); + return 0; +} + +static void +dwarf2_line_op_bc_destroy(void *contents) +{ + dwarf2_line_op *line_op = (dwarf2_line_op *)contents; + if (line_op->operand) + yasm_intnum_destroy(line_op->operand); + if (line_op->ext_operand) + yasm_expr_destroy(line_op->ext_operand); + yasm_xfree(contents); +} + +static void +dwarf2_line_op_bc_print(const void *contents, FILE *f, int indent_level) +{ + /* TODO */ +} + +static yasm_bc_resolve_flags +dwarf2_line_op_bc_resolve(yasm_bytecode *bc, int save, + yasm_calc_bc_dist_func calc_bc_dist) +{ + yasm_internal_error(N_("tried to resolve a dwarf2 line_op bytecode")); + /*@notreached@*/ + return YASM_BC_RESOLVE_MIN_LEN; +} + +static int +dwarf2_line_op_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_expr_func output_expr, + yasm_output_reloc_func output_reloc) +{ + dwarf2_line_op *line_op = (dwarf2_line_op *)bc->contents; + unsigned char *buf = *bufp; + + YASM_WRITE_8(buf, line_op->opcode); + if (line_op->operand) + buf += yasm_intnum_get_leb128(line_op->operand, buf, + line_op->opcode == DW_LNS_advance_line); + if (line_op->ext_opcode > 0) { + YASM_WRITE_8(buf, line_op->ext_opcode); + if (line_op->ext_operand) { + output_expr(&line_op->ext_operand, buf, line_op->ext_operandsize, + line_op->ext_operandsize*8, 0, + (unsigned long)(buf-*bufp), bc, 0, 0, d); + buf += line_op->ext_operandsize; + } + } + + *bufp = buf; + return 0; +} + +int +yasm_dwarf2__line_directive(yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2, + const char *name, yasm_section *sect, + yasm_valparamhead *valparams, unsigned long line) +{ + if (yasm__strcasecmp(name, "loc") == 0) { + /*@dependent@*/ /*@null@*/ const yasm_intnum *intn; + dwarf2_section_data *dsd; + dwarf2_loc *loc = yasm_xmalloc(sizeof(dwarf2_loc)); + + /* File number (required) */ + yasm_valparam *vp = yasm_vps_first(valparams); + if (!vp || !vp->param) { + yasm__error(line, N_("file number required")); + yasm_xfree(loc); + return 0; + } + intn = yasm_expr_get_intnum(&vp->param, NULL); + if (!intn) { + yasm__error(line, N_("file number is not a constant")); + yasm_xfree(loc); + return 0; + } + if (yasm_intnum_sign(intn) != 1) { + yasm__error(line, N_("file number less than one")); + yasm_xfree(loc); + return 0; + } + loc->file = yasm_intnum_get_uint(intn); + + /* Line number (required) */ + vp = yasm_vps_next(vp); + if (!vp || !vp->param) { + yasm__error(line, N_("line number required")); + yasm_xfree(loc); + return 0; + } + intn = yasm_expr_get_intnum(&vp->param, NULL); + if (!intn) { + yasm__error(line, N_("file number is not a constant")); + yasm_xfree(loc); + return 0; + } + loc->line = yasm_intnum_get_uint(intn); + + /* Generate new section data if it doesn't already exist */ + dsd = yasm_section_get_data(sect, &yasm_dwarf2__section_data_cb); + if (!dsd) { + dsd = yasm_xmalloc(sizeof(dwarf2_section_data)); + STAILQ_INIT(&dsd->locs); + yasm_section_add_data(sect, &yasm_dwarf2__section_data_cb, dsd); + } + + /* Defaults for optional settings */ + loc->column = 0; + loc->isa_change = 0; + loc->isa = 0; + loc->is_stmt = IS_STMT_NOCHANGE; + loc->basic_block = 0; + loc->prologue_end = 0; + loc->epilogue_begin = 0; + + /* Optional column number */ + vp = yasm_vps_next(vp); + if (vp && vp->param) { + intn = yasm_expr_get_intnum(&vp->param, NULL); + if (!intn) { + yasm__error(line, N_("column number is not a constant")); + yasm_xfree(loc); + return 0; + } + loc->column = yasm_intnum_get_uint(intn); + vp = yasm_vps_next(vp); + } + + /* Other options */ + while (vp && vp->val) { + if (yasm__strcasecmp(vp->val, "basic_block") == 0) + loc->basic_block = 1; + else if (yasm__strcasecmp(vp->val, "prologue_end") == 0) + loc->prologue_end = 1; + else if (yasm__strcasecmp(vp->val, "epilogue_begin") == 0) + loc->epilogue_begin = 1; + else if (yasm__strcasecmp(vp->val, "is_stmt") == 0) { + if (!vp->param) { + yasm__error(line, N_("is_stmt requires value")); + yasm_xfree(loc); + return 0; + } + intn = yasm_expr_get_intnum(&vp->param, NULL); + if (!intn) { + yasm__error(line, N_("is_stmt value is not a constant")); + yasm_xfree(loc); + return 0; + } + if (yasm_intnum_is_zero(intn)) + loc->is_stmt = IS_STMT_SET; + else if (yasm_intnum_is_pos1(intn)) + loc->is_stmt = IS_STMT_CLEAR; + else { + yasm__error(line, N_("is_stmt value not 0 or 1")); + yasm_xfree(loc); + return 0; + } + } else if (yasm__strcasecmp(vp->val, "isa") == 0) { + if (!vp->param) { + yasm__error(line, N_("isa requires value")); + yasm_xfree(loc); + return 0; + } + intn = yasm_expr_get_intnum(&vp->param, NULL); + if (!intn) { + yasm__error(line, N_("isa value is not a constant")); + yasm_xfree(loc); + return 0; + } + if (yasm_intnum_sign(intn) < 0) { + yasm__error(line, N_("isa value less than zero")); + yasm_xfree(loc); + return 0; + } + loc->isa_change = 1; + loc->isa = yasm_intnum_get_uint(intn); + } else + yasm__warning(YASM_WARN_GENERAL, line, + N_("unrecognized loc option `%s'"), vp->val); + } + + /* Append new location */ + loc->vline = line; + loc->bc = NULL; + loc->sym = NULL; + STAILQ_INSERT_TAIL(&dsd->locs, loc, link); + + return 0; + } else if (yasm__strcasecmp(name, "file") == 0) { + /*@dependent@*/ /*@null@*/ const yasm_intnum *file_intn; + size_t filenum; + + yasm_valparam *vp = yasm_vps_first(valparams); + + if (vp->val) { + /* Just a bare filename */ + yasm_object_set_source_fn(dbgfmt_dwarf2->object, vp->val); + return 0; + } + + /* Otherwise.. first vp is the file number */ + file_intn = yasm_expr_get_intnum(&vp->param, NULL); + if (!file_intn) { + yasm__error(line, N_("file number is not a constant")); + return 0; + } + filenum = (size_t)yasm_intnum_get_uint(file_intn); + + vp = yasm_vps_next(vp); + if (!vp || !vp->val) { + yasm__error(line, N_("file number given but no filename")); + return 0; + } + + dwarf2_dbgfmt_add_file(dbgfmt_dwarf2, filenum, vp->val); + return 0; + } + return 1; +} + diff --git a/modules/dbgfmts/dwarf2/tests/pass64/dwarf64_2loc.asm b/modules/dbgfmts/dwarf2/tests/pass64/dwarf64_2loc.asm index 2e6c5969..5c7fcc88 100644 --- a/modules/dbgfmts/dwarf2/tests/pass64/dwarf64_2loc.asm +++ b/modules/dbgfmts/dwarf2/tests/pass64/dwarf64_2loc.asm @@ -4,3 +4,5 @@ .loc 1 1 0 .loc 1 2 0 xorq %rax, %rax +.section .debug_info +.byte 1 diff --git a/modules/dbgfmts/dwarf2/tests/pass64/dwarf64_2loc.hex b/modules/dbgfmts/dwarf2/tests/pass64/dwarf64_2loc.hex index 0a8a2eeb..6a6e3f4c 100644 --- a/modules/dbgfmts/dwarf2/tests/pass64/dwarf64_2loc.hex +++ b/modules/dbgfmts/dwarf2/tests/pass64/dwarf64_2loc.hex @@ -38,7 +38,7 @@ 00 00 00 -30 +70 01 00 00 @@ -58,13 +58,14 @@ 00 40 00 -07 +08 00 01 00 48 31 c0 +01 3c 00 00 @@ -129,7 +130,6 @@ fb 00 01 01 -00 32 00 00 @@ -142,7 +142,7 @@ fb 00 00 00 -02 +04 00 00 00 @@ -168,6 +168,18 @@ fb 75 67 5f +69 +6e +66 +6f +00 +2e +64 +65 +62 +75 +67 +5f 6c 69 6e @@ -276,6 +288,54 @@ ff 00 03 00 +06 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +03 +00 +05 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +03 +00 04 00 00 @@ -366,7 +426,11 @@ ff 00 00 00 -34 +00 +00 +00 +00 +40 00 00 00 @@ -398,7 +462,7 @@ ff 00 00 00 -3e +4a 00 00 00 @@ -430,7 +494,7 @@ ff 00 00 00 -24 +30 00 00 00 @@ -454,7 +518,7 @@ ff 00 00 00 -dc +e8 00 00 00 @@ -494,7 +558,7 @@ dc 00 00 00 -2c +38 00 00 00 @@ -518,7 +582,7 @@ dc 00 00 00 -e0 +ec 00 00 00 @@ -526,7 +590,7 @@ e0 00 00 00 -48 +78 00 00 00 @@ -538,7 +602,7 @@ e0 00 00 00 -03 +05 00 00 00 @@ -654,6 +718,70 @@ e0 00 00 00 +01 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +01 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +13 +00 +00 +00 +01 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +44 +00 +00 +00 +00 +00 +00 +00 40 00 00 @@ -686,7 +814,7 @@ e0 00 00 00 -13 +1f 00 00 00 @@ -730,7 +858,7 @@ e0 00 00 00 -05 +06 00 00 00 -- 2.40.0