3 * copied and modified from sym.c
4 * Support GNU Exec symbol tables
16 #include <minix/a.out.h>
31 struct newnlist
*n_next
;
37 unsigned long n_value
;
42 struct newnlist
*start
;
47 PRIVATE
struct symtab_s symtab
;
49 FORWARD
_PROTOTYPE( void gnu_sort
, (struct newnlist
*array
,
50 struct newnlist
*top
));
51 FORWARD
_PROTOTYPE( int gnu_symeq
, (char *t
, struct newnlist
*sp
));
52 FORWARD
_PROTOTYPE( int gnu_symprefix
, (char *t
, struct newnlist
*sp
));
53 FORWARD
_PROTOTYPE( struct newnlist
*gnu_sname
, (char *name
, int is_text
,
55 FORWARD
_PROTOTYPE( struct newnlist
*gnu_sval
, (off_t value
, int where
) );
56 FORWARD
_PROTOTYPE( void gnu_sym
, (struct newnlist
*sp
, off_t off
) );
59 PUBLIC
void gnu_init( filename
)
63 unsigned int string_size
;
67 register struct symtab_s
*tp
;
70 if ( (fd
= open( filename
, O_RDONLY
)) < 0 ||
71 read( fd
, (char *) &header
, sizeof header
) != sizeof header
)
73 do_error( "gnu_load - reading header" );
74 if ( fd
>= 0) close( fd
);
78 if ( (string_size
= lseek( fd
, 0, SEEK_END
) ) == -1 )
80 do_error( "gnu_load - determining file size" );
85 string_size
-= A_SYMPOS( header
);
87 if ( (int) header
.a_syms
< 0 ||
88 (unsigned) header
.a_syms
!= header
.a_syms
||
89 (tp
->start
= (struct newnlist
*) malloc( string_size
))
90 == (struct newnlist
*) NULL
&&
93 do_error( "gnu_load - allocating memory" );
98 if ( lseek( fd
, A_SYMPOS( header
), SEEK_SET
) != A_SYMPOS( header
) )
100 do_error( "gnu_load - reading header" );
105 if ( read( fd
, (char *) tp
->start
, string_size
) < 0 )
107 do_error( "gnu_load - reading symbols" );
113 tp
->nsym
= (unsigned int) header
.a_syms
/ sizeof (struct newnlist
);
114 tp
->end
= tp
->start
+ tp
->nsym
;
116 names
= (char *) tp
->start
+ header
.a_syms
;
118 for ( p
= tp
->start
; p
< tp
->end
; p
++)
120 p
->n_un
.n_name
= names
+ p
->n_un
.n_strx
;
124 /* sort on value only, name search not used much and storage a problem */
125 Printf("Sorting %d GNU symbols ....", tp
->nsym
);
126 gnu_sort( tp
->start
, tp
->end
);
131 PUBLIC
long gnu_symbolvalue( name
, is_text
)
135 register struct newnlist
*sp
;
136 sp
= gnu_sname(name
,is_text
,0);
144 PRIVATE
struct newnlist
*gnu_sname( name
, is_text
, allflag
)
150 unsigned char sclass
;
153 register struct newnlist
*sp
;
154 register struct symtab_s
*tp
;
160 /* find and print all matching symbols */
161 for ( sp
= tp
->start
; sp
< tp
->end
; ++sp
)
163 if ( gnu_symprefix( name
, sp
) )
166 for ( s
= sp
->n_un
.n_name
, send
= s
+ strlen(s
);
167 *s
!= 0 && s
< send
; ++s
)
169 for ( ; s
<= send
; ++s
)
171 switch( sp
->n_type
& NN_TYPE
)
173 case NN_ABS
: schar
= 'a'; break;
174 case NN_TEXT
: schar
= 't'; break;
175 case NN_DATA
: schar
= 'd'; break;
176 case NN_BSS
: schar
= 'b'; break;
177 default: schar
= '?'; break;
179 if ( (sp
->n_type
& NN_EXT
) && schar
!= '?' )
183 outh32( sp
->n_value
);
190 /* find symbol by dumb linear search */
191 for ( sp
= tp
->start
; sp
< tp
->end
; ++sp
)
193 sclass
= sp
->n_type
& NN_TYPE
;
194 if ( (is_text
&& sclass
== NN_TEXT
||
195 !is_text
&& (sclass
== NN_DATA
||
196 sclass
== NN_BSS
)) &&
197 gnu_symeq( name
, sp
) )
204 PRIVATE
struct newnlist
*gnu_sval( value
, where
)
211 unsigned char sclass
;
212 register struct newnlist
*sp
;
213 register struct symtab_s
*tp
;
217 /* find last symbol with value <= desired one by binary search */
218 for ( left
= 0, right
= tp
->nsym
- 1; left
<= right
; )
220 middle
= (left
+ right
) / 2;
221 sp
= tp
->start
+ middle
;
222 if ( value
< sp
->n_value
)
228 /* otherwise tp->start + right may wrap around to > tp->start !! */
229 for ( sp
= tp
->start
+ right
; sp
>= tp
->start
; --sp
)
231 if ( !(sp
->n_type
& NN_EXT
) ) continue;
232 sclass
= sp
->n_type
& NN_TYPE
;
233 if ( (where
== CSEG
&& sclass
== NN_TEXT
) ||
235 (sclass
== NN_DATA
|| sclass
== NN_BSS
)) )
242 PRIVATE
void gnu_sym( sp
, off
)
249 for ( s
= sp
->n_un
.n_name
, send
= s
+ strlen(s
); *s
!= 0 && s
< send
; ++s
)
251 if ( (off
-= sp
->n_value
) != 0 )
258 /* shell sort symbols on value */
260 PRIVATE
void gnu_sort( array
, top
)
261 struct newnlist
*array
;
262 struct newnlist
*top
;
267 register struct newnlist
*left
;
268 register struct newnlist
*right
;
269 struct newnlist swaptemp
;
273 /* choose gaps according to Knuth V3 p95 */
274 for ( gap
= 1, i
= 4; (j
= 3 * i
+ 1) < size
; gap
= i
, i
= j
)
278 for ( j
= gap
; j
< size
; ++j
)
279 for ( i
= j
- gap
; i
>= 0; i
-= gap
)
282 right
= array
+ (i
+ gap
);
283 if ( (off_t
) left
->n_value
<=
291 while ( (gap
/= 3) != 0 );
294 PUBLIC
void gnu_symbolic( value
, separator
)
298 register struct newnlist
*sp
;
301 if (value
< st_addr
|| value
> end_addr
) {
308 if ( (sp
= gnu_sval( value
, CSEG
)) != NULL
)
310 gnu_sym( sp
, value
);
312 else if ( (sp
= gnu_sval( value
, DSEG
)) != NULL
)
314 gnu_sym( sp
, value
);
319 off
= value
- st_addr
;
326 outbyte( separator
);
330 PRIVATE
int gnu_symeq( t
, sp
)
334 return strncmp( t
, sp
->n_un
.n_name
, strlen(t
) ) == 0;
337 PRIVATE
int gnu_symprefix( t
, sp
)
344 for ( ; *t
== '_'; ++t
)
346 for ( s
= sp
->n_un
.n_name
, send
= s
+ strlen(s
);
347 s
< send
&& *s
== '_'; ++s
)
349 return strncmp( s
, t
, send
- s
) == 0;
354 /* list all symbols - test for selection criteria */
356 PUBLIC
void gnu_listsym( tchar
)
359 register struct symtab_s
*tp
;
360 register struct newnlist
*sp
;
367 for ( sp
= tp
->start
; sp
< tp
->end
; ++sp
)
369 switch( sp
->n_type
& NN_TYPE
)
371 case NN_ABS
: schar
= 'a'; break;
372 case NN_TEXT
: schar
= 't'; break;
373 case NN_DATA
: schar
= 'd'; break;
374 case NN_BSS
: schar
= 'b'; break;
375 default: schar
= '?'; break;
378 if ( (sp
->n_type
& NN_EXT
) && schar
!= '?' )
381 /* check for selection */
382 if ( tchar
!= '*' && schar
!= tchar
)
385 /* print symbol type and value */
386 outh32( sp
->n_value
);
390 for ( s
= sp
->n_un
.n_name
, send
= s
+ strlen(s
);
391 *s
!= 0 && s
< send
; ++s
) outbyte( *s
);
396 PUBLIC
int gnu_text_symbol(value
)
401 if ((sp
= gnu_sval(value
, CSEG
)) != NULL
&& sp
->n_value
== value
)
410 PUBLIC
int gnu_finds_data(off
,data_seg
)
416 if ((sp
= gnu_sval(off
, data_seg
)) != NULL
)
425 PUBLIC
int gnu_finds_pc(pc
)
430 if ((sp
= gnu_sval(pc
, CSEG
)) != NULL
)
440 #endif /* EXTRA_SYMBOLS */