summaryrefslogtreecommitdiff
path: root/output
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2003-07-09 19:11:10 +0000
committerH. Peter Anvin <hpa@zytor.com>2003-07-09 19:11:10 +0000
commit73320328c1232260bd569a8fb045124ad55f342d (patch)
treeb4f6d74703a9b21078ddeb6225809d2fd8be65cd /output
parentda4c3983b21ab483c8b5899259462b90da4a3c1d (diff)
downloadnasm-73320328c1232260bd569a8fb045124ad55f342d.tar.gz
nasm-73320328c1232260bd569a8fb045124ad55f342d.tar.bz2
nasm-73320328c1232260bd569a8fb045124ad55f342d.zip
Generate stabs format debugging info for ELF
Diffstat (limited to 'output')
-rw-r--r--output/outelf.c390
1 files changed, 371 insertions, 19 deletions
diff --git a/output/outelf.c b/output/outelf.c
index f006571..6067e9f 100644
--- a/output/outelf.c
+++ b/output/outelf.c
@@ -116,7 +116,7 @@ extern struct ofmt of_elf;
#define SYM_DATA 0x01
#define SYM_FUNCTION 0x02
-#define GLOBAL_TEMP_BASE 15 /* bigger than any constant sym id */
+#define GLOBAL_TEMP_BASE 6 /* bigger than any constant sym id */
#define SEG_ALIGN 16 /* alignment of sections in file */
#define SEG_ALIGN_1 (SEG_ALIGN-1)
@@ -141,6 +141,63 @@ static struct SAA *elf_build_symtab (long *, long *);
static struct SAA *elf_build_reltab (long *, struct Reloc *);
static void add_sectname (char *, char *);
+
+/* this stuff is needed for the stabs debugging format */
+#define N_SO 0x64 /* ID for main source file */
+#define N_SOL 0x84 /* ID for sub-source file */
+#define N_BINCL 0x82
+#define N_EINCL 0xA2
+#define N_SLINE 0x44
+#define TY_STABSSYMLIN 0x40 /* ouch */
+
+struct stabentry {
+ unsigned long n_strx;
+ unsigned char n_type;
+ unsigned char n_other;
+ unsigned short n_desc;
+ unsigned long n_value;
+};
+
+struct erel {
+ int offset,info;
+};
+
+struct symlininfo {
+ int offset;
+ int section; /* section index */
+ char *name; /* shallow-copied pointer of section name */
+};
+
+struct linelist {
+ struct symlininfo info;
+ int line;
+ char *filename;
+ struct linelist * next;
+ struct linelist * last;
+};
+
+static struct linelist *stabslines=0;
+static int stabs_immcall=0;
+static int currentline=0;
+static int numlinestabs=0;
+static char * stabs_filename=0;
+static int symtabsection;
+static unsigned char *stabbuf=0,*stabstrbuf=0,*stabrelbuf=0;
+static int stablen,stabstrlen,stabrellen;
+
+
+void stabs_init(struct ofmt *,void *,FILE *,efunc );
+void stabs_linenum(const char *filename,long linenumber,long);
+void stabs_deflabel(char *,long ,long ,int ,char *);
+void stabs_directive(const char *,const char *);
+void stabs_typevalue(long );
+void stabs_output(int ,void *);
+void stabs_generate();
+void stabs_cleanup();
+
+/* end of stabs debugging stuff */
+
+
/*
* Special section numbers which are used to define ELF special
* symbols, which can be used with WRT to provide PIC relocation
@@ -150,7 +207,7 @@ static long elf_gotpc_sect, elf_gotoff_sect;
static long elf_got_sect, elf_plt_sect;
static long elf_sym_sect;
-static void elf_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval)
+static void elf_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval)
{
elffp = fp;
error = errfunc;
@@ -185,7 +242,7 @@ static void elf_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval)
def_seg = seg_alloc();
}
-static void elf_cleanup(int debuginfo)
+static void elf_cleanup(int debuginfo)
{
struct Reloc *r;
int i;
@@ -209,9 +266,12 @@ static void elf_cleanup(int debuginfo)
saa_free (syms);
raa_free (bsym);
saa_free (strs);
+ if (of_elf.current_dfmt) {
+ of_elf.current_dfmt->cleanup();
+ }
}
-static void add_sectname (char *firsthalf, char *secondhalf)
+static void add_sectname (char *firsthalf, char *secondhalf)
{
int len = strlen(firsthalf)+strlen(secondhalf);
while (shstrtablen + len + 1 > shstrtabsize)
@@ -221,7 +281,7 @@ static void add_sectname (char *firsthalf, char *secondhalf)
shstrtablen += len+1;
}
-static int elf_make_section (char *name, int type, int flags, int align)
+static int elf_make_section (char *name, int type, int flags, int align)
{
struct Section *s;
@@ -252,7 +312,7 @@ static int elf_make_section (char *name, int type, int flags, int align)
return nsects-1;
}
-static long elf_section_names (char *name, int pass, int *bits)
+static long elf_section_names (char *name, int pass, int *bits)
{
char *p;
int flags_and, flags_or, type, align, i;
@@ -354,7 +414,7 @@ static long elf_section_names (char *name, int pass, int *bits)
}
static void elf_deflabel (char *name, long segment, long offset,
- int is_global, char *special)
+ int is_global, char *special)
{
int pos = strslen;
struct Symbol *sym;
@@ -465,7 +525,7 @@ fprintf(stderr, " elf_deflabel: %s, seg=%ld, off=%ld, is_global=%d, %s\n",
if (sym->type == SYM_GLOBAL) {
/*
- * There's a problem here that needs fixing.
+ * There's a problem here that needs fixing.
* If sym->section == SHN_ABS, then the first line of the
* else section causes a core dump, because its a reference
* beyond the end of the section array.
@@ -485,7 +545,7 @@ fprintf(stderr, " elf_deflabel: %s, seg=%ld, off=%ld, is_global=%d, %s\n",
{
bsym = raa_write (bsym, segment, nglobs);
}
- else if (sym->section != SHN_ABS)
+ else if (sym->section != SHN_ABS)
{
/*
* This is a global symbol; so we must add it to the linked
@@ -552,7 +612,7 @@ fprintf(stderr, " elf_deflabel: %s, seg=%ld, off=%ld, is_global=%d, %s\n",
}
static void elf_add_reloc (struct Section *sect, long segment,
- int type)
+ int type)
{
struct Reloc *r;
@@ -601,7 +661,7 @@ static void elf_add_reloc (struct Section *sect, long segment,
*/
static long elf_add_gsym_reloc (struct Section *sect,
long segment, long offset,
- int type, int exact)
+ int type, int exact)
{
struct Reloc *r;
struct Section *s;
@@ -673,6 +733,7 @@ static void elf_out (long segto, const void *data, unsigned long type,
long addr;
unsigned char mydata[4], *p;
int i;
+ static struct symlininfo sinfo;
type &= OUT_TYPMASK;
@@ -696,10 +757,21 @@ static void elf_out (long segto, const void *data, unsigned long type,
int tempint; /* ignored */
if (segto != elf_section_names (".text", 2, &tempint))
error (ERR_PANIC, "strange segment conditions in ELF driver");
- else
- s = sects[nsects-1];
+ else {
+ s = sects[nsects-1];
+ i=nsects-1;
+ }
}
+ /* again some stabs debugging stuff */
+ if (of_elf.current_dfmt) {
+ sinfo.offset=s->len;
+ sinfo.section=i;
+ sinfo.name=s->name;
+ of_elf.current_dfmt->debug_output(TY_STABSSYMLIN,&sinfo);
+ }
+ /* end of debugging stuff */
+
if (s->type == SHT_NOBITS && type != OUT_RESERVE) {
error(ERR_WARNING, "attempt to initialise memory in"
" BSS section `%s': ignored", s->name);
@@ -827,9 +899,10 @@ static void elf_out (long segto, const void *data, unsigned long type,
}
}
-static void elf_write(void)
+static void elf_write(void)
{
int nsections, align;
+ int scount;
char *p;
int commlen;
char comment[64];
@@ -844,7 +917,11 @@ static void elf_write(void)
* sections `.comment', `.shstrtab', `.symtab' and `.strtab',
* then optionally relocation sections for the user sections.
*/
- nsections = 5; /* SHN_UNDEF and the fixed ones */
+ if (of_elf.current_dfmt)
+ nsections=8;
+ else
+ nsections = 5; /* SHN_UNDEF and the fixed ones */
+
add_sectname ("", ".comment");
add_sectname ("", ".shstrtab");
add_sectname ("", ".symtab");
@@ -857,6 +934,13 @@ static void elf_write(void)
}
}
+ if (of_elf.current_dfmt) {
+ /* in case the debug information is wanted, just add these three sections... */
+ add_sectname("",".stab");
+ add_sectname("",".stabstr");
+ add_sectname(".rel",".stab");
+ }
+
/*
* Do the comment.
*/
@@ -906,6 +990,7 @@ static void elf_write(void)
elf_sects = nasm_malloc(sizeof(*elf_sects) * (2 * nsects + 10));
elf_section_header (0, 0, 0, NULL, FALSE, 0L, 0, 0, 0, 0); /* SHN_UNDEF */
+ scount=1; /* needed for the stabs debugging to track the symtable section */
p = shstrtab+1;
for (i=0; i<nsects; i++) {
elf_section_header (p - shstrtab, sects[i]->type, sects[i]->flags,
@@ -913,15 +998,19 @@ static void elf_write(void)
sects[i]->data : NULL), TRUE,
sects[i]->len, 0, 0, sects[i]->align, 0);
p += strlen(p)+1;
+ scount++; /* dito */
}
elf_section_header (p - shstrtab, 1, 0, comment, FALSE,
(long)commlen, 0, 0, 1, 0);/* .comment */
+ scount++; /* dito */
p += strlen(p)+1;
elf_section_header (p - shstrtab, 3, 0, shstrtab, FALSE,
(long)shstrtablen, 0, 0, 1, 0);/* .shstrtab */
+ scount++; /* dito */
p += strlen(p)+1;
elf_section_header (p - shstrtab, 2, 0, symtab, TRUE,
symtablen, nsects+4, symtablocal, 4, 16);/* .symtab */
+ symtabsection = scount; /* now we got the symtab section index in the ELF file */
p += strlen(p)+1;
elf_section_header (p - shstrtab, 3, 0, strs, TRUE,
strslen, 0, 0, 1, 0); /* .strtab */
@@ -930,7 +1019,25 @@ static void elf_write(void)
elf_section_header (p - shstrtab, 9, 0, sects[i]->rel, TRUE,
sects[i]->rellen, nsects+3, i+1, 4, 8);
}
+ if (of_elf.current_dfmt) {
+ /* for debugging information, create the last three sections
+ which are the .stab , .stabstr and .rel.stab sections respectively */
+
+ /* this function call creates the stab sections in memory */
+ stabs_generate();
+
+ if ((stabbuf)&&(stabstrbuf)&&(stabrelbuf)) {
+ p += strlen(p)+1;
+ elf_section_header(p-shstrtab,1,0,stabbuf,0,stablen,nsections-2,0,4,12);
+ p += strlen(p)+1;
+ elf_section_header(p-shstrtab,3,0,stabstrbuf,0,stabstrlen,0,0,4,0);
+
+ p += strlen(p)+1;
+ /* link -> symtable info -> section to refer to */
+ elf_section_header(p-shstrtab,9,0,stabrelbuf,0,stabrellen,symtabsection,nsections-3,4,8);
+ }
+ }
fwrite (align_str, align, 1, elffp);
/*
@@ -942,7 +1049,7 @@ static void elf_write(void)
saa_free (symtab);
}
-static struct SAA *elf_build_symtab (long *len, long *local)
+static struct SAA *elf_build_symtab (long *len, long *local)
{
struct SAA *s = saa_init(1L);
struct Symbol *sym;
@@ -1055,7 +1162,7 @@ static struct SAA *elf_build_reltab (long *len, struct Reloc *r) {
static void elf_section_header (int name, int type, int flags,
void *data, int is_saa, long datalen,
- int link, int info, int align, int eltsize)
+ int link, int info, int align, int eltsize)
{
elf_sects[elf_nsect].data = data;
elf_sects[elf_nsect].len = datalen;
@@ -1076,7 +1183,7 @@ static void elf_section_header (int name, int type, int flags,
fwritelong ((long)eltsize, elffp);
}
-static void elf_write_sections (void)
+static void elf_write_sections (void)
{
int i;
for (i = 0; i < elf_nsect; i++)
@@ -1127,11 +1234,25 @@ static int elf_set_info(enum geninfo type, char **val)
return 0;
}
+static struct dfmt df_stabs = {
+ "ELF32 (i386) stabs debug format for Linux",
+ "stabs",
+ stabs_init,
+ stabs_linenum,
+ stabs_deflabel,
+ stabs_directive,
+ stabs_typevalue,
+ stabs_output,
+ stabs_cleanup
+};
+
+struct dfmt *elf_debugs_arr[2]={&df_stabs,NULL};
+
struct ofmt of_elf = {
"ELF32 (i386) object files (e.g. Linux)",
"elf",
NULL,
- null_debug_arr,
+ elf_debugs_arr,
&null_debug_form,
elf_stdmac,
elf_init,
@@ -1145,4 +1266,235 @@ struct ofmt of_elf = {
elf_cleanup
};
+/* again, the stabs debugging stuff (code) */
+
+void stabs_init(struct ofmt *of,void *id,FILE *fp,efunc error) {
+}
+
+void stabs_linenum(const char *filename,long linenumber,long segto) {
+ if (!stabs_filename) {
+ stabs_filename = (char *)malloc(strlen(filename)+1);
+ strcpy(stabs_filename,filename);
+ } else {
+ if (strcmp(stabs_filename,filename)) {
+ /* yep, a memory leak...this program is one-shot anyway, so who cares...
+ in fact, this leak comes in quite handy to maintain a list of files
+ encountered so far in the symbol lines... */
+ stabs_filename = (char *)malloc(strlen(filename)+1);
+ strcpy(stabs_filename,filename);
+ }
+ }
+ stabs_immcall=1;
+ currentline=linenumber;
+}
+
+void stabs_deflabel(char *name,long segment,long offset,int is_global,char *special) {
+}
+
+void stabs_directive(const char *directive,const char *params) {
+}
+
+void stabs_typevalue(long type) {
+}
+
+void stabs_output(int type,void *param) {
+ struct symlininfo *s;
+ struct linelist *el;
+ if (type==TY_STABSSYMLIN) {
+ if (stabs_immcall) {
+ s=(struct symlininfo *)param;
+ if (strcmp( s->name,".text")) return; /* we are only interested in the text stuff */
+ numlinestabs++;
+ el=(struct linelist *)malloc(sizeof(struct linelist));
+ el->info.offset=s->offset;
+ el->info.section=s->section;
+ el->info.name=s->name;
+ el->line=currentline;
+ el->filename=stabs_filename;
+ el->next=0;
+ if (stabslines) {
+ stabslines->last->next=el;
+ stabslines->last=el;
+ } else {
+ stabslines=el;
+ stabslines->last=el;
+ }
+ }
+ }
+ stabs_immcall=0;
+}
+
+
+/* for creating the .stab , .stabstr and .rel.stab sections in memory */
+
+void stabs_generate() {
+ int i,numfiles,strsize,numstabs=0,currfile,mainfileindex;
+ struct erel rentry;
+ unsigned char *sbuf,*ssbuf,*rbuf,*sptr,*rptr;
+ char **allfiles;
+ int *fileidx;
+
+ struct linelist *ptr;
+ struct stabentry stab;
+
+ ptr=stabslines;
+
+ allfiles = (char **)malloc(numlinestabs*sizeof(char *));
+ for (i=0;i<numlinestabs;i++) allfiles[i]=0;
+ numfiles=0;
+ while (ptr) {
+ if (numfiles==0) {
+ allfiles[0]=ptr->filename;
+ numfiles++;
+ } else {
+ for (i=0;i<numfiles;i++) {
+ if (!strcmp(allfiles[i],ptr->filename)) break;
+ }
+ if (i>=numfiles) {
+ allfiles[i]=ptr->filename;
+ numfiles++;
+ }
+ }
+ ptr=ptr->next;
+ }
+ strsize=1;
+ fileidx = (int *)malloc(numfiles*sizeof(int));
+ for (i=0;i<numfiles;i++) {
+ fileidx[i]=strsize;
+ strsize+=strlen(allfiles[i])+1;
+ }
+ mainfileindex=0;
+ for (i=0;i<numfiles;i++) {
+ if (!strcmp(allfiles[i],elf_module)) {
+ mainfileindex=i;
+ break;
+ }
+ }
+
+
+ /* worst case size of the stab buffer would be:
+ the sourcefiles changes each line, which would mean 1 SOL, 1 SYMLIN per line
+ */
+ sbuf = (unsigned char *)malloc((numlinestabs*2+3)*sizeof(struct stabentry));
+
+ ssbuf = (unsigned char *)malloc(strsize);
+
+ rbuf = (unsigned char *)malloc(numlinestabs*8*(2+3));
+ rptr=rbuf;
+
+ for (i=0;i<numfiles;i++) {
+ strcpy(ssbuf+fileidx[i],allfiles[i]);
+ }
+ ssbuf[0]=0;
+
+ stabstrlen = strsize; /* set global variable for length of stab strings */
+
+ sptr=sbuf;
+ /* this is the first stab, its strx points to the filename of the
+ the source-file, the n_desc field should be set to the number
+ of remaining stabs
+ */
+ stab.n_strx = fileidx[0];
+ stab.n_type=0;
+ stab.n_other=0;
+ stab.n_desc=0; /* # of remaining stabs (to be determined later) */
+ stab.n_value = strlen(allfiles[0])+1;
+ memcpy(sptr,&stab,sizeof(struct stabentry));
+ sptr+=sizeof(struct stabentry);
+
+ ptr=stabslines;
+ for (i=0;i<numfiles;i++) if (!strcmp(allfiles[i],ptr->filename)) break;
+ currfile=i;
+
+ /* this is the stab for the main source file */
+ stab.n_strx = fileidx[mainfileindex];
+ stab.n_type=N_SO;
+ stab.n_other=0;
+ stab.n_desc=0;
+ stab.n_value = 0; /* strlen(allfiles[mainfileindex])+1; */
+ memcpy(sptr,&stab,sizeof(struct stabentry));
+ /* relocation stuff */
+ rentry.offset=(sptr-sbuf)+8;
+ /* the following section+3 assumption relies on the following order of output sections:
+ 0 -> dummy
+ 1 -> .text
+ 2 -> .data
+ 3 -> .comment
+ 4 -> .strtab
+ ... this is an ugly hack and should be improved in the near future
+ */
+ rentry.info=((ptr->info.section+3)<<8)|R_386_32;
+ memcpy(rptr,&rentry,8);
+ rptr+=8;
+ sptr+=sizeof(struct stabentry);
+
+ numstabs=1;
+ currfile=mainfileindex;
+
+ while (ptr) {
+ if (strcmp(allfiles[currfile],ptr->filename)) {
+ /* oops file has changed... */
+ for (i=0;i<numfiles;i++) if (!strcmp(allfiles[i],ptr->filename)) break;
+ currfile=i;
+ stab.n_strx = fileidx[currfile];
+ stab.n_type=N_SOL;
+ stab.n_other=0;
+ stab.n_desc=0;
+ /* stab.n_value = strlen(allfiles[currfile])+1; */
+ stab.n_value = ptr->info.offset;
+ memcpy(sptr,&stab,sizeof(struct stabentry));
+ /* relocation stuff */
+ rentry.offset=(sptr-sbuf)+8;
+ rentry.info=((ptr->info.section+3)<<8)|R_386_32;
+ memcpy(rptr,&rentry,8);
+ rptr+=8;
+ sptr+=sizeof(struct stabentry);
+ numstabs++;
+ }
+ stab.n_strx=0;
+ stab.n_type=N_SLINE;
+ stab.n_other=0;
+ stab.n_desc=ptr->line;
+ stab.n_value=ptr->info.offset;
+ memcpy(sptr,&stab,sizeof(struct stabentry));
+ numstabs++;
+
+ /* relocation stuff */
+ rentry.offset=(sptr-sbuf)+8;
+ rentry.info=((ptr->info.section+3)<<8)|R_386_32;
+ memcpy(rptr,&rentry,8);
+ rptr+=8;
+
+ sptr+=sizeof(struct stabentry);
+ ptr=ptr->next;
+
+ }
+
+
+ ((struct stabentry *)sbuf)->n_desc=numstabs;
+
+ free(allfiles);
+ free(fileidx);
+
+ stablen = (sptr-sbuf);
+ stabrellen=(rptr-rbuf);
+ stabrelbuf= rbuf;
+ stabbuf = sbuf;
+ stabstrbuf = ssbuf;
+}
+
+void stabs_cleanup() {
+ struct linelist *ptr,*del;
+ if (!stabslines) return;
+ ptr=stabslines;
+ while (ptr) {
+ del=ptr;
+ ptr=ptr->next;
+ free(del);
+ }
+ if (stabbuf) free(stabbuf);
+ if (stabrelbuf) free(stabrelbuf);
+ if (stabstrbuf) free(stabstrbuf);
+}
+
#endif /* OF_ELF */