STABS debugging information. This includes, naturally, several draft

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
0.3
Michael Urman 22 years ago
parent 4a4aa52a85
commit 47576797ad
  1. 19
      frontends/yasm/yasm.c
  2. 67
      libyasm/bytecode.c
  3. 16
      libyasm/bytecode.h
  4. 4
      libyasm/coretype.h
  5. 51
      libyasm/dbgfmt.h
  6. 2
      modules/dbgfmts/Makefile.inc
  7. 6
      modules/dbgfmts/null/null-dbgfmt.c
  8. 8
      modules/dbgfmts/stabs/Makefile.inc
  9. 450
      modules/dbgfmts/stabs/stabs-dbgfmt.c
  10. 2
      modules/objfmts/bin/bin-objfmt.c
  11. 2
      modules/objfmts/coff/coff-objfmt.c
  12. 81
      modules/objfmts/elf/elf-objfmt.c
  13. 12
      modules/objfmts/elf/elf.c
  14. 2
      modules/objfmts/elf/elf.h

@ -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");

@ -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,

@ -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@*/;

@ -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

@ -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

@ -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

@ -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*/
};

@ -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

@ -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
};

@ -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) {

@ -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) {

@ -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
};

@ -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)
{

@ -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);

Loading…
Cancel
Save