]> granicus.if.org Git - yasm/commitdiff
STABS debugging information. This includes, naturally, several draft
authorMichael Urman <mu@tortall.net>
Fri, 15 Aug 2003 03:43:55 +0000 (03:43 -0000)
committerMichael Urman <mu@tortall.net>
Fri, 15 Aug 2003 03:43:55 +0000 (03:43 -0000)
changes to the dbgfmt interface, and other assorted updates, including:
* yasm.c now calls df->initialize() and df->generate()
* a dbgfmt bytecode type with associated handling
* yasm_output_reloc_func type for use particularly by dbgfmts
* df: initialize updated; generate, bc_dbgfmt_data_{output|delete|print} added
* null-dbgfmt structure brought in line with these additions
* elf-objfmt made aware of stabs sections, and what to do with them

The bad news:
* just enough stabs output to support line number information in GDB
* GDB identifies function labels off by 3 bytes in my test, but line
  numbers remain correct, somehow.  Unknown whether stabs-dbgfmt or GDB
  at fault.

svn path=/trunk/yasm/; revision=1037

14 files changed:
frontends/yasm/yasm.c
libyasm/bytecode.c
libyasm/bytecode.h
libyasm/coretype.h
libyasm/dbgfmt.h
modules/dbgfmts/Makefile.inc
modules/dbgfmts/null/null-dbgfmt.c
modules/dbgfmts/stabs/Makefile.inc [new file with mode: 0644]
modules/dbgfmts/stabs/stabs-dbgfmt.c [new file with mode: 0644]
modules/objfmts/bin/bin-objfmt.c
modules/objfmts/coff/coff-objfmt.c
modules/objfmts/elf/elf-objfmt.c
modules/objfmts/elf/elf.c
modules/objfmts/elf/elf.h

index 0d6a2cc18cff26fcc0de4c780482bd567cd599f2..e162254a2ca7b4d6406d3db148fe4502cdd633f9 100644 (file)
@@ -456,6 +456,20 @@ main(int argc, char *argv[])
                                             "yasm.out");
     }
 
