From: Peter Johnson Date: Wed, 31 May 2006 06:13:01 +0000 (-0000) Subject: Merge [1333]-[1543] (inclusive) into new-optimizer branch. This results in X-Git-Tag: v0.6.0~172^2~34 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=eca4d7c5c26a4308754fe88f8dfce3521e3a1525;p=yasm Merge [1333]-[1543] (inclusive) into new-optimizer branch. This results in a temporary regression of functionality but will yield some benefits later on (chief among them is easier eventual merging back to the mainline!). svn path=/branches/new-optimizer/; revision=1545 --- eca4d7c5c26a4308754fe88f8dfce3521e3a1525 diff --cc frontends/yasm/yasm.c index b00b62a5,f66e9c26..e32f136d --- a/frontends/yasm/yasm.c +++ b/frontends/yasm/yasm.c @@@ -613,37 -627,20 +616,20 @@@ main(int argc, char *argv[] /* Check for undefined symbols */ yasm_symtab_parser_finalize(yasm_object_get_symtab(object), strcmp(cur_parser_module->keyword, "gas")==0, - cur_objfmt); - - if (yasm_get_num_errors(warning_error) > 0) { - yasm_errwarn_output_all(yasm_object_get_linemap(object), warning_error, - print_yasm_error, print_yasm_warning); - cleanup(object); - return EXIT_FAILURE; - } + cur_objfmt, errwarns); + check_errors(errwarns, object); /* Finalize parse */ - yasm_object_finalize(object); - - if (yasm_get_num_errors(warning_error) > 0) { - yasm_errwarn_output_all(yasm_object_get_linemap(object), warning_error, - print_yasm_error, print_yasm_warning); - cleanup(object); - return EXIT_FAILURE; - } + yasm_object_finalize(object, errwarns); + check_errors(errwarns, object); /* Optimize */ - cur_optimizer_module->optimize(object, errwarns); + yasm_object_optimize(object, cur_arch); - - if (yasm_get_num_errors(warning_error) > 0) { - yasm_errwarn_output_all(yasm_object_get_linemap(object), warning_error, - print_yasm_error, print_yasm_warning); - cleanup(object); - return EXIT_FAILURE; - } + check_errors(errwarns, object); /* generate any debugging information */ - yasm_dbgfmt_generate(cur_dbgfmt); + yasm_dbgfmt_generate(cur_dbgfmt, errwarns); + check_errors(errwarns, object); /* open the object file for output (if not already opened by dbg objfmt) */ if (!obj && strcmp(cur_objfmt_module->keyword, "dbg") != 0) { diff --cc libyasm/Makefile.inc index 09391eb8,d411e71a..6582a57a --- a/libyasm/Makefile.inc +++ b/libyasm/Makefile.inc @@@ -1,28 -1,33 +1,36 @@@ # $Id$ + libyasm_a_SOURCES += libyasm/arch.c + libyasm_a_SOURCES += libyasm/assocdat.c + libyasm_a_SOURCES += libyasm/bitvect.c + libyasm_a_SOURCES += libyasm/bc-align.c + libyasm_a_SOURCES += libyasm/bc-data.c + libyasm_a_SOURCES += libyasm/bc-incbin.c + libyasm_a_SOURCES += libyasm/bc-insn.c + libyasm_a_SOURCES += libyasm/bc-org.c + libyasm_a_SOURCES += libyasm/bc-reserve.c libyasm_a_SOURCES += libyasm/bytecode.c + libyasm_a_SOURCES += libyasm/errwarn.c libyasm_a_SOURCES += libyasm/expr.c - libyasm_a_SOURCES += libyasm/symrec.c libyasm_a_SOURCES += libyasm/file.c - libyasm_a_SOURCES += libyasm/section.c - libyasm_a_SOURCES += libyasm/arch.c - libyasm_a_SOURCES += libyasm/objfmt.c - libyasm_a_SOURCES += libyasm/intnum.c libyasm_a_SOURCES += libyasm/floatnum.c libyasm_a_SOURCES += libyasm/hamt.c - libyasm_a_SOURCES += libyasm/bitvect.c - libyasm_a_SOURCES += libyasm/valparam.c - libyasm_a_SOURCES += libyasm/errwarn.c + libyasm_a_SOURCES += libyasm/intnum.c libyasm_a_SOURCES += libyasm/linemgr.c - libyasm_a_SOURCES += libyasm/assocdat.c - libyasm_a_SOURCES += libyasm/xmalloc.c - libyasm_a_SOURCES += libyasm/xstrdup.c - libyasm_a_SOURCES += libyasm/strcasecmp.c + libyasm_a_SOURCES += libyasm/md5.c libyasm_a_SOURCES += libyasm/mergesort.c + libyasm_a_SOURCES += libyasm/phash.c + libyasm_a_SOURCES += libyasm/section.c + libyasm_a_SOURCES += libyasm/strcasecmp.c libyasm_a_SOURCES += libyasm/strsep.c + libyasm_a_SOURCES += libyasm/symrec.c + libyasm_a_SOURCES += libyasm/valparam.c + libyasm_a_SOURCES += libyasm/value.c + libyasm_a_SOURCES += libyasm/xmalloc.c + libyasm_a_SOURCES += libyasm/xstrdup.c +libyasm_a_SOURCES += libyasm/qq.c +libyasm_a_SOURCES += libyasm/stack.c +libyasm_a_SOURCES += libyasm/interval_tree.c libyasm_a_SOURCES += module.c module.c: $(top_srcdir)/libyasm/module.in genmodule$(EXEEXT) Makefile @@@ -50,28 -61,23 +64,25 @@@ modinclude_HEADERS += libyasm/dbgfmt. modinclude_HEADERS += libyasm/errwarn.h modinclude_HEADERS += libyasm/expr.h modinclude_HEADERS += libyasm/expr-int.h - modinclude_HEADERS += libyasm/symrec.h - modinclude_HEADERS += libyasm/linemgr.h - modinclude_HEADERS += libyasm/coretype.h modinclude_HEADERS += libyasm/file.h - modinclude_HEADERS += libyasm/section.h - modinclude_HEADERS += libyasm/arch.h - modinclude_HEADERS += libyasm/dbgfmt.h - modinclude_HEADERS += libyasm/objfmt.h + modinclude_HEADERS += libyasm/floatnum.h + modinclude_HEADERS += libyasm/hamt.h + modinclude_HEADERS += libyasm/intnum.h + modinclude_HEADERS += libyasm/linemgr.h modinclude_HEADERS += libyasm/listfmt.h + modinclude_HEADERS += libyasm/md5.h + modinclude_HEADERS += libyasm/module.h + modinclude_HEADERS += libyasm/objfmt.h -modinclude_HEADERS += libyasm/optimizer.h modinclude_HEADERS += libyasm/parser.h + modinclude_HEADERS += libyasm/phash.h modinclude_HEADERS += libyasm/preproc.h - modinclude_HEADERS += libyasm/intnum.h - modinclude_HEADERS += libyasm/floatnum.h - modinclude_HEADERS += libyasm/hamt.h - modinclude_HEADERS += libyasm/bitvect.h + modinclude_HEADERS += libyasm/section.h + modinclude_HEADERS += libyasm/symrec.h modinclude_HEADERS += libyasm/valparam.h - modinclude_HEADERS += libyasm/compat-queue.h - modinclude_HEADERS += libyasm/assocdat.h - modinclude_HEADERS += libyasm/module.h + modinclude_HEADERS += libyasm/value.h +modinclude_HEADERS += libyasm/qq.h +modinclude_HEADERS += libyasm/stack.h +modinclude_HEADERS += libyasm/interval_tree.h EXTRA_DIST += libyasm/tests/Makefile.inc diff --cc libyasm/arch.h index 9e4efbb3,0d94c7b2..99cc93fc --- a/libyasm/arch.h +++ b/libyasm/arch.h @@@ -248,11 -234,11 +234,17 @@@ typedef struct yasm_arch_module */ unsigned int wordsize; + /** Long/short jump size descriminator. Number of bytes (+/-) a short + * jump can range over. Used to size optimization FIFOs, so don't + * make this extremely large (e.g. >1000). + */ + const unsigned long jmpsize_threshold; ++ + /** Worst case minimum instruction length in bytes. + * Call yasm_arch_min_insn_len() to get the minimum instruction length of + * a particular #yasm_arch. + */ + unsigned int min_insn_len; } yasm_arch_module; #ifdef YASM_LIB_INTERNAL @@@ -604,8 -520,8 +526,10 @@@ yasm_effaddr *yasm_arch_ea_create(yasm_ (((yasm_arch_base *)arch)->module->keyword) #define yasm_arch_wordsize(arch) \ (((yasm_arch_base *)arch)->module->wordsize) +#define yasm_arch_jmpsize_threshold(arch) \ + (((yasm_arch_base *)arch)->module->jmpsize_threshold) + #define yasm_arch_min_insn_len(arch) \ + (((yasm_arch_base *)arch)->module->min_insn_len) #define yasm_arch_create(module, machine, parser, error) \ module->create(machine, parser, error) diff --cc libyasm/bc-align.c index 00000000,ed2fab83..0506a506 mode 000000,100644..100644 --- a/libyasm/bc-align.c +++ b/libyasm/bc-align.c @@@ -1,0 -1,224 +1,239 @@@ + /* + * Align bytecode + * + * Copyright (C) 2005-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. + */ + #define YASM_LIB_INTERNAL + #include "util.h" + /*@unused@*/ RCSID("$Id$"); + + #include "coretype.h" + + #include "errwarn.h" + #include "intnum.h" + #include "expr.h" + + #include "bytecode.h" + + #include "bc-int.h" + + + typedef struct bytecode_align { + /*@only@*/ yasm_expr *boundary; /* alignment boundary */ + + /* What to fill intervening locations with, NULL if using code_fill */ + /*@only@*/ /*@null@*/ yasm_expr *fill; + + /* Maximum number of bytes to skip, NULL if no maximum. */ + /*@only@*/ /*@null@*/ yasm_expr *maxskip; + + /* Code fill, NULL if using 0 fill */ + /*@null@*/ const unsigned char **code_fill; + } bytecode_align; + + static void bc_align_destroy(void *contents); + static void bc_align_print(const void *contents, FILE *f, int indent_level); + static void bc_align_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc); -static yasm_bc_resolve_flags bc_align_resolve - (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist); ++static int bc_align_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, ++ void *add_span_data); ++static int bc_align_expand(yasm_bytecode *bc, int span, long old_val, ++ long new_val, /*@out@*/ long *neg_thres, ++ /*@out@*/ long *pos_thres); + static int bc_align_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_value_func output_value, + /*@null@*/ yasm_output_reloc_func output_reloc); + + static const yasm_bytecode_callback bc_align_callback = { + bc_align_destroy, + bc_align_print, + bc_align_finalize, - bc_align_resolve, ++ bc_align_calc_len, ++ bc_align_expand, + bc_align_tobytes, + 0 + }; + + + static void + bc_align_destroy(void *contents) + { + bytecode_align *align = (bytecode_align *)contents; + if (align->boundary) + yasm_expr_destroy(align->boundary); + if (align->fill) + yasm_expr_destroy(align->fill); + if (align->maxskip) + yasm_expr_destroy(align->maxskip); + yasm_xfree(contents); + } + + static void + bc_align_print(const void *contents, FILE *f, int indent_level) + { + const bytecode_align *align = (const bytecode_align *)contents; + fprintf(f, "%*s_Align_\n", indent_level, ""); + fprintf(f, "%*sBoundary=", indent_level, ""); + yasm_expr_print(align->boundary, f); + fprintf(f, "\n%*sFill=", indent_level, ""); + yasm_expr_print(align->fill, f); + fprintf(f, "\n%*sMax Skip=", indent_level, ""); + yasm_expr_print(align->maxskip, f); + fprintf(f, "\n"); + } + + static void + bc_align_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc) + { + bytecode_align *align = (bytecode_align *)bc->contents; + if (!yasm_expr_get_intnum(&align->boundary, NULL)) + yasm_error_set(YASM_ERROR_NOT_CONSTANT, + N_("align boundary must be a constant")); + if (align->fill && !yasm_expr_get_intnum(&align->fill, NULL)) + yasm_error_set(YASM_ERROR_NOT_CONSTANT, + N_("align fill must be a constant")); + if (align->maxskip && !yasm_expr_get_intnum(&align->maxskip, NULL)) + yasm_error_set(YASM_ERROR_NOT_CONSTANT, + N_("align maximum skip must be a constant")); + } + -static yasm_bc_resolve_flags -bc_align_resolve(yasm_bytecode *bc, int save, - yasm_calc_bc_dist_func calc_bc_dist) ++static int ++bc_align_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, ++ void *add_span_data) + { ++ yasm_internal_error(N_("align not yet implemented")); ++#if 0 + bytecode_align *align = (bytecode_align *)bc->contents; + unsigned long end; + unsigned long boundary = + yasm_intnum_get_uint(yasm_expr_get_intnum(&align->boundary, NULL)); + + if (boundary == 0) { + bc->len = 0; + return YASM_BC_RESOLVE_MIN_LEN; + } + + end = bc->offset; + if (bc->offset & (boundary-1)) + end = (bc->offset & ~(boundary-1)) + boundary; + + bc->len = end - bc->offset; + + if (align->maxskip) { + unsigned long maxskip = + yasm_intnum_get_uint(yasm_expr_get_intnum(&align->maxskip, NULL)); + if ((end - bc->offset) > maxskip) + bc->len = 0; + } - return YASM_BC_RESOLVE_MIN_LEN; ++#endif ++ return 0; ++} ++ ++static int ++bc_align_expand(yasm_bytecode *bc, int span, long old_val, long new_val, ++ /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres) ++{ ++ yasm_internal_error(N_("align not yet implemented")); ++ return 0; + } + + static int + bc_align_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_value_func output_value, + /*@unused@*/ yasm_output_reloc_func output_reloc) + { + bytecode_align *align = (bytecode_align *)bc->contents; + unsigned long len; + unsigned long boundary = + yasm_intnum_get_uint(yasm_expr_get_intnum(&align->boundary, NULL)); + + if (boundary == 0) + return 0; + else { + unsigned long end = bc->offset; + if (bc->offset & (boundary-1)) + end = (bc->offset & ~(boundary-1)) + boundary; + len = end - bc->offset; + if (len == 0) + return 0; + if (align->maxskip) { + unsigned long maxskip = + yasm_intnum_get_uint(yasm_expr_get_intnum(&align->maxskip, + NULL)); + if (len > maxskip) + return 0; + } + } + + if (align->fill) { + unsigned long v; + v = yasm_intnum_get_uint(yasm_expr_get_intnum(&align->fill, NULL)); + memset(*bufp, (int)v, len); + *bufp += len; + } else if (align->code_fill) { + unsigned long maxlen = 15; + while (!align->code_fill[maxlen] && maxlen>0) + maxlen--; + if (maxlen == 0) { + yasm_error_set(YASM_ERROR_GENERAL, + N_("could not find any code alignment size")); + return 1; + } + + /* Fill with maximum code fill as much as possible */ + while (len > maxlen) { + memcpy(*bufp, align->code_fill[maxlen], maxlen); + *bufp += maxlen; + len -= maxlen; + } + + if (!align->code_fill[len]) { + yasm_error_set(YASM_ERROR_VALUE, + N_("invalid alignment size %d"), len); + return 1; + } + /* Handle rest of code fill */ + memcpy(*bufp, align->code_fill[len], len); + *bufp += len; + } else { + /* Just fill with 0 */ + memset(*bufp, 0, len); + *bufp += len; + } + return 0; + } + + yasm_bytecode * + yasm_bc_create_align(yasm_expr *boundary, yasm_expr *fill, + yasm_expr *maxskip, const unsigned char **code_fill, + unsigned long line) + { + bytecode_align *align = yasm_xmalloc(sizeof(bytecode_align)); + + align->boundary = boundary; + align->fill = fill; + align->maxskip = maxskip; + align->code_fill = code_fill; + + return yasm_bc_create_common(&bc_align_callback, align, line); + } diff --cc libyasm/bc-data.c index 00000000,a253534d..c6913bdc mode 000000,100644..100644 --- a/libyasm/bc-data.c +++ b/libyasm/bc-data.c @@@ -1,0 -1,455 +1,456 @@@ + /* + * Data (and LEB128) bytecode + * + * Copyright (C) 2001-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. + */ + #define YASM_LIB_INTERNAL + #include "util.h" + /*@unused@*/ RCSID("$Id$"); + + #include "coretype.h" + + #include "errwarn.h" + #include "intnum.h" + #include "expr.h" + #include "value.h" + + #include "bytecode.h" + #include "arch.h" + + #include "bc-int.h" + + + struct yasm_dataval { + /*@reldef@*/ STAILQ_ENTRY(yasm_dataval) link; + + enum { DV_EMPTY, DV_VALUE, DV_RAW, DV_ULEB128, DV_SLEB128 } type; + + union { + yasm_value val; + struct { + /*@only@*/ unsigned char *contents; + unsigned long len; + } raw; + } data; + }; + + typedef struct bytecode_data { + /* converted data (linked list) */ + yasm_datavalhead datahead; + } bytecode_data; + + static void bc_data_destroy(void *contents); + static void bc_data_print(const void *contents, FILE *f, int indent_level); + static void bc_data_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc); -static yasm_bc_resolve_flags bc_data_resolve - (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist); ++static int bc_data_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, ++ void *add_span_data); + static int bc_data_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_value_func output_value, + /*@null@*/ yasm_output_reloc_func output_reloc); + + static const yasm_bytecode_callback bc_data_callback = { + bc_data_destroy, + bc_data_print, + bc_data_finalize, - bc_data_resolve, ++ bc_data_calc_len, ++ yasm_bc_expand_common, + bc_data_tobytes, + 0 + }; + + + static void + bc_data_destroy(void *contents) + { + bytecode_data *bc_data = (bytecode_data *)contents; + yasm_dvs_destroy(&bc_data->datahead); + yasm_xfree(contents); + } + + static void + bc_data_print(const void *contents, FILE *f, int indent_level) + { + const bytecode_data *bc_data = (const bytecode_data *)contents; + fprintf(f, "%*s_Data_\n", indent_level, ""); + fprintf(f, "%*sElements:\n", indent_level+1, ""); + yasm_dvs_print(&bc_data->datahead, f, indent_level+2); + } + + static void + bc_data_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc) + { + bytecode_data *bc_data = (bytecode_data *)bc->contents; + yasm_dataval *dv; + yasm_intnum *intn; + + /* Convert values from simple expr to value. */ + STAILQ_FOREACH(dv, &bc_data->datahead, link) { + switch (dv->type) { + case DV_VALUE: + if (yasm_value_finalize(&dv->data.val)) { + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("data expression too complex")); + return; + } + break; + case DV_ULEB128: + case DV_SLEB128: + intn = yasm_expr_get_intnum(&dv->data.val.abs, NULL); + if (!intn) { + yasm_error_set(YASM_ERROR_NOT_CONSTANT, + N_("LEB128 requires constant values")); + return; + } + /* Warn for negative values in unsigned environment. + * This could be an error instead: the likelihood this is + * desired is very low! + */ + if (yasm_intnum_sign(intn) == -1 && dv->type == DV_ULEB128) + yasm_warn_set(YASM_WARN_GENERAL, + N_("negative value in unsigned LEB128")); + break; + default: + break; + } + } + } + -static yasm_bc_resolve_flags -bc_data_resolve(yasm_bytecode *bc, int save, - yasm_calc_bc_dist_func calc_bc_dist) ++static int ++bc_data_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, ++ void *add_span_data) + { + bytecode_data *bc_data = (bytecode_data *)bc->contents; + yasm_dataval *dv; + yasm_intnum *intn; + + /* Count up element sizes, rounding up string length. */ + STAILQ_FOREACH(dv, &bc_data->datahead, link) { + switch (dv->type) { + case DV_EMPTY: + break; + case DV_VALUE: + bc->len += dv->data.val.size/8; + break; + case DV_RAW: + bc->len += dv->data.raw.len; + break; + case DV_ULEB128: + case DV_SLEB128: + intn = yasm_expr_get_intnum(&dv->data.val.abs, NULL); + if (!intn) + yasm_internal_error(N_("non-constant in data_tobytes")); + bc->len += + yasm_intnum_size_leb128(intn, dv->type == DV_SLEB128); + break; + } + } + - return YASM_BC_RESOLVE_MIN_LEN; ++ return 0; + } + + static int + bc_data_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_value_func output_value, + /*@unused@*/ yasm_output_reloc_func output_reloc) + { + bytecode_data *bc_data = (bytecode_data *)bc->contents; + yasm_dataval *dv; + unsigned char *bufp_orig = *bufp; + yasm_intnum *intn; + unsigned int val_len; + + STAILQ_FOREACH(dv, &bc_data->datahead, link) { + switch (dv->type) { + case DV_EMPTY: + break; + case DV_VALUE: + val_len = dv->data.val.size/8; + if (output_value(&dv->data.val, *bufp, val_len, + (unsigned long)(*bufp-bufp_orig), bc, 1, d)) + return 1; + *bufp += val_len; + break; + case DV_RAW: + memcpy(*bufp, dv->data.raw.contents, dv->data.raw.len); + *bufp += dv->data.raw.len; + break; + case DV_ULEB128: + case DV_SLEB128: + intn = yasm_expr_get_intnum(&dv->data.val.abs, NULL); + if (!intn) + yasm_internal_error(N_("non-constant in data_tobytes")); + *bufp += + yasm_intnum_get_leb128(intn, *bufp, dv->type == DV_SLEB128); + } + } + + return 0; + } + + yasm_bytecode * + yasm_bc_create_data(yasm_datavalhead *datahead, unsigned int size, + int append_zero, yasm_arch *arch, unsigned long line) + { + bytecode_data *data = yasm_xmalloc(sizeof(bytecode_data)); + yasm_bytecode *bc = yasm_bc_create_common(&bc_data_callback, data, line); + yasm_dataval *dv, *dv2, *dvo; + yasm_intnum *intn; + unsigned long len = 0, rlen, i; + + + yasm_dvs_initialize(&data->datahead); + + /* Prescan input data for length, etc. Careful: this needs to be + * precisely paired with the second loop. + */ + STAILQ_FOREACH(dv, datahead, link) { + switch (dv->type) { + case DV_EMPTY: + break; + case DV_VALUE: + case DV_ULEB128: + case DV_SLEB128: + intn = yasm_expr_get_intnum(&dv->data.val.abs, NULL); + if (intn && dv->type == DV_VALUE && (arch || size == 1)) + len += size; + else if (intn && dv->type == DV_ULEB128) + len += yasm_intnum_size_leb128(intn, 0); + else if (intn && dv->type == DV_SLEB128) + len += yasm_intnum_size_leb128(intn, 1); + else { + if (len > 0) { + /* Create bytecode for all previous len */ + dvo = yasm_dv_create_raw(yasm_xmalloc(len), len); + STAILQ_INSERT_TAIL(&data->datahead, dvo, link); + len = 0; + } + + /* Create bytecode for this value */ + dvo = yasm_xmalloc(sizeof(yasm_dataval)); + STAILQ_INSERT_TAIL(&data->datahead, dvo, link); + } + break; + case DV_RAW: + rlen = dv->data.raw.len; + /* find count, rounding up to nearest multiple of size */ + rlen = (rlen + size - 1) / size; + len += rlen*size; + break; + } + if (append_zero) + len++; + } + + /* Create final dataval for any trailing length */ + if (len > 0) { + dvo = yasm_dv_create_raw(yasm_xmalloc(len), len); + STAILQ_INSERT_TAIL(&data->datahead, dvo, link); + } + + /* Second iteration: copy data and delete input datavals. */ + dv = STAILQ_FIRST(datahead); + dvo = STAILQ_FIRST(&data->datahead); + len = 0; + while (dv) { + switch (dv->type) { + case DV_EMPTY: + break; + case DV_VALUE: + case DV_ULEB128: + case DV_SLEB128: + intn = yasm_expr_get_intnum(&dv->data.val.abs, NULL); + if (intn && dv->type == DV_VALUE && (arch || size == 1)) { + if (size == 1) + yasm_intnum_get_sized(intn, + &dvo->data.raw.contents[len], + 1, 8, 0, 0, 1); + else + yasm_arch_intnum_tobytes(arch, intn, + &dvo->data.raw.contents[len], + size, size*8, 0, bc, 1); + yasm_value_delete(&dv->data.val); + len += size; + } else if (intn && dv->type == DV_ULEB128) { + len += yasm_intnum_get_leb128(intn, + &dvo->data.raw.contents[len], + 0); + } else if (intn && dv->type == DV_SLEB128) { + len += yasm_intnum_get_leb128(intn, + &dvo->data.raw.contents[len], + 1); + } else { + dvo->type = dv->type; + dvo->data.val = dv->data.val; /* structure copy */ + dvo->data.val.size = size*8; /* remember size */ + dvo = STAILQ_NEXT(dvo, link); + len = 0; + } + break; + case DV_RAW: + rlen = dv->data.raw.len; + memcpy(&dvo->data.raw.contents[len], dv->data.raw.contents, + rlen); + yasm_xfree(dv->data.raw.contents); + len += rlen; + /* pad with 0's to nearest multiple of size */ + rlen %= size; + if (rlen > 0) { + rlen = size-rlen; + for (i=0; idata.raw.contents[len++] = 0; + } + break; + } + if (append_zero) + dvo->data.raw.contents[len++] = 0; + dv2 = STAILQ_NEXT(dv, link); + yasm_xfree(dv); + dv = dv2; + } + + return bc; + } + + yasm_bytecode * + yasm_bc_create_leb128(yasm_datavalhead *datahead, int sign, unsigned long line) + { + yasm_dataval *dv; + + /* Convert all values into LEB type, error on strings/raws */ + STAILQ_FOREACH(dv, datahead, link) { + switch (dv->type) { + case DV_VALUE: + dv->type = sign ? DV_SLEB128 : DV_ULEB128; + break; + case DV_RAW: + yasm_error_set(YASM_ERROR_VALUE, + N_("LEB128 does not allow string constants")); + break; + default: + break; + } + } + + return yasm_bc_create_data(datahead, 0, 0, 0, line); + } + + yasm_dataval * + yasm_dv_create_expr(yasm_expr *e) + { + yasm_dataval *retval = yasm_xmalloc(sizeof(yasm_dataval)); + + retval->type = DV_VALUE; + yasm_value_initialize(&retval->data.val, e, 0); + + return retval; + } + + yasm_dataval * + yasm_dv_create_raw(unsigned char *contents, unsigned long len) + { + yasm_dataval *retval = yasm_xmalloc(sizeof(yasm_dataval)); + + retval->type = DV_RAW; + retval->data.raw.contents = contents; + retval->data.raw.len = len; + + return retval; + } + + void + yasm_dvs_destroy(yasm_datavalhead *headp) + { + yasm_dataval *cur, *next; + + cur = STAILQ_FIRST(headp); + while (cur) { + next = STAILQ_NEXT(cur, link); + switch (cur->type) { + case DV_VALUE: + yasm_value_delete(&cur->data.val); + break; + case DV_RAW: + yasm_xfree(cur->data.raw.contents); + break; + default: + break; + } + yasm_xfree(cur); + cur = next; + } + STAILQ_INIT(headp); + } + + yasm_dataval * + yasm_dvs_append(yasm_datavalhead *headp, yasm_dataval *dv) + { + if (dv) { + STAILQ_INSERT_TAIL(headp, dv, link); + return dv; + } + return (yasm_dataval *)NULL; + } + + void + yasm_dvs_print(const yasm_datavalhead *head, FILE *f, int indent_level) + { + yasm_dataval *cur; + unsigned long i; + + STAILQ_FOREACH(cur, head, link) { + switch (cur->type) { + case DV_EMPTY: + fprintf(f, "%*sEmpty\n", indent_level, ""); + break; + case DV_VALUE: + fprintf(f, "%*sValue:\n", indent_level, ""); + yasm_value_print(&cur->data.val, f, indent_level+1); + break; + case DV_RAW: + fprintf(f, "%*sLength=%lu\n", indent_level, "", + cur->data.raw.len); + fprintf(f, "%*sBytes=[", indent_level, ""); + for (i=0; idata.raw.len; i++) + fprintf(f, "0x%02x, ", cur->data.raw.contents[i]); + fprintf(f, "]\n"); + break; + case DV_ULEB128: + fprintf(f, "%*sULEB128 value:\n", indent_level, ""); + yasm_value_print(&cur->data.val, f, indent_level+1); + break; + case DV_SLEB128: + fprintf(f, "%*sSLEB128 value:\n", indent_level, ""); + yasm_value_print(&cur->data.val, f, indent_level+1); + break; + } + } + } + + /* Non-macro yasm_dvs_initialize() for non-YASM_LIB_INTERNAL users. */ + #undef yasm_dvs_initialize + void + yasm_dvs_initialize(yasm_datavalhead *headp) + { + STAILQ_INIT(headp); + } diff --cc libyasm/bc-incbin.c index 00000000,fd7f79e3..7201f8df mode 000000,100644..100644 --- a/libyasm/bc-incbin.c +++ b/libyasm/bc-incbin.c @@@ -1,0 -1,271 +1,260 @@@ + /* + * Incbin bytecode + * + * Copyright (C) 2001-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. + */ + #define YASM_LIB_INTERNAL + #include "util.h" + /*@unused@*/ RCSID("$Id$"); + + #include "coretype.h" + + #include "errwarn.h" + #include "intnum.h" + #include "expr.h" + #include "value.h" + + #include "bytecode.h" + + #include "bc-int.h" + + + typedef struct bytecode_incbin { + /*@only@*/ char *filename; /* file to include data from */ + + /* starting offset to read from (NULL=0) */ + /*@only@*/ /*@null@*/ yasm_expr *start; + + /* maximum number of bytes to read (NULL=no limit) */ + /*@only@*/ /*@null@*/ yasm_expr *maxlen; + } bytecode_incbin; + + static void bc_incbin_destroy(void *contents); + static void bc_incbin_print(const void *contents, FILE *f, int indent_level); + static void bc_incbin_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc); -static yasm_bc_resolve_flags bc_incbin_resolve - (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist); ++static int bc_incbin_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, ++ void *add_span_data); + static int bc_incbin_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_value_func output_value, + /*@null@*/ yasm_output_reloc_func output_reloc); + + static const yasm_bytecode_callback bc_incbin_callback = { + bc_incbin_destroy, + bc_incbin_print, + bc_incbin_finalize, - bc_incbin_resolve, ++ bc_incbin_calc_len, ++ yasm_bc_expand_common, + bc_incbin_tobytes, + 0 + }; + + + static void + bc_incbin_destroy(void *contents) + { + bytecode_incbin *incbin = (bytecode_incbin *)contents; + yasm_xfree(incbin->filename); + yasm_expr_destroy(incbin->start); + yasm_expr_destroy(incbin->maxlen); + yasm_xfree(contents); + } + + static void + bc_incbin_print(const void *contents, FILE *f, int indent_level) + { + const bytecode_incbin *incbin = (const bytecode_incbin *)contents; + fprintf(f, "%*s_IncBin_\n", indent_level, ""); + fprintf(f, "%*sFilename=`%s'\n", indent_level, "", + incbin->filename); + fprintf(f, "%*sStart=", indent_level, ""); + if (!incbin->start) + fprintf(f, "nil (0)"); + else + yasm_expr_print(incbin->start, f); + fprintf(f, "%*sMax Len=", indent_level, ""); + if (!incbin->maxlen) + fprintf(f, "nil (unlimited)"); + else + yasm_expr_print(incbin->maxlen, f); + fprintf(f, "\n"); + } + + static void + bc_incbin_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc) + { + bytecode_incbin *incbin = (bytecode_incbin *)bc->contents; + yasm_value val; + + if (yasm_value_finalize_expr(&val, incbin->start, 0)) + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("start expression too complex")); + else if (val.rel) + yasm_error_set(YASM_ERROR_NOT_ABSOLUTE, + N_("start expression not absolute")); + incbin->start = val.abs; + + if (yasm_value_finalize_expr(&val, incbin->maxlen, 0)) + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("maximum length expression too complex")); + else if (val.rel) + yasm_error_set(YASM_ERROR_NOT_ABSOLUTE, + N_("maximum length expression not absolute")); + incbin->maxlen = val.abs; + } + -static yasm_bc_resolve_flags -bc_incbin_resolve(yasm_bytecode *bc, int save, - yasm_calc_bc_dist_func calc_bc_dist) ++static int ++bc_incbin_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, ++ void *add_span_data) + { + bytecode_incbin *incbin = (bytecode_incbin *)bc->contents; + FILE *f; - /*@null@*/ yasm_expr *temp; - yasm_expr **tempp; + /*@dependent@*/ /*@null@*/ const yasm_intnum *num; + unsigned long start = 0, maxlen = 0xFFFFFFFFUL, flen; + + /* Try to convert start to integer value */ + if (incbin->start) { - if (save) { - temp = NULL; - tempp = &incbin->start; - } else { - temp = yasm_expr_copy(incbin->start); - assert(temp != NULL); - tempp = &temp; - } - num = yasm_expr_get_intnum(tempp, calc_bc_dist); ++ num = yasm_expr_get_intnum(&incbin->start, NULL); + if (num) + start = yasm_intnum_get_uint(num); - yasm_expr_destroy(temp); - if (!num) - return YASM_BC_RESOLVE_UNKNOWN_LEN; ++ if (!num) { ++ /* FIXME */ ++ yasm_error_set(YASM_ERROR_NOT_IMPLEMENTED, ++ N_("incbin does not yet understand non-constant")); ++ return -1; ++ } + } + + /* Try to convert maxlen to integer value */ + if (incbin->maxlen) { - if (save) { - temp = NULL; - tempp = &incbin->maxlen; - } else { - temp = yasm_expr_copy(incbin->maxlen); - assert(temp != NULL); - tempp = &temp; - } - num = yasm_expr_get_intnum(tempp, calc_bc_dist); ++ num = yasm_expr_get_intnum(&incbin->maxlen, NULL); + if (num) + maxlen = yasm_intnum_get_uint(num); - yasm_expr_destroy(temp); - if (!num) - return YASM_BC_RESOLVE_UNKNOWN_LEN; ++ if (!num) { ++ /* FIXME */ ++ yasm_error_set(YASM_ERROR_NOT_IMPLEMENTED, ++ N_("incbin does not yet understand non-constant")); ++ return -1; ++ } + } + + /* FIXME: Search include path for filename. Save full path back into + * filename if save is true. + */ + + /* Open file and determine its length */ + f = fopen(incbin->filename, "rb"); + if (!f) { + yasm_error_set(YASM_ERROR_IO, + N_("`incbin': unable to open file `%s'"), + incbin->filename); - return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN; ++ return -1; + } + if (fseek(f, 0L, SEEK_END) < 0) { + yasm_error_set(YASM_ERROR_IO, + N_("`incbin': unable to seek on file `%s'"), + incbin->filename); - return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN; ++ return -1; + } + flen = (unsigned long)ftell(f); + fclose(f); + + /* Compute length of incbin from start, maxlen, and len */ + if (start > flen) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("`incbin': start past end of file `%s'"), + incbin->filename); + start = flen; + } + flen -= start; + if (incbin->maxlen) + if (maxlen < flen) + flen = maxlen; + bc->len += flen; - return YASM_BC_RESOLVE_MIN_LEN; ++ return 0; + } + + static int + bc_incbin_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_value_func output_value, + /*@unused@*/ yasm_output_reloc_func output_reloc) + { + bytecode_incbin *incbin = (bytecode_incbin *)bc->contents; + FILE *f; + /*@dependent@*/ /*@null@*/ const yasm_intnum *num; + unsigned long start = 0; + + /* Convert start to integer value */ + if (incbin->start) { + num = yasm_expr_get_intnum(&incbin->start, NULL); + if (!num) + yasm_internal_error( + N_("could not determine start in bc_tobytes_incbin")); + start = yasm_intnum_get_uint(num); + } + + /* Open file */ + f = fopen(incbin->filename, "rb"); + if (!f) { + yasm_error_set(YASM_ERROR_IO, N_("`incbin': unable to open file `%s'"), + incbin->filename); + return 1; + } + + /* Seek to start of data */ + if (fseek(f, (long)start, SEEK_SET) < 0) { + yasm_error_set(YASM_ERROR_IO, + N_("`incbin': unable to seek on file `%s'"), + incbin->filename); + fclose(f); + return 1; + } + + /* Read len bytes */ + if (fread(*bufp, 1, (size_t)bc->len, f) < (size_t)bc->len) { + yasm_error_set(YASM_ERROR_IO, + N_("`incbin': unable to read %lu bytes from file `%s'"), + bc->len, incbin->filename); + fclose(f); + return 1; + } + + *bufp += bc->len; + fclose(f); + return 0; + } + + yasm_bytecode * + yasm_bc_create_incbin(char *filename, yasm_expr *start, yasm_expr *maxlen, + unsigned long line) + { + bytecode_incbin *incbin = yasm_xmalloc(sizeof(bytecode_incbin)); + + /*@-mustfree@*/ + incbin->filename = filename; + incbin->start = start; + incbin->maxlen = maxlen; + /*@=mustfree@*/ + + return yasm_bc_create_common(&bc_incbin_callback, incbin, line); + } diff --cc libyasm/bc-insn.c index 00000000,48fb2112..4d3afacb mode 000000,100644..100644 --- a/libyasm/bc-insn.c +++ b/libyasm/bc-insn.c @@@ -1,0 -1,347 +1,348 @@@ + /* + * Insn bytecode + * + * Copyright (C) 2005-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. + */ + #define YASM_LIB_INTERNAL + #include "util.h" + /*@unused@*/ RCSID("$Id$"); + + #include "coretype.h" + + #include "errwarn.h" + #include "expr.h" + #include "value.h" + + #include "bytecode.h" + #include "arch.h" + + #include "bc-int.h" + + + typedef struct bytecode_insn { + /*@dependent@*/ yasm_arch *arch; + unsigned long insn_data[4]; + + int num_operands; + /*@null@*/ yasm_insn_operands operands; + + /* array of 4-element prefix_data arrays */ + int num_prefixes; + /*@null@*/ unsigned long **prefixes; + + /* array of segment prefixes */ + int num_segregs; + /*@null@*/ unsigned long *segregs; + } bytecode_insn; + + static void bc_insn_destroy(void *contents); + static void bc_insn_print(const void *contents, FILE *f, int indent_level); + static void bc_insn_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc); -static yasm_bc_resolve_flags bc_insn_resolve - (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist); ++static int bc_insn_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, ++ void *add_span_data); + static int bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_value_func output_value, + /*@null@*/ yasm_output_reloc_func output_reloc); + + static const yasm_bytecode_callback bc_insn_callback = { + bc_insn_destroy, + bc_insn_print, + bc_insn_finalize, - bc_insn_resolve, ++ bc_insn_calc_len, ++ yasm_bc_expand_common, + bc_insn_tobytes, + 0 + }; + + + yasm_immval * + yasm_imm_create_expr(yasm_expr *e) + { + yasm_immval *im = yasm_xmalloc(sizeof(yasm_immval)); + + if (yasm_value_finalize_expr(&im->val, e, 0)) + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("immediate expression too complex")); + im->sign = 0; + + return im; + } + + const yasm_expr * + yasm_ea_get_disp(const yasm_effaddr *ea) + { + return ea->disp.abs; + } + + void + yasm_ea_set_len(yasm_effaddr *ptr, unsigned int len) + { + if (!ptr) + return; + + /* Currently don't warn if length truncated, as this is called only from + * an explicit override, where we expect the user knows what they're doing. + */ + + ptr->disp.size = (unsigned char)len; + } + + void + yasm_ea_set_nosplit(yasm_effaddr *ptr, unsigned int nosplit) + { + if (!ptr) + return; + + ptr->nosplit = (unsigned char)nosplit; + } + + void + yasm_ea_set_strong(yasm_effaddr *ptr, unsigned int strong) + { + if (!ptr) + return; + + ptr->strong = (unsigned char)strong; + } + + void + yasm_ea_set_segreg(yasm_effaddr *ea, unsigned long segreg) + { + if (!ea) + return; + + if (segreg != 0 && ea->segreg != 0) + yasm_warn_set(YASM_WARN_GENERAL, + N_("multiple segment overrides, using leftmost")); + + ea->segreg = segreg; + } + + /*@-nullstate@*/ + void + yasm_ea_destroy(yasm_effaddr *ea) + { + ea->callback->destroy(ea); + yasm_value_delete(&ea->disp); + yasm_xfree(ea); + } + /*@=nullstate@*/ + + /*@-nullstate@*/ + void + yasm_ea_print(const yasm_effaddr *ea, FILE *f, int indent_level) + { + fprintf(f, "%*sDisp:\n", indent_level, ""); + yasm_value_print(&ea->disp, f, indent_level+1); + fprintf(f, "%*sNoSplit=%u\n", indent_level, "", (unsigned int)ea->nosplit); + ea->callback->print(ea, f, indent_level); + } + /*@=nullstate@*/ + + static void + bc_insn_destroy(void *contents) + { + bytecode_insn *insn = (bytecode_insn *)contents; + if (insn->num_operands > 0) + yasm_ops_delete(&insn->operands, 0); + if (insn->num_prefixes > 0) { + int i; + for (i=0; inum_prefixes; i++) + yasm_xfree(insn->prefixes[i]); + yasm_xfree(insn->prefixes); + } + if (insn->num_segregs > 0) + yasm_xfree(insn->segregs); + yasm_xfree(contents); + } + + static void + bc_insn_print(const void *contents, FILE *f, int indent_level) + { + } + + static void + bc_insn_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc) + { + bytecode_insn *insn = (bytecode_insn *)bc->contents; + int i; + yasm_insn_operand *op; + yasm_error_class eclass; + char *str, *xrefstr; + unsigned long xrefline; + + /* Simplify the operands' expressions first. */ + for (i = 0, op = yasm_ops_first(&insn->operands); + op && inum_operands; op = yasm_operand_next(op), i++) { + /* Check operand type */ + switch (op->type) { + case YASM_INSN__OPERAND_MEMORY: + /* Don't get over-ambitious here; some archs' memory expr + * parser are sensitive to the presence of *1, etc, so don't + * simplify reg*1 identities. + */ + if (op->data.ea) + op->data.ea->disp.abs = + yasm_expr__level_tree(op->data.ea->disp.abs, 1, 1, 0, + NULL, NULL, NULL, NULL); + if (yasm_error_occurred()) { + /* Add a pointer to where it was used to the error */ + yasm_error_fetch(&eclass, &str, &xrefline, &xrefstr); + if (xrefstr) { + yasm_error_set_xref(xrefline, "%s", xrefstr); + yasm_xfree(xrefstr); + } + if (str) { + yasm_error_set(eclass, "%s in memory expression", str); + yasm_xfree(str); + } + return; + } + break; + case YASM_INSN__OPERAND_IMM: + op->data.val = + yasm_expr__level_tree(op->data.val, 1, 1, 1, NULL, NULL, + NULL, NULL); + if (yasm_error_occurred()) { + /* Add a pointer to where it was used to the error */ + yasm_error_fetch(&eclass, &str, &xrefline, &xrefstr); + if (xrefstr) { + yasm_error_set_xref(xrefline, "%s", xrefstr); + yasm_xfree(xrefstr); + } + if (str) { + yasm_error_set(eclass, "%s in immediate expression", + str); + yasm_xfree(str); + } + return; + } + break; + default: + break; + } + } + + yasm_arch_finalize_insn(insn->arch, bc, prev_bc, insn->insn_data, + insn->num_operands, &insn->operands, + insn->num_prefixes, insn->prefixes, + insn->num_segregs, insn->segregs); + } + -static yasm_bc_resolve_flags -bc_insn_resolve(yasm_bytecode *bc, int save, - yasm_calc_bc_dist_func calc_bc_dist) ++static int ++bc_insn_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, ++ void *add_span_data) + { - yasm_internal_error(N_("bc_insn_resolve() is not implemented")); ++ yasm_internal_error(N_("bc_insn_calc_len() is not implemented")); + /*@notreached@*/ - return YASM_BC_RESOLVE_ERROR; ++ return 0; + } + + static int + bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_value_func output_value, + /*@unused@*/ yasm_output_reloc_func output_reloc) + { + yasm_internal_error(N_("bc_insn_tobytes() is not implemented")); + /*@notreached@*/ + return 1; + } + + yasm_bytecode * + yasm_bc_create_insn(yasm_arch *arch, const unsigned long insn_data[4], + int num_operands, /*@null@*/ yasm_insn_operands *operands, + unsigned long line) + { + bytecode_insn *insn = yasm_xmalloc(sizeof(bytecode_insn)); + + insn->arch = arch; + insn->insn_data[0] = insn_data[0]; + insn->insn_data[1] = insn_data[1]; + insn->insn_data[2] = insn_data[2]; + insn->insn_data[3] = insn_data[3]; + insn->num_operands = num_operands; + if (operands) + insn->operands = *operands; /* structure copy */ + else + yasm_ops_initialize(&insn->operands); + insn->num_prefixes = 0; + insn->prefixes = NULL; + insn->num_segregs = 0; + insn->segregs = NULL; + + return yasm_bc_create_common(&bc_insn_callback, insn, line); + } + + yasm_bytecode * + yasm_bc_create_empty_insn(yasm_arch *arch, unsigned long line) + { + bytecode_insn *insn = yasm_xmalloc(sizeof(bytecode_insn)); + + insn->arch = arch; + insn->insn_data[0] = 0; + insn->insn_data[1] = 0; + insn->insn_data[2] = 0; + insn->insn_data[3] = 0; + insn->num_operands = 0; + yasm_ops_initialize(&insn->operands); + insn->num_prefixes = 0; + insn->prefixes = NULL; + insn->num_segregs = 0; + insn->segregs = NULL; + + return yasm_bc_create_common(&bc_insn_callback, insn, line); + } + + void + yasm_bc_insn_add_prefix(yasm_bytecode *bc, const unsigned long prefix_data[4]) + { + bytecode_insn *insn = (bytecode_insn *)bc->contents; + + assert(bc->callback == bc_insn_callback); + + insn->prefixes = + yasm_xrealloc(insn->prefixes, + (insn->num_prefixes+1)*sizeof(unsigned long *)); + insn->prefixes[insn->num_prefixes] = + yasm_xmalloc(4*sizeof(unsigned long)); + insn->prefixes[insn->num_prefixes][0] = prefix_data[0]; + insn->prefixes[insn->num_prefixes][1] = prefix_data[1]; + insn->prefixes[insn->num_prefixes][2] = prefix_data[2]; + insn->prefixes[insn->num_prefixes][3] = prefix_data[3]; + insn->num_prefixes++; + } + + void + yasm_bc_insn_add_seg_prefix(yasm_bytecode *bc, unsigned long segreg) + { + bytecode_insn *insn = (bytecode_insn *)bc->contents; + + assert(bc->callback == bc_insn_callback); + + insn->segregs = + yasm_xrealloc(insn->segregs, + (insn->num_segregs+1)*sizeof(unsigned long)); + insn->segregs[insn->num_segregs] = segreg; + insn->num_segregs++; + } diff --cc libyasm/bc-int.h index 9bdea87c,5bb86357..a25eeb3b --- a/libyasm/bc-int.h +++ b/libyasm/bc-int.h @@@ -59,13 -31,12 +31,14 @@@ typedef struct yasm_bytecode_callback void (*destroy) (/*@only@*/ void *contents); void (*print) (const void *contents, FILE *f, int indent_level); void (*finalize) (yasm_bytecode *bc, yasm_bytecode *prev_bc); - yasm_bc_resolve_flags (*resolve) - (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist); + int (*calc_len) (yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data); + int (*expand) (yasm_bytecode *bc, int span, long old_val, long new_val, + /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres); int (*tobytes) (yasm_bytecode *bc, unsigned char **bufp, void *d, - yasm_output_expr_func output_expr, + yasm_output_value_func output_value, /*@null@*/ yasm_output_reloc_func output_reloc); + int reserve; /* Reserve space instead of outputting data */ } yasm_bytecode_callback; struct yasm_bytecode { diff --cc libyasm/bc-org.c index 00000000,0d4da09f..27760192 mode 000000,100644..100644 --- a/libyasm/bc-org.c +++ b/libyasm/bc-org.c @@@ -1,0 -1,132 +1,147 @@@ + /* + * ORG bytecode + * + * Copyright (C) 2005-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. + */ + #define YASM_LIB_INTERNAL + #include "util.h" + /*@unused@*/ RCSID("$Id$"); + + #include "coretype.h" + #include "file.h" + + #include "errwarn.h" + #include "intnum.h" + #include "expr.h" + #include "value.h" + + #include "bytecode.h" + + #include "bc-int.h" + + + typedef struct bytecode_org { + unsigned long start; /* target starting offset within section */ + } bytecode_org; + + static void bc_org_destroy(void *contents); + static void bc_org_print(const void *contents, FILE *f, int indent_level); + static void bc_org_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc); -static yasm_bc_resolve_flags bc_org_resolve - (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist); ++static int bc_org_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, ++ void *add_span_data); ++static int bc_org_expand(yasm_bytecode *bc, int span, long old_val, ++ long new_val, /*@out@*/ long *neg_thres, ++ /*@out@*/ long *pos_thres); + static int bc_org_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_value_func output_value, + /*@null@*/ yasm_output_reloc_func output_reloc); + + static const yasm_bytecode_callback bc_org_callback = { + bc_org_destroy, + bc_org_print, + bc_org_finalize, - bc_org_resolve, ++ bc_org_calc_len, ++ bc_org_expand, + bc_org_tobytes, + 0 + }; + + + static void + bc_org_destroy(void *contents) + { + yasm_xfree(contents); + } + + static void + bc_org_print(const void *contents, FILE *f, int indent_level) + { + const bytecode_org *org = (const bytecode_org *)contents; + fprintf(f, "%*s_Org_\n", indent_level, ""); + fprintf(f, "%*sStart=%lu\n", indent_level, "", org->start); + } + + static void + bc_org_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc) + { + } + -static yasm_bc_resolve_flags -bc_org_resolve(yasm_bytecode *bc, int save, - yasm_calc_bc_dist_func calc_bc_dist) ++static int ++bc_org_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, ++ void *add_span_data) + { ++ yasm_internal_error(N_("org not yet implemented")); ++#if 0 + bytecode_org *org = (bytecode_org *)bc->contents; + + /* Check for overrun */ + if (bc->offset > org->start) { + yasm_error_set(YASM_ERROR_GENERAL, + N_("ORG overlap with already existing data")); + return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN; + } + + /* Generate space to start offset */ + bc->len = org->start - bc->offset; - return YASM_BC_RESOLVE_MIN_LEN; ++#endif ++ return 0; ++} ++ ++static int ++bc_org_expand(yasm_bytecode *bc, int span, long old_val, long new_val, ++ /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres) ++{ ++ yasm_internal_error(N_("org not yet implemented")); ++ return 0; + } + + static int + bc_org_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_value_func output_value, + /*@unused@*/ yasm_output_reloc_func output_reloc) + { + bytecode_org *org = (bytecode_org *)bc->contents; + unsigned long len, i; + + /* Sanity check for overrun */ + if (bc->offset > org->start) { + yasm_error_set(YASM_ERROR_GENERAL, + N_("ORG overlap with already existing data")); + return 1; + } + len = org->start - bc->offset; + for (i=0; istart = start; + + return yasm_bc_create_common(&bc_org_callback, org, line); + } diff --cc libyasm/bc-reserve.c index 00000000,9e1fa1a7..03280d18 mode 000000,100644..100644 --- a/libyasm/bc-reserve.c +++ b/libyasm/bc-reserve.c @@@ -1,0 -1,162 +1,158 @@@ + /* + * Bytecode utility functions + * + * Copyright (C) 2001 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. + */ + #define YASM_LIB_INTERNAL + #include "util.h" + /*@unused@*/ RCSID("$Id$"); + + #include "coretype.h" + + #include "errwarn.h" + #include "intnum.h" + #include "expr.h" + #include "value.h" + + #include "bytecode.h" + + #include "bc-int.h" + #include "expr-int.h" + + + typedef struct bytecode_reserve { + /*@only@*/ /*@null@*/ yasm_expr *numitems; /* number of items to reserve */ + unsigned char itemsize; /* size of each item (in bytes) */ + } bytecode_reserve; + + static void bc_reserve_destroy(void *contents); + static void bc_reserve_print(const void *contents, FILE *f, int indent_level); + static void bc_reserve_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc); -static yasm_bc_resolve_flags bc_reserve_resolve - (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist); ++static int bc_reserve_calc_len(yasm_bytecode *bc, ++ yasm_bc_add_span_func add_span, ++ void *add_span_data); + static int bc_reserve_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_value_func output_value, + /*@null@*/ yasm_output_reloc_func output_reloc); + + static const yasm_bytecode_callback bc_reserve_callback = { + bc_reserve_destroy, + bc_reserve_print, + bc_reserve_finalize, - bc_reserve_resolve, ++ bc_reserve_calc_len, ++ yasm_bc_expand_common, + bc_reserve_tobytes, + 1 + }; + + + static void + bc_reserve_destroy(void *contents) + { + bytecode_reserve *reserve = (bytecode_reserve *)contents; + yasm_expr_destroy(reserve->numitems); + yasm_xfree(contents); + } + + static void + bc_reserve_print(const void *contents, FILE *f, int indent_level) + { + const bytecode_reserve *reserve = (const bytecode_reserve *)contents; + fprintf(f, "%*s_Reserve_\n", indent_level, ""); + fprintf(f, "%*sNum Items=", indent_level, ""); + yasm_expr_print(reserve->numitems, f); + fprintf(f, "\n%*sItem Size=%u\n", indent_level, "", + (unsigned int)reserve->itemsize); + } + + static void + bc_reserve_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc) + { + bytecode_reserve *reserve = (bytecode_reserve *)bc->contents; + yasm_value val; + + if (yasm_value_finalize_expr(&val, reserve->numitems, 0)) + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("reserve expression too complex")); + else if (val.rel) + yasm_error_set(YASM_ERROR_NOT_ABSOLUTE, + N_("reserve expression not absolute")); + else if (val.abs && yasm_expr__contains(val.abs, YASM_EXPR_FLOAT)) + yasm_error_set(YASM_ERROR_VALUE, + N_("expression must not contain floating point value")); + reserve->numitems = val.abs; + } + -static yasm_bc_resolve_flags -bc_reserve_resolve(yasm_bytecode *bc, int save, - yasm_calc_bc_dist_func calc_bc_dist) ++static int ++bc_reserve_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, ++ void *add_span_data) + { + bytecode_reserve *reserve = (bytecode_reserve *)bc->contents; - yasm_bc_resolve_flags retval = YASM_BC_RESOLVE_MIN_LEN; - /*@null@*/ yasm_expr *temp; - yasm_expr **tempp; + /*@dependent@*/ /*@null@*/ const yasm_intnum *num; + + if (!reserve->numitems) - return YASM_BC_RESOLVE_MIN_LEN; - - if (save) { - temp = NULL; - tempp = &reserve->numitems; - } else { - temp = yasm_expr_copy(reserve->numitems); - assert(temp != NULL); - tempp = &temp; - } - num = yasm_expr_get_intnum(tempp, calc_bc_dist); ++ return 0; ++ ++ num = yasm_expr_get_intnum(&reserve->numitems, NULL); + if (!num) { - /* For reserve, just say non-constant quantity instead of allowing - * the circular reference error to filter through. - */ ++ /* Check for use of floats first. */ ++ if (reserve->numitems && ++ yasm_expr__contains(reserve->numitems, YASM_EXPR_FLOAT)) { ++ yasm_error_set(YASM_ERROR_VALUE, ++ N_("expression must not contain floating point value")); ++ return -1; ++ } ++ /* FIXME: Non-constant currently not allowed. */ + yasm_error_set(YASM_ERROR_NOT_CONSTANT, + N_("attempt to reserve non-constant quantity of space")); - retval = YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN; - } else - bc->len += yasm_intnum_get_uint(num)*reserve->itemsize; - yasm_expr_destroy(temp); - return retval; ++ return -1; ++ } ++ ++ bc->len += yasm_intnum_get_uint(num)*reserve->itemsize; ++ return 0; + } + + static int + bc_reserve_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_value_func output_value, + /*@unused@*/ yasm_output_reloc_func output_reloc) + { + yasm_internal_error(N_("bc_reserve_tobytes called")); + /*@notreached@*/ + return 1; + } + + yasm_bytecode * + yasm_bc_create_reserve(yasm_expr *numitems, unsigned int itemsize, + unsigned long line) + { + bytecode_reserve *reserve = yasm_xmalloc(sizeof(bytecode_reserve)); + + /*@-mustfree@*/ + reserve->numitems = numitems; + /*@=mustfree@*/ + reserve->itemsize = (unsigned char)itemsize; + + return yasm_bc_create_common(&bc_reserve_callback, reserve, line); + } diff --cc libyasm/bytecode.c index daffb2ba,7138b3ce..e008da1a --- a/libyasm/bytecode.c +++ b/libyasm/bytecode.c @@@ -1286,91 -170,78 +179,80 @@@ yasm_bc_finalize(yasm_bytecode *bc, yas } /*@null@*/ yasm_intnum * - yasm_common_calc_bc_dist(/*@null@*/ yasm_bytecode *precbc1, - /*@null@*/ yasm_bytecode *precbc2) + yasm_common_calc_bc_dist(yasm_bytecode *precbc1, yasm_bytecode *precbc2) { - unsigned int dist; + unsigned long dist; yasm_intnum *intn; - if (precbc2) { - dist = precbc2->offset + precbc2->len; - if (precbc1) { - if (dist < precbc1->offset + precbc1->len) { - intn = yasm_intnum_create_uint(precbc1->offset + precbc1->len - - dist); - yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL, precbc1->line); - return intn; - } - dist -= precbc1->offset + precbc1->len; - } - return yasm_intnum_create_uint(dist); - } else { - if (precbc1) { - intn = yasm_intnum_create_uint(precbc1->offset + precbc1->len); - yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL, precbc1->line); - return intn; - } else { - return yasm_intnum_create_uint(0); - } + if (precbc1->section != precbc2->section) + return NULL; + + dist = precbc2->offset + precbc2->len; + if (dist < precbc1->offset + precbc1->len) { + intn = yasm_intnum_create_uint(precbc1->offset + precbc1->len - dist); + yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL); + return intn; } + dist -= precbc1->offset + precbc1->len; + return yasm_intnum_create_uint(dist); } -yasm_bc_resolve_flags -yasm_bc_resolve(yasm_bytecode *bc, int save, - yasm_calc_bc_dist_func calc_bc_dist) +int +yasm_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) { - yasm_bc_resolve_flags retval = YASM_BC_RESOLVE_MIN_LEN; - /*@null@*/ yasm_expr *temp; - yasm_expr **tempp; - /*@dependent@*/ /*@null@*/ const yasm_intnum *num; + int retval = 0; - bc->len = 0; /* start at 0 */ + bc->len = 0; if (!bc->callback) yasm_internal_error(N_("got empty bytecode in bc_resolve")); else - retval = bc->callback->resolve(bc, save, calc_bc_dist); - - /* Multiply len by number of multiples */ + retval = bc->callback->calc_len(bc, add_span, add_span_data); +#if 0 + /* Check for multiples */ if (bc->multiple) { - if (save) { - temp = NULL; - tempp = &bc->multiple; - } else { - temp = yasm_expr_copy(bc->multiple); - assert(temp != NULL); - tempp = &temp; - } - num = yasm_expr_get_intnum(tempp, calc_bc_dist); + /*@dependent@*/ /*@null@*/ const yasm_intnum *num; + + num = yasm_expr_get_intnum(&bc->multiple, NULL); if (!num) { - retval = YASM_BC_RESOLVE_UNKNOWN_LEN; - if (temp && yasm_expr__contains(temp, YASM_EXPR_FLOAT)) { + if (yasm_expr__contains(bc->multiple, YASM_EXPR_FLOAT)) { - yasm__error(bc->line, + yasm_error_set(YASM_ERROR_VALUE, N_("expression must not contain floating point value")); - retval |= YASM_BC_RESOLVE_ERROR; + retval = -1; + } else { + /* FIXME: Non-constant currently not allowed. */ + yasm__error(bc->line, + N_("attempt to use non-constant multiple")); + retval = -1; } - } else { - if (yasm_intnum_sign(num) >= 0) - bc->len *= yasm_intnum_get_uint(num); - else - retval |= YASM_BC_RESOLVE_ERROR; } - yasm_expr_destroy(temp); } - +#endif /* If we got an error somewhere along the line, clear out any calc len */ - if (retval & YASM_BC_RESOLVE_UNKNOWN_LEN) + if (retval < 0) bc->len = 0; return retval; } +int +yasm_bc_expand(yasm_bytecode *bc, int span, long old_val, long new_val, + /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres) +{ + if (!bc->callback) { + yasm_internal_error(N_("got empty bytecode in bc_set_long")); + /*@unreached@*/ + return 0; + } else + return bc->callback->expand(bc, span, old_val, new_val, neg_thres, + pos_thres); +} + /*@null@*/ /*@only@*/ unsigned char * yasm_bc_tobytes(yasm_bytecode *bc, unsigned char *buf, unsigned long *bufsize, - /*@out@*/ unsigned long *multiple, /*@out@*/ int *gap, - void *d, yasm_output_expr_func output_expr, + /*@out@*/ int *gap, void *d, + yasm_output_value_func output_value, /*@null@*/ yasm_output_reloc_func output_reloc) /*@sets *buf@*/ { diff --cc libyasm/bytecode.h index 8260c88e,621bd052..181d1bb5 --- a/libyasm/bytecode.h +++ b/libyasm/bytecode.h @@@ -47,14 -89,14 +89,6 @@@ typedef struct yasm_datavalhead yasm_da /*@reldef@*/ STAILQ_HEAD(yasm_datavalhead, yasm_dataval); #endif - /** Create an immediate value from an unsigned integer. - * \param int_val unsigned integer - * \param line virtual line (from yasm_linemap) - * \return Newly allocated immediate value. - */ - /*@only@*/ yasm_immval *yasm_imm_create_int(unsigned long int_val, - unsigned long line); -/** Return value flags for yasm_bc_resolve(). */ -typedef enum { - YASM_BC_RESOLVE_NONE = 0, /**< Ok, but length is not minimum. */ - YASM_BC_RESOLVE_ERROR = 1<<0, /**< Error found, output. */ - YASM_BC_RESOLVE_MIN_LEN = 1<<1, /**< Length is minimum possible. */ - YASM_BC_RESOLVE_UNKNOWN_LEN = 1<<2 /**< Length indeterminate. */ -} yasm_bc_resolve_flags; -- /** Create an immediate value from an expression. * \param e expression (kept, do not free). * \return Newly allocated immediate value. @@@ -270,47 -312,27 +304,50 @@@ void yasm_bc_finalize(yasm_bytecode *bc * yasm_expr output functions. * \see yasm_calc_bc_dist_func for parameter descriptions. */ - /*@null@*/ yasm_intnum *yasm_common_calc_bc_dist - (/*@null@*/ yasm_bytecode *precbc1, /*@null@*/ yasm_bytecode *precbc2); + /*@null@*/ /*@only@*/ yasm_intnum *yasm_common_calc_bc_dist + (yasm_bytecode *precbc1, yasm_bytecode *precbc2); -/** Resolve labels in a bytecode, and calculate its length. - * Tries to minimize the length as much as possible. - * \note Sometimes it's impossible to determine if a length is the minimum - * possible. In this case, this function returns that the length is NOT - * the minimum. +/** - * \param critical dependent expression for bytecode expansion ++ * \param value dependent value for bytecode expansion ++ * \param origin_prevbc origin for distance computation to relative portion of ++ * value; value.rel and origin must be within the same ++ * section. + * \param neg_thres negative threshold for long/short decision + * \param pos_thres positive threshold for long/short decision + */ +typedef void (*yasm_bc_add_span_func) - (void *add_span_data, yasm_bytecode *bc, int id, - /*@only@*/ yasm_expr *dependent, long neg_thres, long pos_thres); ++ (void *add_span_data, yasm_bytecode *bc, int id, yasm_value *value, ++ /*@null@*/ yasm_bytecode *origin_prevbc, long neg_thres, long pos_thres); + +/** Resolve EQUs in a bytecode and calculate its minimum size. - * Returns dependent bytecode spans for cases where, if the length spanned ++ * Generates dependent bytecode spans for cases where, if the length spanned + * increases, it could cause the bytecode size to increase. + * Any bytecode multiple is NOT included in the length or spans generation; + * this must be handled at a higher level. + * \param bc bytecode + * \return 0 if no error occurred, nonzero if there was an error recognized + * (and output) during execution. + * \note May store to bytecode updated expressions and the short length. + */ +int yasm_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data); + +/** Recalculate a bytecode's length based on an expanded span length. * \param bc bytecode - * \param save when zero, this function does \em not modify bc other - * than the length/size values (i.e. it doesn't keep the - * values returned by calc_bc_dist except temporarily to - * try to minimize the length); when nonzero, all fields - * in bc may be modified by this function - * \param calc_bc_dist function used to determine bytecode distance - * \return Flags indicating whether the length is the minimum possible, - * indeterminate, and if there was an error recognized (and output) - * during execution. + * \param span span ID (as given to yasm_bc_add_span_func in + * yasm_bc_calc_len) + * \param old_val previous span value + * \param new_val new span value + * \param neg_thres negative threshold for long/short decision (returned) + * \param pos_thres postivie threshold for long/short decision (returned) + * \return 0 if bc no longer dependent on this span's length, negative if + * there was an error recognized (and output) during execution, and + * positive if bc size may increase for this span further based on the + * new negative and positive thresholds returned. + * \note May store to bytecode updated expressions and the updated length. */ -yasm_bc_resolve_flags yasm_bc_resolve(yasm_bytecode *bc, int save, - yasm_calc_bc_dist_func calc_bc_dist); +int yasm_bc_expand(yasm_bytecode *bc, int span, long old_val, long new_val, + /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres); /** Convert a bytecode into its byte representation. * \param bc bytecode diff --cc libyasm/intnum.c index b8e0a5ac,160d5dd4..94b8e733 --- a/libyasm/intnum.c +++ b/libyasm/intnum.c @@@ -650,47 -789,9 +789,46 @@@ yasm_intnum_check_size(const yasm_intnu return (Set_Max(val) < (long)size); } +int +yasm_intnum_in_range(const yasm_intnum *intn, long low, long high) +{ + wordptr val = result; + wordptr lval = op1static; + wordptr hval = op2static; + + /* If not already a bitvect, convert value to be written to a bitvect */ + if (intn->type == INTNUM_BV) + val = intn->val.bv; + else { + BitVector_Empty(val); + BitVector_Chunk_Store(val, 32, 0, intn->val.ul); + } + + /* Convert high and low to bitvects */ + BitVector_Empty(lval); + if (low >= 0) + BitVector_Chunk_Store(lval, 32, 0, (unsigned long)low); + else { + BitVector_Chunk_Store(lval, 32, 0, (unsigned long)(-low)); + BitVector_Negate(lval, lval); + } + + BitVector_Empty(hval); + if (high >= 0) + BitVector_Chunk_Store(hval, 32, 0, (unsigned long)high); + else { + BitVector_Chunk_Store(hval, 32, 0, (unsigned long)(-high)); + BitVector_Negate(hval, hval); + } + + /* Compare! */ + return (BitVector_Compare(val, lval) >= 0 + && BitVector_Compare(val, hval) <= 0); +} + - unsigned long - yasm_intnum_get_leb128(const yasm_intnum *intn, unsigned char *ptr, int sign) + static unsigned long + get_leb128(wordptr val, unsigned char *ptr, int sign) { - wordptr val = op1static; unsigned long i, size; unsigned char *ptr_orig = ptr; diff --cc libyasm/section.c index 346f18c7,f351d636..241805ab --- a/libyasm/section.c +++ b/libyasm/section.c @@@ -536,265 -601,3 +605,276 @@@ yasm_section_print(const yasm_section * } } } + +/* + * Robertson (1977) optimizer + * Based (somewhat loosely) on the algorithm given in: + * MRC Technical Summary Report # 1779 + * CODE GENERATION FOR SHORT/LONG ADDRESS MACHINES + * Edward L. Robertson + * Mathematics Research Center + * University of Wisconsin-Madison + * 610 Walnut Street + * Madison, Wisconsin 53706 + * August 1977 + * + * Key components of algorithm: + * - start assuming all short forms + * - build spans for short->long transition dependencies + * - if a long form is needed, walk the dependencies and update + * Major differences from Robertson's algorithm: + * - detection of cycles + * - any difference of two locations is allowed + * - handling of alignment gaps + * - handling of multiples + * + * Data structures: + * - Interval tree to store spans and associated data + * - Queue Q + * + * Each span keeps track of: + * - Associated bytecode (bytecode that depends on the span length) + * - Active/inactive state (starts out active) + * - Sign (negative/positive; negative being "backwards" in address) + * - Current length in bytes + * - New length in bytes + * - Negative/Positive thresholds + * - Span ID (unique within each bytecode) + * + * How org and align are handled: + * Some portions are critical values that must not depend on any bytecode + * offset (either relative or absolute). + * + * ALIGN: 0 length (always). Bump offset to alignment. Span from 0 to + * align bytecode, update on any change. If span length + * increases past alignment, increase offset by alignment and update + * dependent spans. Alignment is critical value. + * ORG: Same as align, but if span's length exceeds org value, error. + * ORG value is critical value. + * + * How times is handled: + * + * TIMES: Handled separately from bytecode "raw" size. If not span-dependent, + * trivial (just multiplied in at any bytecode size increase). Span + * dependent times update on any change (span ID 0). If the resultant + * next bytecode offset would be less than the old next bytecode offset, + * error. Otherwise increase offset and update dependent spans. + * + * To reduce interval tree size, a first expansion pass is performed + * before the spans are added to the tree. + * + * Basic algorithm outline: + * + * 1. Initialization: + * a. Number bytecodes sequentially (via bc_index) and calculate offsets + * of all bytecodes assuming minimum length, building a list of all + * dependent spans as we go. + * "minimum" here means absolute minimum: + * - align 0 length + * - times values (with span-dependent values) assumed to be 0 + * - org bumps offset + * b. Iterate over spans. Set span length based on bytecode offsets + * determined in 1a. If span is "certainly" long because the span + * is an absolute reference to another section (or external) or the + * distance calculated based on the minimum length is greater than the + * span's threshold, expand the span's bytecode, and if no further + * expansion can result, delete the span. Otherwise (or if the + * expansion results in another threshold of expansion), add span to + * interval tree. + * c. Iterate over bytecodes to update all bytecode offsets based on new + * (expanded) lengths calculated in 1b. + * d. Iterate over spans. Update span's length based on new bytecode offsets + * determined in 1c. If span's length exceeds long threshold, add that + * span to Q. + * 2. Main loop: + * While Q not empty: + * Expand BC dependent on span at head of Q (and remove span from Q). + * Update span: + * If BC no longer dependent on span, mark span as inactive. + * If BC has new thresholds for span, update span. + * If BC increased in size, for each active span that contains BC: + * Increase span length by difference between short and long BC length. + * If span exceeds long threshold (or is flagged to recalculate on any + * change), add it to tail of Q. + * 3. Final pass over bytecodes to generate final offsets. + */ + +typedef struct yasm_span { + /*@reldef@*/ STAILQ_ENTRY(yasm_span) link; + + /*@dependent@*/ yasm_bytecode *bc; + - /*@owned@*/ yasm_expr *dependent; ++ yasm_value *depval; ++ yasm_bytecode *origin_prevbc; + + /* Special handling: see descriptions above */ + enum { + NOT_SPECIAL = 0, + SPECIAL_ALIGN, + SPECIAL_ORG, + SPECIAL_TIMES + } special; + + long cur_val; + long new_val; + + long neg_thres; + long pos_thres; + + int id; + + int active; +} yasm_span; + +typedef struct optimize_data { + /*@reldef@*/ STAILQ_HEAD(yasm_spanhead, yasm_span) spans; +} optimize_data; + +static void +optimize_add_span(void *add_span_data, yasm_bytecode *bc, int id, - /*@only@*/ yasm_expr *dependent, long neg_thres, - long pos_thres) ++ yasm_value *value, /*@null@*/ yasm_bytecode *origin_prevbc, ++ long neg_thres, long pos_thres) +{ + optimize_data *optd = (optimize_data *)add_span_data; + yasm_span *span = yasm_xmalloc(sizeof(yasm_span)); + + span->bc = bc; - span->dependent = dependent; ++ span->depval = value; ++ span->origin_prevbc = origin_prevbc; + span->special = NOT_SPECIAL; + span->cur_val = 0; + span->new_val = 0; + span->neg_thres = neg_thres; + span->pos_thres = pos_thres; + span->id = id; + span->active = 1; + + STAILQ_INSERT_TAIL(&optd->spans, span, link); +} + +static void +update_all_bc_offsets(yasm_object *object) +{ + yasm_section *sect; + + STAILQ_FOREACH(sect, &object->sections, link) { + unsigned long offset = 0; + + yasm_bytecode *cur = STAILQ_FIRST(§->bcs); + yasm_bytecode *prev; + + /* Skip our locally created empty bytecode first. */ + prev = cur; + cur = STAILQ_NEXT(cur, link); + + /* Iterate through the remainder, if any. */ + while (cur) { + cur->offset = offset; + offset += cur->len; + prev = cur; + cur = STAILQ_NEXT(cur, link); + } + } +} + +void +yasm_object_optimize(yasm_object *object, yasm_arch *arch) +{ + yasm_section *sect; + unsigned long bc_index = 0; + int saw_error = 0; + optimize_data optd; + yasm_span *span; + long neg_thres, pos_thres; + + STAILQ_INIT(&optd.spans); + + /* Step 1a */ + STAILQ_FOREACH(sect, &object->sections, link) { + unsigned long offset = 0; + + yasm_bytecode *cur = STAILQ_FIRST(§->bcs); + yasm_bytecode *prev; + + cur->bc_index = bc_index++; + + /* Skip our locally created empty bytecode first. */ + prev = cur; + cur = STAILQ_NEXT(cur, link); + + /* Iterate through the remainder, if any. */ + while (cur) { + cur->bc_index = bc_index++; + + if (yasm_bc_calc_len(cur, optimize_add_span, &optd)) + saw_error = 1; + + /* TODO: times */ + if (cur->multiple) + yasm_internal_error("multiple not yet supported"); + + cur->offset = offset; + offset += cur->len; + prev = cur; + cur = STAILQ_NEXT(cur, link); + } + } + + if (saw_error) + return; - ++#if 0 + /* Step 1b */ + STAILQ_FOREACH(span, &optd.spans, link) { - yasm_expr *depcopy = yasm_expr_copy(span->dependent); - yasm_intnum *intn = - yasm_expr_get_intnum(&depcopy, yasm_common_calc_bc_dist); - if (intn) - span->new_val = yasm_intnum_get_int(intn); - else { - /* absolute, external, or too complex; force to longer form */ - span->new_val = LONG_MAX; - span->active = 0; ++ /* Handle absolute portion */ ++ if (span->depval->abs) { ++ yasm_expr *depcopy = yasm_expr_copy(span->depval->abs); ++ yasm_intnum *intn = ++ yasm_expr_get_intnum(&depcopy, yasm_common_calc_bc_dist); ++ if (intn) ++ span->new_val = yasm_intnum_get_int(intn); ++ else { ++ /* absolute, external, or too complex; force to longer form */ ++ span->new_val = LONG_MAX; ++ span->active = 0; ++ } ++ yasm_expr_destroy(depcopy); ++ } else ++ span->new_val = 0; ++ ++ /* Handle relative portion */ ++ if (span->depval->rel && span->new_val != LONG_MAX) { ++ span->new_val += + } + + if (span->new_val < span->neg_thres + || span->new_val > span->pos_thres) { + int retval = yasm_bc_expand(span->bc, span->id, span->cur_val, + span->new_val, &neg_thres, &pos_thres); + if (retval < 0) + saw_error = 1; + else if (retval > 0) { + span->neg_thres = neg_thres; + span->pos_thres = pos_thres; + } else + span->active = 0; + } + span->cur_val = span->new_val; - yasm_expr_destroy(depcopy); + } - ++#endif + if (saw_error) + return; + + /* Step 1c */ + update_all_bc_offsets(object); + + /* Step 1d */ + STAILQ_FOREACH(span, &optd.spans, link) { + if (!span->active) + continue; + } + + /* Step 2 */ + + /* Step 3 */ + update_all_bc_offsets(object); +} diff --cc modules/arch/lc3b/lc3barch.c index 7691b081,4792b070..cefbeb19 --- a/modules/arch/lc3b/lc3barch.c +++ b/modules/arch/lc3b/lc3barch.c @@@ -188,6 -198,6 +198,7 @@@ yasm_arch_module yasm_lc3b_LTX_arch = lc3b_ea_create_expr, lc3b_machines, "lc3b", - 2, - 512 + 16, ++ 512, + 2 }; diff --cc modules/arch/x86/x86arch.c index be37760e,52e486c1..72b2b4da --- a/modules/arch/x86/x86arch.c +++ b/modules/arch/x86/x86arch.c @@@ -383,6 -461,6 +461,7 @@@ yasm_arch_module yasm_x86_LTX_arch = yasm_x86__ea_create_expr, x86_machines, "x86", - 2, - 128 + 16, ++ 128, + 1 }; diff --cc modules/arch/x86/x86arch.h index 7065f487,88ed771d..725d3d97 --- a/modules/arch/x86/x86arch.h +++ b/modules/arch/x86/x86arch.h @@@ -187,44 -204,43 +204,17 @@@ typedef struct x86_insn /* None */ X86_POSTOP_NONE = 0, -- /* Shift opcodes have an immediate form and a ,1 form (with no -- * immediate). In the parser, we set this and opcode_len=1, but store - * the non-,1 version in the second byte of the opcode array. We then - * the ,1 version in the second byte of the opcode array. We then -- * choose between the two versions once we know the actual value of -- * imm (because we don't know it in the parser module). -- * -- * A override to force the imm version should just leave this at -- * 0. Then later code won't know the ,1 version even exists. -- * TODO: Figure out how this affects CPU flags processing. -- */ -- X86_POSTOP_SHIFT, -- /* Instructions that take a sign-extended imm8 as well as imm values * (eg, the arith instructions and a subset of the imul instructions) - * should set this and put the non-imm8 form in the second byte of the - * should set this and put the imm8 form in the second byte of the -- * opcode. ++ * should set this and put the imm8 form in the second (and possibly ++ * third) byte of the opcode. */ X86_POSTOP_SIGNEXT_IMM8, -- /* Long (modrm+sib) mov instructions in amd64 can be optimized into -- * short mov instructions if a 32-bit address override is applied in -- * 64-bit mode to an EA of just an offset (no registers) and the -- * target register is al/ax/eax/rax. -- */ -- X86_POSTOP_SHORTMOV, -- /* Override any attempt at address-size override to 16 bits, and never * generate a prefix. This is used for the ENTER opcode. */ -- X86_POSTOP_ADDRESS16, -- -- /* Used for 64-bit mov immediate, which can take a sign-extended -- * imm32 as well as imm64 values. The imm32 form is put in the -- * second byte of the opcode and its ModRM byte is put in the third -- * byte of the opcode. - * FIXME: Update for new optimizer. -- */ -- X86_POSTOP_SIGNEXT_IMM32 ++ X86_POSTOP_ADDRESS16 } postop; } x86_insn; @@@ -267,33 -280,18 +254,17 @@@ void yasm_x86__bc_apply_prefixe * 1 if invalid EA, or 2 if indeterminate EA. */ int yasm_x86__expr_checkea - (yasm_expr **ep, unsigned char *addrsize, unsigned int bits, - unsigned int nosplit, int address16_op, unsigned char *displen, - unsigned char *modrm, unsigned char *v_modrm, unsigned char *n_modrm, - unsigned char *sib, unsigned char *v_sib, unsigned char *n_sib, - unsigned char *pcrel, unsigned char *rex); - - void yasm_x86__parse_cpu(yasm_arch *arch, const char *cpuid, - unsigned long line); - - int yasm_x86__parse_check_reg - (yasm_arch *arch, /*@out@*/ unsigned long data[1], const char *id, - unsigned long line); - int yasm_x86__parse_check_reggroup - (yasm_arch *arch, /*@out@*/ unsigned long data[1], const char *id, - unsigned long line); - int yasm_x86__parse_check_segreg - (yasm_arch *arch, /*@out@*/ unsigned long data[1], const char *id, - unsigned long line); - int yasm_x86__parse_check_insn - (yasm_arch *arch, /*@out@*/ unsigned long data[4], const char *id, - unsigned long line); - int yasm_x86__parse_check_prefix + (x86_effaddr *x86_ea, unsigned char *addrsize, unsigned int bits, - int address16_op, unsigned char *rex, - yasm_calc_bc_dist_func calc_bc_dist); ++ int address16_op, unsigned char *rex); + + void yasm_x86__parse_cpu(yasm_arch *arch, const char *cpuid, size_t cpuid_len); + + yasm_arch_insnprefix yasm_x86__parse_check_insnprefix (yasm_arch *arch, /*@out@*/ unsigned long data[4], const char *id, - unsigned long line); - int yasm_x86__parse_check_targetmod - (yasm_arch *arch, /*@out@*/ unsigned long data[1], const char *id, - unsigned long line); + size_t id_len); + yasm_arch_regtmod yasm_x86__parse_check_regtmod + (yasm_arch *arch, /*@out@*/ unsigned long *data, const char *id, + size_t id_len); void yasm_x86__finalize_insn (yasm_arch *arch, yasm_bytecode *bc, yasm_bytecode *prev_bc, diff --cc modules/arch/x86/x86bc.c index 7bfc4cc6,62ef563b..d5bbfa18 --- a/modules/arch/x86/x86bc.c +++ b/modules/arch/x86/x86bc.c @@@ -69,37 -45,28 +45,37 @@@ static void x86_ea_print(const yasm_eff static void x86_bc_insn_destroy(void *contents); static void x86_bc_insn_print(const void *contents, FILE *f, int indent_level); -static yasm_bc_resolve_flags x86_bc_insn_resolve - (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist); +static int x86_bc_insn_calc_len(yasm_bytecode *bc, + yasm_bc_add_span_func add_span, + void *add_span_data); +static int x86_bc_insn_expand(yasm_bytecode *bc, int span, long old_val, + long new_val, /*@out@*/ long *neg_thres, + /*@out@*/ long *pos_thres); static int x86_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, - void *d, yasm_output_expr_func output_expr, + void *d, yasm_output_value_func output_value, /*@null@*/ yasm_output_reloc_func output_reloc); static void x86_bc_jmp_destroy(void *contents); static void x86_bc_jmp_print(const void *contents, FILE *f, int indent_level); -static yasm_bc_resolve_flags x86_bc_jmp_resolve - (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist); +static int x86_bc_jmp_calc_len(yasm_bytecode *bc, + yasm_bc_add_span_func add_span, + void *add_span_data); +static int x86_bc_jmp_expand(yasm_bytecode *bc, int span, long old_val, + long new_val, /*@out@*/ long *neg_thres, + /*@out@*/ long *pos_thres); static int x86_bc_jmp_tobytes(yasm_bytecode *bc, unsigned char **bufp, - void *d, yasm_output_expr_func output_expr, + void *d, yasm_output_value_func output_value, /*@null@*/ yasm_output_reloc_func output_reloc); static void x86_bc_jmpfar_destroy(void *contents); static void x86_bc_jmpfar_print(const void *contents, FILE *f, int indent_level); -static yasm_bc_resolve_flags x86_bc_jmpfar_resolve - (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist); +static int x86_bc_jmpfar_calc_len(yasm_bytecode *bc, + yasm_bc_add_span_func add_span, + void *add_span_data); static int x86_bc_jmpfar_tobytes (yasm_bytecode *bc, unsigned char **bufp, void *d, - yasm_output_expr_func output_expr, + yasm_output_value_func output_value, /*@null@*/ yasm_output_reloc_func output_reloc); /* Effective address callback structures */ @@@ -115,27 -82,27 +91,30 @@@ static const yasm_bytecode_callback x86 x86_bc_insn_destroy, x86_bc_insn_print, yasm_bc_finalize_common, - x86_bc_insn_resolve, + x86_bc_insn_calc_len, + x86_bc_insn_expand, - x86_bc_insn_tobytes + x86_bc_insn_tobytes, + 0 }; static const yasm_bytecode_callback x86_bc_callback_jmp = { x86_bc_jmp_destroy, x86_bc_jmp_print, yasm_bc_finalize_common, - x86_bc_jmp_resolve, + x86_bc_jmp_calc_len, + x86_bc_jmp_expand, - x86_bc_jmp_tobytes + x86_bc_jmp_tobytes, + 0 }; static const yasm_bytecode_callback x86_bc_callback_jmpfar = { x86_bc_jmpfar_destroy, x86_bc_jmpfar_print, yasm_bc_finalize_common, - x86_bc_jmpfar_resolve, + x86_bc_jmpfar_calc_len, + yasm_bc_expand_common, - x86_bc_jmpfar_tobytes + x86_bc_jmpfar_tobytes, + 0 }; int @@@ -537,121 -497,189 +509,87 @@@ x86_common_calc_len(const x86_common *c return len; } -static yasm_bc_resolve_flags -x86_bc_insn_resolve(yasm_bytecode *bc, int save, - yasm_calc_bc_dist_func calc_bc_dist) +static int +x86_bc_insn_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) { x86_insn *insn = (x86_insn *)bc->contents; - /*@null@*/ yasm_expr *temp; - x86_effaddr *x86_ea = (x86_effaddr *)insn->ea; - yasm_effaddr *ea = &x86_ea->ea; + x86_effaddr *x86_ea = insn->x86_ea; yasm_immval *imm = insn->imm; - yasm_bc_resolve_flags retval = YASM_BC_RESOLVE_MIN_LEN; - if (ea) { - if (ea->disp) { - /* Handle shortmov special-casing */ - if (insn->postop == X86_POSTOP_SHORTMOV && - insn->common.mode_bits == 64 && insn->common.addrsize == 32 && - !yasm_expr__contains(ea->disp, YASM_EXPR_REG)) { - yasm_x86__ea_set_disponly((yasm_effaddr *)x86_ea); - /* Make the short form permanent. */ - insn->opcode.opcode[0] = insn->opcode.opcode[1]; - } + if (x86_ea) { - /* Create temp copy of disp, etc. */ - x86_effaddr eat = *x86_ea; /* structure copy */ - - /* Don't overwrite original expression portion */ - if (x86_ea->ea.disp.abs) - eat.ea.disp.abs = yasm_expr_copy(x86_ea->ea.disp.abs); - - /* Handle shortmov special-casing */ - if (insn->postop == X86_POSTOP_SHORTMOV && - insn->common.mode_bits == 64 && insn->common.addrsize == 32 && - (!eat.ea.disp.abs || - !yasm_expr__contains(eat.ea.disp.abs, YASM_EXPR_REG))) { - yasm_x86__ea_set_disponly(&eat); - - if (save) { - /* Make the short form permanent. */ - insn->opcode.opcode[0] = insn->opcode.opcode[1]; - } - } - + /* Check validity of effective address and calc R/M bits of + * Mod/RM byte and SIB byte. We won't know the Mod field + * of the Mod/RM byte until we know more about the + * displacement. + */ - switch (yasm_x86__expr_checkea(&eat, &insn->common.addrsize, ++ if (yasm_x86__expr_checkea(x86_ea, &insn->common.addrsize, + insn->common.mode_bits, insn->postop == X86_POSTOP_ADDRESS16, - &insn->rex, calc_bc_dist)) { - case 1: - yasm_expr_destroy(eat.ea.disp.abs); - /* failed, don't bother checking rest of insn */ - return YASM_BC_RESOLVE_UNKNOWN_LEN|YASM_BC_RESOLVE_ERROR; - case 2: - yasm_expr_destroy(eat.ea.disp.abs); - /* failed, don't bother checking rest of insn */ - return YASM_BC_RESOLVE_UNKNOWN_LEN; - default: - yasm_expr_destroy(eat.ea.disp.abs); - /* okay */ - break; - } - - if (eat.ea.disp.size != 8) { - /* Fits into a word/dword, or unknown. */ - retval = YASM_BC_RESOLVE_NONE; /* may not be smallest size */ ++ &insn->rex)) ++ /* failed, don't bother checking rest of insn */ ++ return -1; - /* Check validity of effective address and calc R/M bits of - * Mod/RM byte and SIB byte. We won't know the Mod field - * of the Mod/RM byte until we know more about the - * displacement. - /* Handle unknown case, make displen word-sized */ - if (eat.ea.need_nonzero_len) - eat.ea.disp.size = (insn->common.addrsize == 16) ? 16 : 32; - } ++ if (x86_ea->ea.disp.size == 0) { ++ /* Handle unknown case, default to byte-sized and set as ++ * critical expression. + */ - if (yasm_x86__expr_checkea(&ea->disp, &insn->common.addrsize, - insn->common.mode_bits, ea->nosplit, - insn->postop == X86_POSTOP_ADDRESS16, &ea->len, - &x86_ea->modrm, &x86_ea->valid_modrm, &x86_ea->need_modrm, - &x86_ea->sib, &x86_ea->valid_sib, &x86_ea->need_sib, - &x86_ea->pcrel, &insn->rex)) - /* failed, don't bother checking rest of insn */ - return -1; - - /* Handle address16 postop case */ - if (insn->postop == X86_POSTOP_ADDRESS16) - insn->common.addrsize = 0; - - if (ea->len == 0xff) { - /* Handle unknown case, default to byte-sized and set as - * critical expression. - */ - bc->len += 1; - add_span(add_span_data, bc, 1, yasm_expr_copy(ea->disp), -128, - 127); - } else - bc->len += ea->len; - } ++ bc->len += 1; ++ add_span(add_span_data, bc, 1, &x86_ea->ea.disp, NULL, -128, 127); ++ } else ++ bc->len + x86_ea->ea.disp.size/8; + + /* Handle address16 postop case */ + if (insn->postop == X86_POSTOP_ADDRESS16) + insn->common.addrsize = 0; - /* If we had forced ea->len but had to override, save it now */ - if (x86_ea->ea.disp.size != 0 && - x86_ea->ea.disp.size != eat.ea.disp.size) - x86_ea->ea.disp.size = eat.ea.disp.size; - - if (save) { - eat.ea.disp.abs = x86_ea->ea.disp.abs; /* Copy back original */ - *x86_ea = eat; /* structure copy */ - if (x86_ea->ea.disp.size == 0) { - yasm_value_delete(&x86_ea->ea.disp); - x86_ea->ea.need_disp = 0; - } - } - /* Compute length of ea and add to total */ - bc->len += eat.need_modrm + (eat.need_sib ? 1:0) + eat.ea.disp.size/8; - bc->len += (eat.ea.segreg != 0) ? 1 : 0; + bc->len += x86_ea->need_modrm + (x86_ea->need_sib ? 1:0); + bc->len += (x86_ea->ea.segreg != 0) ? 1 : 0; } if (imm) { - int immlen = imm->len; - - if (imm->val) { - /* TODO: check imm->len vs. sized len from expr? */ - - /* Handle signext_imm8 postop special-casing */ - if (insn->postop == X86_POSTOP_SIGNEXT_IMM8) { - /*@dependent@*/ /*@null@*/ yasm_intnum *num; - num = yasm_expr_get_intnum(&imm->val, NULL); - if (num) { - int val = yasm_intnum_get_int(num); - if (val >= -128 && val <= 127) { - /* We can use the sign-extended byte form: shorten - * the immediate length to 1. - */ - imm->len = 1; - immlen = 1; - } else { - /* We can't use the ,1. */ - insn->opcode.opcode[0] = insn->opcode.opcode[1]; - } - insn->postop = X86_POSTOP_NONE; - } else { - /* Unknown; default to byte form and set as critical - * expression. - */ - immlen = 1; - add_span(add_span_data, bc, 2, yasm_expr_copy(imm->val), - -128, 127); - } - } - /*@null@*/ yasm_expr *temp = NULL; - const yasm_intnum *num = NULL; ++ yasm_intnum *zero = yasm_intnum_create_uint(0); ++ const yasm_intnum *num = zero; + unsigned int immlen = imm->val.size; + long val; - /* Handle shift postop special-casing */ - if (insn->postop == X86_POSTOP_SHIFT) { - /*@dependent@*/ /*@null@*/ yasm_intnum *num; - num = yasm_expr_get_intnum(&imm->val, NULL); - if (num) { - if (yasm_intnum_get_uint(num) == 1) { - /* We can use the ,1. */ - yasm_expr_destroy(imm->val); - yasm_xfree(imm); - insn->imm = NULL; - immlen = 0; - } else { - /* We can't use the ,1. */ - insn->opcode.opcode[0] = insn->opcode.opcode[1]; - } - insn->postop = X86_POSTOP_NONE; - } else { - /* Just assume we can't use the ,1 form: allowing this - * is more work than it's worth. - if (imm->val.abs) { - temp = yasm_expr_copy(imm->val.abs); - assert(temp != NULL); - num = yasm_expr_get_intnum(&temp, calc_bc_dist); - } ++ if (imm->val.abs) ++ num = yasm_expr_get_intnum(&imm->val.abs, NULL); + + /* TODO: check imm->len vs. sized len from expr? */ + - switch (insn->postop) { - case X86_POSTOP_SIGNEXT_IMM8: - /* Handle signext_imm8 postop special-casing */ ++ /* Handle signext_imm8 postop special-casing */ ++ if (insn->postop == X86_POSTOP_SIGNEXT_IMM8) { ++ if (imm->val.rel || num) { + if (imm->val.rel) - val = 1000; /* has relative portion, don't collapse */ - else if (num) - val = yasm_intnum_get_int(num); ++ val = 1000; /* has relative portion, don't collapse */ + else - val = 0; ++ val = yasm_intnum_get_int(num); + if (val >= -128 && val <= 127) { + /* We can use the sign-extended byte form: shorten - * the immediate length to 1. ++ * the immediate length to 1 and make the byte form ++ * permanent. */ - insn->opcode.opcode[0] = insn->opcode.opcode[1]; - insn->postop = X86_POSTOP_NONE; ++ imm->val.size = 8; + immlen = 8; - if (save) { - /* Make the byte form permanent. */ - insn->opcode.opcode[0] = insn->opcode.opcode[1]; - imm->val.size = 8; - if (insn->opcode.opcode[2] != 0) { - insn->opcode.opcode[1] = insn->opcode.opcode[2]; - insn->opcode.len++; - } - } else if (insn->opcode.opcode[2] != 0) - bc->len++; - } - /* Not really necessary, but saves confusion over it. */ - if (save) - insn->postop = X86_POSTOP_NONE; - break; - - case X86_POSTOP_SIGNEXT_IMM32: - /* Handle signext_imm32 postop special-casing */ - if (!num || yasm_intnum_check_size(num, 32, 0, 1)) { - bc->len++; /* Due to ModRM byte */ - immlen = 32; - if (save) { - /* Throwaway REX byte */ - unsigned char rex_temp = 0; - - /* Build ModRM EA - CAUTION: this depends on - * opcode 0 being a mov instruction! - */ - insn->x86_ea = yasm_x86__ea_create_reg( - (unsigned long)insn->opcode.opcode[0]-0xB8, - &rex_temp, 64); - - /* Make the imm32s form permanent. */ - insn->opcode.opcode[0] = insn->opcode.opcode[1]; - imm->val.size = 32; ++ if (insn->opcode.opcode[2] != 0) { ++ insn->opcode.opcode[1] = insn->opcode.opcode[2]; ++ insn->opcode.len++; + } } - /* Not really necessary, but saves confusion over it. */ - if (save) - insn->postop = X86_POSTOP_NONE; - break; - - case X86_POSTOP_SHIFT: - /* Handle shift postop special-casing */ - if (num && yasm_intnum_get_uint(num) == 1) { - /* We can use the ,1 form: no imm (set to 0 len) */ - immlen = 0; - - if (save) { - /* Make the ,1 form permanent. */ - insn->opcode.opcode[0] = insn->opcode.opcode[1]; - /* Delete imm, as it's not needed. */ - yasm_value_delete(&imm->val); - yasm_xfree(imm); - insn->imm = (yasm_immval *)NULL; - } - } else - retval = YASM_BC_RESOLVE_NONE; /* could still get ,1 */ - - /* Not really necessary, but saves confusion over it. */ - if (save) - insn->postop = X86_POSTOP_NONE; - break; - - default: - break; ++ insn->postop = X86_POSTOP_NONE; ++ } else { ++ /* Unknown; default to byte form and set as critical ++ * expression. ++ */ ++ immlen = 8; ++ add_span(add_span_data, bc, 2, &imm->val, NULL, -128, 127); + } } - bc->len += immlen; - yasm_expr_destroy(temp); ++ yasm_intnum_destroy(zero); + + bc->len += immlen/8; } bc->len += insn->opcode.len; @@@ -662,118 -690,172 +600,137 @@@ (insn->common.mode_bits == 64 && insn->common.opersize == 64 && insn->def_opersize_64 != 64))) bc->len++; + return 0; +} + +static int +x86_bc_insn_expand(yasm_bytecode *bc, int span, long old_val, long new_val, + /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres) +{ + x86_insn *insn = (x86_insn *)bc->contents; + /*@null@*/ yasm_expr *temp; - x86_effaddr *x86_ea = (x86_effaddr *)insn->ea; ++ x86_effaddr *x86_ea = insn->x86_ea; + yasm_effaddr *ea = &x86_ea->ea; + yasm_immval *imm = insn->imm; + - if (ea && ea->disp) { ++ if (ea && ea->disp.abs) { + /* Change displacement length into word-sized */ - if (ea->len == 0xff) { - ea->len = (insn->common.addrsize == 16) ? 2U : 4U; ++ if (ea->disp.size == 0) { ++ ea->disp.size = (insn->common.addrsize == 16) ? 16 : 32; + x86_ea->modrm &= ~0300; + x86_ea->modrm |= 0200; + bc->len--; - bc->len += ea->len; ++ bc->len += ea->disp.size/8; + } + } - if (imm && imm->val) { - return retval; ++ if (imm && imm->val.abs) { + if (insn->postop == X86_POSTOP_SIGNEXT_IMM8) { + bc->len--; - bc->len += imm->len; ++ bc->len += imm->val.size/8; + insn->postop = X86_POSTOP_NONE; + } + } + + return 0; } -static yasm_bc_resolve_flags -x86_bc_jmp_resolve(yasm_bytecode *bc, int save, - yasm_calc_bc_dist_func calc_bc_dist) +static int +x86_bc_jmp_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) { x86_jmp *jmp = (x86_jmp *)bc->contents; - yasm_bc_resolve_flags retval = YASM_BC_RESOLVE_MIN_LEN; + yasm_bytecode *target_prevbc; + /*@null@*/ yasm_expr *temp; + /*@only@*/ yasm_intnum *num; + /*@dependent@*/ /*@null@*/ yasm_intnum *num2; + long rel; unsigned char opersize; - x86_jmp_opcode_sel jrtype = JMP_NONE; /* As opersize may be 0, figure out its "real" value. */ opersize = (jmp->common.opersize == 0) ? jmp->common.mode_bits : jmp->common.opersize; - /* We only check to see if forced forms are actually legal if we're in - * save mode. Otherwise we assume that they are legal. - */ - switch (jmp->op_sel) { - case JMP_SHORT_FORCED: - /* 1 byte relative displacement */ - jrtype = JMP_SHORT; - if (save) { - /* does a short form exist? */ - if (jmp->shortop.len == 0) { - yasm_error_set(YASM_ERROR_TYPE, - N_("short jump does not exist")); - return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN; - } - - if (!jmp->target.rel) - num = yasm_intnum_create_uint(0); - else if (!yasm_symrec_get_label(jmp->target.rel, &target_prevbc) - || target_prevbc->section != jmp->origin_prevbc->section - || !(num = calc_bc_dist(jmp->origin_prevbc, - target_prevbc))) { - /* External or out of segment, so we can't check distance. - * This depends on the objfmt supporting 8-bit relocs. - * While most don't, some might, so allow it. The objfmt - * will error if not supported. - */ - break; - } + bc->len += x86_common_calc_len(&jmp->common); - if (jmp->target.abs) { - temp = yasm_expr_copy(jmp->target.abs); - num2 = yasm_expr_get_intnum(&temp, calc_bc_dist); - if (!num2) { - yasm_expr_destroy(temp); - yasm_error_set(YASM_ERROR_TOO_COMPLEX, - N_("jump target too complex")); - return YASM_BC_RESOLVE_ERROR | - YASM_BC_RESOLVE_UNKNOWN_LEN; - } - yasm_intnum_calc(num, YASM_EXPR_ADD, num2); - yasm_expr_destroy(temp); - } + if (jmp->op_sel == JMP_NEAR_FORCED || jmp->shortop.len == 0) { + if (jmp->nearop.len == 0) { - yasm__error(bc->line, N_("near jump does not exist")); ++ yasm_error_set(YASM_ERROR_TYPE, N_("near jump does not exist")); + return -1; + } - rel = yasm_intnum_get_int(num); - yasm_intnum_destroy(num); - rel -= jmp->shortop.len+1; - /* short displacement must fit in -128 <= rel <= +127 */ - if (rel < -128 || rel > 127) { - yasm_error_set(YASM_ERROR_OVERFLOW, - N_("short jump out of range")); - return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN; - } - } - break; - case JMP_NEAR_FORCED: - /* 2/4 byte relative displacement (depending on operand size) */ - jrtype = JMP_NEAR; - if (save) { - if (jmp->nearop.len == 0) { - yasm_error_set(YASM_ERROR_TYPE, - N_("near jump does not exist")); - return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN; - } - } - break; - default: - /* Due to code in x86_finalize_jmp(), we can only get here if - * there's BOTH short and near opcodes available, and it wasn't - * forced by the user. - */ - if (!jmp->target.rel) - num = yasm_intnum_create_uint(0); - else if (!yasm_symrec_get_label(jmp->target.rel, &target_prevbc) - || target_prevbc->section != jmp->origin_prevbc->section - || !(num = calc_bc_dist(jmp->origin_prevbc, - target_prevbc))) { - /* It's unknown. Thus, assume near displacement. */ - jrtype = JMP_NEAR; - retval = YASM_BC_RESOLVE_NONE; - break; - } + /* Near jump, no spans needed */ + bc->len += jmp->nearop.len; + bc->len += (opersize == 16) ? 2 : 4; + return 0; + } - /* Try to find shortest displacement based on difference between - * target expr value and origin offset. - */ - if (jmp->target.abs) { - temp = yasm_expr_copy(jmp->target.abs); - num2 = yasm_expr_get_intnum(&temp, calc_bc_dist); - if (!num2) { - yasm_expr_destroy(temp); - yasm_error_set(YASM_ERROR_TOO_COMPLEX, - N_("jump target too complex")); - return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN; - } - yasm_intnum_calc(num, YASM_EXPR_ADD, num2); - yasm_expr_destroy(temp); - } + if (jmp->op_sel == JMP_SHORT_FORCED || jmp->nearop.len == 0) { + if (jmp->shortop.len == 0) { - yasm__error(bc->line, N_("short jump does not exist")); ++ yasm_error_set(YASM_ERROR_TYPE, N_("short jump does not exist")); + return -1; + } - rel = yasm_intnum_get_int(num); - yasm_intnum_destroy(num); - rel -= jmp->shortop.len+1; - /* short displacement must fit within -128 <= rel <= +127 */ - if (rel >= -128 && rel <= 127) { - /* It fits into a short displacement. */ - jrtype = JMP_SHORT; - } else { - /* Near for now, but could get shorter in the future as - * there's a short form available. - */ - jrtype = JMP_NEAR; - retval = YASM_BC_RESOLVE_NONE; - } - break; + /* We want to be sure to error if we exceed short length, so + * put it in as a dependent expression (falling through). + */ } - /* Short jump, generate span */ - switch (jrtype) { - case JMP_SHORT: - if (save) - jmp->op_sel = JMP_SHORT; - if (jmp->shortop.len == 0) - return YASM_BC_RESOLVE_UNKNOWN_LEN; /* size not available */ - ++ if (jmp->target.rel ++ && (!yasm_symrec_get_label(jmp->target.rel, &target_prevbc) ++ || target_prevbc->section != jmp->origin_prevbc->section)) { ++ /* External or out of segment, so we can't check distance. ++ * Allowing forced short jumps depends on the objfmt supporting ++ * 8-bit relocs. While most don't, some might, so allow it here. ++ * Otherwise default to word-sized. ++ * The objfmt will error if not supported. ++ */ ++ if (jmp->op_sel == JMP_SHORT_FORCED || jmp->nearop.len == 0) { + bc->len += jmp->shortop.len + 1; - break; - case JMP_NEAR: - if (save) - jmp->op_sel = JMP_NEAR; - if (jmp->nearop.len == 0) - return YASM_BC_RESOLVE_UNKNOWN_LEN; /* size not available */ - ++ } else { + bc->len += jmp->nearop.len; + bc->len += (opersize == 16) ? 2 : 4; - break; - default: - yasm_internal_error(N_("unknown jump type")); ++ } ++ return 0; ++ } ++ ++ /* Default to short jump and generate span */ + bc->len += jmp->shortop.len + 1; - add_span(add_span_data, bc, 1, - yasm_expr_create(YASM_EXPR_SUB, - yasm_expr_expr(yasm_expr_copy(jmp->target)), - yasm_expr_sym(jmp->origin), bc->line), - -128, 127); ++ add_span(add_span_data, bc, 1, &jmp->target, jmp->origin_prevbc, -128, 127); + return 0; +} + +static int +x86_bc_jmp_expand(yasm_bytecode *bc, int span, long old_val, long new_val, + /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres) +{ + x86_jmp *jmp = (x86_jmp *)bc->contents; + unsigned char opersize; + + if (span != 1) + yasm_internal_error(N_("unrecognized span id")); + + /* As opersize may be 0, figure out its "real" value. */ + opersize = (jmp->common.opersize == 0) ? + jmp->common.mode_bits : jmp->common.opersize; + + if (jmp->nearop.len == 0) { - yasm__error(bc->line, N_("short jump out of range")); ++ yasm_error_set(YASM_ERROR_VALUE, N_("short jump out of range")); + return -1; } - bc->len += x86_common_resolve(&jmp->common); - return retval; + /* Upgrade to a near jump */ + jmp->op_sel = JMP_NEAR; + bc->len -= jmp->shortop.len + 1; + bc->len += jmp->nearop.len; + bc->len += (opersize == 16) ? 2 : 4; + + return 0; } -static yasm_bc_resolve_flags -x86_bc_jmpfar_resolve(yasm_bytecode *bc, int save, - yasm_calc_bc_dist_func calc_bc_dist) +static int +x86_bc_jmpfar_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) { x86_jmpfar *jmpfar = (x86_jmpfar *)bc->contents; unsigned char opersize; @@@ -860,40 -941,43 +816,42 @@@ x86_bc_insn_tobytes(yasm_bytecode *bc, YASM_WRITE_8(*bufp, x86_ea->sib); } - if (ea->disp) { - /* Simplify expression */ - ea->disp = yasm_expr_simplify(ea->disp, yasm_common_calc_bc_dist); - if (x86_ea->pcrel) { - /*@null@*/ yasm_expr *wrt = yasm_expr_extract_wrt(&ea->disp); - ea->disp = - yasm_expr_create(YASM_EXPR_SUB, yasm_expr_expr(ea->disp), - yasm_expr_sym(x86_ea->origin), bc->line); - if (wrt) { - ea->disp = - yasm_expr_create(YASM_EXPR_WRT, - yasm_expr_expr(ea->disp), - yasm_expr_expr(wrt), bc->line); - } - if (output_expr(&ea->disp, *bufp, ea->len, - (size_t)(ea->len*8), 0, - (unsigned long)(*bufp-bufp_orig), bc, 1, 1, - d)) - return 1; - } else { - if (output_expr(&ea->disp, *bufp, ea->len, - (size_t)(ea->len*8), 0, - (unsigned long)(*bufp-bufp_orig), bc, 0, 1, - d)) - return 1; + if (x86_ea->ea.need_disp) { + x86_effaddr eat = *x86_ea; /* structure copy */ + unsigned char addrsize = insn->common.addrsize; + unsigned int disp_len = x86_ea->ea.disp.size/8; + + eat.valid_modrm = 0; /* force checkea to actually run */ + + if (x86_ea->ea.disp.abs) { + /* Call checkea() to simplify the registers out of the + * displacement. Throw away all of the return values except + * for the modified expr. + */ + if (yasm_x86__expr_checkea + (&eat, &addrsize, insn->common.mode_bits, - insn->postop == X86_POSTOP_ADDRESS16, &insn->rex, - yasm_common_calc_bc_dist)) ++ insn->postop == X86_POSTOP_ADDRESS16, &insn->rex)) + yasm_internal_error(N_("checkea failed")); + x86_ea->ea.disp.abs = eat.ea.disp.abs; } - *bufp += ea->len; - } else { - /* 0 displacement, but we didn't know it before, so we have to - * write out 0 value. - * FIXME: Is this still needed? - */ - for (i=0; ilen; i++) - YASM_WRITE_8(*bufp, 0); + + if (x86_ea->ea.disp.ip_rel) { + /* Adjust relative displacement to end of bytecode */ + /*@only@*/ yasm_intnum *delta; + delta = yasm_intnum_create_int(-(long)bc->len); + if (!x86_ea->ea.disp.abs) + x86_ea->ea.disp.abs = + yasm_expr_create_ident(yasm_expr_int(delta), bc->line); + else + x86_ea->ea.disp.abs = + yasm_expr_create(YASM_EXPR_ADD, + yasm_expr_expr(x86_ea->ea.disp.abs), + yasm_expr_int(delta), bc->line); + } + if (output_value(&x86_ea->ea.disp, *bufp, disp_len, + (unsigned long)(*bufp-bufp_orig), bc, 1, d)) + return 1; + *bufp += disp_len; } } diff --cc modules/arch/x86/x86expr.c index 1570e8b7,b83d7979..01a1cb45 --- a/modules/arch/x86/x86expr.c +++ b/modules/arch/x86/x86expr.c @@@ -247,22 -247,47 +247,46 @@@ x86_expr_checkea_distcheck_reg(yasm_exp * and 0 if all values successfully determined and saved in data. */ static int - x86_expr_checkea_getregusage(yasm_expr **ep, /*@null@*/ yasm_expr **wrt, - /*@null@*/ int *indexreg, unsigned char *pcrel, unsigned int bits, - void *data, int *(*get_reg)(yasm_expr__item *ei, int *regnum, void *d)) + x86_expr_checkea_getregusage(yasm_expr **ep, /*@null@*/ int *indexreg, + int *pcrel, unsigned int bits, void *data, - int *(*get_reg)(yasm_expr__item *ei, int *regnum, void *d), - yasm_calc_bc_dist_func calc_bc_dist) ++ int *(*get_reg)(yasm_expr__item *ei, int *regnum, void *d)) { int i; int *reg; int regnum; int indexval = 0; int indexmult = 0; - yasm_expr *e; + yasm_expr *e, *wrt; /*@-unqualifiedtrans@*/ - *ep = yasm_expr__level_tree(*ep, 1, indexreg == 0, NULL, NULL, NULL, NULL); - if (*wrt) - *wrt = yasm_expr__level_tree(*wrt, 1, indexreg == 0, NULL, NULL, NULL, - NULL); - *ep = yasm_expr__level_tree(*ep, 1, 1, indexreg == 0, calc_bc_dist, NULL, - NULL, NULL); ++ *ep = yasm_expr__level_tree(*ep, 1, 1, indexreg == 0, NULL, NULL, NULL, ++ NULL); + + /* Check for WRT rip first */ + wrt = yasm_expr_extract_wrt(ep); + if (wrt && wrt->op == YASM_EXPR_IDENT && + wrt->terms[0].type == YASM_EXPR_REG) { + if (bits != 64) { /* only valid in 64-bit mode */ + yasm_expr_destroy(wrt); + return 1; + } + reg = get_reg(&wrt->terms[0], ®num, data); + if (!reg || regnum != 16) { /* only accept rip */ + yasm_expr_destroy(wrt); + return 1; + } + (*reg)++; + + /* Delete WRT. Set pcrel to 1 to indicate to x86 + * bytecode code to do PC-relative displacement transform. + */ + *pcrel = 1; + yasm_expr_destroy(wrt); + } else if (wrt) { + yasm_expr_destroy(wrt); + return 1; + } + /*@=unqualifiedtrans@*/ assert(*ep != NULL); e = *ep; @@@ -464,57 -469,63 +463,76 @@@ x86_checkea_calc_displen(x86_effaddr *x } else if (dispreq) { /* for BP/EBP, there *must* be a displacement value, but we * may not know the size (8 or 16/32) for sure right now. - * We can't leave displen at 0, because that just means - * unknown displacement, including none. */ - *displen = 0xff; - *modrm |= 0100; - *v_modrm = 1; + x86_ea->ea.need_nonzero_len = 1; ++ x86_ea->modrm |= 0100; ++ x86_ea->valid_modrm = 1; ++ return 0; + } + - if (x86_ea->ea.disp.rel || - (x86_ea->ea.disp.abs && - !(intn = yasm_expr_get_intnum(&x86_ea->ea.disp.abs, NULL)))) { - /* expr still has unknown values or is relative: - * assume 16/32-bit disp - */ ++ /* Relative displacement; basically all object formats need non-byte ++ * for relocation here, so just do that. ++ */ ++ if (x86_ea->ea.disp.rel) + x86_ea->ea.disp.size = wordsize; - x86_ea->modrm |= 0200; - x86_ea->valid_modrm = 1; - return 0; - } + + /* don't try to find out what size displacement we have if + * displen is known. + */ + if (x86_ea->ea.disp.size != 0) { + if (x86_ea->ea.disp.size == 8) + x86_ea->modrm |= 0100; + else + x86_ea->modrm |= 0200; + x86_ea->valid_modrm = 1; return 0; } + /* At this point there's 3 possibilities for the displacement: + * - None (if =0) + * - signed 8 bit (if in -128 to 127 range) + * - 16/32 bit (word size) + * For now, check intnum value right now; if it's not 0, + * assume 8 bit and set up for allowing 16 bit later. + * FIXME: this should really set up two thresholds, one for 8-bit + * expansion and one for 16-bit expansion. The complex expression + * equaling zero is probably a rare case, so we ignore it for now. + */ - - intn = yasm_expr_get_intnum(ep, NULL); - if (!intn) { ++ if (x86_ea->ea.disp.abs && ++ !(intn = yasm_expr_get_intnum(&x86_ea->ea.disp.abs, NULL))) { + /* expr still has unknown values: treat like BP/EBP above */ - *displen = 0xff; - *modrm |= 0100; - *v_modrm = 1; ++ x86_ea->ea.need_nonzero_len = 1; ++ x86_ea->modrm |= 0100; ++ x86_ea->valid_modrm = 1; + return 0; - } ++ } + - dispval = yasm_intnum_get_int(intn); + if (intn) + dispval = yasm_intnum_get_int(intn); + else + dispval = 0; /* Figure out what size displacement we will have. */ - if (dispval == 0) { + if (!x86_ea->ea.need_nonzero_len && dispval == 0) { /* if we know that the displacement is 0 right now, - * go ahead and delete the expr (making it so no - * displacement value is included in the output). + * go ahead and delete the expr and make it so no + * displacement value is included in the output. * The Mod bits of ModRM are set to 0 above, and * we're done with the ModRM byte! - * - * Don't do this if we came from dispreq check above, so - * check *displen. */ - yasm_expr_destroy(e); - *ep = (yasm_expr *)NULL; + yasm_expr_destroy(x86_ea->ea.disp.abs); + x86_ea->ea.disp.abs = NULL; + x86_ea->ea.need_disp = 0; } else if (dispval >= -128 && dispval <= 127) { /* It fits into a signed byte */ - *displen = 1; - *modrm |= 0100; + x86_ea->ea.disp.size = 8; + x86_ea->modrm |= 0100; } else { /* It's a 16/32-bit displacement */ - *displen = wordsize; - *modrm |= 0200; + x86_ea->ea.disp.size = wordsize; + x86_ea->modrm |= 0200; } - *v_modrm = 1; /* We're done with ModRM */ + x86_ea->valid_modrm = 1; /* We're done with ModRM */ } return 0; @@@ -547,21 -558,12 +565,11 @@@ x86_expr_checkea_getregsize_callback(ya } int - yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize, - unsigned int bits, unsigned int nosplit, - int address16_op, unsigned char *displen, - unsigned char *modrm, unsigned char *v_modrm, - unsigned char *n_modrm, unsigned char *sib, - unsigned char *v_sib, unsigned char *n_sib, - unsigned char *pcrel, unsigned char *rex) + yasm_x86__expr_checkea(x86_effaddr *x86_ea, unsigned char *addrsize, - unsigned int bits, int address16_op, unsigned char *rex, - yasm_calc_bc_dist_func calc_bc_dist) ++ unsigned int bits, int address16_op, unsigned char *rex) { - yasm_expr *e, *wrt; int retval; - /* First split off any top-level WRT. We'll add it back in at the end */ - wrt = yasm_expr_extract_wrt(ep); - e = *ep; - if (*addrsize == 0) { /* we need to figure out the address size from what we know about: * - the displacement length @@@ -648,13 -652,30 +658,29 @@@ reg3264_data.regs = reg3264mult; reg3264_data.bits = bits; reg3264_data.addrsize = *addrsize; - if (x86_expr_checkea_getregusage(ep, &wrt, &indexreg, pcrel, bits, - ®3264_data, - x86_expr_checkea_get_reg3264)) { - yasm__error((*ep)->line, N_("invalid effective address")); - return 1; + if (x86_ea->ea.disp.abs) { + int pcrel = 0; + switch (x86_expr_checkea_getregusage + (&x86_ea->ea.disp.abs, &indexreg, &pcrel, bits, - ®3264_data, x86_expr_checkea_get_reg3264, - calc_bc_dist)) { ++ ®3264_data, x86_expr_checkea_get_reg3264)) { + case 1: + yasm_error_set(YASM_ERROR_VALUE, + N_("invalid effective address")); + return 1; + case 2: + if (pcrel) { + x86_ea->ea.disp.curpos_rel = 1; + x86_ea->ea.disp.ip_rel = 1; + } + return 2; + default: + if (pcrel) { + x86_ea->ea.disp.curpos_rel = 1; + x86_ea->ea.disp.ip_rel = 1; + } + break; + } } - e = *ep; /* If indexreg mult is 0, discard it. * This is possible because of the way indexreg is found in @@@ -885,17 -904,33 +909,33 @@@ } /* 16-bit cannot have SIB */ - *sib = 0; - *v_sib = 0; - *n_sib = 0; - - if (x86_expr_checkea_getregusage(ep, &wrt, NULL, pcrel, bits, - ®16mult, - x86_expr_checkea_get_reg16)) { - yasm__error((*ep)->line, N_("invalid effective address")); - return 1; + x86_ea->sib = 0; + x86_ea->valid_sib = 0; + x86_ea->need_sib = 0; + + if (x86_ea->ea.disp.abs) { + int pcrel = 0; + switch (x86_expr_checkea_getregusage + (&x86_ea->ea.disp.abs, (int *)NULL, &pcrel, bits, - ®16mult, x86_expr_checkea_get_reg16, calc_bc_dist)) { ++ ®16mult, x86_expr_checkea_get_reg16)) { + case 1: + yasm_error_set(YASM_ERROR_VALUE, + N_("invalid effective address")); + return 1; + case 2: + if (pcrel) { + x86_ea->ea.disp.curpos_rel = 1; + x86_ea->ea.disp.ip_rel = 1; + } + return 2; + default: + if (pcrel) { + x86_ea->ea.disp.curpos_rel = 1; + x86_ea->ea.disp.ip_rel = 1; + } + break; + } } - e = *ep; /* reg multipliers not 0 or 1 are illegal. */ if (reg16mult.bx & ~1 || reg16mult.si & ~1 || reg16mult.di & ~1 || diff --cc modules/arch/x86/x86id.c index 7f1d50aa,03770ae2..f0245707 --- a/modules/arch/x86/x86id.c +++ b/modules/arch/x86/x86id.c @@@ -106,6 -108,6 +108,7 @@@ RCSID("$Id$") * 14 = CR4 * 15 = memory offset (an EA, but with no registers allowed) * [special case for MOV opcode] ++ * 16 = immediate, value=1 (for special-case shift) * - 3 bits = size (user-specified, or from register size): * 0 = any size acceptable/no size spec acceptable (dep. on strict) * 1/2/3/4 = 8/16/32/64 bits (from user or reg size) @@@ -143,17 -147,17 +148,16 @@@ * 9 = operand size goes into address size (jmp only) * A = far jump (outputs a farjmp instead of normal insn) * The below describes postponed actions: actions which can't be completed at -- * parse-time due to things like EQU and complex expressions. For these, some ++ * parse-time due to possibly dependent expressions. For these, some * additional data (stored in the second byte of the opcode with a one-byte * opcode) is passed to later stages of the assembler with flags set to * indicate postponed actions. * - 3 bits = postponed action: * 0 = none -- * 1 = shift operation with a ,1 short form (instead of imm8). -- * 2 = large imm16/32 that can become a sign-extended imm8. -- * 3 = could become a short opcode mov with bits=64 and a32 prefix -- * 4 = forced 16-bit address size (override ignored, no prefix) -- * 5 = large imm64 that can become a sign-extended imm32. ++ * 1 = large imm16/32 that can become a sign-extended imm8. ++ * 2 = could become a short opcode mov with bits=64 and a32 prefix ++ * 3 = forced 16-bit address size (override ignored, no prefix) ++ * 4 = large imm64 that can become a sign-extended imm32. */ #define OPT_Imm 0x0 #define OPT_Reg 0x1 @@@ -177,6 -181,6 +181,7 @@@ #define OPT_SS 0x13 #define OPT_CR4 0x14 #define OPT_MemOffs 0x15 ++#define OPT_Imm1 0x16 #define OPT_MASK 0x1F #define OPS_Any (0UL<<5) @@@ -217,11 -222,11 +223,10 @@@ #define OPA_MASK (0xFUL<<13) #define OPAP_None (0UL<<17) --#define OPAP_ShiftOp (1UL<<17) --#define OPAP_SImm8Avail (2UL<<17) --#define OPAP_ShortMov (3UL<<17) --#define OPAP_A16 (4UL<<17) --#define OPAP_SImm32Avail (5UL<<17) ++#define OPAP_SImm8Avail (1UL<<17) ++#define OPAP_ShortMov (2UL<<17) ++#define OPAP_A16 (3UL<<17) ++#define OPAP_SImm32Avail (4UL<<17) #define OPAP_MASK (7UL<<17) typedef struct x86_insn_info { @@@ -1075,33 -1073,28 +1073,28 @@@ static const x86_insn_info imul_insn[] static const x86_insn_info shift_insn[] = { { CPU_Any, MOD_SpAdd|MOD_GasSufB, 0, 0, 0, 1, {0xD2, 0, 0}, 0, 2, {OPT_RM|OPS_8|OPA_EA, OPT_Creg|OPS_8|OPA_None, 0} }, -- /* FIXME: imm8 is only avail on 186+, but we use imm8 to get to postponed -- * ,1 form, so it has to be marked as Any. We need to store the active -- * CPU flags somewhere to pass that parse-time info down the line. -- */ - { CPU_Any, MOD_SpAdd|MOD_GasSufB, 0, 0, 0, 1, {0xD0, 0xC0, 0}, 0, 2, - { CPU_Any, MOD_SpAdd|MOD_GasSufB, 0, 0, 0, 1, {0xC0, 0xD0, 0}, 0, 2, -- {OPT_RM|OPS_8|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm|OPAP_ShiftOp, -- 0} }, ++ { CPU_Any, MOD_SpAdd|MOD_GasSufB, 0, 0, 0, 1, {0xD0, 0, 0}, 0, 2, ++ {OPT_RM|OPS_8|OPA_EA, OPT_Imm1|OPS_8|OPS_Relaxed|OPA_None, 0} }, ++ { CPU_186, MOD_SpAdd|MOD_GasSufB, 0, 0, 0, 1, {0xC0, 0, 0}, 0, 2, ++ {OPT_RM|OPS_8|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0} }, { CPU_Any, MOD_SpAdd|MOD_GasSufW, 16, 0, 0, 1, {0xD3, 0, 0}, 0, 2, {OPT_RM|OPS_16|OPA_EA, OPT_Creg|OPS_8|OPA_None, 0} }, - { CPU_Any, MOD_SpAdd|MOD_GasSufW, 16, 0, 0, 1, {0xD1, 0xC1, 0}, 0, 2, - { CPU_Any, MOD_SpAdd|MOD_GasSufW, 16, 0, 0, 1, {0xC1, 0xD1, 0}, 0, 2, -- {OPT_RM|OPS_16|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm|OPAP_ShiftOp, -- 0} }, ++ { CPU_Any, MOD_SpAdd|MOD_GasSufW, 16, 0, 0, 1, {0xD1, 0, 0}, 0, 2, ++ {OPT_RM|OPS_16|OPA_EA, OPT_Imm1|OPS_8|OPS_Relaxed|OPA_None, 0} }, ++ { CPU_186, MOD_SpAdd|MOD_GasSufW, 16, 0, 0, 1, {0xC1, 0, 0}, 0, 2, ++ {OPT_RM|OPS_16|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0} }, { CPU_Any, MOD_SpAdd|MOD_GasSufL, 32, 0, 0, 1, {0xD3, 0, 0}, 0, 2, {OPT_RM|OPS_32|OPA_EA, OPT_Creg|OPS_8|OPA_None, 0} }, - { CPU_Any, MOD_SpAdd|MOD_GasSufL, 32, 0, 0, 1, {0xD1, 0xC1, 0}, 0, 2, - { CPU_Any, MOD_SpAdd|MOD_GasSufL, 32, 0, 0, 1, {0xC1, 0xD1, 0}, 0, 2, -- {OPT_RM|OPS_32|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm|OPAP_ShiftOp, - 0} }, - { CPU_Hammer|CPU_64, MOD_SpAdd, 64, 0, 0, 1, {0xD3, 0, 0}, 0, 2, - {OPT_RM|OPS_64|OPA_EA, OPT_Creg|OPS_8|OPA_None, 0} }, - { CPU_Hammer|CPU_64, MOD_SpAdd, 64, 0, 0, 1, {0xD1, 0xC1, 0}, 0, 2, - {OPT_RM|OPS_64|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm|OPAP_ShiftOp, -- 0} }, ++ { CPU_386, MOD_SpAdd|MOD_GasSufL, 32, 0, 0, 1, {0xD1, 0, 0}, 0, 2, ++ {OPT_RM|OPS_32|OPA_EA, OPT_Imm1|OPS_8|OPS_Relaxed|OPA_None, 0} }, ++ { CPU_386, MOD_SpAdd|MOD_GasSufL, 32, 0, 0, 1, {0xC1, 0, 0}, 0, 2, ++ {OPT_RM|OPS_32|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0} }, { CPU_Hammer|CPU_64, MOD_SpAdd|MOD_GasSufQ, 64, 0, 0, 1, {0xD3, 0, 0}, 0, 2, {OPT_RM|OPS_64|OPA_EA, OPT_Creg|OPS_8|OPA_None, 0} }, - { CPU_Hammer|CPU_64, MOD_SpAdd|MOD_GasSufQ, 64, 0, 0, 1, {0xD1, 0xC1, 0}, - { CPU_Hammer|CPU_64, MOD_SpAdd|MOD_GasSufQ, 64, 0, 0, 1, {0xC1, 0xD1, 0}, -- 0, 2, {OPT_RM|OPS_64|OPA_EA, -- OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm|OPAP_ShiftOp, 0} }, ++ { CPU_Hammer|CPU_64, MOD_SpAdd|MOD_GasSufQ, 64, 0, 0, 1, {0xD1, 0, 0}, ++ 0, 2, {OPT_RM|OPS_64|OPA_EA, OPT_Imm1|OPS_8|OPS_Relaxed|OPA_None, 0} }, ++ { CPU_Hammer|CPU_64, MOD_SpAdd|MOD_GasSufQ, 64, 0, 0, 1, {0xC1, 0, 0}, ++ 0, 2, {OPT_RM|OPS_64|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0} }, /* In GAS mode, single operands are equivalent to shifting by 1 forms */ { CPU_Any, MOD_SpAdd|MOD_GasOnly|MOD_GasSufB, 0, 0, 0, 1, {0xD0, 0, 0}, 0, 1, {OPT_RM|OPS_8|OPA_EA, 0, 0} }, @@@ -2207,7 -2234,9 +2234,10 @@@ yasm_x86__finalize_insn(yasm_arch *arch unsigned char im_sign; unsigned char spare; int i; - static const unsigned int size_lookup[] = {0, 1, 2, 4, 8, 10, 16, 0}; + unsigned int size_lookup[] = {0, 8, 16, 32, 64, 80, 128, 0}; ++ unsigned long do_postop = 0; + + size_lookup[7] = mode_bits; if (!info) { num_info = 1; @@@ -2479,6 -2509,6 +2510,15 @@@ YASM_EXPR_REG)) mismatch = 1; break; ++ case OPT_Imm1: ++ if (op->type == YASM_INSN__OPERAND_IMM) { ++ const yasm_intnum *num; ++ num = yasm_expr_get_intnum(&op->data.val, NULL); ++ if (!num || !yasm_intnum_is_pos1(num)) ++ mismatch = 1; ++ } else ++ mismatch = 1; ++ break; default: yasm_internal_error(N_("invalid operand type")); } @@@ -2808,20 -2838,20 +2848,17 @@@ switch ((int)(info->operands[i] & OPAP_MASK)) { case OPAP_None: break; -- case OPAP_ShiftOp: -- insn->postop = X86_POSTOP_SHIFT; -- break; case OPAP_SImm8Avail: insn->postop = X86_POSTOP_SIGNEXT_IMM8; break; case OPAP_ShortMov: -- insn->postop = X86_POSTOP_SHORTMOV; ++ do_postop = OPAP_ShortMov; break; case OPAP_A16: insn->postop = X86_POSTOP_ADDRESS16; break; case OPAP_SImm32Avail: -- insn->postop = X86_POSTOP_SIGNEXT_IMM32; ++ do_postop = OPAP_SImm32Avail; break; default: yasm_internal_error( @@@ -2856,6 -2885,6 +2892,53 @@@ insn->common.addrsize = 0; } ++ /* Handle non-span-dependent post-ops here */ ++ switch (do_postop) { ++ case OPAP_ShortMov: ++ /* Long (modrm+sib) mov instructions in amd64 can be optimized into ++ * short mov instructions if a 32-bit address override is applied in ++ * 64-bit mode to an EA of just an offset (no registers) and the ++ * target register is al/ax/eax/rax. ++ */ ++ if (insn->common.mode_bits == 64 && insn->common.addrsize == 32 && ++ (!insn->x86_ea->ea.disp.abs || ++ !yasm_expr__contains(insn->x86_ea->ea.disp.abs, ++ YASM_EXPR_REG))) { ++ yasm_x86__ea_set_disponly(insn->x86_ea); ++ /* Make the short form permanent. */ ++ insn->opcode.opcode[0] = insn->opcode.opcode[1]; ++ } ++ insn->opcode.opcode[1] = 0; /* avoid possible confusion */ ++ break; ++ case OPAP_SImm32Avail: ++ /* Used for 64-bit mov immediate, which can take a sign-extended ++ * imm32 as well as imm64 values. The imm32 form is put in the ++ * second byte of the opcode and its ModRM byte is put in the third ++ * byte of the opcode. ++ */ ++ if (!insn->imm->val.abs || ++ yasm_intnum_check_size( ++ yasm_expr_get_intnum(&insn->imm->val.abs, NULL), ++ 32, 0, 1)) { ++ /* Throwaway REX byte */ ++ unsigned char rex_temp = 0; ++ ++ /* Build ModRM EA - CAUTION: this depends on ++ * opcode 0 being a mov instruction! ++ */ ++ insn->x86_ea = yasm_x86__ea_create_reg( ++ (unsigned long)insn->opcode.opcode[0]-0xB8, &rex_temp, 64); ++ ++ /* Make the imm32s form permanent. */ ++ insn->opcode.opcode[0] = insn->opcode.opcode[1]; ++ insn->imm->val.size = 32; ++ } ++ insn->opcode.opcode[1] = 0; /* avoid possible confusion */ ++ break; ++ default: ++ break; ++ } ++ /* Transform the bytecode */ yasm_x86__bc_transform_insn(bc, insn); } diff --cc modules/dbgfmts/Makefile.inc index 80922198,cf0a5ffd..845b3a7d --- a/modules/dbgfmts/Makefile.inc +++ b/modules/dbgfmts/Makefile.inc @@@ -3,5 -5,7 +5,7 @@@ EXTRA_DIST += modules/dbgfmts/dwarf2/Ma EXTRA_DIST += modules/dbgfmts/null/Makefile.inc EXTRA_DIST += modules/dbgfmts/stabs/Makefile.inc + include modules/dbgfmts/codeview/Makefile.inc + include modules/dbgfmts/dwarf2/Makefile.inc include modules/dbgfmts/null/Makefile.inc -include modules/dbgfmts/stabs/Makefile.inc +#include modules/dbgfmts/stabs/Makefile.inc diff --cc modules/dbgfmts/codeview/cv-symline.c index 00000000,dc0c3ab4..78c1059a mode 000000,100644..100644 --- a/modules/dbgfmts/codeview/cv-symline.c +++ b/modules/dbgfmts/codeview/cv-symline.c @@@ -1,0 -1,1102 +1,1106 @@@ + /* + * CodeView debugging format - symbol and 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 "cv-dbgfmt.h" + + enum cv8_symheadtype { + CV8_DEBUG_SYMS = 0xF1, /* CV5 symbol information */ + CV8_LINE_NUMS = 0xF2, /* line numbers for a section */ + CV8_FILE_STRTAB = 0xF3, /* filename string table */ + CV8_FILE_INFO = 0xF4 /* source file info */ + }; + + enum cv_symtype { + /* Non-modal Symbols */ + CV_S_COMPILE = 0x0001, /* Compile Flag */ + CV_S_REGISTER = 0x0002, /* Register */ + CV_S_CONSTANT = 0x0003, /* Constant */ + CV_S_UDT = 0x0004, /* User-defined Type */ + CV_S_SSEARCH = 0x0005, /* Start Search */ + CV_S_END = 0x0006, /* End of Block */ + CV_S_SKIP = 0x0007, /* Skip Record */ + CV_S_OBJNAME = 0x0009, /* Object File Name */ + CV_S_ENDARG = 0x000a, /* End of Arguments */ + CV_S_COBOLUDT = 0x000b, /* COBOL User-defined Type */ + CV_S_MANYREG = 0x000c, /* Many Registers */ + CV_S_RETURN = 0x000d, /* Function Return */ + CV_S_ENTRYTHIS = 0x000e, /* "this" at Method Entry */ + + /* Symbols for 16:16 Segmented Architectures */ + CV_S_BPREL16 = 0x0100, /* BP Relative 16:16 */ + CV_S_LDATA16 = 0x0101, /* Local Data 16:16 */ + CV_S_GDATA16 = 0x0102, /* Global Data Symbol 16:16 */ + CV_S_PUB16 = 0x0103, /* Public Symbol 16:16 */ + CV_S_LPROC16 = 0x0104, /* Local Start 16:16 */ + CV_S_GPROC16 = 0x0105, /* Global Start 16:16 */ + CV_S_THUNK16 = 0x0106, /* Thunk Start 16:16 */ + CV_S_BLOCK16 = 0x0107, /* Block Start 16:16 */ + CV_S_WITH16 = 0x0108, /* With Start 16:16 */ + CV_S_LABEL16 = 0x0109, /* Code Label 16:16 */ + CV_S_CEXMODEL16 = 0x0110, /* Change Execution Model 16:16 */ + CV_S_VFTPATH16 = 0x010b, /* Virtual Function Table Path 16:16 */ + CV_S_REGREL16 = 0x010c, /* Register Relative 16:16 */ + + /* Symbols for 16:32 Segmented Architectures */ + CV_S_BPREL32 = 0x0200, /* BP Relative 16:32 */ + CV_S_LDATA32 = 0x0201, /* Local Data 16:32 */ + CV_S_GDATA32 = 0x0202, /* Global Data Symbol 16:32 */ + CV_S_PUB32 = 0x0203, /* Public Symbol 16:32 */ + CV_S_LPROC32 = 0x0204, /* Local Start 16:32 */ + CV_S_GPROC32 = 0x0205, /* Global Start 16:32 */ + CV_S_THUNK32 = 0x0206, /* Thunk Start 16:32 */ + CV_S_BLOCK32 = 0x0207, /* Block Start 16:32 */ + CV_S_WITH32 = 0x0208, /* With Start 16:32 */ + CV_S_LABEL32 = 0x0209, /* Code Label 16:32 */ + CV_S_CEXMODEL32 = 0x0210, /* Change Execution Model 16:32 */ + CV_S_VFTPATH32 = 0x020b, /* Virtual Function Table Path 16:32 */ + CV_S_REGREL32 = 0x020c, /* Register Relative 16:32 */ + CV_S_LTHREAD32 = 0x020d, /* Local Thread Storage 16:32 */ + CV_S_GTHREAD32 = 0x020e, /* Global Thread Storage 16:32 */ + + /* Symbols for MIPS */ + CV_S_LPROCMIPS = 0x0300, /* Local procedure start MIPS */ + CV_S_GPROCMIPS = 0x0301, /* Global procedure start MIPS */ + + /* Symbols for CV8 - strings are 0 terminated rather than length-prefix. + * Incomplete and unofficial. + */ + CV8_S_OBJNAME = 0x1101, /* Object File Name */ + CV8_S_LABEL32 = 0x1105, /* Code Label 16:32 */ + CV8_S_LDATA32 = 0x110c, /* Local Data 16:32 */ + CV8_S_GDATA32 = 0x110d, /* Global Data 16:32 */ + CV8_S_LPROC32 = 0x1110, /* Local Start 16:32 */ + CV8_S_COMPILE = 0x1116 /* Compile Flag */ + }; + + typedef struct cv8_symhead { + yasm_dbgfmt_cv *dbgfmt_cv; + enum cv8_symheadtype type; + yasm_bytecode *start_prevbc; + yasm_bytecode *end_prevbc; + int first; /* nonzero if first symhead in section */ + } cv8_symhead; + + typedef struct cv8_fileinfo { + yasm_dbgfmt_cv *dbgfmt_cv; + const cv_filename *fn; + } cv8_fileinfo; + + /* Note: each line number group is associated with a file AND a section */ + typedef struct cv8_linepair { + unsigned long offset; + unsigned long line; + } cv8_linepair; + + /* Decrease linked list overhead a bit doing it this way */ + typedef struct cv8_lineset { + STAILQ_ENTRY(cv8_lineset) link; + cv8_linepair pairs[126]; + size_t num_pairs; + } cv8_lineset; + + typedef struct cv8_lineinfo { + STAILQ_ENTRY(cv8_lineinfo) link; + yasm_dbgfmt_cv *dbgfmt_cv; + const cv_filename *fn; /* filename associated with line numbers */ + yasm_section *sect; /* section line numbers are for */ + yasm_symrec *sectsym; /* symbol for beginning of sect */ + unsigned long num_linenums; + STAILQ_HEAD(, cv8_lineset) linesets; + } cv8_lineinfo; + + /* Symbols use a bit of meta-programming to encode formats: each character + * of format represents the output generated, as follows: + * 'b' : 1 byte value (integer) + * 'h' : 2 byte value (integer) + * 'w' : 4 byte value (integer) + * 'Y' : symrec SECREL+SECTION (pointer) + * 'T' : type index (integer) + * 'S' : length-prefixed string (pointer) + * 'Z' : 0-terminated string (pointer) + */ + typedef struct cv_sym { + yasm_dbgfmt_cv *dbgfmt_cv; + enum cv_symtype type; + const char *format; + union { + unsigned long i; + void *p; + } args[10]; + } cv_sym; + + /* Bytecode callback function prototypes */ + static void cv8_symhead_bc_destroy(void *contents); + static void cv8_symhead_bc_print(const void *contents, FILE *f, + int indent_level); -static yasm_bc_resolve_flags cv8_symhead_bc_resolve - (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist); ++static int cv8_symhead_bc_calc_len ++ (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data); + static int cv8_symhead_bc_tobytes + (yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_value_func output_value, + /*@null@*/ yasm_output_reloc_func output_reloc); + + static void cv8_fileinfo_bc_destroy(void *contents); + static void cv8_fileinfo_bc_print(const void *contents, FILE *f, + int indent_level); -static yasm_bc_resolve_flags cv8_fileinfo_bc_resolve - (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist); ++static int cv8_fileinfo_bc_calc_len ++ (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data); + static int cv8_fileinfo_bc_tobytes + (yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_value_func output_value, + /*@null@*/ yasm_output_reloc_func output_reloc); + + static void cv8_lineinfo_bc_destroy(void *contents); + static void cv8_lineinfo_bc_print(const void *contents, FILE *f, + int indent_level); -static yasm_bc_resolve_flags cv8_lineinfo_bc_resolve - (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist); ++static int cv8_lineinfo_bc_calc_len ++ (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data); + static int cv8_lineinfo_bc_tobytes + (yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_value_func output_value, + /*@null@*/ yasm_output_reloc_func output_reloc); + + static void cv_sym_bc_destroy(void *contents); + static void cv_sym_bc_print(const void *contents, FILE *f, int indent_level); -static yasm_bc_resolve_flags cv_sym_bc_resolve - (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist); ++static int cv_sym_bc_calc_len ++ (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data); + static int cv_sym_bc_tobytes + (yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_value_func output_value, + /*@null@*/ yasm_output_reloc_func output_reloc); + + /* Bytecode callback structures */ + static const yasm_bytecode_callback cv8_symhead_bc_callback = { + cv8_symhead_bc_destroy, + cv8_symhead_bc_print, + yasm_bc_finalize_common, - cv8_symhead_bc_resolve, ++ cv8_symhead_bc_calc_len, ++ yasm_bc_expand_common, + cv8_symhead_bc_tobytes, + 0 + }; + + static const yasm_bytecode_callback cv8_fileinfo_bc_callback = { + cv8_fileinfo_bc_destroy, + cv8_fileinfo_bc_print, + yasm_bc_finalize_common, - cv8_fileinfo_bc_resolve, ++ cv8_fileinfo_bc_calc_len, ++ yasm_bc_expand_common, + cv8_fileinfo_bc_tobytes, + 0 + }; + + static const yasm_bytecode_callback cv8_lineinfo_bc_callback = { + cv8_lineinfo_bc_destroy, + cv8_lineinfo_bc_print, + yasm_bc_finalize_common, - cv8_lineinfo_bc_resolve, ++ cv8_lineinfo_bc_calc_len, ++ yasm_bc_expand_common, + cv8_lineinfo_bc_tobytes, + 0 + }; + + static const yasm_bytecode_callback cv_sym_bc_callback = { + cv_sym_bc_destroy, + cv_sym_bc_print, + yasm_bc_finalize_common, - cv_sym_bc_resolve, ++ cv_sym_bc_calc_len, ++ yasm_bc_expand_common, + cv_sym_bc_tobytes, + 0 + }; + + static cv8_symhead *cv8_add_symhead(yasm_dbgfmt_cv *dbgfmt_cv, + yasm_section *sect, unsigned long type, + int first); + static void cv8_set_symhead_end(cv8_symhead *head, yasm_bytecode *end_prevbc); + + static yasm_bytecode *cv8_add_fileinfo + (yasm_dbgfmt_cv *dbgfmt_cv, yasm_section *sect, const cv_filename *fn); + + static unsigned long cv_sym_size(const cv_sym *cvs); + + + static cv_sym * + cv8_add_sym_objname(yasm_dbgfmt_cv *dbgfmt_cv, yasm_section *sect, + /*@keep@*/ char *objname) + { + yasm_bytecode *bc; + cv_sym *cvs = yasm_xmalloc(sizeof(cv_sym)); + cvs->dbgfmt_cv = dbgfmt_cv; + cvs->type = CV8_S_OBJNAME; + cvs->format = "wZ"; + cvs->args[0].i = 0; /* signature (0=asm) */ + cvs->args[1].p = objname; /* object filename */ + + bc = yasm_bc_create_common(&cv_sym_bc_callback, cvs, 0); + bc->len = cv_sym_size(cvs); + yasm_cv__append_bc(sect, bc); + return cvs; + } + + static cv_sym * + cv8_add_sym_compile(yasm_dbgfmt_cv *dbgfmt_cv, yasm_section *sect, + /*@keep@*/ char *creator) + { + yasm_bytecode *bc; + cv_sym *cvs = yasm_xmalloc(sizeof(cv_sym)); + cvs->dbgfmt_cv = dbgfmt_cv; + cvs->type = CV8_S_COMPILE; + cvs->format = "wwwwZh"; + cvs->args[0].i = 3; /* language (3=Masm) */ + + /* target processor; 0xD0 = AMD64 */ + if (strcmp(yasm_arch_keyword(dbgfmt_cv->arch), "x86") == 0) { + if (strcmp(yasm_arch_get_machine(dbgfmt_cv->arch), "amd64") == 0) + cvs->args[1].i = 0xD0; + else + cvs->args[1].i = 0x6; /* 686, FIXME */ + } else + cvs->args[1].i = 0; /* XXX: unknown */ + + cvs->args[2].i = 0; /* flags (assume 0 for now) */ + cvs->args[3].i = 0; /* creator version number (assume 0 for now) */ + cvs->args[4].p = creator; /* creator string */ + cvs->args[5].i = 0; /* no pairs of key/value */ + + bc = yasm_bc_create_common(&cv_sym_bc_callback, cvs, 0); + bc->len = cv_sym_size(cvs); + yasm_cv__append_bc(sect, bc); + return cvs; + } + + static cv_sym * + cv8_add_sym_label(yasm_dbgfmt_cv *dbgfmt_cv, yasm_section *sect, + yasm_symrec *sym) + { + yasm_bytecode *bc; + cv_sym *cvs = yasm_xmalloc(sizeof(cv_sym)); + cvs->dbgfmt_cv = dbgfmt_cv; + cvs->type = CV8_S_LABEL32; + cvs->format = "YbZ"; + cvs->args[0].p = sym; /* symrec for label */ + cvs->args[1].i = 0; /* flags (assume 0 for now) */ + cvs->args[2].p = yasm__xstrdup(yasm_symrec_get_name(sym)); + + bc = yasm_bc_create_common(&cv_sym_bc_callback, cvs, 0); + bc->len = cv_sym_size(cvs); + yasm_cv__append_bc(sect, bc); + return cvs; + } + + static cv_sym * + cv8_add_sym_data(yasm_dbgfmt_cv *dbgfmt_cv, yasm_section *sect, + unsigned long type, yasm_symrec *sym, int is_global) + { + yasm_bytecode *bc; + cv_sym *cvs = yasm_xmalloc(sizeof(cv_sym)); + cvs->dbgfmt_cv = dbgfmt_cv; + cvs->type = is_global ? CV8_S_GDATA32 : CV8_S_LDATA32; + cvs->format = "wYZ"; + cvs->args[0].i = type; /* type index */ + cvs->args[1].p = sym; /* symrec for label */ + cvs->args[2].p = yasm__xstrdup(yasm_symrec_get_name(sym)); + + bc = yasm_bc_create_common(&cv_sym_bc_callback, cvs, 0); + bc->len = cv_sym_size(cvs); + yasm_cv__append_bc(sect, bc); + return cvs; + } + + static size_t + cv_dbgfmt_add_file(yasm_dbgfmt_cv *dbgfmt_cv, size_t filenum, + const char *filename) + { + char *pathname; + size_t i; + yasm_md5_context context; + FILE *f; + unsigned char *buf; + size_t len; + + /* 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_cv->filenames[filenum].filename || + strcmp(dbgfmt_cv->filenames[filenum].filename, filename) == 0) + break; + } + } else + filenum--; /* array index is 0-based */ + + /* Realloc table if necessary */ + if (filenum >= dbgfmt_cv->filenames_allocated) { + size_t old_allocated = dbgfmt_cv->filenames_allocated; + dbgfmt_cv->filenames_allocated = filenum+32; + dbgfmt_cv->filenames = yasm_xrealloc(dbgfmt_cv->filenames, + sizeof(cv_filename)*dbgfmt_cv->filenames_allocated); + for (i=old_allocated; ifilenames_allocated; i++) { + dbgfmt_cv->filenames[i].pathname = NULL; + dbgfmt_cv->filenames[i].filename = NULL; + dbgfmt_cv->filenames[i].str_off = 0; + dbgfmt_cv->filenames[i].info_off = 0; + } + } + + /* Calculate MD5 checksum of file */ + buf = yasm_xmalloc(1024); + yasm_md5_init(&context); + f = fopen(filename, "rb"); + if (!f) + yasm__fatal(N_("codeview: could not open source file")); + while ((len = fread(buf, 1, 1024, f)) > 0) + yasm_md5_update(&context, buf, len); + yasm_md5_final(dbgfmt_cv->filenames[filenum].digest, &context); + fclose(f); + yasm_xfree(buf); + + /* Actually save in table */ + if (dbgfmt_cv->filenames[filenum].pathname) + yasm_xfree(dbgfmt_cv->filenames[filenum].pathname); + if (dbgfmt_cv->filenames[filenum].filename) + yasm_xfree(dbgfmt_cv->filenames[filenum].filename); + + pathname = yasm__abspath(filename); + dbgfmt_cv->filenames[filenum].pathname = pathname; + dbgfmt_cv->filenames[filenum].filename = yasm__xstrdup(filename); + + /* Update table size */ + if (filenum >= dbgfmt_cv->filenames_size) + dbgfmt_cv->filenames_size = filenum + 1; + + return filenum; + } + + static yasm_bytecode * + cv_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, NULL, 0); + yasm_bc_finalize(bc, yasm_cv__append_bc(sect, bc)); - yasm_bc_resolve(bc, 0, NULL); ++ yasm_bc_calc_len(bc, NULL, NULL); + return bc; + } + + typedef struct cv_line_info { + yasm_section *debug_symline; + yasm_dbgfmt_cv *dbgfmt_cv; + yasm_errwarns *errwarns; + unsigned int num_lineinfos; + STAILQ_HEAD(, cv8_lineinfo) cv8_lineinfos; + /*@null@*/ cv8_lineinfo *cv8_cur_li; + /*@null@*/ cv8_lineset *cv8_cur_ls; + } cv_line_info; + + static int + cv_generate_line_bc(yasm_bytecode *bc, /*@null@*/ void *d) + { + cv_line_info *info = (cv_line_info *)d; + yasm_dbgfmt_cv *dbgfmt_cv = info->dbgfmt_cv; + size_t i; + const char *filename; + unsigned long line; + /*@null@*/ yasm_bytecode *nextbc = yasm_bc__next(bc); + yasm_section *sect = yasm_bc_get_section(bc); + + if (nextbc && bc->offset == nextbc->offset) + return 0; + + yasm_linemap_lookup(dbgfmt_cv->linemap, bc->line, &filename, &line); + + if (!info->cv8_cur_li + || strcmp(filename, info->cv8_cur_li->fn->filename) != 0) { + yasm_bytecode *sectbc; + char symname[8]; + + /* first see if we already have a lineinfo that is for this section and + * filename + */ + STAILQ_FOREACH(info->cv8_cur_li, &info->cv8_lineinfos, link) { + if (sect == info->cv8_cur_li->sect + && strcmp(filename, info->cv8_cur_li->fn->filename) == 0) + break; + } + + if (info->cv8_cur_li) { + info->cv8_cur_ls = STAILQ_LAST(&info->cv8_cur_li->linesets, + cv8_lineset, link); + goto done; /* found one */ + } + + /* Nope; find file */ + for (i=0; ifilenames_size; i++) { + if (strcmp(filename, dbgfmt_cv->filenames[i].filename) == 0) + break; + } + if (i >= dbgfmt_cv->filenames_size) + yasm_internal_error(N_("could not find filename in table")); + + /* and create new lineinfo structure */ + info->cv8_cur_li = yasm_xmalloc(sizeof(cv8_lineinfo)); + info->cv8_cur_li->dbgfmt_cv = dbgfmt_cv; + info->cv8_cur_li->fn = &dbgfmt_cv->filenames[i]; + info->cv8_cur_li->sect = sect; + sectbc = yasm_section_bcs_first(sect); + if (sectbc->symrecs && sectbc->symrecs[0]) + info->cv8_cur_li->sectsym = sectbc->symrecs[0]; + else { + sprintf(symname, ".%06u", info->num_lineinfos++); + info->cv8_cur_li->sectsym = + yasm_symtab_define_label(dbgfmt_cv->symtab, symname, sectbc, + 1, 0); + } + info->cv8_cur_li->num_linenums = 0; + STAILQ_INIT(&info->cv8_cur_li->linesets); + STAILQ_INSERT_TAIL(&info->cv8_lineinfos, info->cv8_cur_li, link); + info->cv8_cur_ls = NULL; + } + done: + + /* build new lineset if necessary */ + if (!info->cv8_cur_ls || info->cv8_cur_ls->num_pairs >= 126) { + info->cv8_cur_ls = yasm_xmalloc(sizeof(cv8_lineset)); + info->cv8_cur_ls->num_pairs = 0; + STAILQ_INSERT_TAIL(&info->cv8_cur_li->linesets, info->cv8_cur_ls, link); + } + + /* add linepair for this bytecode */ + info->cv8_cur_ls->pairs[info->cv8_cur_ls->num_pairs].offset = bc->offset; + info->cv8_cur_ls->pairs[info->cv8_cur_ls->num_pairs].line = + 0x80000000 | line; + info->cv8_cur_ls->num_pairs++; + info->cv8_cur_li->num_linenums++; + + return 0; + } + + static int + cv_generate_line_section(yasm_section *sect, /*@null@*/ void *d) + { + cv_line_info *info = (cv_line_info *)d; + + if (!yasm_section_is_code(sect)) + return 0; /* not code, so no line data for this section */ + + info->cv8_cur_li = NULL; + info->cv8_cur_ls = NULL; + + yasm_section_bcs_traverse(sect, info->errwarns, info, cv_generate_line_bc); + + return 0; + } + + static int + cv_generate_filename(const char *filename, void *d) + { + yasm_dbgfmt_cv *dbgfmt_cv = (yasm_dbgfmt_cv *)d; + cv_dbgfmt_add_file(dbgfmt_cv, 0, filename); + return 0; + } + + static int + cv_generate_sym(yasm_symrec *sym, void *d) + { + cv_line_info *info = (cv_line_info *)d; + yasm_bytecode *precbc; + + /* only care about labels (for now) */ + if (!yasm_symrec_get_label(sym, &precbc)) + return 0; + + /* TODO: add data types; until then, just mark everything as UBYTE */ + if (yasm_section_is_code(yasm_bc_get_section(precbc))) + cv8_add_sym_label(info->dbgfmt_cv, info->debug_symline, sym); + else + cv8_add_sym_data(info->dbgfmt_cv, info->debug_symline, 0x20, sym, + yasm_symrec_get_visibility(sym) & YASM_SYM_GLOBAL?1:0); + return 0; + } + + yasm_section * + yasm_cv__generate_symline(yasm_dbgfmt_cv *dbgfmt_cv, yasm_errwarns *errwarns) + { + cv_line_info info; + int new; + size_t i; + cv8_symhead *head; + cv8_lineinfo *li; + yasm_bytecode *bc; + unsigned long off; + + /* Generate filenames based on linemap */ + yasm_linemap_traverse_filenames(dbgfmt_cv->linemap, dbgfmt_cv, + cv_generate_filename); + + info.dbgfmt_cv = dbgfmt_cv; + info.errwarns = errwarns; + info.debug_symline = yasm_object_get_general(dbgfmt_cv->object, + ".debug$S", 0, 1, 0, 0, &new, + 0); + info.num_lineinfos = 0; + STAILQ_INIT(&info.cv8_lineinfos); + info.cv8_cur_li = NULL; + info.cv8_cur_ls = NULL; + + /* source filenames string table */ + head = cv8_add_symhead(dbgfmt_cv, info.debug_symline, CV8_FILE_STRTAB, 1); + cv_append_str(info.debug_symline, ""); + off = 1; + for (i=0; ifilenames_size; i++) { + if (!dbgfmt_cv->filenames[i].pathname) { + yasm_error_set(YASM_ERROR_GENERAL, + N_("codeview file number %d unassigned"), i+1); + yasm_errwarn_propagate(errwarns, 0); + continue; + } + bc = cv_append_str(info.debug_symline, + dbgfmt_cv->filenames[i].pathname); + dbgfmt_cv->filenames[i].str_off = off; + off += bc->len; + } + cv8_set_symhead_end(head, yasm_section_bcs_last(info.debug_symline)); + + /* Align 4 */ + bc = yasm_bc_create_align + (yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(4)), 0), + NULL, NULL, NULL, 0); + yasm_bc_finalize(bc, yasm_cv__append_bc(info.debug_symline, bc)); - yasm_bc_resolve(bc, 0, NULL); ++ yasm_bc_calc_len(bc, NULL, NULL); + + /* source file info table */ + head = cv8_add_symhead(dbgfmt_cv, info.debug_symline, CV8_FILE_INFO, 0); + off = 0; + for (i=0; ifilenames_size; i++) { + if (!dbgfmt_cv->filenames[i].pathname) + continue; + bc = cv8_add_fileinfo(dbgfmt_cv, info.debug_symline, + &dbgfmt_cv->filenames[i]); + dbgfmt_cv->filenames[i].info_off = off; + off += bc->len; + } + cv8_set_symhead_end(head, yasm_section_bcs_last(info.debug_symline)); + + /* Already aligned 4 */ + + /* Generate line numbers for sections */ + yasm_object_sections_traverse(dbgfmt_cv->object, (void *)&info, + cv_generate_line_section); + + /* Output line numbers for sections */ + STAILQ_FOREACH(li, &info.cv8_lineinfos, link) { + head = cv8_add_symhead(dbgfmt_cv, info.debug_symline, CV8_LINE_NUMS, + 0); + bc = yasm_bc_create_common(&cv8_lineinfo_bc_callback, li, 0); + bc->len = 24+li->num_linenums*8; + yasm_cv__append_bc(info.debug_symline, bc); + cv8_set_symhead_end(head, yasm_section_bcs_last(info.debug_symline)); + } + + /* Already aligned 4 */ + + /* Output debugging symbols */ + head = cv8_add_symhead(dbgfmt_cv, info.debug_symline, CV8_DEBUG_SYMS, 0); + /* add object and compile flag first */ + cv8_add_sym_objname(dbgfmt_cv, info.debug_symline, + yasm__abspath(yasm_object_get_object_fn(dbgfmt_cv->object))); + cv8_add_sym_compile(dbgfmt_cv, info.debug_symline, + yasm__xstrdup(PACKAGE_NAME " " PACKAGE_INTVER "." + PACKAGE_BUILD)); + /* then iterate through symbol table */ + yasm_symtab_traverse(dbgfmt_cv->symtab, &info, cv_generate_sym); + cv8_set_symhead_end(head, yasm_section_bcs_last(info.debug_symline)); + + /* Align 4 at end */ + bc = yasm_bc_create_align + (yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(4)), 0), + NULL, NULL, NULL, 0); + yasm_bc_finalize(bc, yasm_cv__append_bc(info.debug_symline, bc)); - yasm_bc_resolve(bc, 0, NULL); ++ yasm_bc_calc_len(bc, NULL, NULL); + + return info.debug_symline; + } + + static void + cv_out_sym(yasm_symrec *sym, unsigned long off, yasm_bytecode *bc, + unsigned char **bufp, void *d, yasm_output_value_func output_value) + { + yasm_value val; + + /* sym in its section */ + yasm_value_init_sym(&val, sym, 32); + val.section_rel = 1; + output_value(&val, *bufp, 4, off, bc, 0, d); + *bufp += 4; + + /* section index */ + yasm_value_init_sym(&val, sym, 16); + val.seg_of = 1; + output_value(&val, *bufp, 2, off+4, bc, 0, d); + *bufp += 2; + } + + static cv8_symhead * + cv8_add_symhead(yasm_dbgfmt_cv *dbgfmt_cv, yasm_section *sect, + unsigned long type, int first) + { + cv8_symhead *head; + yasm_bytecode *bc; + + head = yasm_xmalloc(sizeof(cv8_symhead)); + head->dbgfmt_cv = dbgfmt_cv; + head->type = type; + head->first = first; + head->start_prevbc = yasm_section_bcs_last(sect); + + bc = yasm_bc_create_common(&cv8_symhead_bc_callback, head, 0); + if (first) + bc->len = 12; + else + bc->len = 8; + + head->end_prevbc = bc; + yasm_cv__append_bc(sect, bc); + return head; + } + + static void + cv8_set_symhead_end(cv8_symhead *head, yasm_bytecode *end_prevbc) + { + head->end_prevbc = end_prevbc; + } + + static void + cv8_symhead_bc_destroy(void *contents) + { + yasm_xfree(contents); + } + + static void + cv8_symhead_bc_print(const void *contents, FILE *f, int indent_level) + { + /* TODO */ + } + -static yasm_bc_resolve_flags -cv8_symhead_bc_resolve(yasm_bytecode *bc, int save, - yasm_calc_bc_dist_func calc_bc_dist) ++static int ++cv8_symhead_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, ++ void *add_span_data) + { - yasm_internal_error(N_("tried to resolve a codeview symhead bytecode")); ++ yasm_internal_error(N_("tried to calc_len a codeview symhead bytecode")); + /*@notreached@*/ - return YASM_BC_RESOLVE_MIN_LEN; ++ return 0; + } + + static int + cv8_symhead_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_value_func output_value, + yasm_output_reloc_func output_reloc) + { + cv8_symhead *head = (cv8_symhead *)bc->contents; + yasm_dbgfmt_cv *dbgfmt_cv = head->dbgfmt_cv; + unsigned char *buf = *bufp; + yasm_intnum *intn, *cval; + + cval = yasm_intnum_create_uint(4); + /* Output "version" if first */ + if (head->first) { + yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc, 0); + buf += 4; + } + + /* Type contained - 4 bytes */ + yasm_intnum_set_uint(cval, head->type); + yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc, 0); + buf += 4; + + /* Total length of info (following this field) - 4 bytes */ + yasm_intnum_set_uint(cval, bc->len); + intn = yasm_common_calc_bc_dist(head->start_prevbc, head->end_prevbc); + yasm_intnum_calc(intn, YASM_EXPR_SUB, cval); + yasm_arch_intnum_tobytes(dbgfmt_cv->arch, intn, buf, 4, 32, 0, bc, 0); + buf += 4; + yasm_intnum_destroy(intn); + + *bufp = buf; + + yasm_intnum_destroy(cval); + return 0; + } + + static yasm_bytecode * + cv8_add_fileinfo(yasm_dbgfmt_cv *dbgfmt_cv, yasm_section *sect, + const cv_filename *fn) + { + cv8_fileinfo *fi; + yasm_bytecode *bc; + + fi = yasm_xmalloc(sizeof(cv8_fileinfo)); + fi->dbgfmt_cv = dbgfmt_cv; + fi->fn = fn; + + bc = yasm_bc_create_common(&cv8_fileinfo_bc_callback, fi, 0); + bc->len = 24; + + yasm_cv__append_bc(sect, bc); + return bc; + } + + static void + cv8_fileinfo_bc_destroy(void *contents) + { + yasm_xfree(contents); + } + + static void + cv8_fileinfo_bc_print(const void *contents, FILE *f, int indent_level) + { + /* TODO */ + } + -static yasm_bc_resolve_flags -cv8_fileinfo_bc_resolve(yasm_bytecode *bc, int save, - yasm_calc_bc_dist_func calc_bc_dist) ++static int ++cv8_fileinfo_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, ++ void *add_span_data) + { - yasm_internal_error(N_("tried to resolve a codeview fileinfo bytecode")); ++ yasm_internal_error(N_("tried to calc_len a codeview fileinfo bytecode")); + /*@notreached@*/ - return YASM_BC_RESOLVE_MIN_LEN; ++ return 0; + } + + static int + cv8_fileinfo_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_value_func output_value, + yasm_output_reloc_func output_reloc) + { + cv8_fileinfo *fi = (cv8_fileinfo *)bc->contents; + yasm_dbgfmt_cv *dbgfmt_cv = fi->dbgfmt_cv; + unsigned char *buf = *bufp; + yasm_intnum *cval; + int i; + + /* Offset in filename string table */ + cval = yasm_intnum_create_uint(fi->fn->str_off); + yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc, 0); + buf += 4; + + /* Checksum type/length */ + yasm_intnum_set_uint(cval, 0x0110); + yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 2, 16, 0, bc, 0); + buf += 2; + + /* Checksum */ + for (i=0; i<16; i++) + YASM_WRITE_8(buf, fi->fn->digest[i]); + + /* Pad */ + YASM_WRITE_8(buf, 0); + YASM_WRITE_8(buf, 0); + + *bufp = buf; + + yasm_intnum_destroy(cval); + return 0; + } + + static void + cv8_lineinfo_bc_destroy(void *contents) + { + cv8_lineinfo *li = (cv8_lineinfo *)contents; + cv8_lineset *ls1, *ls2; + + /* delete line sets */ + ls1 = STAILQ_FIRST(&li->linesets); + while (ls1) { + ls2 = STAILQ_NEXT(ls1, link); + yasm_xfree(ls1); + ls1 = ls2; + } + + yasm_xfree(contents); + } + + static void + cv8_lineinfo_bc_print(const void *contents, FILE *f, int indent_level) + { + /* TODO */ + } + -static yasm_bc_resolve_flags -cv8_lineinfo_bc_resolve(yasm_bytecode *bc, int save, - yasm_calc_bc_dist_func calc_bc_dist) ++static int ++cv8_lineinfo_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, ++ void *add_span_data) + { - yasm_internal_error(N_("tried to resolve a codeview linehead bytecode")); ++ yasm_internal_error(N_("tried to calc_len a codeview linehead bytecode")); + /*@notreached@*/ - return YASM_BC_RESOLVE_MIN_LEN; ++ return 0; + } + + static int + cv8_lineinfo_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_value_func output_value, + yasm_output_reloc_func output_reloc) + { + cv8_lineinfo *li = (cv8_lineinfo *)bc->contents; + yasm_dbgfmt_cv *dbgfmt_cv = li->dbgfmt_cv; + unsigned char *buf = *bufp; + yasm_intnum *cval; + unsigned long i; + cv8_lineset *ls; + + /* start offset and section */ + cv_out_sym(li->sectsym, 0, bc, &buf, d, output_value); + + /* Two bytes of pad/alignment */ + YASM_WRITE_8(buf, 0); + YASM_WRITE_8(buf, 0); + + /* Section length covered by line number info */ + cval = yasm_common_calc_bc_dist(yasm_section_bcs_first(li->sect), + yasm_section_bcs_last(li->sect)); + yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc, 0); + buf += 4; + + /* Offset of source file in info table */ + yasm_intnum_set_uint(cval, li->fn->info_off); + yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc, 0); + buf += 4; + + /* Number of line number pairs */ + yasm_intnum_set_uint(cval, li->num_linenums); + yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc, 0); + buf += 4; + + /* Number of bytes of line number pairs + 12 (no, I don't know why) */ + yasm_intnum_set_uint(cval, li->num_linenums*8+12); + yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc, 0); + buf += 4; + + /* Offset / line number pairs */ + i = 0; + STAILQ_FOREACH(ls, &li->linesets, link) { + unsigned long j; + for (j=0; inum_linenums && j<126; i++, j++) { + /* offset in section */ + yasm_intnum_set_uint(cval, ls->pairs[j].offset); + yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc, + 0); + buf += 4; + + /* line number in file */ + yasm_intnum_set_uint(cval, ls->pairs[j].line); + yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc, + 0); + buf += 4; + } + } + + *bufp = buf; + + yasm_intnum_destroy(cval); + return 0; + } + + static unsigned long + cv_sym_size(const cv_sym *cvs) + { + const char *ch = cvs->format; + unsigned long len = 4; /* sym length and type */ + unsigned long slen; + int arg = 0; + + while (*ch) { + switch (*ch) { + case 'b': + len++; + arg++; + break; + case 'h': + len += 2; + arg++; + break; + case 'w': + len += 4; + arg++; + break; + case 'Y': + len += 6; /* XXX: will be 4 in 16-bit version */ + arg++; + break; + case 'T': + len += 4; /* XXX: will be 2 in CV4 */ + arg++; + break; + case 'S': + len += 1; /* XXX: is this 1 or 2? */ + slen = strlen((const char *)cvs->args[arg++].p); + len += slen <= 0xff ? slen : 0xff; + break; + case 'Z': + len += strlen((const char *)cvs->args[arg++].p) + 1; + break; + default: + yasm_internal_error(N_("unknown sym format character")); + } + ch++; + } + + return len; + } + + static void + cv_sym_bc_destroy(void *contents) + { + cv_sym *cvs = (cv_sym *)contents; + const char *ch = cvs->format; + int arg = 0; + + while (*ch) { + switch (*ch) { + case 'b': + case 'h': + case 'w': + case 'Y': + case 'T': + arg++; + break; /* nothing to destroy */ + case 'S': + case 'Z': + yasm_xfree(cvs->args[arg++].p); + break; + default: + yasm_internal_error(N_("unknown sym format character")); + } + ch++; + } + + yasm_xfree(contents); + } + + static void + cv_sym_bc_print(const void *contents, FILE *f, int indent_level) + { + /* TODO */ + } + -static yasm_bc_resolve_flags -cv_sym_bc_resolve(yasm_bytecode *bc, int save, - yasm_calc_bc_dist_func calc_bc_dist) ++static int ++cv_sym_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, ++ void *add_span_data) + { - yasm_internal_error(N_("tried to resolve a codeview sym bytecode")); ++ yasm_internal_error(N_("tried to calc_len a codeview sym bytecode")); + /*@notreached@*/ - return YASM_BC_RESOLVE_MIN_LEN; ++ return 0; + } + + static int + cv_sym_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_value_func output_value, + yasm_output_reloc_func output_reloc) + { + cv_sym *cvs = (cv_sym *)bc->contents; + yasm_dbgfmt_cv *dbgfmt_cv = cvs->dbgfmt_cv; + unsigned char *buf = *bufp; + yasm_intnum *cval; + const char *ch = cvs->format; + size_t len; + int arg = 0; + + /* Total length of record (following this field) - 2 bytes */ + cval = yasm_intnum_create_uint(bc->len-2); + yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 2, 16, 0, bc, 1); + buf += 2; + + /* Type contained - 2 bytes */ + yasm_intnum_set_uint(cval, cvs->type); + yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 2, 16, 0, bc, 0); + buf += 2; + + while (*ch) { + switch (*ch) { + case 'b': + YASM_WRITE_8(buf, cvs->args[arg].i); + arg++; + break; + case 'h': + yasm_intnum_set_uint(cval, cvs->args[arg++].i); + yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 2, 16, 0, + bc, 0); + buf += 2; + break; + case 'w': + yasm_intnum_set_uint(cval, cvs->args[arg++].i); + yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, + bc, 0); + buf += 4; + break; + case 'Y': + cv_out_sym((yasm_symrec *)cvs->args[arg++].p, + (unsigned long)(buf-(*bufp)), bc, &buf, d, + output_value); + break; + case 'T': + yasm_intnum_set_uint(cval, cvs->args[arg++].i); + yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, + bc, 0); + buf += 4; /* XXX: will be 2 in CV4 */ + break; + case 'S': + len = strlen((char *)cvs->args[arg].p); + len = len <= 0xff ? len : 0xff; + YASM_WRITE_8(buf, len); + memcpy(buf, (char *)cvs->args[arg].p, len); + buf += len; + arg++; + break; + case 'Z': + len = strlen((char *)cvs->args[arg].p)+1; + memcpy(buf, (char *)cvs->args[arg].p, len); + buf += len; + arg++; + break; + default: + yasm_internal_error(N_("unknown leaf format character")); + } + ch++; + } + + *bufp = buf; + + yasm_intnum_destroy(cval); + return 0; + } diff --cc modules/dbgfmts/codeview/cv-type.c index 00000000,51cb897b..c5d049cb mode 000000,100644..100644 --- a/modules/dbgfmts/codeview/cv-type.c +++ b/modules/dbgfmts/codeview/cv-type.c @@@ -1,0 -1,780 +1,781 @@@ + /* + * CodeView debugging format - type 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 "cv-dbgfmt.h" + + enum cv_reservedtype { + /* Bitfields representation - type */ + CV_TYPE_SPECIAL = 0x00<<4, /* Special */ + CV_TYPE_SIGNED = 0x01<<4, /* Signed integral value */ + CV_TYPE_UNSIGNED = 0x02<<4, /* Unsigned integral value */ + CV_TYPE_BOOLEAN = 0x03<<4, /* Boolean */ + CV_TYPE_REAL = 0x04<<4, /* Real */ + CV_TYPE_COMPLEX = 0x05<<4, /* Complex */ + CV_TYPE_SPECIAL2 = 0x06<<4, /* Special2 */ + CV_TYPE_REALINT = 0x07<<4, /* Really int value */ + + /* "size" of CV_TYPE_SPECIAL */ + CV_SPECIAL_NOTYPE = 0x00<<0, /* No type */ + CV_SPECIAL_ABS = 0x01<<0, /* Absolute symbol */ + CV_SPECIAL_SEG = 0x02<<0, /* Segment */ + CV_SPECIAL_VOID = 0x03<<0, /* Void */ + CV_SPECIAL_CURRENCY = 0x04<<0, /* Basic 8-byte currency value */ + CV_SPECIAL_NEARBSTR = 0x05<<0, /* Near Basic string */ + CV_SPECIAL_FARBSTR = 0x06<<0, /* Far Basic string */ + + /* Size of CV_TYPE_SIGNED, CV_TYPE_UNSIGNED, and CV_TYPE_BOOLEAN */ + CV_INTEGER_1BYTE = 0x00<<0, /* 1 byte */ + CV_INTEGER_2BYTE = 0x01<<0, /* 2 byte */ + CV_INTEGER_4BYTE = 0x02<<0, /* 4 byte */ + CV_INTEGER_8BYTE = 0x03<<0, /* 8 byte */ + + /* Size of CV_TYPE_REAL and CV_TYPE_COMPLEX */ + CV_REAL_32BIT = 0x00<<0, /* 32 bit */ + CV_REAL_64BIT = 0x01<<0, /* 64 bit */ + CV_REAL_80BIT = 0x02<<0, /* 80 bit */ + CV_REAL_128BIT = 0x03<<0, /* 128 bit */ + CV_REAL_48BIT = 0x04<<0, /* 48 bit */ + + /* "size" of CV_TYPE_SPECIAL2 */ + CV_SPECIAL2_BIT = 0x00<<0, /* Bit */ + CV_SPECIAL2_PASCHAR = 0x01<<0, /* Pascal CHAR */ + + /* Size of CV_TYPE_REALINT */ + CV_REALINT_CHAR = 0x00<<0, /* Char */ + CV_REALINT_WCHAR = 0x01<<0, /* Wide character */ + CV_REALINT_S2BYTE = 0x02<<0, /* 2-byte signed integer */ + CV_REALINT_U2BYTE = 0x03<<0, /* 2-byte unsigned integer */ + CV_REALINT_S4BYTE = 0x04<<0, /* 4-byte signed integer */ + CV_REALINT_U4BYTE = 0x05<<0, /* 4-byte unsigned integer */ + CV_REALINT_S8BYTE = 0x06<<0, /* 8-byte signed integer */ + CV_REALINT_U8BYTE = 0x07<<0, /* 8-byte unsigned integer */ + + /* Mode */ + CV_MODE_DIRECT = 0x00<<8, /* Direct; not a pointer */ + CV_MODE_NEAR = 0x01<<8, /* Near pointer */ + CV_MODE_FAR = 0x02<<8, /* Far pointer */ + CV_MODE_HUGE = 0x03<<8, /* Huge pointer */ + CV_MODE_NEAR32 = 0x04<<8, /* 32-bit near pointer */ + CV_MODE_FAR32 = 0x05<<8, /* 32-bit far pointer */ + CV_MODE_NEAR64 = 0x06<<8, /* 64-bit near pointer */ + + /* Pure primitive type listing - based on above bitfields */ + + /* Special Types */ + CV_T_NOTYPE = 0x0000, /* Uncharacterized type (no type) */ + CV_T_ABS = 0x0001, /* Absolute symbol */ + CV_T_SEGMENT = 0x0002, /* Segment type */ + CV_T_VOID = 0x0003, /* Void */ + CV_T_PVOID = 0x0103, /* Near pointer to void */ + CV_T_PFVOID = 0x0203, /* Far pointer to void */ + CV_T_PHVOID = 0x0303, /* Huge pointer to void */ + CV_T_32PVOID = 0x0403, /* 32-bit near pointer to void */ + CV_T_32PFVOID = 0x0503, /* 32-bit far pointer to void */ + CV_T_CURRENCY = 0x0004, /* Basic 8-byte currency value */ + CV_T_NBASICSTR = 0x0005, /* Near Basic string */ + CV_T_FBASICSTR = 0x0006, /* Far Basic string */ + CV_T_BIT = 0x0060, /* Bit */ + CV_T_PASCHAR = 0x0061, /* Pascal CHAR */ + /* Character Types */ + CV_T_CHAR = 0x0010, /* 8-bit signed */ + CV_T_UCHAR = 0x0020, /* 8-bit unsigned */ + CV_T_PCHAR = 0x0110, /* Near pointer to 8-bit signed */ + CV_T_PUCHAR = 0x0120, /* Near pointer to 8-bit unsigned */ + CV_T_PFCHAR = 0x0210, /* Far pointer to 8-bit signed */ + CV_T_PFUCHAR = 0x0220, /* Far pointer to 8-bit unsigned */ + CV_T_PHCHAR = 0x0310, /* Huge pointer to 8-bit signed */ + CV_T_PHUCHAR = 0x0320, /* Huge pointer to 8-bit unsigned */ + CV_T_32PCHAR = 0x0410, /* 16:32 near pointer to 8-bit signed */ + CV_T_32PUCHAR = 0x0420, /* 16:32 near pointer to 8-bit unsigned */ + CV_T_32PFCHAR = 0x0510, /* 16:32 far pointer to 8-bit signed */ + CV_T_32PFUCHAR = 0x0520, /* 16:32 far pointer to 8-bit unsigned */ + /* Real Character Types */ + CV_T_RCHAR = 0x0070, /* Real char */ + CV_T_PRCHAR = 0x0170, /* Near pointer to a real char */ + CV_T_PFRCHAR = 0x0270, /* Far pointer to a real char */ + CV_T_PHRCHAR = 0x0370, /* Huge pointer to a real char */ + CV_T_32PRCHAR = 0x0470, /* 16:32 near pointer to a real char */ + CV_T_32PFRCHAR = 0x0570, /* 16:32 far pointer to a real char */ + /* Wide Character Types */ + CV_T_WCHAR = 0x0071, /* Wide char */ + CV_T_PWCHAR = 0x0171, /* Near pointer to a wide char */ + CV_T_PFWCHAR = 0x0271, /* Far pointer to a wide char */ + CV_T_PHWCHAR = 0x0371, /* Huge pointer to a wide char */ + CV_T_32PWCHAR = 0x0471, /* 16:32 near pointer to a wide char */ + CV_T_32PFWCHAR = 0x0571, /* 16:32 far pointer to a wide char */ + /* Real 16-bit Integer Types */ + CV_T_INT2 = 0x0072, /* Real 16-bit signed int */ + CV_T_UINT2 = 0x0073, /* Real 16-bit unsigned int */ + CV_T_PINT2 = 0x0172, /* Near pointer to 16-bit signed int */ + CV_T_PUINT2 = 0x0173, /* Near pointer to 16-bit unsigned int */ + CV_T_PFINT2 = 0x0272, /* Far pointer to 16-bit signed int */ + CV_T_PFUINT2 = 0x0273, /* Far pointer to 16-bit unsigned int */ + CV_T_PHINT2 = 0x0372, /* Huge pointer to 16-bit signed int */ + CV_T_PHUINT2 = 0x0373, /* Huge pointer to 16-bit unsigned int */ + CV_T_32PINT2 = 0x0472, /* 16:32 near pointer to 16-bit signed int */ + CV_T_32PUINT2 = 0x0473, /* 16:32 near pointer to 16-bit unsigned int */ + CV_T_32PFINT2 = 0x0572, /* 16:32 far pointer to 16-bit signed int */ + CV_T_32PFUINT2 = 0x0573, /* 16:32 far pointer to 16-bit unsigned int */ + /* 16-bit Short Types */ + CV_T_SHORT = 0x0011, /* 16-bit signed */ + CV_T_USHORT = 0x0021, /* 16-bit unsigned */ + CV_T_PSHORT = 0x0111, /* Near pointer to 16-bit signed */ + CV_T_PUSHORT = 0x0121, /* Near pointer to 16-bit unsigned */ + CV_T_PFSHORT = 0x0211, /* Far pointer to 16-bit signed */ + CV_T_PFUSHORT = 0x0221, /* Far pointer to 16-bit unsigned */ + CV_T_PHSHORT = 0x0311, /* Huge pointer to 16-bit signed */ + CV_T_PHUSHORT = 0x0321, /* Huge pointer to 16-bit unsigned */ + CV_T_32PSHORT = 0x0411, /* 16:32 near pointer to 16-bit signed */ + CV_T_32PUSHORT = 0x0421, /* 16:32 near pointer to 16-bit unsigned */ + CV_T_32PFSHORT = 0x0511, /* 16:32 far pointer to 16-bit signed */ + CV_T_32PFUSHORT = 0x0521, /* 16:32 far pointer to 16-bit unsigned */ + /* Real 32-bit Integer Types */ + CV_T_INT4 = 0x0074, /* Real 32-bit signed int */ + CV_T_UINT4 = 0x0075, /* Real 32-bit unsigned int */ + CV_T_PINT4 = 0x0174, /* Near pointer to 32-bit signed int */ + CV_T_PUINT4 = 0x0175, /* Near pointer to 32-bit unsigned int */ + CV_T_PFINT4 = 0x0274, /* Far pointer to 32-bit signed int */ + CV_T_PFUINT4 = 0x0275, /* Far pointer to 32-bit unsigned int */ + CV_T_PHINT4 = 0x0374, /* Huge pointer to 32-bit signed int */ + CV_T_PHUINT4 = 0x0375, /* Huge pointer to 32-bit unsigned int */ + CV_T_32PINT4 = 0x0474, /* 16:32 near pointer to 32-bit signed int */ + CV_T_32PUINT4 = 0x0475, /* 16:32 near pointer to 32-bit unsigned int */ + CV_T_32PFINT4 = 0x0574, /* 16:32 far pointer to 32-bit signed int */ + CV_T_32PFUINT4 = 0x0575, /* 16:32 far pointer to 32-bit unsigned int */ + /* 32-bit Long Types */ + CV_T_LONG = 0x0012, /* 32-bit signed */ + CV_T_ULONG = 0x0022, /* 32-bit unsigned */ + CV_T_PLONG = 0x0112, /* Near pointer to 32-bit signed */ + CV_T_PULONG = 0x0122, /* Near pointer to 32-bit unsigned */ + CV_T_PFLONG = 0x0212, /* Far pointer to 32-bit signed */ + CV_T_PFULONG = 0x0222, /* Far pointer to 32-bit unsigned */ + CV_T_PHLONG = 0x0312, /* Huge pointer to 32-bit signed */ + CV_T_PHULONG = 0x0322, /* Huge pointer to 32-bit unsigned */ + CV_T_32PLONG = 0x0412, /* 16:32 near pointer to 32-bit signed */ + CV_T_32PULONG = 0x0422, /* 16:32 near pointer to 32-bit unsigned */ + CV_T_32PFLONG = 0x0512, /* 16:32 far pointer to 32-bit signed */ + CV_T_32PFULONG = 0x0522, /* 16:32 far pointer to 32-bit unsigned */ + /* Real 64-bit int Types */ + CV_T_INT8 = 0x0076, /* 64-bit signed int */ + CV_T_UINT8 = 0x0077, /* 64-bit unsigned int */ + CV_T_PINT8 = 0x0176, /* Near pointer to 64-bit signed int */ + CV_T_PUINT8 = 0x0177, /* Near pointer to 64-bit unsigned int */ + CV_T_PFINT8 = 0x0276, /* Far pointer to 64-bit signed int */ + CV_T_PFUINT8 = 0x0277, /* Far pointer to 64-bit unsigned int */ + CV_T_PHINT8 = 0x0376, /* Huge pointer to 64-bit signed int */ + CV_T_PHUINT8 = 0x0377, /* Huge pointer to 64-bit unsigned int */ + CV_T_32PINT8 = 0x0476, /* 16:32 near pointer to 64-bit signed int */ + CV_T_32PUINT8 = 0x0477, /* 16:32 near pointer to 64-bit unsigned int */ + CV_T_32PFINT8 = 0x0576, /* 16:32 far pointer to 64-bit signed int */ + CV_T_32PFUINT8 = 0x0577, /* 16:32 far pointer to 64-bit unsigned int */ + /* 64-bit Integral Types */ + CV_T_QUAD = 0x0013, /* 64-bit signed */ + CV_T_UQUAD = 0x0023, /* 64-bit unsigned */ + CV_T_PQUAD = 0x0113, /* Near pointer to 64-bit signed */ + CV_T_PUQUAD = 0x0123, /* Near pointer to 64-bit unsigned */ + CV_T_PFQUAD = 0x0213, /* Far pointer to 64-bit signed */ + CV_T_PFUQUAD = 0x0223, /* Far pointer to 64-bit unsigned */ + CV_T_PHQUAD = 0x0313, /* Huge pointer to 64-bit signed */ + CV_T_PHUQUAD = 0x0323, /* Huge pointer to 64-bit unsigned */ + CV_T_32PQUAD = 0x0413, /* 16:32 near pointer to 64-bit signed */ + CV_T_32PUQUAD = 0x0423, /* 16:32 near pointer to 64-bit unsigned */ + CV_T_32PFQUAD = 0x0513, /* 16:32 far pointer to 64-bit signed */ + CV_T_32PFUQUAD = 0x0523, /* 16:32 far pointer to 64-bit unsigned */ + /* 32-bit Real Types */ + CV_T_REAL32 = 0x0040, /* 32-bit real */ + CV_T_PREAL32 = 0x0140, /* Near pointer to 32-bit real */ + CV_T_PFREAL32 = 0x0240, /* Far pointer to 32-bit real */ + CV_T_PHREAL32 = 0x0340, /* Huge pointer to 32-bit real */ + CV_T_32PREAL32 = 0x0440, /* 16:32 near pointer to 32-bit real */ + CV_T_32PFREAL32 = 0x0540, /* 16:32 far pointer to 32-bit real */ + /* 48-bit Real Types */ + CV_T_REAL48 = 0x0044, /* 48-bit real */ + CV_T_PREAL48 = 0x0144, /* Near pointer to 48-bit real */ + CV_T_PFREAL48 = 0x0244, /* Far pointer to 48-bit real */ + CV_T_PHREAL48 = 0x0344, /* Huge pointer to 48-bit real */ + CV_T_32PREAL48 = 0x0444, /* 16:32 near pointer to 48-bit real */ + CV_T_32PFREAL48 = 0x0544, /* 16:32 far pointer to 48-bit real */ + /* 64-bit Real Types */ + CV_T_REAL64 = 0x0041, /* 64-bit real */ + CV_T_PREAL64 = 0x0141, /* Near pointer to 64-bit real */ + CV_T_PFREAL64 = 0x0241, /* Far pointer to 64-bit real */ + CV_T_PHREAL64 = 0x0341, /* Huge pointer to 64-bit real */ + CV_T_32PREAL64 = 0x0441, /* 16:32 near pointer to 64-bit real */ + CV_T_32PFREAL64 = 0x0541, /* 16:32 far pointer to 64-bit real */ + /* 80-bit Real Types */ + CV_T_REAL80 = 0x0042, /* 80-bit real */ + CV_T_PREAL80 = 0x0142, /* Near pointer to 80-bit real */ + CV_T_PFREAL80 = 0x0242, /* Far pointer to 80-bit real */ + CV_T_PHREAL80 = 0x0342, /* Huge pointer to 80-bit real */ + CV_T_32PREAL80 = 0x0442, /* 16:32 near pointer to 80-bit real */ + CV_T_32PFREAL80 = 0x0542, /* 16:32 far pointer to 80-bit real */ + /* 128-bit Real Types */ + CV_T_REAL128 = 0x0043, /* 128-bit real */ + CV_T_PREAL128 = 0x0143, /* Near pointer to 128-bit real */ + CV_T_PFREAL128 = 0x0243, /* Far pointer to 128-bit real */ + CV_T_PHREAL128 = 0x0343, /* Huge pointer to 128-bit real */ + CV_T_32PREAL128 = 0x0443, /* 16:32 near pointer to 128-bit real */ + CV_T_32PFREAL128 = 0x0543, /* 16:32 far pointer to 128-bit real */ + /* 32-bit Complex Types */ + CV_T_CPLX32 = 0x0050, /* 32-bit complex */ + CV_T_PCPLX32 = 0x0150, /* Near pointer to 32-bit complex */ + CV_T_PFCPLX32 = 0x0250, /* Far pointer to 32-bit complex */ + CV_T_PHCPLX32 = 0x0350, /* Huge pointer to 32-bit complex */ + CV_T_32PCPLX32 = 0x0450, /* 16:32 near pointer to 32-bit complex */ + CV_T_32PFCPLX32 = 0x0550, /* 16:32 far pointer to 32-bit complex */ + /* 64-bit Complex Types */ + CV_T_CPLX64 = 0x0051, /* 64-bit complex */ + CV_T_PCPLX64 = 0x0151, /* Near pointer to 64-bit complex */ + CV_T_PFCPLX64 = 0x0251, /* Far pointer to 64-bit complex */ + CV_T_PHCPLX64 = 0x0351, /* Huge pointer to 64-bit complex */ + CV_T_32PCPLX64 = 0x0451, /* 16:32 near pointer to 64-bit complex */ + CV_T_32PFCPLX64 = 0x0551, /* 16:32 far pointer to 64-bit complex */ + /* 80-bit Complex Types */ + CV_T_CPLX80 = 0x0052, /* 80-bit complex */ + CV_T_PCPLX80 = 0x0152, /* Near pointer to 80-bit complex */ + CV_T_PFCPLX80 = 0x0252, /* Far pointer to 80-bit complex */ + CV_T_PHCPLX80 = 0x0352, /* Huge pointer to 80-bit complex */ + CV_T_32PCPLX80 = 0x0452, /* 16:32 near pointer to 80-bit complex */ + CV_T_32PFCPLX80 = 0x0552, /* 16:32 far pointer to 80-bit complex */ + /* 128-bit Complex Types */ + CV_T_CPLX128 = 0x0053, /* 128-bit complex */ + CV_T_PCPLX128 = 0x0153, /* Near pointer to 128-bit complex */ + CV_T_PFCPLX128 = 0x0253, /* Far pointer to 128-bit complex */ + CV_T_PHCPLX128 = 0x0353, /* Huge pointer to 128-bit real */ + CV_T_32PCPLX128 = 0x0453, /* 16:32 near pointer to 128-bit complex */ + CV_T_32PFCPLX128 = 0x0553, /* 16:32 far pointer to 128-bit complex */ + /* Boolean Types */ + CV_T_BOOL08 = 0x0030, /* 8-bit Boolean */ + CV_T_BOOL16 = 0x0031, /* 16-bit Boolean */ + CV_T_BOOL32 = 0x0032, /* 32-bit Boolean */ + CV_T_BOOL64 = 0x0033, /* 64-bit Boolean */ + CV_T_PBOOL08 = 0x0130, /* Near pointer to 8-bit Boolean */ + CV_T_PBOOL16 = 0x0131, /* Near pointer to 16-bit Boolean */ + CV_T_PBOOL32 = 0x0132, /* Near pointer to 32-bit Boolean */ + CV_T_PBOOL64 = 0x0133, /* Near pointer to 64-bit Boolean */ + CV_T_PFBOOL08 = 0x0230, /* Far pointer to 8-bit Boolean */ + CV_T_PFBOOL16 = 0x0231, /* Far pointer to 16-bit Boolean */ + CV_T_PFBOOL32 = 0x0232, /* Far pointer to 32-bit Boolean */ + CV_T_PFBOOL64 = 0x0233, /* Far pointer to 64-bit Boolean */ + CV_T_PHBOOL08 = 0x0330, /* Huge pointer to 8-bit Boolean */ + CV_T_PHBOOL16 = 0x0331, /* Huge pointer to 16-bit Boolean */ + CV_T_PHBOOL32 = 0x0332, /* Huge pointer to 32-bit Boolean */ + CV_T_PHBOOL64 = 0x0333, /* Huge pointer to 64-bit Boolean */ + CV_T_32PBOOL08 = 0x0430, /* 16:32 near pointer to 8-bit Boolean */ + CV_T_32PBOOL16 = 0x0431, /* 16:32 near pointer to 16-bit Boolean */ + CV_T_32PBOOL32 = 0x0432, /* 16:32 near pointer to 32-bit Boolean */ + CV_T_32PBOOL64 = 0x0433, /* 16:32 near pointer to 64-bit Boolean */ + CV_T_32PFBOOL08 = 0x0530, /* 16:32 far pointer to 8-bit Boolean */ + CV_T_32PFBOOL16 = 0x0531, /* 16:32 far pointer to 16-bit Boolean */ + CV_T_32PFBOOL32 = 0x0532, /* 16:32 far pointer to 32-bit Boolean */ + CV_T_32PFBOOL64 = 0x0533, /* 16:32 far pointer to 64-bit Boolean */ + + /* Non-primitive types are stored in the TYPES section (generated in + * cv-type.c) and start at this index (e.g. 0x1000 is the first type + * in TYPES, 0x1001 the second, etc. + */ + CV_FIRST_NONPRIM = 0x1000 + }; + + enum cv_leaftype { + /* Leaf indices for type records that can be referenced from symbols */ + CV4_LF_MODIFIER = 0x0001, /* Type Modifier */ + CV4_LF_POINTER = 0x0002, /* Pointer */ + CV4_LF_ARRAY = 0x0003, /* Simple Array */ + CV4_LF_CLASS = 0x0004, /* Classes */ + CV4_LF_STRUCTURE = 0x0005, /* Structures */ + CV4_LF_UNION = 0x0006, /* Unions */ + CV4_LF_ENUM = 0x0007, /* Enumeration */ + CV4_LF_PROCEDURE = 0x0008, /* Procedure */ + CV4_LF_MFUNCTION = 0x0009, /* Member Function */ + CV4_LF_VTSHAPE = 0x000a, /* Virtual Function Table Shape */ + CV4_LF_BARRAY = 0x000d, /* Basic Array */ + CV4_LF_LABEL = 0x000e, /* Label */ + CV4_LF_NULL = 0x000f, /* Null */ + CV4_LF_DIMARRAY = 0x0011, /* Multiply Dimensioned Array */ + CV4_LF_VFTPATH = 0x0012, /* Path to Virtual Function Table */ + CV4_LF_PRECOMP = 0x0013, /* Reference Precompiled Types */ + CV4_LF_ENDPRECOMP = 0x0014, /* End of Precompiled Types */ + + /* CodeView 5.0 version */ + CV5_LF_MODIFIER = 0x1001, /* Type Modifier */ + CV5_LF_POINTER = 0x1002, /* Pointer */ + CV5_LF_ARRAY = 0x1003, /* Simple Array */ + CV5_LF_CLASS = 0x1004, /* Classes */ + CV5_LF_STRUCTURE = 0x1005, /* Structures */ + CV5_LF_UNION = 0x1006, /* Unions */ + CV5_LF_ENUM = 0x1007, /* Enumeration */ + CV5_LF_PROCEDURE = 0x1008, /* Procedure */ + CV5_LF_MFUNCTION = 0x1009, /* Member Function */ + CV5_LF_VTSHAPE = 0x000a, /* Virtual Function Table Shape */ + CV5_LF_BARRAY = 0x100d, /* Basic Array */ + CV5_LF_LABEL = 0x000e, /* Label */ + CV5_LF_NULL = 0x000f, /* Null */ + CV5_LF_DIMARRAY = 0x100c, /* Multiply Dimensioned Array */ + CV5_LF_VFTPATH = 0x100d, /* Path to Virtual Function Table */ + CV5_LF_PRECOMP = 0x100e, /* Reference Precompiled Types */ + CV5_LF_ENDPRECOMP = 0x0014, /* End of Precompiled Types */ + CV5_LF_TYPESERVER = 0x0016, /* Reference Typeserver */ + + /* Leaf indices for type records that can be referenced from other type + * records + */ + CV4_LF_SKIP = 0x0200, /* Skip */ + CV4_LF_ARGLIST = 0x0201, /* Argument List */ + CV4_LF_DEFARG = 0x0202, /* Default Argument */ + CV4_LF_LIST = 0x0203, /* Arbitrary List */ + CV4_LF_FIELDLIST = 0x0204, /* Field List */ + CV4_LF_DERIVED = 0x0205, /* Derived Classes */ + CV4_LF_BITFIELD = 0x0206, /* Bit Fields */ + CV4_LF_METHODLIST = 0x0207, /* Method List */ + CV4_LF_DIMCONU = 0x0208, /* Dimensioned Array with Constant Upper Bound */ + CV4_LF_DIMCONLU = 0x0209, /* Dimensioned Array with Constant Lower and Upper Bounds */ + CV4_LF_DIMVARU = 0x020a, /* Dimensioned Array with Variable Upper Bound */ + CV4_LF_DIMVARLU = 0x020b, /* Dimensioned Array with Variable Lower and Upper Bounds */ + CV4_LF_REFSYM = 0x020c, /* Referenced Symbol */ + + /* CodeView 5.0 version */ + CV5_LF_SKIP = 0x1200, /* Skip */ + CV5_LF_ARGLIST = 0x1201, /* Argument List */ + CV5_LF_DEFARG = 0x1202, /* Default Argument */ + CV5_LF_FIELDLIST = 0x1203, /* Field List */ + CV5_LF_DERIVED = 0x1204, /* Derived Classes */ + CV5_LF_BITFIELD = 0x1205, /* Bit Fields */ + CV5_LF_METHODLIST = 0x1206, /* Method List */ + CV5_LF_DIMCONU = 0x1207, /* Dimensioned Array with Constant Upper Bound */ + CV5_LF_DIMCONLU = 0x1208, /* Dimensioned Array with Constant Lower and Upper Bounds */ + CV5_LF_DIMVARU = 0x1209, /* Dimensioned Array with Variable Upper Bound */ + CV5_LF_DIMVARLU = 0x120a, /* Dimensioned Array with Variable Lower and Upper Bounds */ + CV5_LF_REFSYM = 0x020c, /* Referenced Symbol */ + + /* Leaf indices for fields of complex lists */ + CV4_LF_BCLASS = 0x0400, /* Real Base Class */ + CV4_LF_VBCLASS = 0x0401, /* Direct Virtual Base Class */ + CV4_LF_IVBCLASS = 0x0402, /* Indirect Virtual Base Class */ + CV4_LF_ENUMERATE = 0x0403, /* Enumeration Name and Value */ + CV4_LF_FRIENDFCN = 0x0404, /* Friend Function */ + CV4_LF_INDEX = 0x0405, /* Index To Another Type Record */ + CV4_LF_MEMBER = 0x0406, /* Data Member */ + CV4_LF_STMEMBER = 0x0407, /* Static Data Member */ + CV4_LF_METHOD = 0x0408, /* Method */ + CV4_LF_NESTTYPE = 0x0409, /* Nested Type Definition */ + CV4_LF_VFUNCTAB = 0x040a, /* Virtual Function Table Pointer */ + CV4_LF_FRIENDCLS = 0x040b, /* Friend Class */ + CV4_LF_ONEMETHOD = 0x040c, /* One Method */ + CV4_LF_VFUNCOFF = 0x040d, /* Virtual Function Offset */ + + /* CodeView 5.0 version */ + CV5_LF_BCLASS = 0x1400, /* Real Base Class */ + CV5_LF_VBCLASS = 0x1401, /* Direct Virtual Base Class */ + CV5_LF_IVBCLASS = 0x1402, /* Indirect Virtual Base Class */ + CV5_LF_ENUMERATE = 0x0403, /* Enumeration Name and Value */ + CV5_LF_FRIENDFCN = 0x1403, /* Friend Function */ + CV5_LF_INDEX = 0x1404, /* Index To Another Type Record */ + CV5_LF_MEMBER = 0x1405, /* Data Member */ + CV5_LF_STMEMBER = 0x1406, /* Static Data Member */ + CV5_LF_METHOD = 0x1407, /* Method */ + CV5_LF_NESTTYPE = 0x1408, /* Nested Type Definition */ + CV5_LF_VFUNCTAB = 0x1409, /* Virtual Function Table Pointer */ + CV5_LF_FRIENDCLS = 0x140a, /* Friend Class */ + CV5_LF_ONEMETHOD = 0x140b, /* One Method */ + CV5_LF_VFUNCOFF = 0x140c, /* Virtual Function Offset */ + CV5_LF_NESTTYPEEX = 0x140d, /* Nested Type Extended Definition */ + CV5_LF_MEMBERMODIFY = 0x140e, /* Member Modification */ + /* XXX: CodeView 5.0 spec also lists 0x040f as LF_MEMBERMODIFY? */ + + /* Leaf indices for numeric fields of symbols and type records */ + CV_LF_NUMERIC = 0x8000, + CV_LF_CHAR = 0x8000, /* Signed Char (8-bit) */ + CV_LF_SHORT = 0x8001, /* Signed Short (16-bit) */ + CV_LF_USHORT = 0x8002, /* Unsigned Short (16-bit) */ + CV_LF_LONG = 0x8003, /* Signed Long (32-bit) */ + CV_LF_ULONG = 0x8004, /* Unsigned Long (32-bit) */ + CV_LF_REAL32 = 0x8005, /* 32-bit Float */ + CV_LF_REAL64 = 0x8006, /* 64-bit Float */ + CV_LF_REAL80 = 0x8007, /* 80-bit Float */ + CV_LF_REAL128 = 0x8008, /* 128-bit Float */ + CV_LF_QUADWORD = 0x8009, /* Signed Quad Word (64-bit) */ + CV_LF_UQUADWORD = 0x800a, /* Unsigned Quad Word (64-bit) */ + CV_LF_REAL48 = 0x800b, /* 48-bit Float */ + CV_LF_COMPLEX32 = 0x800c, /* 32-bit Complex */ + CV_LF_COMPLEX64 = 0x800d, /* 64-bit Complex */ + CV_LF_COMPLEX80 = 0x800e, /* 80-bit Complex */ + CV_LF_COMPLEX128 = 0x800f, /* 128-bit Complex */ + CV_LF_VARSTRING = 0x8010, /* Variable-length String */ + + /* Leaf padding bytes */ + CV_LF_PAD0 = 0xf0, + CV_LF_PAD1 = 0xf1, + CV_LF_PAD2 = 0xf2, + CV_LF_PAD3 = 0xf3, + CV_LF_PAD4 = 0xf4, + CV_LF_PAD5 = 0xf5, + CV_LF_PAD6 = 0xf6, + CV_LF_PAD7 = 0xf7, + CV_LF_PAD8 = 0xf8, + CV_LF_PAD9 = 0xf9, + CV_LF_PAD10 = 0xfa, + CV_LF_PAD11 = 0xfb, + CV_LF_PAD12 = 0xfc, + CV_LF_PAD13 = 0xfc, + CV_LF_PAD14 = 0xfe, + CV_LF_PAD15 = 0xff + }; + + /* Leaves use a bit of meta-programming to encode formats: each character + * of format represents the output generated, as follows: + * 'b' : 1 byte value (integer) + * 'h' : 2 byte value (integer) + * 'w' : 4 byte value (integer) + * 'L' : subleaf, recurses into cv_leaf (pointer) + * 'T' : 4 byte type index, pulls cv_type.index from cv_type (pointer) + * 'S' : length-prefixed string (pointer) + */ + typedef struct cv_leaf { + enum cv_leaftype type; + const char *format; /* format of args */ + union { + unsigned long i; + void *p; + } args[6]; + } cv_leaf; + + typedef struct cv_type { + yasm_dbgfmt_cv *dbgfmt_cv; + unsigned long indx; /* type # (must be same as output order) */ + size_t num_leaves; + /*@null@*/ /*@only@*/ cv_leaf **leaves; + } cv_type; + + /* Bytecode callback function prototypes */ + static void cv_type_bc_destroy(void *contents); + static void cv_type_bc_print(const void *contents, FILE *f, int indent_level); -static yasm_bc_resolve_flags cv_type_bc_resolve - (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist); ++static int cv_type_bc_calc_len ++ (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data); + static int cv_type_bc_tobytes + (yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_value_func output_value, + /*@null@*/ yasm_output_reloc_func output_reloc); + + /* Bytecode callback structures */ + static const yasm_bytecode_callback cv_type_bc_callback = { + cv_type_bc_destroy, + cv_type_bc_print, + yasm_bc_finalize_common, - cv_type_bc_resolve, ++ cv_type_bc_calc_len, ++ yasm_bc_expand_common, + cv_type_bc_tobytes, + 0 + }; + + static cv_type *cv_type_create(yasm_dbgfmt_cv *dbgfmt_cv, unsigned long indx); + static void cv_type_append_leaf(cv_type *type, /*@keep@*/ cv_leaf *leaf); + + + static cv_leaf * + cv_leaf_create_label(int is_far) + { + cv_leaf *leaf = yasm_xmalloc(sizeof(cv_leaf)); + leaf->type = CV5_LF_LABEL; + leaf->format = "h"; + leaf->args[0].i = is_far ? 4 : 0; + return leaf; + } + + yasm_section * + yasm_cv__generate_type(yasm_dbgfmt_cv *dbgfmt_cv) + { + int new; + unsigned long indx = CV_FIRST_NONPRIM; + yasm_section *debug_type; + yasm_bytecode *bc; + cv_type *type; + + debug_type = yasm_object_get_general(dbgfmt_cv->object, ".debug$T", 0, 1, + 0, 0, &new, 0); + + /* Add label type */ + type = cv_type_create(dbgfmt_cv, indx++); + cv_type_append_leaf(type, cv_leaf_create_label(0)); + bc = yasm_bc_create_common(&cv_type_bc_callback, type, 0); + yasm_bc_finalize(bc, yasm_cv__append_bc(debug_type, bc)); - yasm_bc_resolve(bc, 0, NULL); ++ yasm_bc_calc_len(bc, NULL, NULL); + + return debug_type; + } + + static void + cv_leaf_destroy(cv_leaf *leaf) + { + const char *ch = leaf->format; + int arg = 0; + + while (*ch) { + switch (*ch) { + case 'b': + case 'h': + case 'w': + arg++; + break; /* nothing to destroy */ + case 'L': + cv_leaf_destroy((cv_leaf *)leaf->args[arg++].p); + break; + case 'T': + arg++; /* nothing to destroy */ + break; + case 'S': + yasm_xfree(leaf->args[arg++].p); + break; + default: + yasm_internal_error(N_("unknown leaf format character")); + } + ch++; + } + } + + static unsigned long + cv_leaf_size(const cv_leaf *leaf) + { + const char *ch = leaf->format; + unsigned long len = 2; /* leaf type */ + unsigned long slen; + int arg = 0; + + while (*ch) { + switch (*ch) { + case 'b': + len++; + arg++; + break; + case 'h': + len += 2; + arg++; + break; + case 'w': + len += 4; + arg++; + break; + case 'L': + len += cv_leaf_size((const cv_leaf *)leaf->args[arg++].p); + break; + case 'T': + len += 4; /* XXX: will be 2 in CV4 */ + arg++; + break; + case 'S': + len += 1; /* XXX: is this 1 or 2? */ + slen = strlen((const char *)leaf->args[arg++].p); + len += slen <= 0xff ? slen : 0xff; + break; + default: + yasm_internal_error(N_("unknown leaf format character")); + } + ch++; + } + + return len; + } + + static void + cv_leaf_tobytes(const cv_leaf *leaf, yasm_bytecode *bc, yasm_arch *arch, + unsigned char **bufp, yasm_intnum *cval) + { + unsigned char *buf = *bufp; + const char *ch = leaf->format; + size_t len; + int arg = 0; + + /* leaf type */ + yasm_intnum_set_uint(cval, leaf->type); + yasm_arch_intnum_tobytes(arch, cval, buf, 2, 16, 0, bc, 0); + buf += 2; + + while (*ch) { + switch (*ch) { + case 'b': + YASM_WRITE_8(buf, leaf->args[arg].i); + arg++; + break; + case 'h': + yasm_intnum_set_uint(cval, leaf->args[arg++].i); + yasm_arch_intnum_tobytes(arch, cval, buf, 2, 16, 0, bc, 0); + buf += 2; + break; + case 'w': + yasm_intnum_set_uint(cval, leaf->args[arg++].i); + yasm_arch_intnum_tobytes(arch, cval, buf, 4, 32, 0, bc, 0); + buf += 4; + break; + case 'L': + cv_leaf_tobytes((const cv_leaf *)leaf->args[arg++].p, bc, arch, + &buf, cval); + break; + case 'T': + yasm_intnum_set_uint(cval, + ((const cv_type *)leaf->args[arg++].p)->indx); + yasm_arch_intnum_tobytes(arch, cval, buf, 4, 32, 0, bc, 0); + buf += 4; /* XXX: will be 2 in CV4 */ + break; + case 'S': + len = strlen((const char *)leaf->args[arg].p); + len = len <= 0xff ? len : 0xff; + YASM_WRITE_8(buf, len); + memcpy(buf, (const char *)leaf->args[arg].p, len); + buf += len; + arg++; + break; + default: + yasm_internal_error(N_("unknown leaf format character")); + } + ch++; + } + + *bufp = buf; + } + + static cv_type * + cv_type_create(yasm_dbgfmt_cv *dbgfmt_cv, unsigned long indx) + { + cv_type *type = yasm_xmalloc(sizeof(cv_type)); + + type->dbgfmt_cv = dbgfmt_cv; + type->indx = indx; + type->num_leaves = 0; + type->leaves = NULL; + + return type; + } + + static void + cv_type_append_leaf(cv_type *type, /*@keep@*/ cv_leaf *leaf) + { + type->num_leaves++; + + /* This is inefficient for large numbers of leaves, but that won't happen + * until we add structure support. + */ + type->leaves = yasm_xrealloc(type->leaves, + type->num_leaves*sizeof(cv_leaf *)); + + type->leaves[type->num_leaves-1] = leaf; + } + + static void + cv_type_bc_destroy(void *contents) + { + cv_type *type = (cv_type *)contents; + size_t i; + + for (i=0; inum_leaves; i++) + cv_leaf_destroy(type->leaves[i]); + if (type->leaves) + yasm_xfree(type->leaves); + yasm_xfree(contents); + } + + static void + cv_type_bc_print(const void *contents, FILE *f, int indent_level) + { + /* TODO */ + } + -static yasm_bc_resolve_flags -cv_type_bc_resolve(yasm_bytecode *bc, int save, - yasm_calc_bc_dist_func calc_bc_dist) ++static int ++cv_type_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, ++ void *add_span_data) + { + cv_type *type = (cv_type *)bc->contents; + size_t i; + + if (type->indx == CV_FIRST_NONPRIM) + bc->len = 4+2; + else + bc->len = 2; + + for (i=0; inum_leaves; i++) + bc->len += cv_leaf_size(type->leaves[i]); + + /* Pad to multiple of 4 */ + if (bc->len & 0x3) + bc->len += 4-(bc->len & 0x3); + - return YASM_BC_RESOLVE_MIN_LEN; ++ return 0; + } + + static int + cv_type_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_value_func output_value, + yasm_output_reloc_func output_reloc) + { + cv_type *type = (cv_type *)bc->contents; + yasm_dbgfmt_cv *dbgfmt_cv = type->dbgfmt_cv; + unsigned char *buf = *bufp; + yasm_intnum *cval; + size_t i; + unsigned long reclen = bc->len - 2; + + cval = yasm_intnum_create_uint(4); /* version */ + if (type->indx == CV_FIRST_NONPRIM) { + yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc, 1); + buf += 4; + reclen -= 4; + } + + /* Total length of record (following this field) - 2 bytes */ + yasm_intnum_set_uint(cval, reclen); + yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 2, 16, 0, bc, 1); + buf += 2; + + /* Leaves */ + for (i=0; inum_leaves; i++) + cv_leaf_tobytes(type->leaves[i], bc, dbgfmt_cv->arch, &buf, cval); + + /* Pad to multiple of 4 */ + switch ((buf-(*bufp)) & 0x3) { + case 3: + YASM_WRITE_8(buf, CV_LF_PAD3); + case 2: + YASM_WRITE_8(buf, CV_LF_PAD2); + case 1: + YASM_WRITE_8(buf, CV_LF_PAD1); + case 0: + break; + } + + *bufp = buf; + + yasm_intnum_destroy(cval); + return 0; + } diff --cc modules/dbgfmts/dwarf2/dwarf2-aranges.c index 00000000,7c4010b0..b8056fd6 mode 000000,100644..100644 --- a/modules/dbgfmts/dwarf2/dwarf2-aranges.c +++ b/modules/dbgfmts/dwarf2/dwarf2-aranges.c @@@ -1,0 -1,126 +1,126 @@@ + /* + * 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, NULL, 0); + yasm_bc_finalize(bc, yasm_dwarf2__append_bc(debug_aranges, bc)); - yasm_bc_resolve(bc, 0, NULL); ++ yasm_bc_calc_len(bc, NULL, 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; + /*@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 */ + start = yasm_expr_create_ident( + yasm_expr_sym(yasm_dwarf2__bc_sym(dbgfmt_dwarf2->symtab, + yasm_section_bcs_first(sect))), 0); + length = yasm_expr_create_ident( + yasm_expr_int(yasm_common_calc_bc_dist( + yasm_section_bcs_first(sect), yasm_section_bcs_last(sect))), 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); ++ yasm_bc_calc_len(bc, NULL, 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 --cc modules/dbgfmts/dwarf2/dwarf2-dbgfmt.c index 00000000,f9e9dac5..54f10f4f mode 000000,100644..100644 --- a/modules/dbgfmts/dwarf2/dwarf2-dbgfmt.c +++ b/modules/dbgfmts/dwarf2/dwarf2-dbgfmt.c @@@ -1,0 -1,356 +1,357 @@@ + /* + * 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. + */ + #include + /*@unused@*/ RCSID("$Id$"); + + #define YASM_LIB_INTERNAL + #define YASM_BC_INTERNAL + #include + + #include "dwarf2-dbgfmt.h" + + struct dwarf2_head { + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2; + yasm_bytecode *start_prevbc; + yasm_bytecode *end_prevbc; + /*@null@*/ yasm_section *debug_ptr; + int with_address; + int with_segment; + }; + + /* Bytecode callback function prototypes */ + 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_head_bc_calc_len ++ (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data); + static int dwarf2_head_bc_tobytes + (yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_value_func output_value, + /*@null@*/ yasm_output_reloc_func output_reloc); + + /* Bytecode callback structures */ + static const yasm_bytecode_callback dwarf2_head_bc_callback = { + dwarf2_head_bc_destroy, + dwarf2_head_bc_print, + yasm_bc_finalize_common, - dwarf2_head_bc_resolve, ++ dwarf2_head_bc_calc_len, ++ yasm_bc_expand_common, + dwarf2_head_bc_tobytes, + 0 + }; + + /* 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; + + + static /*@null@*/ /*@only@*/ yasm_dbgfmt * + dwarf2_dbgfmt_create(yasm_object *object, yasm_objfmt *of, yasm_arch *a) + { + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = + yasm_xmalloc(sizeof(yasm_dbgfmt_dwarf2)); + size_t i; + + dbgfmt_dwarf2->dbgfmt.module = &yasm_dwarf2_LTX_dbgfmt; + + dbgfmt_dwarf2->object = object; + dbgfmt_dwarf2->symtab = yasm_object_get_symtab(object); + dbgfmt_dwarf2->linemap = yasm_object_get_linemap(object); + dbgfmt_dwarf2->arch = a; + + dbgfmt_dwarf2->dirs_allocated = 32; + dbgfmt_dwarf2->dirs_size = 0; + dbgfmt_dwarf2->dirs = + yasm_xmalloc(sizeof(char *)*dbgfmt_dwarf2->dirs_allocated); + + dbgfmt_dwarf2->filenames_allocated = 32; + dbgfmt_dwarf2->filenames_size = 0; + 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; + } + + dbgfmt_dwarf2->format = DWARF2_FORMAT_32BIT; /* TODO: flexible? */ + + dbgfmt_dwarf2->sizeof_address = yasm_arch_get_address_size(a)/8; + switch (dbgfmt_dwarf2->format) { + case DWARF2_FORMAT_32BIT: + dbgfmt_dwarf2->sizeof_offset = 4; + break; + case DWARF2_FORMAT_64BIT: + dbgfmt_dwarf2->sizeof_offset = 8; + break; + } + dbgfmt_dwarf2->min_insn_len = yasm_arch_min_insn_len(a); + + return (yasm_dbgfmt *)dbgfmt_dwarf2; + } + + static void + dwarf2_dbgfmt_destroy(/*@only@*/ yasm_dbgfmt *dbgfmt) + { + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = (yasm_dbgfmt_dwarf2 *)dbgfmt; + size_t i; + for (i=0; idirs_size; i++) + if (dbgfmt_dwarf2->dirs[i]) + yasm_xfree(dbgfmt_dwarf2->dirs[i]); + yasm_xfree(dbgfmt_dwarf2->dirs); + 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); + } + + /* Add a bytecode to a section, updating offset on insertion; + * no optimization necessary. + */ + 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); + return precbc; + } + + static void + dwarf2_dbgfmt_generate(yasm_dbgfmt *dbgfmt, yasm_errwarns *errwarns) + { + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = (yasm_dbgfmt_dwarf2 *)dbgfmt; + size_t num_line_sections; + /*@null@*/ yasm_section *debug_info, *debug_line, *main_code; + + /* If we don't have any .file directives, generate line information + * based on the asm source. + */ + debug_line = yasm_dwarf2__generate_line(dbgfmt_dwarf2, errwarns, + dbgfmt_dwarf2->filenames_size == 0, + &main_code, &num_line_sections); + + /* 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);*/ + } + } + + yasm_symrec * + yasm_dwarf2__bc_sym(yasm_symtab *symtab, yasm_bytecode *bc) + { + /*@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 sym; + } + + 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) + { + dwarf2_head *head; + yasm_bytecode *bc; + + head = yasm_xmalloc(sizeof(dwarf2_head)); + head->dbgfmt_dwarf2 = dbgfmt_dwarf2; + head->start_prevbc = yasm_section_bcs_last(sect); + + 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) + bc->len += 4; + + if (debug_ptr) { + head->debug_ptr = 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; + } + + void + yasm_dwarf2__set_head_end(dwarf2_head *head, yasm_bytecode *end_prevbc) + { + head->end_prevbc = end_prevbc; + } + + static void + dwarf2_head_bc_destroy(void *contents) + { + yasm_xfree(contents); + } + + static void + dwarf2_head_bc_print(const void *contents, FILE *f, int indent_level) + { + /* TODO */ + } + -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_head_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, ++ void *add_span_data) + { - yasm_internal_error(N_("tried to resolve a dwarf2 head bytecode")); ++ yasm_internal_error(N_("tried to calc_len a dwarf2 head bytecode")); + /*@notreached@*/ - return YASM_BC_RESOLVE_MIN_LEN; ++ return 0; + } + + static int + dwarf2_head_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_value_func output_value, + yasm_output_reloc_func output_reloc) + { + dwarf2_head *head = (dwarf2_head *)bc->contents; + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = head->dbgfmt_dwarf2; + unsigned char *buf = *bufp; + yasm_intnum *intn, *cval; + + 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 aranges info (following this field) */ + cval = yasm_intnum_create_uint(dbgfmt_dwarf2->sizeof_offset); + intn = yasm_common_calc_bc_dist(head->start_prevbc, head->end_prevbc); + yasm_intnum_calc(intn, YASM_EXPR_SUB, cval); + yasm_arch_intnum_tobytes(dbgfmt_dwarf2->arch, intn, buf, + dbgfmt_dwarf2->sizeof_offset, + dbgfmt_dwarf2->sizeof_offset*8, 0, bc, 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); + buf += 2; + + /* Pointer to another debug section */ + if (head->debug_ptr) { + yasm_value value; + yasm_value_init_sym(&value, + yasm_dwarf2__bc_sym(dbgfmt_dwarf2->symtab, + yasm_section_bcs_first(head->debug_ptr)), + dbgfmt_dwarf2->sizeof_offset*8); + output_value(&value, buf, dbgfmt_dwarf2->sizeof_offset, + (unsigned long)(buf-*bufp), bc, 0, d); + buf += dbgfmt_dwarf2->sizeof_offset; + } + + /* Size of the offset portion of the address */ + if (head->with_address) + YASM_WRITE_8(buf, dbgfmt_dwarf2->sizeof_address); + + /* Size of a segment descriptor. 0 = flat address space */ + if (head->with_segment) + YASM_WRITE_8(buf, 0); + + *bufp = buf; + + yasm_intnum_destroy(cval); + return 0; + } + + static void + dwarf2_section_data_destroy(void *data) + { + dwarf2_section_data *dsd = data; + dwarf2_loc *n1, *n2; + + /* Delete locations */ + n1 = STAILQ_FIRST(&dsd->locs); + while (n1) { + n2 = STAILQ_NEXT(n1, link); + yasm_xfree(n1); + n1 = n2; + } + + yasm_xfree(data); + } + + static void + dwarf2_section_data_print(void *data, FILE *f, int indent_level) + { + /* TODO */ + } + + static int + dwarf2_dbgfmt_directive(yasm_dbgfmt *dbgfmt, const char *name, + yasm_section *sect, yasm_valparamhead *valparams, + unsigned long line) + { + yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = (yasm_dbgfmt_dwarf2 *)dbgfmt; + return yasm_dwarf2__line_directive(dbgfmt_dwarf2, name, sect, valparams, + line); + } + + /* Define dbgfmt structure -- see dbgfmt.h for details */ + yasm_dbgfmt_module yasm_dwarf2_LTX_dbgfmt = { + "DWARF2 debugging format", + "dwarf2", + dwarf2_dbgfmt_create, + dwarf2_dbgfmt_destroy, + dwarf2_dbgfmt_directive, + dwarf2_dbgfmt_generate + }; diff --cc modules/dbgfmts/dwarf2/dwarf2-info.c index 00000000,c2692fe5..11ac620b mode 000000,100644..100644 --- a/modules/dbgfmts/dwarf2/dwarf2-info.c +++ b/modules/dbgfmts/dwarf2/dwarf2-info.c @@@ -1,0 -1,440 +1,441 @@@ + /* + * 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. + */ + #ifdef HAVE_CONFIG_H + #include + #undef HAVE_CONFIG_H + #endif + + /* Need either unistd.h or direct.h (on Windows) to prototype getcwd() */ + #ifdef HAVE_UNISTD_H + #include + #elif defined(WIN32) || defined(_WIN32) + #include + #endif + + #include + /*@unused@*/ RCSID("$Id$"); + + #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_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_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_calc_len ++ (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data); + static int dwarf2_abbrev_bc_tobytes + (yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_value_func output_value, + /*@null@*/ yasm_output_reloc_func output_reloc); + + /* Bytecode callback structures */ + + 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_calc_len, ++ yasm_bc_expand_common, + dwarf2_abbrev_bc_tobytes, + 0 + }; + + + 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, NULL, 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); ++ yasm_bc_calc_len(bc, NULL, 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, NULL, 0); + yasm_bc_finalize(bc, yasm_dwarf2__append_bc(sect, bc)); - yasm_bc_resolve(bc, 0, NULL); ++ yasm_bc_calc_len(bc, NULL, 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); + + yasm_section_set_align(debug_abbrev, 0, 0); + yasm_section_set_align(debug_info, 0, 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_expr_create_ident(yasm_expr_sym( + yasm_dwarf2__bc_sym(dbgfmt_dwarf2->symtab, + yasm_section_bcs_first(debug_line))), 0), + dbgfmt_dwarf2->sizeof_offset, 0); + + if (main_code) { + yasm_symrec *first; + first = yasm_dwarf2__bc_sym(dbgfmt_dwarf2->symtab, + yasm_section_bcs_first(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_expr_create_ident(yasm_expr_sym(first), 0), + 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_expr_create(YASM_EXPR_ADD, yasm_expr_sym(first), + yasm_expr_int(yasm_common_calc_bc_dist( + yasm_section_bcs_first(main_code), + yasm_section_bcs_last(main_code))), 0), + 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; + abbrev->tag = 0; + abbrev->has_children = 0; + STAILQ_INIT(&abbrev->attrs); + 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_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) ++static int ++dwarf2_abbrev_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, ++ void *add_span_data) + { - yasm_internal_error(N_("tried to resolve a dwarf2 aranges head bytecode")); ++ yasm_internal_error(N_("tried to calc_len a dwarf2 aranges head bytecode")); + /*@notreached@*/ - return YASM_BC_RESOLVE_MIN_LEN; ++ return 0; + } + + static int + dwarf2_abbrev_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_value_func output_value, + 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 --cc modules/dbgfmts/dwarf2/dwarf2-line.c index 00000000,5245a73c..e4c35fdc mode 000000,100644..100644 --- a/modules/dbgfmts/dwarf2/dwarf2-line.c +++ b/modules/dbgfmts/dwarf2/dwarf2-line.c @@@ -1,0 -1,998 +1,1000 @@@ + /* + * 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; + /*@null@*/ /*@dependent@*/ yasm_symrec *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_calc_len ++ (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data); + static int dwarf2_spp_bc_tobytes + (yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_value_func output_value, + /*@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_calc_len ++ (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data); + static int dwarf2_line_op_bc_tobytes + (yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_value_func output_value, + /*@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_calc_len, ++ yasm_bc_expand_common, + dwarf2_spp_bc_tobytes, + 0 + }; + + 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_calc_len, ++ yasm_bc_expand_common, + dwarf2_line_op_bc_tobytes, + 0 + }; + + + 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, + /*@null@*/ yasm_symrec *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_set(YASM_ERROR_GENERAL, + 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, loc->sym); + 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; + yasm_errwarns *errwarns; + + /* 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, info->errwarns, &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, + yasm_errwarns *errwarns, 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, 1, 0, 0, &new, + 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_set(YASM_ERROR_GENERAL, + N_("dwarf2 file number %d unassigned"), i+1); + yasm_errwarn_propagate(errwarns, 0); + continue; + } + 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) ++static int ++dwarf2_spp_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, ++ void *add_span_data) + { - yasm_internal_error(N_("tried to resolve a dwarf2 spp bytecode")); ++ yasm_internal_error(N_("tried to calc_len a dwarf2 spp bytecode")); + /*@notreached@*/ - return YASM_BC_RESOLVE_MIN_LEN; ++ return 0; + } + + static int + dwarf2_spp_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_value_func output_value, + 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 *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); + 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); + 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) ++static int ++dwarf2_line_op_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, ++ void *add_span_data) + { - yasm_internal_error(N_("tried to resolve a dwarf2 line_op bytecode")); ++ yasm_internal_error(N_("tried to calc_len a dwarf2 line_op bytecode")); + /*@notreached@*/ - return YASM_BC_RESOLVE_MIN_LEN; ++ return 0; + } + + static int + dwarf2_line_op_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, + yasm_output_value_func output_value, + 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) { + yasm_value value; + yasm_value_init_sym(&value, line_op->ext_operand, + line_op->ext_operandsize*8); + output_value(&value, buf, line_op->ext_operandsize, + (unsigned long)(buf-*bufp), bc, 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_set(YASM_ERROR_SYNTAX, N_("file number required")); + yasm_xfree(loc); + return 0; + } + intn = yasm_expr_get_intnum(&vp->param, NULL); + if (!intn) { + yasm_error_set(YASM_ERROR_NOT_CONSTANT, + N_("file number is not a constant")); + yasm_xfree(loc); + return 0; + } + if (yasm_intnum_sign(intn) != 1) { + yasm_error_set(YASM_ERROR_VALUE, + 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_set(YASM_ERROR_SYNTAX, N_("line number required")); + yasm_xfree(loc); + return 0; + } + intn = yasm_expr_get_intnum(&vp->param, NULL); + if (!intn) { + yasm_error_set(YASM_ERROR_NOT_CONSTANT, + 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_set(YASM_ERROR_NOT_CONSTANT, + 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_set(YASM_ERROR_SYNTAX, + N_("is_stmt requires value")); + yasm_xfree(loc); + return 0; + } + intn = yasm_expr_get_intnum(&vp->param, NULL); + if (!intn) { + yasm_error_set(YASM_ERROR_NOT_CONSTANT, + 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_set(YASM_ERROR_VALUE, + 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_set(YASM_ERROR_SYNTAX, N_("isa requires value")); + yasm_xfree(loc); + return 0; + } + intn = yasm_expr_get_intnum(&vp->param, NULL); + if (!intn) { + yasm_error_set(YASM_ERROR_NOT_CONSTANT, + N_("isa value is not a constant")); + yasm_xfree(loc); + return 0; + } + if (yasm_intnum_sign(intn) < 0) { + yasm_error_set(YASM_ERROR_VALUE, + N_("isa value less than zero")); + yasm_xfree(loc); + return 0; + } + loc->isa_change = 1; + loc->isa = yasm_intnum_get_uint(intn); + } else + yasm_warn_set(YASM_WARN_GENERAL, + 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_set(YASM_ERROR_NOT_CONSTANT, + 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_set(YASM_ERROR_SYNTAX, + N_("file number given but no filename")); + return 0; + } + + dwarf2_dbgfmt_add_file(dbgfmt_dwarf2, filenum, vp->val); + return 0; + } + return 1; + } +