minix/commands/mdb/gnu_sym.c
Gianluca Guida cc17b27a2b Build NetBSD libc library in world in ELF mode.
3 sets of libraries are built now:
  . ack: all libraries that ack can compile (/usr/lib/i386/)
  . clang+elf: all libraries with minix headers (/usr/lib/)
  . clang+elf: all libraries with netbsd headers (/usr/netbsd/)

Once everything can be compiled with netbsd libraries and headers, the
/usr/netbsd hierarchy will be obsolete and its libraries compiled with
netbsd headers will be installed in /usr/lib, and its headers
in /usr/include. (i.e. minix libc and current minix headers set
will be gone.)

To use the NetBSD libc system (libraries + headers) before
it is the default libc, see:
   http://wiki.minix3.org/en/DevelopersGuide/UsingNetBSDCode
This wiki page also documents the maintenance of the patch
files of minix-specific changes to imported NetBSD code.

Changes in this commit:
  . libsys: Add NBSD compilation and create a safe NBSD-based libc.
  . Port rest of libraries (except libddekit) to new header system.
  . Enable compilation of libddekit with new headers.
  . Enable kernel compilation with new headers.
  . Enable drivers compilation with new headers.
  . Port legacy commands to new headers and libc.
  . Port servers to new headers.
  . Add <sys/sigcontext.h> in compat library.
  . Remove dependency file in tree.
  . Enable compilation of common/lib/libc/atomic in libsys
  . Do not generate RCSID strings in libc.
  . Temporarily disable zoneinfo as they are incompatible with NetBSD format
  . obj-nbsd for .gitignore
  . Procfs: use only integer arithmetic. (Antoine Leca)
  . Increase ramdisk size to create NBSD-based images.
  . Remove INCSYMLINKS handling hack.
  . Add nbsd_include/sys/exec_elf.h
  . Enable ELF compilation with NBSD libc.
  . Add 'make nbsdsrc' in tools to download reference NetBSD sources.
  . Automate minix-port.patch creation.
  . Avoid using fstavfs() as it is *extremely* slow and unneeded.
  . Set err() as PRIVATE to avoid name clash with libc.
  . [NBSD] servers/vm: remove compilation warnings.
  . u32 is not a long in NBSD headers.
  . UPDATING info on netbsd hierarchy
  . commands fixes for netbsd libc
2011-06-24 11:46:30 +02:00

444 lines
8.9 KiB
C

