Home | History | Annotate | Download | only in stabs
      1 /*
      2  * Stabs debugging format
      3  *
      4  *  Copyright (C) 2003-2007  Michael Urman
      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  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
     16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
     19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     25  * POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 #include <util.h>
     28 
     29 #include <libyasm.h>
     30 
     31 typedef enum {
     32     N_UNDF = 0x00,      /* Undefined */
     33     N_GSYM = 0x20,      /* Global symbol */
     34     N_FNAME = 0x22,     /* Function name (BSD Fortran) */
     35     N_FUN = 0x24,       /* Function name or Text segment variable */
     36     N_STSYM = 0x26,     /* Data segment file-scope variable */
     37     N_LCSYM = 0x28,     /* BSS segment file-scope variable */
     38     N_MAIN = 0x2a,      /* Name of main routine */
     39     N_ROSYM = 0x2c,     /* Variable in .rodata section */
     40     N_PC = 0x30,        /* Global symbol (Pascal) */
     41     N_SYMS = 0x32,      /* Number of symbols (Ultrix V4.0) */
     42     N_NOMAP = 0x34,     /* No DST map */
     43     N_OBJ = 0x38,       /* Object file (Solaris2) */
     44     N_OPT = 0x3c,       /* Debugger options (Solaris2) */
     45     N_RSYM = 0x40,      /* Register variable */
     46     N_M2C = 0x42,       /* Modula-2 compilation unit */
     47     N_SLINE = 0x44,     /* Line numbers in .text segment */
     48     N_DSLINE = 0x46,    /* Line numbers in .data segment */
     49     N_BSLINE = 0x48,    /* Line numbers in .bss segment */
     50     N_BROWS = 0x48,     /* Source code .cb file's path */
     51     N_DEFD = 0x4a,      /* GNU Modula-2 definition module dependency */
     52     N_FLINE = 0x4c,     /* Function start/body/end line numbers (Solaris2) */
     53     N_EHDECL = 0x50,    /* GNU C++ exception variable */
     54     N_MOD2 = 0x50,      /* Modula2 info for imc (Ultrix V4.0) */
     55     N_CATCH = 0x54,     /* GNU C++ catch clause */
     56     N_SSYM = 0x60,      /* Structure or union element */
     57     N_ENDM = 0x62,      /* Last stab for module (Solaris2) */
     58     N_SO = 0x64,        /* Path and name of source files */
     59     N_LSYM = 0x80,      /* Stack variable */
     60     N_BINCL = 0x84,     /* Beginning of include file */
     61     N_SOL = 0x84,       /* Name of include file */
     62     N_PSYM = 0xa0,      /* Parameter variable */
     63     N_EINCL = 0xa2,     /* End of include file */
     64     N_ENTRY = 0xa4,     /* Alternate entry point */
     65     N_LBRAC = 0xc0,     /* Beginning of lexical block */
     66     N_EXCL = 0xc2,      /* Placeholder for a deleted include file */
     67     N_SCOPE = 0xc4,     /* Modula 2 scope info (Sun) */
     68     N_RBRAC = 0xe0,     /* End of lexical block */
     69     N_BCOMM = 0xe2,     /* Begin named common block */
     70     N_ECOMM = 0xe4,     /* End named common block */
     71     N_ECOML = 0xe8,     /* Member of common block */
     72     N_WITH = 0xea,      /* Pascal with statement: type,,0,0,offset (Solaris2) */
     73     N_NBTEXT = 0xf0,    /* Gould non-base registers */
     74     N_NBDATA = 0xf2,    /* Gould non-base registers */
     75     N_NBBSS = 0xf4,     /* Gould non-base registers */
     76     N_NBSTS = 0xf6,     /* Gould non-base registers */
     77     N_NBLCS = 0xf8      /* Gould non-base registers */
     78 } stabs_stab_type;
     79 
     80 typedef struct yasm_dbgfmt_stabs {
     81     yasm_dbgfmt_base dbgfmt;        /* base structure */
     82 } yasm_dbgfmt_stabs;
     83 
     84 typedef struct {
     85     unsigned long lastline;     /* track line and file of bytecodes */
     86     unsigned long curline;
     87     const char *lastfile;
     88     const char *curfile;
     89 
     90     unsigned int stablen;       /* size of a stab for current machine */
     91     unsigned long stabcount;    /* count stored stabs; doesn't include first */
     92 
     93     yasm_section *stab;         /* sections to which stabs, stabstrs appended */
     94     yasm_section *stabstr;
     95 
     96     yasm_bytecode *basebc;      /* base bytecode from which to track SLINEs */
     97 
     98     yasm_object *object;
     99     yasm_linemap *linemap;
    100     yasm_errwarns *errwarns;
    101 } stabs_info;
    102 
    103 typedef struct {
    104     /*@null@*/ yasm_bytecode *bcstr;    /* bytecode in stabstr for string */
    105     stabs_stab_type type;               /* stab type: N_* */
    106     unsigned char other;                /* unused, but stored here anyway */
    107     unsigned short desc;                /* description element of a stab */
    108     /*@null@*/ yasm_symrec *symvalue;   /* value element needing relocation */
    109     /*@null@*/yasm_bytecode *bcvalue;   /* relocated stab's bytecode */
    110     unsigned long value;                /* fallthrough value if above NULL */
    111 } stabs_stab;
    112 
    113 /* Bytecode callback function prototypes */
    114 
    115 static void stabs_bc_str_destroy(void *contents);
    116 static void stabs_bc_str_print(const void *contents, FILE *f, int
    117                                indent_level);
    118 static int stabs_bc_str_calc_len
    119     (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
    120 static int stabs_bc_str_tobytes
    121     (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
    122      yasm_output_value_func output_value,
    123      /*@null@*/ yasm_output_reloc_func output_reloc);
    124 
    125 static void stabs_bc_stab_destroy(void *contents);
    126 static void stabs_bc_stab_print(const void *contents, FILE *f, int
    127                                 indent_level);
    128 static int stabs_bc_stab_calc_len
    129     (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
    130 static int stabs_bc_stab_tobytes
    131     (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
    132      yasm_output_value_func output_value,
    133      /*@null@*/ yasm_output_reloc_func output_reloc);
    134 
    135 /* Bytecode callback structures */
    136 
    137 static const yasm_bytecode_callback stabs_bc_str_callback = {
    138     stabs_bc_str_destroy,
    139     stabs_bc_str_print,
    140     yasm_bc_finalize_common,
    141     NULL,
    142     stabs_bc_str_calc_len,
    143     yasm_bc_expand_common,
    144     stabs_bc_str_tobytes,
    145     0
    146 };
    147 
    148 static const yasm_bytecode_callback stabs_bc_stab_callback = {
    149     stabs_bc_stab_destroy,
    150     stabs_bc_stab_print,
    151     yasm_bc_finalize_common,
    152     NULL,
    153     stabs_bc_stab_calc_len,
    154     yasm_bc_expand_common,
    155     stabs_bc_stab_tobytes,
    156     0
    157 };
    158 
    159 yasm_dbgfmt_module yasm_stabs_LTX_dbgfmt;
    160 
    161 
    162 static /*@null@*/ /*@only@*/ yasm_dbgfmt *
    163 stabs_dbgfmt_create(yasm_object *object)
    164 {
    165     yasm_dbgfmt_stabs *dbgfmt_stabs = yasm_xmalloc(sizeof(yasm_dbgfmt_stabs));
    166     dbgfmt_stabs->dbgfmt.module = &yasm_stabs_LTX_dbgfmt;
    167     return (yasm_dbgfmt *)dbgfmt_stabs;
    168 }
    169 
    170 static void
    171 stabs_dbgfmt_destroy(/*@only@*/ yasm_dbgfmt *dbgfmt)
    172 {
    173     yasm_xfree(dbgfmt);
    174 }
    175 
    176 /* Create and add a new strtab-style string bytecode to a section, updating
    177  * offset on insertion; no optimization necessary */
    178 /* Copies the string, so you must still free yours as normal */
    179 static yasm_bytecode *
    180 stabs_dbgfmt_append_bcstr(yasm_section *sect, const char *str)
    181 {
    182     yasm_bytecode *bc;
    183 
    184     bc = yasm_bc_create_common(&stabs_bc_str_callback, yasm__xstrdup(str), 0);
    185     bc->len = (unsigned long)(strlen(str)+1);
    186     bc->offset = yasm_bc_next_offset(yasm_section_bcs_last(sect));
    187 
    188     yasm_section_bcs_append(sect, bc);
    189 
    190     return bc;
    191 }
    192 
    193 /* Create and add a new stab bytecode to a section, updating offset on
    194  * insertion; no optimization necessary. */
    195 /* Requires a string bytecode, or NULL, for its string entry */
    196 static stabs_stab *
    197 stabs_dbgfmt_append_stab(stabs_info *info, yasm_section *sect,
    198                          /*@null@*/ yasm_bytecode *bcstr, stabs_stab_type type,
    199                          unsigned long desc, /*@null@*/ yasm_symrec *symvalue,
    200                          /*@null@*/ yasm_bytecode *bcvalue, unsigned long value)
    201 {
    202     yasm_bytecode *bc;
    203     stabs_stab *stab = yasm_xmalloc(sizeof(stabs_stab));
    204 
    205     stab->other = 0;
    206     stab->bcstr = bcstr;
    207     stab->type = type;
    208     stab->desc = (unsigned short)desc;
    209     stab->symvalue = symvalue;
    210     stab->bcvalue = bcvalue;
    211     stab->value = value;
    212 
    213     bc = yasm_bc_create_common(&stabs_bc_stab_callback, stab,
    214                                bcvalue ? bcvalue->line : 0);
    215     bc->len = info->stablen;
    216     bc->offset = yasm_bc_next_offset(yasm_section_bcs_last(sect));
    217 
    218     yasm_section_bcs_append(sect, bc);
    219 
    220     info->stabcount++;
    221     return stab;
    222 }
    223 
    224 static void
    225 stabs_dbgfmt_generate_n_fun(stabs_info *info, yasm_bytecode *bc)
    226 {
    227     /* check all syms at this bc for potential function syms */
    228     int bcsym;
    229     for (bcsym=0; bc->symrecs && bc->symrecs[bcsym]; bcsym++)
    230     {
    231         char *str;
    232         yasm_symrec *sym = bc->symrecs[bcsym];
    233         const char *name = yasm_symrec_get_name(sym);
    234 
    235         /* best guess algorithm - ignore labels containing a . or $ */
    236         if (strchr(name, '.') || strchr(name, '$'))
    237             continue;
    238 
    239         /* if a function, update basebc, and output a funcname:F1 stab */
    240         info->basebc = bc;
    241 
    242         str = yasm_xmalloc(strlen(name)+4);
    243         strcpy(str, name);
    244         strcat(str, ":F1");
    245         stabs_dbgfmt_append_stab(info, info->stab,
    246                                  stabs_dbgfmt_append_bcstr(info->stabstr, str),
    247                                  N_FUN, 0, sym, info->basebc, 0);
    248         yasm_xfree(str);
    249         break;
    250     }
    251 }
    252 
    253 static int
    254 stabs_dbgfmt_generate_bcs(yasm_bytecode *bc, void *d)
    255 {
    256     stabs_info *info = (stabs_info *)d;
    257     yasm_linemap_lookup(info->linemap, bc->line, &info->curfile,
    258                         &info->curline);
    259 
    260     /* check for new function */
    261     stabs_dbgfmt_generate_n_fun(info, bc);
    262 
    263     if (info->lastfile != info->curfile) {
    264         info->lastline = 0; /* new file, so line changes */
    265         /*stabs_dbgfmt_append_stab(info, info->stab,
    266             stabs_dbgfmt_append_bcstr(info->stabstr, info->curfile),
    267             N_SOL, 0, NULL, bc, 0);*/
    268     }
    269 
    270     /* output new line stabs if there's a basebc (known function) */
    271     if (info->basebc != NULL && info->curline != info->lastline) {
    272         info->lastline = bc->line;
    273         stabs_dbgfmt_append_stab(info, info->stab, NULL, N_SLINE,
    274                                  info->curline, NULL, NULL,
    275                                  bc->offset - info->basebc->offset);
    276     }
    277 
    278     info->lastline = info->curline;
    279     info->lastfile = info->curfile;
    280 
    281     return 0;
    282 }
    283 
    284 static int
    285 stabs_dbgfmt_generate_sections(yasm_section *sect, /*@null@*/ void *d)
    286 {
    287     stabs_info *info = (stabs_info *)d;
    288     const char *sectname=yasm_section_get_name(sect);
    289 
    290     /* each section has a different base symbol */
    291     info->basebc = NULL;
    292 
    293     /* handle first (pseudo) bc separately */
    294     stabs_dbgfmt_generate_n_fun(d, yasm_section_bcs_first(sect));
    295 
    296     yasm_section_bcs_traverse(sect, info->errwarns, d,
    297                               stabs_dbgfmt_generate_bcs);
    298 
    299     if (yasm__strcasecmp(sectname, ".text")==0) {
    300         /* Close out last function by appending a null SO stab after last bc */
    301         yasm_bytecode *bc = yasm_section_bcs_last(sect);
    302         yasm_symrec *sym =
    303             yasm_symtab_define_label(info->object->symtab, ".n_so", bc, 1,
    304                                      bc->line);
    305         stabs_dbgfmt_append_stab(info, info->stab, 0, N_SO, 0, sym, bc, 0);
    306     }
    307 
    308     return 1;
    309 }
    310 
    311 static void
    312 stabs_dbgfmt_generate(yasm_object *object, yasm_linemap *linemap,
    313                       yasm_errwarns *errwarns)
    314 {
    315     stabs_info info;
    316     int new;
    317     yasm_bytecode *dbgbc;
    318     stabs_stab *stab;
    319     yasm_bytecode *filebc, *nullbc, *laststr, *firstbc;
    320     yasm_symrec *firstsym;
    321     yasm_section *stext;
    322 
    323     /* Stablen is determined by arch/machine */
    324     if (yasm__strcasecmp(yasm_arch_keyword(object->arch), "x86") == 0) {
    325         info.stablen = 12;
    326     }
    327     else /* unknown machine; generate nothing */
    328         return;
    329 
    330     info.object = object;
    331     info.linemap = linemap;
    332     info.errwarns = errwarns;
    333     info.lastline = 0;
    334     info.stabcount = 0;
    335     info.stab = yasm_object_get_general(object, ".stab", 4, 0, 0, &new, 0);
    336     if (!new) {
    337         yasm_bytecode *last = yasm_section_bcs_last(info.stab);
    338         if (last == NULL) {
    339             yasm_error_set(YASM_ERROR_GENERAL,
    340                 N_("stabs debugging conflicts with user-defined section .stab"));
    341             yasm_errwarn_propagate(errwarns,
    342                                    yasm_section_bcs_first(info.stab)->line);
    343         } else {
    344             yasm_warn_set(YASM_WARN_GENERAL,
    345                 N_("stabs debugging overrides empty section .stab"));
    346             yasm_errwarn_propagate(errwarns, 0);
    347         }
    348     }
    349 
    350     info.stabstr =
    351         yasm_object_get_general(object, ".stabstr", 1, 0, 0, &new, 0);
    352     if (!new) {
    353         yasm_bytecode *last = yasm_section_bcs_last(info.stabstr);
    354         if (last == NULL) {
    355             yasm_error_set(YASM_ERROR_GENERAL,
    356                 N_("stabs debugging conflicts with user-defined section .stabstr"));
    357             yasm_errwarn_propagate(errwarns,
    358                                    yasm_section_bcs_first(info.stab)->line);
    359         } else {
    360             yasm_warn_set(YASM_WARN_GENERAL,
    361                 N_("stabs debugging overrides empty section .stabstr"));
    362             yasm_errwarn_propagate(errwarns, 0);
    363         }
    364     }
    365 
    366     /* initial pseudo-stab */
    367     stab = yasm_xmalloc(sizeof(stabs_stab));
    368     dbgbc = yasm_bc_create_common(&stabs_bc_stab_callback, stab, 0);
    369     dbgbc->len = info.stablen;
    370     dbgbc->offset = 0;
    371     yasm_section_bcs_append(info.stab, dbgbc);
    372 
    373     /* initial strtab bytecodes */
    374     nullbc = stabs_dbgfmt_append_bcstr(info.stabstr, "");
    375     filebc = stabs_dbgfmt_append_bcstr(info.stabstr, object->src_filename);
    376 
    377     stext = yasm_object_find_general(object, ".text");
    378     firstsym = yasm_symtab_use(object->symtab, ".text", 0);
    379     firstbc = yasm_section_bcs_first(stext);
    380     /* N_SO file stab */
    381     stabs_dbgfmt_append_stab(&info, info.stab, filebc, N_SO, 0,
    382                              firstsym, firstbc, 0);
    383 
    384     yasm_object_sections_traverse(object, (void *)&info,
    385                                   stabs_dbgfmt_generate_sections);
    386 
    387     /* fill initial pseudo-stab's fields */
    388     laststr = yasm_section_bcs_last(info.stabstr);
    389     if (laststr == NULL)
    390         yasm_internal_error(".stabstr has no entries");
    391 
    392     stab->bcvalue = NULL;
    393     stab->symvalue = NULL;
    394     stab->value = yasm_bc_next_offset(laststr);
    395     stab->bcstr = filebc;
    396     stab->type = N_UNDF;
    397     stab->other = 0;
    398     if (info.stabcount > 0xffff) {
    399         yasm_warn_set(YASM_WARN_GENERAL, N_("over 65535 stabs"));
    400         yasm_errwarn_propagate(errwarns, 0);
    401         stab->desc = 0xffff;
    402     } else
    403         stab->desc = (unsigned short)info.stabcount;
    404 }
    405 
    406 static int
    407 stabs_bc_stab_tobytes(yasm_bytecode *bc, unsigned char **bufp,
    408                       unsigned char *bufstart, void *d,
    409                       yasm_output_value_func output_value,
    410                       yasm_output_reloc_func output_reloc)
    411 {
    412     /* This entire function, essentially the core of rendering stabs to a file,
    413      * needs to become endian aware.  Size appears not to be an issue, as known
    414      * 64-bit systems use truncated values in 32-bit fields. */
    415 
    416     const stabs_stab *stab = (const stabs_stab *)bc->contents;
    417     unsigned char *buf = *bufp;
    418 
    419     YASM_WRITE_32_L(buf, stab->bcstr ? stab->bcstr->offset : 0);
    420     YASM_WRITE_8(buf, stab->type);
    421     YASM_WRITE_8(buf, stab->other);
    422     YASM_WRITE_16_L(buf, stab->desc);
    423 
    424     if (stab->symvalue != NULL) {
    425         bc->offset += 8;
    426         output_reloc(stab->symvalue, bc, buf, 4, 32, 0, d);
    427         bc->offset -= 8;
    428         buf += 4;
    429     }
    430     else if (stab->bcvalue != NULL) {
    431         YASM_WRITE_32_L(buf, stab->bcvalue->offset);
    432     }
    433     else {
    434         YASM_WRITE_32_L(buf, stab->value);
    435     }
    436 
    437     *bufp = buf;
    438     return 0;
    439 }
    440 
    441 static int
    442 stabs_bc_str_tobytes(yasm_bytecode *bc, unsigned char **bufp,
    443                      unsigned char *bufstart, void *d,
    444                      yasm_output_value_func output_value,
    445                      yasm_output_reloc_func output_reloc)
    446 {
    447     const char *str = (const char *)bc->contents;
    448     unsigned char *buf = *bufp;
    449 
    450     strcpy((char *)buf, str);
    451     buf += strlen(str)+1;
    452 
    453     *bufp = buf;
    454     return 0;
    455 }
    456 
    457 static void
    458 stabs_bc_stab_destroy(void *contents)
    459 {
    460     yasm_xfree(contents);
    461 }
    462 
    463 static void
    464 stabs_bc_str_destroy(void *contents)
    465 {
    466     yasm_xfree(contents);
    467 }
    468 
    469 static void
    470 stabs_bc_stab_print(const void *contents, FILE *f, int indent_level)
    471 {
    472     const stabs_stab *stab = (const stabs_stab *)contents;
    473     const char *str = "";
    474     fprintf(f, "%*s.stabs \"%s\", 0x%x, 0x%x, 0x%x, 0x%lx\n",
    475             indent_level, "", str, stab->type, stab->other, stab->desc,
    476             stab->bcvalue ? stab->bcvalue->offset : stab->value);
    477 }
    478 
    479 static void
    480 stabs_bc_str_print(const void *contents, FILE *f, int indent_level)
    481 {
    482     fprintf(f, "%*s\"%s\"\n", indent_level, "", (const char *)contents);
    483 }
    484 
    485 static int
    486 stabs_bc_stab_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
    487                        void *add_span_data)
    488 {
    489     yasm_internal_error(N_("tried to resolve a stabs stab bytecode"));
    490     /*@notreached@*/
    491     return 0;
    492 }
    493 
    494 static int
    495 stabs_bc_str_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
    496                       void *add_span_data)
    497 {
    498     yasm_internal_error(N_("tried to resolve a stabs str bytecode"));
    499     /*@notreached@*/
    500     return 0;
    501 }
    502 
    503 /* Define dbgfmt structure -- see dbgfmt.h for details */
    504 yasm_dbgfmt_module yasm_stabs_LTX_dbgfmt = {
    505     "Stabs debugging format",
    506     "stabs",
    507     NULL,       /* no directives */
    508     stabs_dbgfmt_create,
    509     stabs_dbgfmt_destroy,
    510     stabs_dbgfmt_generate
    511 };
    512