+    /* Initialize the debug format */
+    if (cur_dbgfmt->initialize) {
+       if (cur_dbgfmt->initialize(in_filename, obj_filename, &yasm_std_linemgr,
+                                  cur_objfmt, cur_arch, machine_name))
+       {
+           print_error(
+               _("%s: debug format `%s' does not work with object format `%s'"),
+               _("FATAL"), cur_dbgfmt->keyword, cur_objfmt->keyword);
+           if (in != stdin)
+               fclose(in);
+           return EXIT_FAILURE;
+       }
+    }
+
     /* Initialize the object format */
     if (cur_objfmt->initialize) {
        if (cur_objfmt->initialize(in_filename, obj_filename, cur_dbgfmt,
@@ -549,6 +563,11 @@ main(int argc, char *argv[])
        return EXIT_FAILURE;
     }
 
+    /* generate any debugging information */
+    if (cur_dbgfmt->generate) {
+       cur_dbgfmt->generate(sections);
+    }
+
     /* open the object file for output (if not already opened by dbg objfmt) */
     if (!obj && strcmp(cur_objfmt->keyword, "dbg") != 0) {
        obj = open_obj("wb");
index 179a06d7b3b67521bdb03a1faf054d6e69add115..b03f4dfc40b7524c2822f527b9cdb00d86fd17b4 100644 (file)
@@ -37,6 +37,7 @@
 
 #include "bytecode.h"
 #include "objfmt.h"
+#include "dbgfmt.h"
 
 #include "arch.h"
 
@@ -98,6 +99,14 @@ typedef struct bytecode_objfmt_data {
     /*@only@*/ void *data;             /* objfmt-specific data */
 } bytecode_objfmt_data;
 
+typedef struct bytecode_dbgfmt_data {
+    yasm_bytecode bc;   /* base structure */
+
+    unsigned int type;                 /* dbgfmt-specific type */
+    /*@dependent@*/ yasm_dbgfmt *df;   /* dbgfmt that created the data */
+    /*@only@*/ void *data;             /* dbgfmt-specific data */
+} bytecode_dbgfmt_data;
+
 /* Static structures for when NULL is passed to conversion functions. */
 /*  for Convert*ToBytes() */
 unsigned char bytes_static[16];
@@ -300,6 +309,31 @@ yasm_bc_new_objfmt_data(unsigned int type, unsigned long len, yasm_objfmt *of,
     return (yasm_bytecode *)objfmt_data;
 }
 
+yasm_bytecode *
+yasm_bc_new_dbgfmt_data(unsigned int type, unsigned long len, yasm_dbgfmt *df,
+                       void *data, unsigned long lindex)
+{
+    bytecode_dbgfmt_data *dbgfmt_data;
+
+    dbgfmt_data = (bytecode_dbgfmt_data *)
+       yasm_bc_new_common(YASM_BC__DBGFMT_DATA, sizeof(bytecode_dbgfmt_data),
+                          lindex);
+
+    dbgfmt_data->type = type;
+    dbgfmt_data->df = df;
+    /*@-mustfree@*/
+    dbgfmt_data->data = data;
+    /*@=mustfree@*/
+
+    /* Yes, this breaks the paradigm just a little.  But this data is very
+     * unlike other bytecode data--it's internally generated after the
+     * other bytecodes have been resolved, and the length is ALWAYS known.
+     */
+    dbgfmt_data->bc.len = len;
+
+    return (yasm_bytecode *)dbgfmt_data;
+}
+
 void
 yasm_bc_delete(yasm_bytecode *bc)
 {
@@ -307,6 +341,7 @@ yasm_bc_delete(yasm_bytecode *bc)
     bytecode_reserve *reserve;
     bytecode_incbin *incbin;
     bytecode_objfmt_data *objfmt_data;
+    bytecode_dbgfmt_data *dbgfmt_data;
 
     if (!bc)
        return;
@@ -340,6 +375,15 @@ yasm_bc_delete(yasm_bytecode *bc)
                yasm_internal_error(
                    N_("objfmt can't handle its own objfmt data bytecode"));
            break;
+       case YASM_BC__DBGFMT_DATA:
+           dbgfmt_data = (bytecode_dbgfmt_data *)bc;
+           if (dbgfmt_data->df->bc_dbgfmt_data_delete)
+               dbgfmt_data->df->bc_dbgfmt_data_delete(dbgfmt_data->type,
+                                                      dbgfmt_data->data);
+           else
+               yasm_internal_error(
+                   N_("dbgfmt can't handle its own dbgfmt data bytecode"));
+           break;
        default:
            if ((unsigned int)bc->type < (unsigned int)cur_arch->bc_type_max)
                cur_arch->bc_delete(bc);
@@ -361,6 +405,7 @@ yasm_bc_print(FILE *f, int indent_level, const yasm_bytecode *bc)
     const bytecode_incbin *incbin;
     const bytecode_align *align;
     const bytecode_objfmt_data *objfmt_data;
+    const bytecode_dbgfmt_data *dbgfmt_data;
 
     switch (bc->type) {
        case YASM_BC__EMPTY:
@@ -414,6 +459,16 @@ yasm_bc_print(FILE *f, int indent_level, const yasm_bytecode *bc)
            else
                fprintf(f, "%*sUNKNOWN\n", indent_level, "");
            break;
+       case YASM_BC__DBGFMT_DATA:
+           dbgfmt_data = (const bytecode_dbgfmt_data *)bc;
+           fprintf(f, "%*s_DbgFmt_Data_\n", indent_level, "");
+           if (dbgfmt_data->df->bc_dbgfmt_data_print)
+               dbgfmt_data->df->bc_dbgfmt_data_print(f, indent_level,
+                                                     dbgfmt_data->type,
+                                                     dbgfmt_data->data);
+           else
+               fprintf(f, "%*sUNKNOWN\n", indent_level, "");
+           break;
        default:
            if ((unsigned int)bc->type < (unsigned int)cur_arch->bc_type_max)
                cur_arch->bc_print(f, indent_level, bc);
@@ -768,6 +823,7 @@ yasm_bc_tobytes(yasm_bytecode *bc, unsigned char *buf, unsigned long *bufsize,
                /*@out@*/ unsigned long *multiple, /*@out@*/ int *gap,
                const yasm_section *sect, void *d,
                yasm_output_expr_func output_expr,
+               /*@null@*/ yasm_output_reloc_func output_reloc,
                /*@null@*/ yasm_output_bc_objfmt_data_func
                    output_bc_objfmt_data)
     /*@sets *buf@*/
@@ -776,6 +832,7 @@ yasm_bc_tobytes(yasm_bytecode *bc, unsigned char *buf, unsigned long *bufsize,
     unsigned char *origbuf, *destbuf;
     /*@dependent@*/ /*@null@*/ const yasm_intnum *num;
     bytecode_objfmt_data *objfmt_data;
+    bytecode_dbgfmt_data *dbgfmt_data;
     unsigned long datasize;
     int error = 0;
 
@@ -836,6 +893,16 @@ yasm_bc_tobytes(yasm_bytecode *bc, unsigned char *buf, unsigned long *bufsize,
                yasm_internal_error(
                    N_("Have objfmt data bytecode but no way to output it"));
            break;
+       case YASM_BC__DBGFMT_DATA:
+           dbgfmt_data = (bytecode_dbgfmt_data *)bc;
+           if (dbgfmt_data->df->bc_dbgfmt_data_output)
+               error = dbgfmt_data->df->bc_dbgfmt_data_output(bc,
+                           dbgfmt_data->type, dbgfmt_data->data, &destbuf,
+                           sect, output_reloc, d);
+           else
+               yasm_internal_error(
+                   N_("Have dbgfmt data bytecode but no way to output it"));
+           break;
        default:
            if ((unsigned int)bc->type < (unsigned int)cur_arch->bc_type_max)
                error = cur_arch->bc_tobytes(bc, &destbuf, sect, d,
index 276da4c7faf23fb2529d9833f05fba01e3ebeb3c..00989b4f819deb9332131ab9754fa6edb3fb2ed5 100644 (file)
@@ -57,6 +57,7 @@ typedef enum {
     YASM_BC__RESERVE,      /**< Reserved space. */
     YASM_BC__INCBIN,       /**< Included binary file. */
     YASM_BC__ALIGN,        /**< Alignment to a boundary. */
+    YASM_BC__DBGFMT_DATA,   /**< yasm_dbgfmt specific data. */
     YASM_BC__OBJFMT_DATA    /**< yasm_objfmt specific data. */
 } yasm_bytecode_type;
 
@@ -192,6 +193,18 @@ void yasm_bc_set_multiple(yasm_bytecode *bc, /*@keep@*/ yasm_expr *e);
     (unsigned int type, unsigned long len, yasm_objfmt *of,
      /*@only@*/ void *data, unsigned long lindex);
 
+/** Create a bytecode that includes yasm_dbgfmt-specific data.
+ * \param type         yasm_dbgfmt-specific type
+ * \param len          length (in bytes) of data
+ * \param df           yasm_dbgfmt storing the data
+ * \param data         data (kept, do not free)
+ * \param lindex       line index (as from yasm_linemgr) for the bytecode
+ * \return Newly allocated bytecode.
+ */
+/*@only@*/ yasm_bytecode *yasm_bc_new_dbgfmt_data
+    (unsigned int type, unsigned long len, yasm_dbgfmt *df,
+     /*@only@*/ void *data, unsigned long lindex);
+
 /** Delete (free allocated memory for) a bytecode.
  * \param bc   bytecode (only pointer to it); may be NULL
  */
@@ -258,6 +271,8 @@ yasm_bc_resolve_flags yasm_bc_resolve(yasm_bytecode *bc, int save,
  *                     representation
  * \param output_bc_objfmt_data        function to call to convert yasm_objfmt data
  *                             bytecodes into their byte representation
+ * \param objfmt_output_reloc   function to call to output relocation entries
+ *                             for a single sym
  * \return Newly allocated buffer that should be used instead of buf for
  *        reading the byte representation, or NULL if buf was big enough to
  *        hold the entire byte representation.
@@ -268,6 +283,7 @@ yasm_bc_resolve_flags yasm_bc_resolve(yasm_bytecode *bc, int save,
     (yasm_bytecode *bc, unsigned char *buf, unsigned long *bufsize,
      /*@out@*/ unsigned long *multiple, /*@out@*/ int *gap,
      const yasm_section *sect, void *d, yasm_output_expr_func output_expr,
+     /*@null@*/ yasm_output_reloc_func output_reloc,
      /*@null@*/ yasm_output_bc_objfmt_data_func output_bc_objfmt_data)
     /*@sets *buf@*/;
 
index 46d8762da48cb12f82b3dabe7f755b2ce125c13f..01bf6ec0d58996e95ad3c548200dbb3ca3262493 100644 (file)
@@ -177,6 +177,10 @@ typedef int (*yasm_output_expr_func)
      /*@observer@*/ const yasm_section *sect, yasm_bytecode *bc, int rel,
      int warn, /*@null@*/ void *d) /*@uses *ep@*/;
 
+typedef int (*yasm_output_reloc_func)
+    (yasm_symrec *sym, yasm_bytecode *bc, unsigned char *buf, size_t destsize,
+     size_t valsize, int rel, int warn, const yasm_section *sect, void *d);
+
 /** Convert a yasm_objfmt-specific data bytecode into its byte representation.
  * Usually implemented by object formats to output their own generated data.
  * \param type         yasm_objfmt-specific type
index 57ce67a1d574dafe661cf8c526d436c57866cd80..a6a8e077ab3a0908fe39da9b2e430dae47ffea15 100644 (file)
@@ -43,7 +43,7 @@
  * definitions match the module loader's function definitions.  The version
  * number must never be decreased.
  */
-#define YASM_DBGFMT_VERSION    0
+#define YASM_DBGFMT_VERSION    1
 
 /** YASM debug format interface. */
 struct yasm_dbgfmt {
@@ -66,9 +66,11 @@ struct yasm_dbgfmt {
      * \param in_filename   primary input filename
      * \param obj_filename  object filename
      * \param of           object format in use
+     * \return Nonzero if object format does not provide needed support.
      */
-    void (*initialize) (const char *in_filename, const char *obj_filename,
-                       yasm_objfmt *of);
+    int (*initialize) (const char *in_filename, const char *obj_filename,
+                      yasm_linemgr *lm, yasm_objfmt *of, yasm_arch *a,
+                      const char *machine);
 
     /** Clean up anything allocated by initialize().  Function may be
      * unimplemented (NULL) if not needed by the debug format.
@@ -76,10 +78,51 @@ struct yasm_dbgfmt {
     void (*cleanup) (void);
 
     /** DEBUG directive support.
+     * \param name         directive name
      * \param valparams            value/parameters
      * \param lindex       line index (as from yasm_linemgr)
+     * \return Nonzero if directive was not recognized; 0 if directive was
+     *        recognized even if it wasn't valid.
      */
-    void (*directive) (yasm_valparamhead *valparams, unsigned long lindex);
+    int (*directive) (const char *name, yasm_valparamhead *valparams,
+                     unsigned long lindex);
+
+    /** Generate debugging information bytecodes
+     * \param sections     list of sections
+     */
+    void (*generate) (yasm_sectionhead *sections);
+
+    /** Output debug format-specific bytecode data (YASM_BC_DBGFMT_DATA).
+     * Function may be unimplemented (NULL) if no YASM_BC_DBGFMT_DATA is ever
+     * allocated by the debug format.
+     * \param type             debug format-specific bytecode type
+     * \param data             debug format-specific data
+     * \param buf              provided buffer, as long as registered length
+     */
+    int (*bc_dbgfmt_data_output)(yasm_bytecode *bc, unsigned int type,
+                                const void *data, unsigned char **buf,
+                                const yasm_section *sect,
+                                yasm_output_reloc_func output_reloc,
+                                void *objfmt_d);
+
+    /** Delete debug format-specific bytecode data (YASM_BC_DBGFMT_DATA).
+     * Funtion may be unimplemented (NULL) if no YASM_BC_DBGFMT_DATA is ever
+     * allocated by the debug format.
+     * \param type     debug format-specific bytecode type
+     * \param data     debug-format specific data
+     */
+    void (*bc_dbgfmt_data_delete)(unsigned int type, /*@only@*/ void *data);
+
+    /** Print debug format-specific bytecode data (YASM_BC_DBGFMT_DATA).  For
+     * debugging purposes.  Function may be unimplemented (NULL) if no
+     * YASM_BC_DBGFMT_DATA is ever allocated by the debug format.
+     * \param f                        file
+     * \param indent_level     indentation level
+     * \param type             debug format-specific bytecode type
+     * \param data             debug format-specific data
+     */
+    void (*bc_dbgfmt_data_print)(FILE *f, int indent_level, unsigned int type,
+                                const void *data);
 };
 
 #endif
index 70e93732ef862aa80d1638485c1ad90693f1e2df..e61366de0ecf9f550133efc098addaf74ac29c84 100644 (file)
@@ -1,5 +1,7 @@
 # $IdPath$
 
 EXTRA_DIST += modules/dbgfmts/null/Makefile.inc
+EXTRA_DIST += modules/dbgfmts/stabs/Makefile.inc
 
 include modules/dbgfmts/null/Makefile.inc
+include modules/dbgfmts/stabs/Makefile.inc
index 7bc698dedc3d7c33643128fe82256fc2246f13cf..55d71c9f61379c152affed308f39ad7bcd5c7c2f 100644 (file)
@@ -38,5 +38,9 @@ yasm_dbgfmt yasm_null_LTX_dbgfmt = {
     "null",
     NULL,   /*null_dbgfmt_initialize*/
     NULL,   /*null_dbgfmt_cleanup*/
-    NULL    /*null_dbgfmt_directive*/
+    NULL,   /*null_dbgfmt_directive*/
+    NULL,   /*null_dbgfmt_generate*/
+    NULL,   /*null_dbgfmt_bc_data_output*/
+    NULL,   /*null_dbgfmt_bc_data_delete*/
+    NULL    /*null_dbgfmt_bc_data_print*/
 };
diff --git a/modules/dbgfmts/stabs/Makefile.inc b/modules/dbgfmts/stabs/Makefile.inc
new file mode 100644 (file)
index 0000000..8954772
--- /dev/null
@@ -0,0 +1,8 @@
+# $IdPath$
+
+pkglib_LTLIBRARIES += dbgfmt_stabs.la
+
+dbgfmt_stabs_la_SOURCES = modules/dbgfmts/stabs/stabs-dbgfmt.c
+dbgfmt_stabs_la_LDFLAGS = -module -avoid-version -no-undefined
+dbgfmt_stabs_la_LIBADD = libyasm.la
+YASM_MODULES += -dlopen dbgfmt_stabs.la
diff --git a/modules/dbgfmts/stabs/stabs-dbgfmt.c b/modules/dbgfmts/stabs/stabs-dbgfmt.c
new file mode 100644 (file)
index 0000000..efb56db
--- /dev/null
@@ -0,0 +1,450 @@
+/*
+ * Stabs debugging format
+ *
+ *  Copyright (C) 2003  Michael Urman
+ *
+ * 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 <util.h>
+/*@unused@*/ RCSID("$IdPath$");
+
+#define YASM_LIB_INTERNAL
+#define YASM_BC_INTERNAL
+#include <libyasm.h>
+
+typedef enum {
+    N_UNDF = 0x00,     /* Undefined */
+    N_GSYM = 0x20,     /* Global symbol */
+    N_FNAME = 0x22,    /* Function name (BSD Fortran) */
+    N_FUN = 0x24,      /* Function name or Text segment variable */
+    N_STSYM = 0x26,    /* Data segment file-scope variable */
+    N_LCSYM = 0x28,    /* BSS segment file-scope variable */
+    N_MAIN = 0x2a,     /* Name of main routine */
+    N_ROSYM = 0x2c,    /* Variable in .rodata section */
+    N_PC = 0x30,       /* Global symbol (Pascal) */
+    N_SYMS = 0x32,     /* Number of symbols (Ultrix V4.0) */
+    N_NOMAP = 0x34,    /* No DST map */
+    N_OBJ = 0x38,      /* Object file (Solaris2) */
+    N_OPT = 0x3c,      /* Debugger options (Solaris2) */
+    N_RSYM = 0x40,     /* Register variable */
+    N_M2C = 0x42,      /* Modula-2 compilation unit */
+    N_SLINE = 0x44,    /* Line numbers in .text segment */
+    N_DSLINE = 0x46,   /* Line numbers in .data segment */
+    N_BSLINE = 0x48,   /* Line numbers in .bss segment */
+    N_BROWS = 0x48,    /* Source code .cb file's path */
+    N_DEFD = 0x4a,     /* GNU Modula-2 definition module dependency */
+    N_FLINE = 0x4c,    /* Function start/body/end line numbers (Solaris2) */
+    N_EHDECL = 0x50,   /* GNU C++ exception variable */
+    N_MOD2 = 0x50,     /* Modula2 info for imc (Ultrix V4.0) */
+    N_CATCH = 0x54,    /* GNU C++ catch clause */
+    N_SSYM = 0x60,     /* Structure or union element */
+    N_ENDM = 0x62,     /* Last stab for module (Solaris2) */
+    N_SO = 0x64,       /* Path and name of source files */
+    N_LSYM = 0x80,     /* Stack variable */
+    N_BINCL = 0x84,    /* Beginning of include file */
+    N_SOL = 0x84,      /* Name of include file */
+    N_PSYM = 0xa0,     /* Parameter variable */
+    N_EINCL = 0xa2,    /* End of include file */
+    N_ENTRY = 0xa4,    /* Alternate entry point */
+    N_LBRAC = 0xc0,    /* Beginning of lexical block */
+    N_EXCL = 0xc2,     /* Placeholder for a deleted include file */
+    N_SCOPE = 0xc4,    /* Modula 2 scope info (Sun) */
+    N_RBRAC = 0xe0,    /* End of lexical block */
+    N_BCOMM = 0xe2,    /* Begin named common block */
+    N_ECOMM = 0xe4,    /* End named common block */
+    N_ECOML = 0xe8,    /* Member of common block */
+    N_WITH = 0xea,     /* Pascal with statement: type,,0,0,offset (Solaris2) */
+    N_NBTEXT = 0xf0,   /* Gould non-base registers */
+    N_NBDATA = 0xf2,   /* Gould non-base registers */
+    N_NBBSS = 0xf4,    /* Gould non-base registers */
+    N_NBSTS = 0xf6,    /* Gould non-base registers */
+    N_NBLCS = 0xf8     /* Gould non-base registers */
+} stabs_stab_type;
+
+#define STABS_DEBUG_DATA 1
+#define STABS_DEBUG_STR 2
+
+typedef struct {
+    unsigned long lastline;    /* track line and file of bytecodes */
+    unsigned long curline;
+    const char *lastfile;
+    const char *curfile;
+
+    unsigned int stablen;      /* size of a stab for current machine */
+    unsigned long stabcount;   /* count stored stabs; doesn't include first */
+
+    yasm_section *stab;                /* sections to which stabs, stabstrs appended */
+    yasm_section *stabstr;
+    yasm_symrec *firstsym;     /* track leading sym of section/function */
+    yasm_bytecode *firstbc;    /* and its bytecode */
+} stabs_info;
+
+typedef struct {
+    /*@null@*/ yasm_bytecode *bcstr;   /* bytecode in stabstr for string */
+    stabs_stab_type type;              /* stab type: N_* */
+    unsigned char other;               /* unused, but stored here anyway */
+    unsigned short desc;               /* description element of a stab */
+    /*@null@*/ yasm_symrec *symvalue;  /* value element needing relocation */
+    /*@null@*/yasm_bytecode *bcvalue;  /* relocated stab's bytecode */
+    unsigned long value;               /* fallthrough value if above NULL */
+} stabs_stab;
+
+/* helper struct for finding first sym (and bytecode) of a section */
+typedef struct {
+    yasm_symrec *sym;
+    yasm_bytecode *precbc;
+    yasm_section *sect;
+} stabs_symsect;
+
+yasm_dbgfmt yasm_stabs_LTX_dbgfmt;
+
+static yasm_objfmt *cur_objfmt = NULL;
+static const char *filename = NULL;
+static yasm_linemgr *linemgr = NULL;
+static yasm_arch *cur_arch = NULL;
+static const char *cur_machine = NULL;
+static size_t stabs_relocsize_bits = 0;
+static size_t stabs_relocsize_bytes = 0;
+
+static int
+stabs_dbgfmt_initialize(const char *in_filename, const char *obj_filename,
+                       yasm_linemgr *lm, yasm_objfmt *of, yasm_arch *a,
+                       const char *machine)
+{
+    cur_objfmt = of;
+    filename = in_filename;
+    linemgr = lm;
+    cur_arch = a;
+    cur_machine = machine;
+    return 0;
+}
+
+static void
+stabs_dbgfmt_cleanup(void)
+{
+}
+
+/* Create and add a new strtab-style string bytecode to a section, updating
+ * offset on insertion; no optimization necessary */
+/* Copies the string, so you must still free yours as normal */
+static yasm_bytecode *
+stabs_dbgfmt_append_bcstr(yasm_section *sect, const char *str)
+{
+    yasm_bytecode *bc = yasm_bc_new_dbgfmt_data(
+                           STABS_DEBUG_STR, strlen(str)+1,
+                           &yasm_stabs_LTX_dbgfmt,
+                           (void *)yasm__xstrdup(str), 0);
+    yasm_bytecodehead *bcs = yasm_section_get_bytecodes(sect);
+    yasm_bytecode *precbc = yasm_bcs_last(bcs);
+    bc->offset = precbc ? precbc->offset + precbc->len : 0;
+    yasm_bcs_append(bcs, bc);
+
+    return bc;
+}
+
+/* Create and add a new stab bytecode to a section, updating offset on
+ * insertion; no optimization necessary. */
+/* Requires a string bytecode, or NULL, for its string entry */
+static stabs_stab *
+stabs_dbgfmt_append_stab(stabs_info *info, yasm_section *sect,
+                        /*@null@*/ yasm_bytecode *bcstr, stabs_stab_type type,
+                        unsigned long desc, /*@null@*/ yasm_symrec *symvalue,
+                        /*@null@*/ yasm_bytecode *bcvalue, unsigned long value)
+{
+    yasm_bytecode *bc, *precbc;
+    yasm_bytecodehead *bcs;
+    stabs_stab *stab = yasm_xmalloc(sizeof(stabs_stab));
+    stab->other = 0;
+    stab->bcstr = bcstr;
+    stab->type = type;
+    stab->desc = (unsigned short)desc;
+    stab->symvalue = symvalue;
+    stab->bcvalue = bcvalue;
+    stab->value = value;
+
+    bc = yasm_bc_new_dbgfmt_data(STABS_DEBUG_DATA, info->stablen,
+                                &yasm_stabs_LTX_dbgfmt, (void *)stab,
+                                bcvalue ? bcvalue->line : 0);
+    bcs = yasm_section_get_bytecodes(sect);
+    precbc = yasm_bcs_last(bcs);
+    bc->offset = precbc ? precbc->offset + precbc->len : 0;
+    yasm_bcs_append(bcs, bc);
+    info->stabcount++;
+    return stab;
+}
+
+/* Update current first sym and bytecode if it's in the right section */
+static int
+stabs_dbgfmt_first_sym_traversal(yasm_symrec *sym, void *d)
+{
+    stabs_symsect *symsect = (stabs_symsect *)d;
+    yasm_section *sect;
+    yasm_bytecode *precbc;
+
+    if (!yasm_symrec_get_label(sym, &sect, &precbc))
+       return 1;
+    if (precbc == NULL)
+       precbc = yasm_bcs_first(yasm_section_get_bytecodes(sect));
+    if ((sect == symsect->sect)
+       && ((symsect->sym == NULL)
+           || precbc->offset < symsect->precbc->offset))
+    {
+       symsect->sym = sym;
+       symsect->precbc = precbc;
+    }
+    return 1;
+}
+
+/* Find the first sym and its preceding bytecode in a given section */
+static void
+stabs_dbgfmt_first_sym_by_sect(stabs_info *info, yasm_section *sect)
+{
+    stabs_symsect symsect = { NULL, NULL, NULL };
+    if (sect == NULL) {
+       info->firstsym = NULL;
+       info->firstbc = NULL;
+    }
+
+    symsect.sect = sect;
+    yasm_symrec_traverse((void *)&symsect, stabs_dbgfmt_first_sym_traversal);
+    info->firstsym = symsect.sym;
+    info->firstbc = symsect.precbc;
+}
+
+static int
+stabs_dbgfmt_generate_bcs(yasm_bytecode *bc, void *d)
+{
+    stabs_info *info = (stabs_info *)d;
+    linemgr->lookup(bc->line, &info->curfile, &info->curline);
+
+    if (info->lastfile != info->curfile) {
+       info->lastline = 0; /* new file, so line changes */
+       /*stabs_dbgfmt_append_stab(info, info->stab,
+           stabs_dbgfmt_append_bcstr(info->stabstr, info->curfile),
+           N_SOL, 0, NULL, bc, 0);*/
+    }
+    if (info->curline != info->lastline) {
+       info->lastline = bc->line;
+       stabs_dbgfmt_append_stab(info, info->stab, NULL, N_SLINE,
+                                info->curline, NULL, NULL,
+                                bc->offset - info->firstbc->offset);
+    }
+
+    info->lastline = info->curline;
+    info->lastfile = info->curfile;
+
+    return 0;
+}
+
+static int
+stabs_dbgfmt_generate_sections(yasm_section *sect, /*@null@*/ void *d)
+{
+    stabs_info *info = (stabs_info *)d;
+    const char *sectname=yasm_section_get_name(sect);
+
+    stabs_dbgfmt_first_sym_by_sect(info, sect);
+    if (yasm__strcasecmp(sectname, ".text")==0) {
+       char *str;
+       const char *symname=yasm_symrec_get_name(info->firstsym);
+       size_t len = strlen(symname)+4;
+       str = yasm_xmalloc(len);
+       snprintf(str, len, "%s:F1", symname);
+       stabs_dbgfmt_append_stab(info, info->stab,
+                                stabs_dbgfmt_append_bcstr(info->stabstr, str),
+                                N_FUN, 0, info->firstsym, info->firstbc, 0);
+       yasm_xfree(str);
+    }
+    yasm_bcs_traverse(yasm_section_get_bytecodes(sect), d,
+                     stabs_dbgfmt_generate_bcs);
+
+    return 1;
+}
+
+static void
+stabs_dbgfmt_generate(yasm_sectionhead *sections)
+{
+    stabs_info info;
+    int new;
+    yasm_bytecode *dbgbc;
+    yasm_bytecodehead *bcs;
+    stabs_stab *stab;
+    yasm_bytecode *filebc, *nullbc, *laststr;
+    yasm_section *stext;
+
+    /* Stablen is determined by arch/machine */
+    if (yasm__strcasecmp(cur_arch->keyword, "x86") == 0) {
+       if (yasm__strcasecmp(cur_machine, "x86") == 0) {
+           info.stablen = 12;
+       }
+       else if (yasm__strcasecmp(cur_machine, "amd64") == 0) {
+           info.stablen = 16;
+       }
+       else
+           return;
+    }
+    else /* unknown machine; generate nothing */
+       return;
+
+    stabs_relocsize_bytes = info.stablen - 8;
+    stabs_relocsize_bits = stabs_relocsize_bytes * 8;
+
+    info.lastline = 0;
+    info.stabcount = 0;
+    info.stab = yasm_sections_switch_general(sections, ".stab", 0, 0, &new, 0);
+    if (!new) {
+       yasm_bytecode *last = yasm_bcs_last(
+           yasm_section_get_bytecodes(info.stab));
+       if (last == NULL)
+           yasm__error(
+               yasm_bcs_first(yasm_section_get_bytecodes(info.stab))->line,
+               N_("stabs debugging conflicts with user-defined section .stab"));
+       else
+           yasm__warning(YASM_WARN_GENERAL, 0,
+               N_("stabs debugging overrides empty section .stab"));
+    }
+
+    info.stabstr = yasm_sections_switch_general(sections, ".stabstr", 0, 0,
+                                               &new, 0);
+    if (!new) {
+       yasm_bytecode *last = yasm_bcs_last(
+           yasm_section_get_bytecodes(info.stabstr));
+       if (last == NULL)
+           yasm__error(
+               yasm_bcs_first(yasm_section_get_bytecodes(info.stabstr))->line,
+               N_("stabs debugging conflicts with user-defined section .stabstr"));
+       else
+           yasm__warning(YASM_WARN_GENERAL, 0,
+               N_("stabs debugging overrides empty section .stabstr"));
+    }
+
+
+
+    /* initial pseudo-stab */
+    stab = yasm_xmalloc(sizeof(stabs_stab));
+    dbgbc = yasm_bc_new_dbgfmt_data(STABS_DEBUG_DATA, info.stablen,
+                                   &yasm_stabs_LTX_dbgfmt, (void *)stab, 0);
+    bcs = yasm_section_get_bytecodes(info.stab);
+    yasm_bcs_append(bcs, dbgbc);
+
+    /* initial strtab bytecodes */
+    nullbc = stabs_dbgfmt_append_bcstr(info.stabstr, "");
+    filebc = stabs_dbgfmt_append_bcstr(info.stabstr, filename);
+
+    stext = yasm_sections_find_general(sections, ".text");
+    info.firstsym = yasm_symrec_use(".text", 0);
+    info.firstbc = yasm_bcs_first(yasm_section_get_bytecodes(stext));
+    /* N_SO file stab */
+    stabs_dbgfmt_append_stab(&info, info.stab, filebc, N_SO, 0,
+                            info.firstsym, info.firstbc, 0);
+
+    yasm_sections_traverse(sections, (void *)&info,
+                          stabs_dbgfmt_generate_sections);
+
+    /* fill initial pseudo-stab's fields */
+    laststr = yasm_bcs_last(yasm_section_get_bytecodes(info.stabstr));
+    if (laststr == NULL)
+       yasm_internal_error(".stabstr has no entries");
+
+    stab->bcvalue = NULL;
+    stab->symvalue = NULL;
+    stab->value = laststr->offset + laststr->len;
+    stab->bcstr = filebc;
+    stab->type = N_UNDF;
+    stab->other = 0;
+    stab->desc = info.stabcount;
+}
+
+static int
+stabs_dbgfmt_bc_data_output(yasm_bytecode *bc, unsigned int type,
+                           const void *data, unsigned char **buf,
+                           const yasm_section *sect,
+                           yasm_output_reloc_func output_reloc, void *objfmt_d)
+{
+    unsigned char *bufp = *buf;
+    if (type == STABS_DEBUG_DATA) {
+       const stabs_stab *stab = data;
+
+       YASM_WRITE_32_L(bufp, stab->bcstr ? stab->bcstr->offset : 0);
+       YASM_WRITE_8(bufp, stab->type);
+       YASM_WRITE_8(bufp, stab->other);
+       YASM_WRITE_16_L(bufp, stab->desc);
+
+       if (stab->symvalue != NULL) {
+           printf("DBG: ");
+           bc->offset += 8;
+           output_reloc(stab->symvalue, bc, bufp, stabs_relocsize_bytes,
+                        stabs_relocsize_bits, 0, 0, sect, objfmt_d);
+           bc->offset -= 8;
+           bufp += stabs_relocsize_bytes;
+       }
+       else if (stab->bcvalue != NULL) {
+           YASM_WRITE_32_L(bufp, stab->bcvalue->offset);
+       }
+       else {
+           YASM_WRITE_32_L(bufp, stab->value);
+       }
+    }
+    else if (type == STABS_DEBUG_STR) {
+       const char *str = data;
+       strcpy((char *)bufp, str);
+       bufp += strlen(str)+1;
+    }
+
+    *buf = bufp;
+    return 0;
+}
+
+static void
+stabs_dbgfmt_bc_data_delete(unsigned int type, void *data)
+{
+    /* both stabs and strs are allocated at the top level pointer */
+    yasm_xfree(data);
+}
+
+static void
+stabs_dbgfmt_bc_data_print(FILE *f, int indent_level, unsigned int type,
+                   const void *data)
+{
+    if (type == STABS_DEBUG_DATA) {
+       const stabs_stab *stab = data;
+       const char *str = "";
+       fprintf(f, "%*s.stabs \"%s\", 0x%x, 0x%x, 0x%x, 0x%lx\n",
+               indent_level, "", str, stab->type, stab->other, stab->desc,
+               stab->bcvalue ? stab->bcvalue->offset : stab->value);
+    }
+    else if (type == STABS_DEBUG_STR)
+       fprintf(f, "%*s\"%s\"\n", indent_level, "", (const char *)data);
+}
+
+/* Define dbgfmt structure -- see dbgfmt.h for details */
+yasm_dbgfmt yasm_stabs_LTX_dbgfmt = {
+    YASM_DBGFMT_VERSION,
+    "Stabs debugging format",
+    "stabs",
+    stabs_dbgfmt_initialize,
+    stabs_dbgfmt_cleanup,
+    NULL /*stabs_dbgfmt_directive*/,
+    stabs_dbgfmt_generate,
+    stabs_dbgfmt_bc_data_output,
+    stabs_dbgfmt_bc_data_delete,
+    stabs_dbgfmt_bc_data_print
+};
index 2026a18833bebbc021cb52642c0223630cd953f4..6cbcdf4c4c8f3d3aedea970d4e709f034553b411 100644 (file)
@@ -189,7 +189,7 @@ bin_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d)
     assert(info != NULL);
 
     bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &multiple, &gap, info->sect,
-                            info, bin_objfmt_output_expr, NULL);
+                            info, bin_objfmt_output_expr, NULL, NULL);
 
     /* Don't bother doing anything else if size ended up being 0. */
     if (size == 0) {
index 05d35884fd58f3e25a39ba111af38e48a0c6dac3..73dd43baf4fb0d0a9ad02396b4b0a8efc2c2567e 100644 (file)
@@ -404,7 +404,7 @@ coff_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d)
     assert(info != NULL);
 
     bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &multiple, &gap, info->sect,
-                            info, coff_objfmt_output_expr, NULL);
+                            info, coff_objfmt_output_expr, NULL, NULL);
 
     /* Don't bother doing anything else if size ended up being 0. */
     if (size == 0) {
index 605f8842240f2865868e1977421b1d7f0c5b9f92..113d61ba1670f6f7fe9848e1cdc35ddae69bc852 100644 (file)
@@ -55,6 +55,7 @@ typedef struct {
     FILE *f;
     elf_secthead *shead;
     yasm_section *sect;
+    yasm_sectionhead *sections;
     unsigned long sindex;
 } elf_objfmt_output_info;
 
@@ -65,6 +66,7 @@ static elf_strtab_head* elf_strtab;           /* strtab entries */
 
 yasm_objfmt yasm_elf_LTX_objfmt;
 static /*@dependent@*/ yasm_arch *cur_arch;
+static /*@dependent@*/ yasm_dbgfmt *cur_dbgfmt;
 
 
 static elf_symtab_entry *
@@ -130,6 +132,7 @@ elf_objfmt_initialize(const char *in_filename,
     elf_symtab_entry *entry;
 
     cur_arch = a;
+    cur_dbgfmt = df;
     if (!elf_set_arch(a, machine))
        return 1;
 
@@ -173,6 +176,32 @@ elf_objfmt_output_align(FILE *f, unsigned int align)
     return pos;
 }
 
+static int
+elf_objfmt_output_reloc(yasm_symrec *sym, yasm_bytecode *bc,
+                       unsigned char *buf, size_t destsize, size_t valsize,
+                       int rel, int warn, const yasm_section *sect, void *d)
+{
+    elf_reloc_entry *reloc;
+    elf_objfmt_output_info *info = d;
+    yasm_intnum *zero = yasm_intnum_new_uint(0);
+    int retval;
+
+    reloc = elf_reloc_entry_new(sym,
+       yasm_intnum_new_uint(bc->offset), rel, valsize);
+    if (reloc == NULL) {
+       yasm__error(bc->line, N_("elf: invalid relocation size"));
+       return 1;
+    }
+    /* allocate .rel sections on a need-basis */
+    if (elf_secthead_append_reloc(info->shead, reloc))
+       elf_objfmt_parse_scnum++;
+
+    retval = cur_arch->intnum_tobytes(zero, buf, destsize, valsize, 0,
+                                     bc, rel, warn, bc->line);
+    yasm_intnum_delete(zero);
+    return retval;
+}
+
 /* PASS1 */
 static int
 elf_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize,
@@ -275,7 +304,8 @@ elf_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d)
        yasm_internal_error("null info struct");
 
     bigbuf = yasm_bc_tobytes(bc, buf, &size, &multiple, &gap, info->sect,
-                            info, elf_objfmt_output_expr, NULL);
+                            info, elf_objfmt_output_expr, 
+                            elf_objfmt_output_reloc, NULL);
 
     /* Don't bother doing anything else if size ended up being 0. */
     if (size == 0) {
@@ -320,6 +350,35 @@ elf_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d)
     return 0;
 }
 
+static elf_secthead *
+elf_objfmt_new_dbg_secthead(yasm_section *sect, elf_objfmt_output_info *info)
+{
+    elf_secthead *shead;
+    elf_section_type type=SHT_PROGBITS;
+    yasm_intnum *align=NULL;
+    elf_size entsize=0;
+    const char *sectname = yasm_section_get_name(sect);
+    elf_strtab_entry *name = elf_strtab_append_str(elf_shstrtab, sectname);
+
+    if (yasm__strcasecmp(sectname, ".stab")==0) {
+       align = yasm_intnum_new_uint(4);
+       entsize = 12;
+    } else if (yasm__strcasecmp(sectname, ".stabstr")==0) {
+       type = SHT_STRTAB;
+       align = yasm_intnum_new_uint(1);
+    }
+    else
+       yasm_internal_error(N_("Unrecognized section without data"));
+
+    shead = elf_secthead_new(name, type, 0, elf_objfmt_parse_scnum++, 0, 0);
+    elf_secthead_set_align(shead, align);
+    elf_secthead_set_entsize(shead, entsize);
+
+    yasm_section_set_of_data(sect, &yasm_elf_LTX_objfmt, shead);
+
+    return shead;
+}
+
 /* PASS1 */
 static int
 elf_objfmt_output_section(yasm_section *sect, /*@null@*/ void *d)
@@ -339,7 +398,7 @@ elf_objfmt_output_section(yasm_section *sect, /*@null@*/ void *d)
        yasm_internal_error("null info struct");
     shead = yasm_section_get_of_data(sect);
     if (shead == NULL)
-       yasm_internal_error("no section header attached to section");
+       shead = elf_objfmt_new_dbg_secthead(sect, info);
 
     /* don't output header-only sections */
     if ((elf_secthead_get_type(shead) & SHT_NOBITS) == SHT_NOBITS)
@@ -448,7 +507,7 @@ elf_objfmt_output(FILE *f, yasm_sectionhead *sections, int all_syms)
      * if all_syms, register them by name.  if not, use strtab entry 0 */
     yasm_symrec_traverse((void *)&all_syms, elf_objfmt_append_local_sym);
     elf_symtab_nlocal = elf_symtab_assign_indices(elf_symtab);
-    
+
     /* output known sections - includes reloc sections which aren't in yasm's
      * list.  Assign indices as we go. */
     info.sindex = 3;
@@ -483,6 +542,21 @@ elf_objfmt_output(FILE *f, yasm_sectionhead *sections, int all_syms)
        return;
     elf_shead_addr = (unsigned long) pos;
 
+    /* stabs debugging support */
+    if (strcmp(cur_dbgfmt->keyword, "stabs")==0) {
+       yasm_section *stabsect = yasm_sections_find_general(sections, ".stab");
+       yasm_section *stabstrsect = yasm_sections_find_general(sections, ".stabstr");
+       if (stabsect && stabstrsect) {
+           elf_secthead *stab = yasm_section_get_of_data(stabsect);
+           elf_secthead *stabstr = yasm_section_get_of_data(stabstrsect);
+           if (stab && stabstr) {
+               elf_secthead_set_link(stab, elf_secthead_get_index(stabstr));
+           }
+           else
+               yasm_internal_error(N_("missing .stab or .stabstr section/data"));
+       }
+    }
+    
     /* output dummy section header - 0 */
     info.sindex = 0;
 
@@ -722,6 +796,7 @@ elf_objfmt_directive(/*@unused@*/ const char *name,
 /* Define valid debug formats to use with this object format */
 static const char *elf_objfmt_dbgfmt_keywords[] = {
     "null",
+    "stabs",
     NULL
 };
 
index d4b06d2f7a3f3e897cd056b70657384647095a79..d18fcfe4d1b77de8a5c843a6bf9a7c3708116873 100644 (file)
@@ -891,6 +891,12 @@ elf_secthead_get_sym(elf_secthead *shead)
     return shead->sym;
 }
 
+elf_section_index
+elf_secthead_get_index(elf_secthead *shead)
+{
+    return shead->index;
+}
+
 const yasm_intnum *
 elf_secthead_set_align(elf_secthead *shead, yasm_intnum *align)
 {
@@ -930,6 +936,12 @@ elf_secthead_set_rel_name(elf_secthead *shead, elf_strtab_entry *entry)
     return shead->rel_name = entry;
 }
 
+elf_size
+elf_secthead_set_entsize(elf_secthead *shead, elf_size size)
+{
+    return shead->entsize = size;
+}
+
 yasm_symrec *
 elf_secthead_set_sym(elf_secthead *shead, yasm_symrec *sym)
 {
index 9a8259733e47101a4d0f6429bd576f873e76f42c..c06fa7ea5568e797d433bd63b951d6c21cf61a19 100644 (file)
@@ -395,6 +395,7 @@ int elf_secthead_is_empty(elf_secthead *shead);
 struct yasm_symrec *elf_secthead_get_sym(elf_secthead *shead);
 const struct yasm_intnum *elf_secthead_set_align(elf_secthead *shead,
                                                 struct yasm_intnum *align);
+elf_section_index elf_secthead_get_index(elf_secthead *shead);
 elf_section_info elf_secthead_set_info(elf_secthead *shead,
                                       elf_section_info info);
 elf_section_index elf_secthead_set_index(elf_secthead *shead,
@@ -405,6 +406,7 @@ elf_section_index elf_secthead_set_rel_index(elf_secthead *shead,
                                             elf_section_index sectidx);
 elf_strtab_entry *elf_secthead_set_rel_name(elf_secthead *shead,
                                            elf_strtab_entry *entry);
+elf_size elf_secthead_set_entsize(elf_secthead *shead, elf_size size);
 struct yasm_symrec *elf_secthead_set_sym(elf_secthead *shead,
                                         struct yasm_symrec *sym);
 void elf_secthead_add_size(elf_secthead *shead, yasm_intnum *size);