Generate stabs format debugging info for ELF

This commit is contained in:
H. Peter Anvin 2003-07-09 19:11:10 +00:00
parent da4c3983b2
commit 73320328c1
3 changed files with 374 additions and 21 deletions

View file

@ -1,6 +1,7 @@
0.98.37
-------
* Added stabs debugging for the ELF output format, patch from
Martin Wawro.
* Fix output/outbin.c to allow origin > 80000000h
* Make -U switch work

View file

@ -15,7 +15,7 @@ bindir = @bindir@
mandir = @mandir@
CC = @CC@
CFLAGS = @CFLAGS@ @GCCFLAGS@ -I$(srcdir) -I.
CFLAGS = @CFLAGS@ @GCCFLAGS@ @DEFS@ -I$(srcdir) -I.
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
PERL = perl

View file

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