/*
* gnu_sym.c for mdb
* copied and modified from sym.c
* Support GNU Exec symbol tables
*/
#include "mdb.h"
#ifdef EXTRA_SYMBOLS
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#ifdef __NBSD_LIBC
#include <compat/a.out.h>
#else
#include <minix/a.out.h>
#endif
#include "proto.h"
#define NN_UNDF 0
#define NN_ABS 2
#define NN_TEXT 4
#define NN_DATA 6
#define NN_BSS 8
#define NN_FN 15
#define NN_EXT 1
#define NN_TYPE 036
struct newnlist {
union {
char *n_name;
struct newnlist *n_next;
long n_strx;
} n_un;
unsigned char n_type;
char n_other;
short n_desc;
unsigned long n_value;
};
struct symtab_s
{
struct newnlist *start;
struct newnlist *end;
unsigned int nsym;
};
PRIVATE struct symtab_s symtab;
FORWARD _PROTOTYPE( void gnu_sort , (struct newnlist *array ,
struct newnlist *top ));
FORWARD _PROTOTYPE( int gnu_symeq , (char *t , struct newnlist *sp ));
FORWARD _PROTOTYPE( int gnu_symprefix , (char *t , struct newnlist *sp ));
FORWARD _PROTOTYPE( struct newnlist *gnu_sname, (char *name, int is_text,
int allflag) );
FORWARD _PROTOTYPE( struct newnlist *gnu_sval, (off_t value, int where) );
FORWARD _PROTOTYPE( void gnu_sym, (struct newnlist *sp, off_t off) );
PUBLIC void gnu_init( filename )
char *filename;
{
struct exec header;
unsigned int string_size;
char *names;
struct newnlist *p;
int fd;
register struct symtab_s *tp;
tp = &symtab;
if ( (fd = open( filename, O_RDONLY)) < 0 ||
read( fd, (char *) &header, sizeof header ) != sizeof header )
{
do_error( "gnu_load - reading header" );
if ( fd >= 0) close( fd );
return;
}
if ( (string_size = lseek( fd, 0, SEEK_END ) ) == -1 )
{
do_error( "gnu_load - determining file size" );
close( fd );
return;
}
string_size -= A_SYMPOS( header );
if ( (int) header.a_syms < 0 ||
(unsigned) header.a_syms != header.a_syms ||
(tp->start = (struct newnlist *) malloc( string_size ))
== (struct newnlist *) NULL &&
header.a_syms != 0 )
{
do_error( "gnu_load - allocating memory" );
close( fd );
return;
}
if ( lseek( fd, A_SYMPOS( header ), SEEK_SET ) != A_SYMPOS( header ) )
{
do_error( "gnu_load - reading header" );
close( fd );
return;
}
if ( read( fd, (char *) tp->start, string_size ) < 0 )
{
do_error( "gnu_load - reading symbols" );
close( fd );
return;
}
close( fd );
tp->nsym = (unsigned int) header.a_syms / sizeof (struct newnlist);
tp->end = tp->start + tp->nsym;
names = (char *) tp->start + header.a_syms;
for ( p = tp->start; p < tp->end; p++)
if(p->n_un.n_strx)
p->n_un.n_name = names + p->n_un.n_strx;
else
p->n_un.n_name = "";
/* sort on value only, name search not used much and storage a problem */
Printf("Sorting %d GNU symbols ....", tp->nsym );
gnu_sort( tp->start, tp->end );
Printf("\n");
}
PUBLIC long gnu_symbolvalue( name, is_text )
char *name;
int is_text;
{
register struct newnlist *sp;
sp = gnu_sname(name,is_text,0);
if (sp != NULL)
return sp->n_value;
else
return 0L;
}
PRIVATE struct newnlist *gnu_sname( name, is_text, allflag )
char *name;
int is_text;
int allflag;
{
char *s;
unsigned char sclass;
int schar;
char *send;
register struct newnlist *sp;
register struct symtab_s *tp;
tp = &symtab;
if ( allflag )
{
/* find and print all matching symbols */
for ( sp = tp->start; sp < tp->end; ++sp )
{
if ( gnu_symprefix( name, sp ) )
{
sp = sp;
for ( s = sp->n_un.n_name, send = s + strlen(s);
*s != 0 && s < send; ++s )
outbyte( *s );
for ( ; s <= send; ++s )
outspace();
switch( sp->n_type & NN_TYPE )
{
case NN_ABS: schar = 'a'; break;
case NN_TEXT: schar = 't'; break;
case NN_DATA: schar = 'd'; break;
case NN_BSS: schar = 'b'; break;
default: schar = '?'; break;
}
if ( (sp->n_type & NN_EXT) && schar != '?' )
schar += 'A' - 'a';
outbyte( schar );
outspace();
outh32( sp->n_value );
outbyte('\n');
}
}
}
else
{
/* find symbol by dumb linear search */
for ( sp = tp->start; sp < tp->end; ++sp )
{
sclass = sp->n_type & NN_TYPE;
if ( (is_text && sclass == NN_TEXT ||
!is_text && (sclass == NN_DATA ||
sclass == NN_BSS)) &&
gnu_symeq( name, sp ) )
return sp;
}
}
return NULL;
}
PRIVATE struct newnlist *gnu_sval( value, where )
off_t value;
int where;
{
int left;
int middle;
int right;
unsigned char sclass;
register struct newnlist *sp;
register struct symtab_s *tp;
tp = &symtab;
/* find last symbol with value <= desired one by binary search */
for ( left = 0, right = tp->nsym - 1; left <= right; )
{
middle = (left + right) / 2;
sp = tp->start + middle;
if ( value < sp->n_value )
right = middle - 1;
else
left = middle + 1;
}
if ( right >= 0 )
/* otherwise tp->start + right may wrap around to > tp->start !! */
for ( sp = tp->start + right; sp >= tp->start; --sp )
{
if ( !(sp->n_type & NN_EXT) ) continue;
sclass = sp->n_type & NN_TYPE;
if ( (where == CSEG && sclass == NN_TEXT) ||
(where != CSEG &&
(sclass == NN_DATA || sclass == NN_BSS)) )
return sp;
}
return NULL;
}
PRIVATE void gnu_sym( sp, off )
struct newnlist *sp;
off_t off;
{
register char *s;
char *send;
for ( s = sp->n_un.n_name, send = s + strlen(s); *s != 0 && s < send; ++s )
outbyte( *s );
if ( (off -= sp->n_value) != 0 )
{
outbyte( '+' );
printhex(off);
}
}
/* shell sort symbols on value */
PRIVATE void gnu_sort( array, top )
struct newnlist *array;
struct newnlist *top;
{
int gap;
int i;
int j;
register struct newnlist *left;
register struct newnlist *right;
struct newnlist swaptemp;
int size;
size = top - array;
/* choose gaps according to Knuth V3 p95 */
for ( gap = 1, i = 4; (j = 3 * i + 1) < size; gap = i, i = j )
;
do
{
for ( j = gap; j < size; ++j )
for ( i = j - gap; i >= 0; i -= gap )
{
left = array + i;
right = array + (i + gap);
if ( (off_t) left->n_value <=
right->n_value )
break;
swaptemp = *left;
*left = *right;
*right = swaptemp;
}
}
while ( (gap /= 3) != 0 );
}
PUBLIC void gnu_symbolic( value, separator )
off_t value;
int separator;
{
register struct newnlist *sp;
long off;
if (value < st_addr || value > end_addr) {
outstr("0x");
printhex(value);
outbyte(separator);
return;
}
if ( (sp = gnu_sval( value, CSEG )) != NULL )
{
gnu_sym( sp, value );
}
else if ( (sp = gnu_sval( value, DSEG )) != NULL )
{
gnu_sym( sp, value );
}
else
{
outstr("_start");
off = value - st_addr;
if ( off != 0 )
{
outbyte( '+' );
printhex(off);
}
}
outbyte( separator );
}
PRIVATE int gnu_symeq( t, sp )
register char *t;
struct newnlist *sp;
{
return strncmp( t, sp->n_un.n_name, strlen(t) ) == 0;
}
PRIVATE int gnu_symprefix( t, sp )
register char *t;
struct newnlist *sp;
{
register char *s;
char *send;
for ( ; *t == '_'; ++t )
;
for ( s = sp->n_un.n_name, send = s + strlen(s);
s < send && *s == '_'; ++s )
;
return strncmp( s, t, send - s ) == 0;
}
/* list all symbols - test for selection criteria */
PUBLIC void gnu_listsym( tchar )
char tchar;
{
register struct symtab_s *tp;
register struct newnlist *sp;
char *s;
char *send;
char schar;
outbyte('\n');
tp = &symtab;
for ( sp = tp->start; sp < tp->end; ++sp )
{
switch( sp->n_type & NN_TYPE )
{
case NN_ABS: schar = 'a'; break;
case NN_TEXT: schar = 't'; break;
case NN_DATA: schar = 'd'; break;
case NN_BSS: schar = 'b'; break;
default: schar = '?'; break;
}
if ( (sp->n_type & NN_EXT) && schar != '?' )
schar += 'A' - 'a';
/* check for selection */
if ( tchar != '*' && schar != tchar)
continue;
/* print symbol type and value */
outh32( sp->n_value );
outspace();
outbyte( schar );
outbyte( '\t' );
for ( s = sp->n_un.n_name, send = s + strlen(s);
*s != 0 && s < send; ++s ) outbyte( *s );
outbyte('\n');
}
}
PUBLIC int gnu_text_symbol(value)
off_t value;
{
struct newnlist *sp;
if ((sp = gnu_sval(value, CSEG)) != NULL && sp->n_value == value)
{
gnu_sym(sp, value);
return TRUE;
}
else
return FALSE;
}
PUBLIC int gnu_finds_data(off,data_seg)
off_t off;
int data_seg;
{
struct newnlist *sp;
if ((sp = gnu_sval(off, data_seg)) != NULL)
{
gnu_sym(sp, off);
return TRUE;
}
else
return FALSE;
}
PUBLIC int gnu_finds_pc(pc)
off_t pc;
{
struct newnlist *sp;
if ((sp = gnu_sval(pc, CSEG)) != NULL)
{
gnu_sym(sp, pc);
return TRUE;
}
else
return FALSE;
}
#endif /* EXTRA_SYMBOLS */