Home | History | Annotate | Download | only in codeview
      1 /*
      2  * CodeView debugging format - symbol and line information
      3  *
      4  *  Copyright (C) 2006-2007  Peter Johnson
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  * 3. Neither the name of the author nor the names of other contributors
     15  *    may be used to endorse or promote products derived from this
     16  *    software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
     19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
     22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     28  * POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 #include <util.h>
     31 
     32 #include <libyasm.h>
     33 
     34 #include "cv-dbgfmt.h"
     35 
     36 enum cv8_symheadtype {
     37     CV8_DEBUG_SYMS      = 0xF1, /* CV5 symbol information */
     38     CV8_LINE_NUMS       = 0xF2, /* line numbers for a section */
     39     CV8_FILE_STRTAB     = 0xF3, /* filename string table */
     40     CV8_FILE_INFO       = 0xF4  /* source file info */
     41 };
     42 
     43 enum cv_symtype {
     44     /* Non-modal Symbols */
     45     CV_S_COMPILE        = 0x0001,       /* Compile Flag */
     46     CV_S_REGISTER       = 0x0002,       /* Register */
     47     CV_S_CONSTANT       = 0x0003,       /* Constant */
     48     CV_S_UDT            = 0x0004,       /* User-defined Type */
     49     CV_S_SSEARCH        = 0x0005,       /* Start Search */
     50     CV_S_END            = 0x0006,       /* End of Block */
     51     CV_S_SKIP           = 0x0007,       /* Skip Record */
     52     CV_S_OBJNAME        = 0x0009,       /* Object File Name */
     53     CV_S_ENDARG         = 0x000a,       /* End of Arguments */
     54     CV_S_COBOLUDT       = 0x000b,       /* COBOL User-defined Type */
     55     CV_S_MANYREG        = 0x000c,       /* Many Registers */
     56     CV_S_RETURN         = 0x000d,       /* Function Return */
     57     CV_S_ENTRYTHIS      = 0x000e,       /* "this" at Method Entry */
     58 
     59     /* Symbols for 16:16 Segmented Architectures */
     60     CV_S_BPREL16        = 0x0100,       /* BP Relative 16:16 */
     61     CV_S_LDATA16        = 0x0101,       /* Local Data 16:16 */
     62     CV_S_GDATA16        = 0x0102,       /* Global Data Symbol 16:16 */
     63     CV_S_PUB16          = 0x0103,       /* Public Symbol 16:16 */
     64     CV_S_LPROC16        = 0x0104,       /* Local Start 16:16 */
     65     CV_S_GPROC16        = 0x0105,       /* Global Start 16:16 */
     66     CV_S_THUNK16        = 0x0106,       /* Thunk Start 16:16 */
     67     CV_S_BLOCK16        = 0x0107,       /* Block Start 16:16 */
     68     CV_S_WITH16         = 0x0108,       /* With Start 16:16 */
     69     CV_S_LABEL16        = 0x0109,       /* Code Label 16:16 */
     70     CV_S_CEXMODEL16     = 0x0110,       /* Change Execution Model 16:16 */
     71     CV_S_VFTPATH16      = 0x010b,       /* Virtual Function Table Path 16:16 */
     72     CV_S_REGREL16       = 0x010c,       /* Register Relative 16:16 */
     73 
     74     /* Symbols for 16:32 Segmented Architectures */
     75     CV_S_BPREL32        = 0x0200,       /* BP Relative 16:32 */
     76     CV_S_LDATA32        = 0x0201,       /* Local Data 16:32 */
     77     CV_S_GDATA32        = 0x0202,       /* Global Data Symbol 16:32 */
     78     CV_S_PUB32          = 0x0203,       /* Public Symbol 16:32 */
     79     CV_S_LPROC32        = 0x0204,       /* Local Start 16:32 */
     80     CV_S_GPROC32        = 0x0205,       /* Global Start 16:32 */
     81     CV_S_THUNK32        = 0x0206,       /* Thunk Start 16:32 */
     82     CV_S_BLOCK32        = 0x0207,       /* Block Start 16:32 */
     83     CV_S_WITH32         = 0x0208,       /* With Start 16:32 */
     84     CV_S_LABEL32        = 0x0209,       /* Code Label 16:32 */
     85     CV_S_CEXMODEL32     = 0x0210,       /* Change Execution Model 16:32 */
     86     CV_S_VFTPATH32      = 0x020b,       /* Virtual Function Table Path 16:32 */
     87     CV_S_REGREL32       = 0x020c,       /* Register Relative 16:32 */
     88     CV_S_LTHREAD32      = 0x020d,       /* Local Thread Storage 16:32 */
     89     CV_S_GTHREAD32      = 0x020e,       /* Global Thread Storage 16:32 */
     90 
     91     /* Symbols for MIPS */
     92     CV_S_LPROCMIPS      = 0x0300,       /* Local procedure start MIPS */
     93     CV_S_GPROCMIPS      = 0x0301,       /* Global procedure start MIPS */
     94 
     95     /* Symbols for CV8 - strings are 0 terminated rather than length-prefix.
     96      * Incomplete and unofficial.
     97      */
     98     CV8_S_OBJNAME       = 0x1101,       /* Object File Name */
     99     CV8_S_LABEL32       = 0x1105,       /* Code Label 16:32 */
    100     CV8_S_LDATA32       = 0x110c,       /* Local Data 16:32 */
    101     CV8_S_GDATA32       = 0x110d,       /* Global Data 16:32 */
    102     CV8_S_LPROC32       = 0x1110,       /* Local Start 16:32 */
    103     CV8_S_COMPILE       = 0x1116        /* Compile Flag */
    104 };
    105 
    106 typedef struct cv8_symhead {
    107     enum cv8_symheadtype type;
    108     yasm_bytecode *start_prevbc;
    109     yasm_bytecode *end_prevbc;
    110     int first;      /* nonzero if first symhead in section */
    111 } cv8_symhead;
    112 
    113 typedef struct cv8_fileinfo {
    114     const cv_filename *fn;
    115 } cv8_fileinfo;
    116 
    117 /* Note: each line number group is associated with a file AND a section */
    118 typedef struct cv8_linepair {
    119     unsigned long offset;
    120     unsigned long line;
    121 } cv8_linepair;
    122 
    123 /* Decrease linked list overhead a bit doing it this way */
    124 typedef struct cv8_lineset {
    125     STAILQ_ENTRY(cv8_lineset) link;
    126     cv8_linepair pairs[126];
    127     size_t num_pairs;
    128 } cv8_lineset;
    129 
    130 typedef struct cv8_lineinfo {
    131     STAILQ_ENTRY(cv8_lineinfo) link;
    132     const cv_filename *fn;      /* filename associated with line numbers */
    133     yasm_section *sect;         /* section line numbers are for */
    134     yasm_symrec *sectsym;       /* symbol for beginning of sect */
    135     unsigned long num_linenums;
    136     STAILQ_HEAD(cv8_lineset_head, cv8_lineset) linesets;
    137 } cv8_lineinfo;
    138 
    139 /* Symbols use a bit of meta-programming to encode formats: each character
    140  * of format represents the output generated, as follows:
    141  * 'b' : 1 byte value (integer)
    142  * 'h' : 2 byte value (integer)
    143  * 'w' : 4 byte value (integer)
    144  * 'Y' : symrec SECREL+SECTION (pointer)
    145  * 'T' : type index (integer)
    146  * 'S' : length-prefixed string (pointer)
    147  * 'Z' : 0-terminated string (pointer)
    148  */
    149 typedef struct cv_sym {
    150     enum cv_symtype type;
    151     const char *format;
    152     union {
    153         unsigned long i;
    154         void *p;
    155     } args[10];
    156 } cv_sym;
    157 
    158 /* Bytecode callback function prototypes */
    159 static void cv8_symhead_bc_destroy(void *contents);
    160 static void cv8_symhead_bc_print(const void *contents, FILE *f,
    161                                  int indent_level);
    162 static int cv8_symhead_bc_calc_len
    163     (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
    164 static int cv8_symhead_bc_tobytes
    165     (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
    166      yasm_output_value_func output_value,
    167      /*@null@*/ yasm_output_reloc_func output_reloc);
    168 
    169 static void cv8_fileinfo_bc_destroy(void *contents);
    170 static void cv8_fileinfo_bc_print(const void *contents, FILE *f,
    171                                   int indent_level);
    172 static int cv8_fileinfo_bc_calc_len
    173     (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
    174 static int cv8_fileinfo_bc_tobytes
    175     (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
    176      yasm_output_value_func output_value,
    177      /*@null@*/ yasm_output_reloc_func output_reloc);
    178 
    179 static void cv8_lineinfo_bc_destroy(void *contents);
    180 static void cv8_lineinfo_bc_print(const void *contents, FILE *f,
    181                                   int indent_level);
    182 static int cv8_lineinfo_bc_calc_len
    183     (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
    184 static int cv8_lineinfo_bc_tobytes
    185     (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
    186      yasm_output_value_func output_value,
    187      /*@null@*/ yasm_output_reloc_func output_reloc);
    188 
    189 static void cv_sym_bc_destroy(void *contents);
    190 static void cv_sym_bc_print(const void *contents, FILE *f, int indent_level);
    191 static int cv_sym_bc_calc_len
    192     (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
    193 static int cv_sym_bc_tobytes
    194     (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
    195      yasm_output_value_func output_value,
    196      /*@null@*/ yasm_output_reloc_func output_reloc);
    197 
    198 /* Bytecode callback structures */
    199 static const yasm_bytecode_callback cv8_symhead_bc_callback = {
    200     cv8_symhead_bc_destroy,
    201     cv8_symhead_bc_print,
    202     yasm_bc_finalize_common,
    203     NULL,
    204     cv8_symhead_bc_calc_len,
    205     yasm_bc_expand_common,
    206     cv8_symhead_bc_tobytes,
    207     0
    208 };
    209 
    210 static const yasm_bytecode_callback cv8_fileinfo_bc_callback = {
    211     cv8_fileinfo_bc_destroy,
    212     cv8_fileinfo_bc_print,
    213     yasm_bc_finalize_common,
    214     NULL,
    215     cv8_fileinfo_bc_calc_len,
    216     yasm_bc_expand_common,
    217     cv8_fileinfo_bc_tobytes,
    218     0
    219 };
    220 
    221 static const yasm_bytecode_callback cv8_lineinfo_bc_callback = {
    222     cv8_lineinfo_bc_destroy,
    223     cv8_lineinfo_bc_print,
    224     yasm_bc_finalize_common,
    225     NULL,
    226     cv8_lineinfo_bc_calc_len,
    227     yasm_bc_expand_common,
    228     cv8_lineinfo_bc_tobytes,
    229     0
    230 };
    231 
    232 static const yasm_bytecode_callback cv_sym_bc_callback = {
    233     cv_sym_bc_destroy,
    234     cv_sym_bc_print,
    235     yasm_bc_finalize_common,
    236     NULL,
    237     cv_sym_bc_calc_len,
    238     yasm_bc_expand_common,
    239     cv_sym_bc_tobytes,
    240     0
    241 };
    242 
    243 static cv8_symhead *cv8_add_symhead(yasm_section *sect, unsigned long type,
    244                                     int first);
    245 static void cv8_set_symhead_end(cv8_symhead *head, yasm_bytecode *end_prevbc);
    246 
    247 static yasm_bytecode *cv8_add_fileinfo
    248     (yasm_section *sect, const cv_filename *fn);
    249 
    250 static unsigned long cv_sym_size(const cv_sym *cvs);
    251 
    252 
    253 static cv_sym *
    254 cv8_add_sym_objname(yasm_section *sect, /*@keep@*/ char *objname)
    255 {
    256     yasm_bytecode *bc;
    257     cv_sym *cvs = yasm_xmalloc(sizeof(cv_sym));
    258     cvs->type = CV8_S_OBJNAME;
    259     cvs->format = "wZ";
    260     cvs->args[0].i = 0;         /* signature (0=asm) */
    261     cvs->args[1].p = objname;   /* object filename */
    262 
    263     bc = yasm_bc_create_common(&cv_sym_bc_callback, cvs, 0);
    264     bc->len = cv_sym_size(cvs);
    265     yasm_cv__append_bc(sect, bc);
    266     return cvs;
    267 }
    268 
    269 static cv_sym *
    270 cv8_add_sym_compile(yasm_object *object, yasm_section *sect,
    271                     /*@keep@*/ char *creator)
    272 {
    273     yasm_bytecode *bc;
    274     cv_sym *cvs = yasm_xmalloc(sizeof(cv_sym));
    275     cvs->type = CV8_S_COMPILE;
    276     cvs->format = "wwwwZh";
    277     cvs->args[0].i = 3;         /* language (3=Masm) */
    278 
    279     /* target processor; 0xD0 = AMD64 */
    280     if (strcmp(yasm_arch_keyword(object->arch), "x86") == 0) {
    281         if (strcmp(yasm_arch_get_machine(object->arch), "amd64") == 0)
    282             cvs->args[1].i = 0xD0;
    283         else
    284             cvs->args[1].i = 0x6;       /* 686, FIXME */
    285     } else
    286         cvs->args[1].i = 0;             /* XXX: unknown */
    287 
    288     cvs->args[2].i = 0;         /* flags (assume 0 for now) */
    289     cvs->args[3].i = 0;         /* creator version number (assume 0 for now) */
    290     cvs->args[4].p = creator;   /* creator string */
    291     cvs->args[5].i = 0;         /* no pairs of key/value */
    292 
    293     bc = yasm_bc_create_common(&cv_sym_bc_callback, cvs, 0);
    294     bc->len = cv_sym_size(cvs);
    295     yasm_cv__append_bc(sect, bc);
    296     return cvs;
    297 }
    298 
    299 static cv_sym *
    300 cv8_add_sym_label(yasm_section *sect, yasm_symrec *sym)
    301 {
    302     yasm_bytecode *bc;
    303     cv_sym *cvs = yasm_xmalloc(sizeof(cv_sym));
    304     cvs->type = CV8_S_LABEL32;
    305     cvs->format = "YbZ";
    306     cvs->args[0].p = sym;       /* symrec for label */
    307     cvs->args[1].i = 0;         /* flags (assume 0 for now) */
    308     cvs->args[2].p = yasm__xstrdup(yasm_symrec_get_name(sym));
    309 
    310     bc = yasm_bc_create_common(&cv_sym_bc_callback, cvs, 0);
    311     bc->len = cv_sym_size(cvs);
    312     yasm_cv__append_bc(sect, bc);
    313     return cvs;
    314 }
    315 
    316 static cv_sym *
    317 cv8_add_sym_data(yasm_section *sect, unsigned long type, yasm_symrec *sym,
    318                  int is_global)
    319 {
    320     yasm_bytecode *bc;
    321     cv_sym *cvs = yasm_xmalloc(sizeof(cv_sym));
    322     cvs->type = is_global ? CV8_S_GDATA32 : CV8_S_LDATA32;
    323     cvs->format = "wYZ";
    324     cvs->args[0].i = type;      /* type index */
    325     cvs->args[1].p = sym;       /* symrec for label */
    326     cvs->args[2].p = yasm__xstrdup(yasm_symrec_get_name(sym));
    327 
    328     bc = yasm_bc_create_common(&cv_sym_bc_callback, cvs, 0);
    329     bc->len = cv_sym_size(cvs);
    330     yasm_cv__append_bc(sect, bc);
    331     return cvs;
    332 }
    333 
    334 static size_t
    335 cv_dbgfmt_add_file(yasm_dbgfmt_cv *dbgfmt_cv, size_t filenum,
    336                    const char *filename)
    337 {
    338     char *pathname;
    339     size_t i;
    340     yasm_md5_context context;
    341     FILE *f;
    342     unsigned char *buf;
    343     size_t len;
    344 
    345     /* Put the filename into the filename table */
    346     if (filenum == 0) {
    347         /* Look to see if we already have that filename in the table */
    348         for (; filenum<dbgfmt_cv->filenames_size; filenum++) {
    349             if (!dbgfmt_cv->filenames[filenum].filename ||
    350                 strcmp(dbgfmt_cv->filenames[filenum].filename, filename) == 0)
    351                 break;
    352         }
    353     } else
    354         filenum--;      /* array index is 0-based */
    355 
    356     /* Realloc table if necessary */
    357     if (filenum >= dbgfmt_cv->filenames_allocated) {
    358         size_t old_allocated = dbgfmt_cv->filenames_allocated;
    359         dbgfmt_cv->filenames_allocated = filenum+32;
    360         dbgfmt_cv->filenames = yasm_xrealloc(dbgfmt_cv->filenames,
    361             sizeof(cv_filename)*dbgfmt_cv->filenames_allocated);
    362         for (i=old_allocated; i<dbgfmt_cv->filenames_allocated; i++) {
    363             dbgfmt_cv->filenames[i].pathname = NULL;
    364             dbgfmt_cv->filenames[i].filename = NULL;
    365             dbgfmt_cv->filenames[i].str_off = 0;
    366             dbgfmt_cv->filenames[i].info_off = 0;
    367         }
    368     }
    369 
    370     /* Calculate MD5 checksum of file */
    371     buf = yasm_xmalloc(1024);
    372     yasm_md5_init(&context);
    373     f = fopen(filename, "rb");
    374     if (!f)
    375         yasm__fatal(N_("codeview: could not open source file"));
    376     while ((len = fread(buf, 1, 1024, f)) > 0)
    377         yasm_md5_update(&context, buf, (unsigned long)len);
    378     yasm_md5_final(dbgfmt_cv->filenames[filenum].digest, &context);
    379     fclose(f);
    380     yasm_xfree(buf);
    381 
    382     /* Actually save in table */
    383     if (dbgfmt_cv->filenames[filenum].pathname)
    384         yasm_xfree(dbgfmt_cv->filenames[filenum].pathname);
    385     if (dbgfmt_cv->filenames[filenum].filename)
    386         yasm_xfree(dbgfmt_cv->filenames[filenum].filename);
    387 
    388     pathname = yasm__abspath(filename);
    389     dbgfmt_cv->filenames[filenum].pathname = pathname;
    390     dbgfmt_cv->filenames[filenum].filename = yasm__xstrdup(filename);
    391 
    392     /* Update table size */
    393     if (filenum >= dbgfmt_cv->filenames_size)
    394         dbgfmt_cv->filenames_size = filenum + 1;
    395 
    396     return filenum;
    397 }
    398 
    399 static yasm_bytecode *
    400 cv_append_str(yasm_section *sect, const char *str)
    401 {
    402     yasm_datavalhead dvs;
    403     yasm_bytecode *bc;
    404 
    405     yasm_dvs_initialize(&dvs);
    406     yasm_dvs_append(&dvs, yasm_dv_create_string(yasm__xstrdup(str),
    407                                                 strlen(str)));
    408     bc = yasm_bc_create_data(&dvs, 1, 1, NULL, 0);
    409     yasm_bc_finalize(bc, yasm_cv__append_bc(sect, bc));
    410     yasm_bc_calc_len(bc, NULL, NULL);
    411     return bc;
    412 }
    413 
    414 typedef struct cv_line_info {
    415     yasm_section *debug_symline;
    416     yasm_object *object;
    417     yasm_dbgfmt_cv *dbgfmt_cv;
    418     yasm_linemap *linemap;
    419     yasm_errwarns *errwarns;
    420     unsigned int num_lineinfos;
    421     STAILQ_HEAD(cv8_lineinfo_head, cv8_lineinfo) cv8_lineinfos;
    422     /*@null@*/ cv8_lineinfo *cv8_cur_li;
    423     /*@null@*/ cv8_lineset *cv8_cur_ls;
    424 } cv_line_info;
    425 
    426 static int
    427 cv_generate_line_bc(yasm_bytecode *bc, /*@null@*/ void *d)
    428 {
    429     cv_line_info *info = (cv_line_info *)d;
    430     yasm_dbgfmt_cv *dbgfmt_cv = info->dbgfmt_cv;
    431     size_t i;
    432     const char *filename;
    433     unsigned long line;
    434     /*@null@*/ yasm_bytecode *nextbc = yasm_bc__next(bc);
    435     yasm_section *sect = yasm_bc_get_section(bc);
    436 
    437     if (nextbc && bc->offset == nextbc->offset)
    438         return 0;
    439 
    440     yasm_linemap_lookup(info->linemap, bc->line, &filename, &line);
    441 
    442     if (!info->cv8_cur_li
    443         || strcmp(filename, info->cv8_cur_li->fn->filename) != 0) {
    444         yasm_bytecode *sectbc;
    445         char symname[8];
    446 
    447         /* first see if we already have a lineinfo that is for this section and
    448          * filename
    449          */
    450         STAILQ_FOREACH(info->cv8_cur_li, &info->cv8_lineinfos, link) {
    451             if (sect == info->cv8_cur_li->sect
    452                 && strcmp(filename, info->cv8_cur_li->fn->filename) == 0)
    453                 break;
    454         }
    455 
    456         if (info->cv8_cur_li) {
    457             info->cv8_cur_ls = STAILQ_LAST(&info->cv8_cur_li->linesets,
    458                                            cv8_lineset, link);
    459             goto done;          /* found one */
    460         }
    461 
    462         /* Nope; find file */
    463         for (i=0; i<dbgfmt_cv->filenames_size; i++) {
    464             if (strcmp(filename, dbgfmt_cv->filenames[i].filename) == 0)
    465                 break;
    466         }
    467         if (i >= dbgfmt_cv->filenames_size)
    468             yasm_internal_error(N_("could not find filename in table"));
    469 
    470         /* and create new lineinfo structure */
    471         info->cv8_cur_li = yasm_xmalloc(sizeof(cv8_lineinfo));
    472         info->cv8_cur_li->fn = &dbgfmt_cv->filenames[i];
    473         info->cv8_cur_li->sect = sect;
    474         sectbc = yasm_section_bcs_first(sect);
    475         if (sectbc->symrecs && sectbc->symrecs[0])
    476             info->cv8_cur_li->sectsym = sectbc->symrecs[0];
    477         else {
    478             sprintf(symname, ".%06u", info->num_lineinfos++);
    479             info->cv8_cur_li->sectsym =
    480                 yasm_symtab_define_label(info->object->symtab, symname, sectbc,
    481                                          1, 0);
    482         }
    483         info->cv8_cur_li->num_linenums = 0;
    484         STAILQ_INIT(&info->cv8_cur_li->linesets);
    485         STAILQ_INSERT_TAIL(&info->cv8_lineinfos, info->cv8_cur_li, link);
    486         info->cv8_cur_ls = NULL;
    487     }
    488 done:
    489 
    490     /* build new lineset if necessary */
    491     if (!info->cv8_cur_ls || info->cv8_cur_ls->num_pairs >= 126) {
    492         info->cv8_cur_ls = yasm_xmalloc(sizeof(cv8_lineset));
    493         info->cv8_cur_ls->num_pairs = 0;
    494         STAILQ_INSERT_TAIL(&info->cv8_cur_li->linesets, info->cv8_cur_ls, link);
    495     }
    496 
    497     /* add linepair for this bytecode */
    498     info->cv8_cur_ls->pairs[info->cv8_cur_ls->num_pairs].offset = bc->offset;
    499     info->cv8_cur_ls->pairs[info->cv8_cur_ls->num_pairs].line =
    500         0x80000000 | line;
    501     info->cv8_cur_ls->num_pairs++;
    502     info->cv8_cur_li->num_linenums++;
    503 
    504     return 0;
    505 }
    506 
    507 static int
    508 cv_generate_line_section(yasm_section *sect, /*@null@*/ void *d)
    509 {
    510     cv_line_info *info = (cv_line_info *)d;
    511 
    512     if (!yasm_section_is_code(sect))
    513         return 0;       /* not code, so no line data for this section */
    514 
    515     info->cv8_cur_li = NULL;
    516     info->cv8_cur_ls = NULL;
    517 
    518     yasm_section_bcs_traverse(sect, info->errwarns, info, cv_generate_line_bc);
    519 
    520     return 0;
    521 }
    522 
    523 static int
    524 cv_generate_filename(const char *filename, void *d)
    525 {
    526     cv_dbgfmt_add_file((yasm_dbgfmt_cv *)d, 0, filename);
    527     return 0;
    528 }
    529 
    530 static int
    531 cv_generate_sym(yasm_symrec *sym, void *d)
    532 {
    533     cv_line_info *info = (cv_line_info *)d;
    534     yasm_bytecode *precbc;
    535     const char *name = yasm_symrec_get_name(sym);
    536 
    537     /* only care about labels (for now).  Don't put in symbols starting with
    538      * ".", as these are typically internally generated ones (like section
    539      * symbols).
    540      */
    541     if (name[0] == '.' || !yasm_symrec_get_label(sym, &precbc))
    542         return 0;
    543 
    544     /* TODO: add data types; until then, just mark everything as UBYTE */
    545     if (yasm_section_is_code(yasm_bc_get_section(precbc)))
    546         cv8_add_sym_label(info->debug_symline, sym);
    547     else
    548         cv8_add_sym_data(info->debug_symline, 0x20, sym,
    549             yasm_symrec_get_visibility(sym) & YASM_SYM_GLOBAL?1:0);
    550     return 0;
    551 }
    552 
    553 yasm_section *
    554 yasm_cv__generate_symline(yasm_object *object, yasm_linemap *linemap,
    555                           yasm_errwarns *errwarns)
    556 {
    557     yasm_dbgfmt_cv *dbgfmt_cv = (yasm_dbgfmt_cv *)object->dbgfmt;
    558     cv_line_info info;
    559     int new;
    560     size_t i;
    561     cv8_symhead *head;
    562     cv8_lineinfo *li;
    563     yasm_bytecode *bc;
    564     unsigned long off;
    565 
    566     /* Generate filenames based on linemap */
    567     yasm_linemap_traverse_filenames(linemap, dbgfmt_cv,
    568                                     cv_generate_filename);
    569 
    570     info.object = object;
    571     info.dbgfmt_cv = dbgfmt_cv;
    572     info.linemap = linemap;
    573     info.errwarns = errwarns;
    574     info.debug_symline =
    575         yasm_object_get_general(object, ".debug$S", 1, 0, 0, &new, 0);
    576     info.num_lineinfos = 0;
    577     STAILQ_INIT(&info.cv8_lineinfos);
    578     info.cv8_cur_li = NULL;
    579     info.cv8_cur_ls = NULL;
    580 
    581     /* source filenames string table */
    582     head = cv8_add_symhead(info.debug_symline, CV8_FILE_STRTAB, 1);
    583     cv_append_str(info.debug_symline, "");
    584     off = 1;
    585     for (i=0; i<dbgfmt_cv->filenames_size; i++) {
    586         if (!dbgfmt_cv->filenames[i].pathname) {
    587             yasm_error_set(YASM_ERROR_GENERAL,
    588                            N_("codeview file number %d unassigned"), i+1);
    589             yasm_errwarn_propagate(errwarns, 0);
    590             continue;
    591         }
    592         bc = cv_append_str(info.debug_symline,
    593                            dbgfmt_cv->filenames[i].pathname);
    594         dbgfmt_cv->filenames[i].str_off = off;
    595         off += bc->len;
    596     }
    597     cv8_set_symhead_end(head, yasm_section_bcs_last(info.debug_symline));
    598 
    599     /* Align 4 */
    600     bc = yasm_bc_create_align
    601         (yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(4)), 0),
    602          NULL, NULL, NULL, 0);
    603     yasm_bc_finalize(bc, yasm_cv__append_bc(info.debug_symline, bc));
    604     yasm_bc_calc_len(bc, NULL, NULL);
    605 
    606     /* source file info table */
    607     head = cv8_add_symhead(info.debug_symline, CV8_FILE_INFO, 0);
    608     off = 0;
    609     for (i=0; i<dbgfmt_cv->filenames_size; i++) {
    610         if (!dbgfmt_cv->filenames[i].pathname)
    611             continue;
    612         bc = cv8_add_fileinfo(info.debug_symline, &dbgfmt_cv->filenames[i]);
    613         dbgfmt_cv->filenames[i].info_off = off;
    614         off += bc->len;
    615     }
    616     cv8_set_symhead_end(head, yasm_section_bcs_last(info.debug_symline));
    617 
    618     /* Already aligned 4 */
    619 
    620     /* Generate line numbers for sections */
    621     yasm_object_sections_traverse(object, (void *)&info,
    622                                   cv_generate_line_section);
    623 
    624     /* Output line numbers for sections */
    625     STAILQ_FOREACH(li, &info.cv8_lineinfos, link) {
    626         head = cv8_add_symhead(info.debug_symline, CV8_LINE_NUMS, 0);
    627         bc = yasm_bc_create_common(&cv8_lineinfo_bc_callback, li, 0);
    628         bc->len = 24+li->num_linenums*8;
    629         yasm_cv__append_bc(info.debug_symline, bc);
    630         cv8_set_symhead_end(head, yasm_section_bcs_last(info.debug_symline));
    631     }
    632 
    633     /* Already aligned 4 */
    634 
    635     /* Output debugging symbols */
    636     head = cv8_add_symhead(info.debug_symline, CV8_DEBUG_SYMS, 0);
    637     /* add object and compile flag first */
    638     cv8_add_sym_objname(info.debug_symline,
    639                         yasm__abspath(object->obj_filename));
    640     if (getenv("YASM_TEST_SUITE"))
    641         cv8_add_sym_compile(object, info.debug_symline,
    642                             yasm__xstrdup("yasm HEAD"));
    643     else
    644         cv8_add_sym_compile(object, info.debug_symline,
    645                             yasm__xstrdup(PACKAGE_STRING));
    646     /* then iterate through symbol table */
    647     yasm_symtab_traverse(object->symtab, &info, cv_generate_sym);
    648     cv8_set_symhead_end(head, yasm_section_bcs_last(info.debug_symline));
    649 
    650     /* Align 4 at end */
    651     bc = yasm_bc_create_align
    652         (yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(4)), 0),
    653          NULL, NULL, NULL, 0);
    654     yasm_bc_finalize(bc, yasm_cv__append_bc(info.debug_symline, bc));
    655     yasm_bc_calc_len(bc, NULL, NULL);
    656 
    657     return info.debug_symline;
    658 }
    659 
    660 static void
    661 cv_out_sym(yasm_symrec *sym, unsigned long off, yasm_bytecode *bc,
    662            unsigned char **bufp, void *d, yasm_output_value_func output_value)
    663 {
    664     yasm_value val;
    665 
    666     /* sym in its section */
    667     yasm_value_init_sym(&val, sym, 32);
    668     val.section_rel = 1;
    669     output_value(&val, *bufp, 4, off, bc, 0, d);
    670     *bufp += 4;
    671 
    672     /* section index */
    673     yasm_value_init_sym(&val, sym, 16);
    674     val.seg_of = 1;
    675     output_value(&val, *bufp, 2, off+4, bc, 0, d);
    676     *bufp += 2;
    677 }
    678 
    679 static cv8_symhead *
    680 cv8_add_symhead(yasm_section *sect, unsigned long type, int first)
    681 {
    682     cv8_symhead *head;
    683     yasm_bytecode *bc;
    684 
    685     head = yasm_xmalloc(sizeof(cv8_symhead));
    686     head->type = type;
    687     head->first = first;
    688     head->start_prevbc = yasm_section_bcs_last(sect);
    689 
    690     bc = yasm_bc_create_common(&cv8_symhead_bc_callback, head, 0);
    691     if (first)
    692         bc->len = 12;
    693     else
    694         bc->len = 8;
    695 
    696     head->end_prevbc = bc;
    697     yasm_cv__append_bc(sect, bc);
    698     return head;
    699 }
    700 
    701 static void
    702 cv8_set_symhead_end(cv8_symhead *head, yasm_bytecode *end_prevbc)
    703 {
    704     head->end_prevbc = end_prevbc;
    705 }
    706 
    707 static void
    708 cv8_symhead_bc_destroy(void *contents)
    709 {
    710     yasm_xfree(contents);
    711 }
    712 
    713 static void
    714 cv8_symhead_bc_print(const void *contents, FILE *f, int indent_level)
    715 {
    716     /* TODO */
    717 }
    718 
    719 static int
    720 cv8_symhead_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
    721                         void *add_span_data)
    722 {
    723     yasm_internal_error(N_("tried to calc_len a codeview symhead bytecode"));
    724     /*@notreached@*/
    725     return 0;
    726 }
    727 
    728 static int
    729 cv8_symhead_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp,
    730                        unsigned char *bufstart, void *d,
    731                        yasm_output_value_func output_value,
    732                        yasm_output_reloc_func output_reloc)
    733 {
    734     yasm_object *object = yasm_section_get_object(bc->section);
    735     cv8_symhead *head = (cv8_symhead *)bc->contents;
    736     unsigned char *buf = *bufp;
    737     yasm_intnum *intn, *cval;
    738 
    739     cval = yasm_intnum_create_uint(4);
    740     /* Output "version" if first */
    741     if (head->first) {
    742         yasm_arch_intnum_tobytes(object->arch, cval, buf, 4, 32, 0, bc, 0);
    743         buf += 4;
    744     }
    745 
    746     /* Type contained - 4 bytes */
    747     yasm_intnum_set_uint(cval, head->type);
    748     yasm_arch_intnum_tobytes(object->arch, cval, buf, 4, 32, 0, bc, 0);
    749     buf += 4;
    750 
    751     /* Total length of info (following this field) - 4 bytes */
    752     yasm_intnum_set_uint(cval, bc->len);
    753     intn = yasm_calc_bc_dist(head->start_prevbc, head->end_prevbc);
    754     yasm_intnum_calc(intn, YASM_EXPR_SUB, cval);
    755     yasm_arch_intnum_tobytes(object->arch, intn, buf, 4, 32, 0, bc, 0);
    756     buf += 4;
    757     yasm_intnum_destroy(intn);
    758 
    759     *bufp = buf;
    760 
    761     yasm_intnum_destroy(cval);
    762     return 0;
    763 }
    764 
    765 static yasm_bytecode *
    766 cv8_add_fileinfo(yasm_section *sect, const cv_filename *fn)
    767 {
    768     cv8_fileinfo *fi;
    769     yasm_bytecode *bc;
    770 
    771     fi = yasm_xmalloc(sizeof(cv8_fileinfo));
    772     fi->fn = fn;
    773 
    774     bc = yasm_bc_create_common(&cv8_fileinfo_bc_callback, fi, 0);
    775     bc->len = 24;
    776 
    777     yasm_cv__append_bc(sect, bc);
    778     return bc;
    779 }
    780 
    781 static void
    782 cv8_fileinfo_bc_destroy(void *contents)
    783 {
    784     yasm_xfree(contents);
    785 }
    786 
    787 static void
    788 cv8_fileinfo_bc_print(const void *contents, FILE *f, int indent_level)
    789 {
    790     /* TODO */
    791 }
    792 
    793 static int
    794 cv8_fileinfo_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
    795                          void *add_span_data)
    796 {
    797     yasm_internal_error(N_("tried to calc_len a codeview fileinfo bytecode"));
    798     /*@notreached@*/
    799     return 0;
    800 }
    801 
    802 static int
    803 cv8_fileinfo_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp,
    804                         unsigned char *bufstart, void *d,
    805                         yasm_output_value_func output_value,
    806                         yasm_output_reloc_func output_reloc)
    807 {
    808     yasm_object *object = yasm_section_get_object(bc->section);
    809     cv8_fileinfo *fi = (cv8_fileinfo *)bc->contents;
    810     unsigned char *buf = *bufp;
    811     yasm_intnum *cval;
    812     int i;
    813 
    814     /* Offset in filename string table */
    815     cval = yasm_intnum_create_uint(fi->fn->str_off);
    816     yasm_arch_intnum_tobytes(object->arch, cval, buf, 4, 32, 0, bc, 0);
    817     buf += 4;
    818 
    819     /* Checksum type/length */
    820     yasm_intnum_set_uint(cval, 0x0110);
    821     yasm_arch_intnum_tobytes(object->arch, cval, buf, 2, 16, 0, bc, 0);
    822     buf += 2;
    823 
    824     /* Checksum */
    825     for (i=0; i<16; i++)
    826         YASM_WRITE_8(buf, fi->fn->digest[i]);
    827 
    828     /* Pad */
    829     YASM_WRITE_8(buf, 0);
    830     YASM_WRITE_8(buf, 0);
    831 
    832     *bufp = buf;
    833 
    834     yasm_intnum_destroy(cval);
    835     return 0;
    836 }
    837 
    838 static void
    839 cv8_lineinfo_bc_destroy(void *contents)
    840 {
    841     cv8_lineinfo *li = (cv8_lineinfo *)contents;
    842     cv8_lineset *ls1, *ls2;
    843 
    844     /* delete line sets */
    845     ls1 = STAILQ_FIRST(&li->linesets);
    846     while (ls1) {
    847         ls2 = STAILQ_NEXT(ls1, link);
    848         yasm_xfree(ls1);
    849         ls1 = ls2;
    850     }
    851 
    852     yasm_xfree(contents);
    853 }
    854 
    855 static void
    856 cv8_lineinfo_bc_print(const void *contents, FILE *f, int indent_level)
    857 {
    858     /* TODO */
    859 }
    860 
    861 static int
    862 cv8_lineinfo_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
    863                          void *add_span_data)
    864 {
    865     yasm_internal_error(N_("tried to calc_len a codeview linehead bytecode"));
    866     /*@notreached@*/
    867     return 0;
    868 }
    869 
    870 static int
    871 cv8_lineinfo_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp,
    872                         unsigned char *bufstart, void *d,
    873                         yasm_output_value_func output_value,
    874                         yasm_output_reloc_func output_reloc)
    875 {
    876     yasm_object *object = yasm_section_get_object(bc->section);
    877     cv8_lineinfo *li = (cv8_lineinfo *)bc->contents;
    878     unsigned char *buf = *bufp;
    879     yasm_intnum *cval;
    880     unsigned long i;
    881     cv8_lineset *ls;
    882 
    883     /* start offset and section */
    884     cv_out_sym(li->sectsym, (unsigned long)(buf - bufstart), bc, &buf,
    885                d, output_value);
    886 
    887     /* Two bytes of pad/alignment */
    888     YASM_WRITE_8(buf, 0);
    889     YASM_WRITE_8(buf, 0);
    890 
    891     /* Section length covered by line number info */
    892     cval = yasm_calc_bc_dist(yasm_section_bcs_first(li->sect),
    893                              yasm_section_bcs_last(li->sect));
    894     yasm_arch_intnum_tobytes(object->arch, cval, buf, 4, 32, 0, bc, 0);
    895     buf += 4;
    896 
    897     /* Offset of source file in info table */
    898     yasm_intnum_set_uint(cval, li->fn->info_off);
    899     yasm_arch_intnum_tobytes(object->arch, cval, buf, 4, 32, 0, bc, 0);
    900     buf += 4;
    901 
    902     /* Number of line number pairs */
    903     yasm_intnum_set_uint(cval, li->num_linenums);
    904     yasm_arch_intnum_tobytes(object->arch, cval, buf, 4, 32, 0, bc, 0);
    905     buf += 4;
    906 
    907     /* Number of bytes of line number pairs + 12 (no, I don't know why) */
    908     yasm_intnum_set_uint(cval, li->num_linenums*8+12);
    909     yasm_arch_intnum_tobytes(object->arch, cval, buf, 4, 32, 0, bc, 0);
    910     buf += 4;
    911 
    912     /* Offset / line number pairs */
    913     i = 0;
    914     STAILQ_FOREACH(ls, &li->linesets, link) {
    915         unsigned long j;
    916         for (j=0; i<li->num_linenums && j<126; i++, j++) {
    917             /* offset in section */
    918             yasm_intnum_set_uint(cval, ls->pairs[j].offset);
    919             yasm_arch_intnum_tobytes(object->arch, cval, buf, 4, 32, 0, bc, 0);
    920             buf += 4;
    921 
    922             /* line number in file */
    923             yasm_intnum_set_uint(cval, ls->pairs[j].line);
    924             yasm_arch_intnum_tobytes(object->arch, cval, buf, 4, 32, 0, bc, 0);
    925             buf += 4;
    926         }
    927     }
    928 
    929     *bufp = buf;
    930 
    931     yasm_intnum_destroy(cval);
    932     return 0;
    933 }
    934 
    935 static unsigned long
    936 cv_sym_size(const cv_sym *cvs)
    937 {
    938     const char *ch = cvs->format;
    939     unsigned long len = 4;  /* sym length and type */
    940     unsigned long slen;
    941     int arg = 0;
    942 
    943     while (*ch) {
    944         switch (*ch) {
    945             case 'b':
    946                 len++;
    947                 arg++;
    948                 break;
    949             case 'h':
    950                 len += 2;
    951                 arg++;
    952                 break;
    953             case 'w':
    954                 len += 4;
    955                 arg++;
    956                 break;
    957             case 'Y':
    958                 len += 6;       /* XXX: will be 4 in 16-bit version */
    959                 arg++;
    960                 break;
    961             case 'T':
    962                 len += 4;       /* XXX: will be 2 in CV4 */
    963                 arg++;
    964                 break;
    965             case 'S':
    966                 len += 1;       /* XXX: is this 1 or 2? */
    967                 slen = (unsigned long)strlen((const char *)cvs->args[arg++].p);
    968                 len += slen <= 0xff ? slen : 0xff;
    969                 break;
    970             case 'Z':
    971                 len +=
    972                     (unsigned long)strlen((const char *)cvs->args[arg++].p) + 1;
    973                 break;
    974             default:
    975                 yasm_internal_error(N_("unknown sym format character"));
    976         }
    977         ch++;
    978     }
    979 
    980     return len;
    981 }
    982 
    983 static void
    984 cv_sym_bc_destroy(void *contents)
    985 {
    986     cv_sym *cvs = (cv_sym *)contents;
    987     const char *ch = cvs->format;
    988     int arg = 0;
    989 
    990     while (*ch) {
    991         switch (*ch) {
    992             case 'b':
    993             case 'h':
    994             case 'w':
    995             case 'Y':
    996             case 'T':
    997                 arg++;
    998                 break;  /* nothing to destroy */
    999             case 'S':
   1000             case 'Z':
   1001                 yasm_xfree(cvs->args[arg++].p);
   1002                 break;
   1003             default:
   1004                 yasm_internal_error(N_("unknown sym format character"));
   1005         }
   1006         ch++;
   1007     }
   1008 
   1009     yasm_xfree(contents);
   1010 }
   1011 
   1012 static void
   1013 cv_sym_bc_print(const void *contents, FILE *f, int indent_level)
   1014 {
   1015     /* TODO */
   1016 }
   1017 
   1018 static int
   1019 cv_sym_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
   1020                    void *add_span_data)
   1021 {
   1022     yasm_internal_error(N_("tried to calc_len a codeview sym bytecode"));
   1023     /*@notreached@*/
   1024     return 0;
   1025 }
   1026 
   1027 static int
   1028 cv_sym_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp,
   1029                   unsigned char *bufstart, void *d,
   1030                   yasm_output_value_func output_value,
   1031                   yasm_output_reloc_func output_reloc)
   1032 {
   1033     yasm_object *object = yasm_section_get_object(bc->section);
   1034     cv_sym *cvs = (cv_sym *)bc->contents;
   1035     unsigned char *buf = *bufp;
   1036     yasm_intnum *cval;
   1037     const char *ch = cvs->format;
   1038     size_t len;
   1039     int arg = 0;
   1040 
   1041     /* Total length of record (following this field) - 2 bytes */
   1042     cval = yasm_intnum_create_uint(bc->len-2);
   1043     yasm_arch_intnum_tobytes(object->arch, cval, buf, 2, 16, 0, bc, 1);
   1044     buf += 2;
   1045 
   1046     /* Type contained - 2 bytes */
   1047     yasm_intnum_set_uint(cval, cvs->type);
   1048     yasm_arch_intnum_tobytes(object->arch, cval, buf, 2, 16, 0, bc, 0);
   1049     buf += 2;
   1050 
   1051     while (*ch) {
   1052         switch (*ch) {
   1053             case 'b':
   1054                 YASM_WRITE_8(buf, cvs->args[arg].i);
   1055                 arg++;
   1056                 break;
   1057             case 'h':
   1058                 yasm_intnum_set_uint(cval, cvs->args[arg++].i);
   1059                 yasm_arch_intnum_tobytes(object->arch, cval, buf, 2, 16, 0,
   1060                                          bc, 0);
   1061                 buf += 2;
   1062                 break;
   1063             case 'w':
   1064                 yasm_intnum_set_uint(cval, cvs->args[arg++].i);
   1065                 yasm_arch_intnum_tobytes(object->arch, cval, buf, 4, 32, 0,
   1066                                          bc, 0);
   1067                 buf += 4;
   1068                 break;
   1069             case 'Y':
   1070                 cv_out_sym((yasm_symrec *)cvs->args[arg++].p,
   1071                            (unsigned long)(buf-bufstart), bc, &buf, d,
   1072                            output_value);
   1073                 break;
   1074             case 'T':
   1075                 yasm_intnum_set_uint(cval, cvs->args[arg++].i);
   1076                 yasm_arch_intnum_tobytes(object->arch, cval, buf, 4, 32, 0,
   1077                                          bc, 0);
   1078                 buf += 4;       /* XXX: will be 2 in CV4 */
   1079                 break;
   1080             case 'S':
   1081                 len = strlen((char *)cvs->args[arg].p);
   1082                 len = len <= 0xff ? len : 0xff;
   1083                 YASM_WRITE_8(buf, len);
   1084                 memcpy(buf, (char *)cvs->args[arg].p, len);
   1085                 buf += len;
   1086                 arg++;
   1087                 break;
   1088             case 'Z':
   1089                 len = strlen((char *)cvs->args[arg].p)+1;
   1090                 memcpy(buf, (char *)cvs->args[arg].p, len);
   1091                 buf += len;
   1092                 arg++;
   1093                 break;
   1094             default:
   1095                 yasm_internal_error(N_("unknown leaf format character"));
   1096         }
   1097         ch++;
   1098     }
   1099 
   1100     *bufp = buf;
   1101 
   1102     yasm_intnum_destroy(cval);
   1103     return 0;
   1104 }
   1105