3 * copied and modified from sym.c
4 * Support GNU Exec symbol tables
17 #include <compat/a.out.h>
19 #include <minix/a.out.h>
35 struct newnlist
*n_next
;
41 unsigned long n_value
;
46 struct newnlist
*start
;
51 static struct symtab_s symtab
;
53 static void gnu_sort(struct newnlist
*array
, struct newnlist
*top
);
54 static int gnu_symeq(char *t
, struct newnlist
*sp
);
55 static int gnu_symprefix(char *t
, struct newnlist
*sp
);
56 static struct newnlist
*gnu_sname(char *name
, int is_text
, int
58 static struct newnlist
*gnu_sval(off_t value
, int where
);
59 static void gnu_sym(struct newnlist
*sp
, off_t off
);
62 void gnu_init( filename
)
66 unsigned int string_size
;
70 register struct symtab_s
*tp
;
73 if ( (fd
= open( filename
, O_RDONLY
)) < 0 ||
74 read( fd
, (char *) &header
, sizeof header
) != sizeof header
)
76 do_error( "gnu_load - reading header" );
77 if ( fd
>= 0) close( fd
);
81 if ( (string_size
= lseek( fd
, 0, SEEK_END
) ) == -1 )
83 do_error( "gnu_load - determining file size" );
88 string_size
-= A_SYMPOS( header
);
90 if ( (int) header
.a_syms
< 0 ||
91 (unsigned) header
.a_syms
!= header
.a_syms
||
92 (tp
->start
= (struct newnlist
*) malloc( string_size
))
93 == (struct newnlist
*) NULL
&&
96 do_error( "gnu_load - allocating memory" );
101 if ( lseek( fd
, A_SYMPOS( header
), SEEK_SET
) != A_SYMPOS( header
) )
103 do_error( "gnu_load - reading header" );
108 if ( read( fd
, (char *) tp
->start
, string_size
) < 0 )
110 do_error( "gnu_load - reading symbols" );
116 tp
->nsym
= (unsigned int) header
.a_syms
/ sizeof (struct newnlist
);
117 tp
->end
= tp
->start
+ tp
->nsym
;
119 names
= (char *) tp
->start
+ header
.a_syms
;
121 for ( p
= tp
->start
; p
< tp
->end
; p
++)
123 p
->n_un
.n_name
= names
+ p
->n_un
.n_strx
;
127 /* sort on value only, name search not used much and storage a problem */
128 Printf("Sorting %d GNU symbols ....", tp
->nsym
);
129 gnu_sort( tp
->start
, tp
->end
);
134 long gnu_symbolvalue( name
, is_text
)
138 register struct newnlist
*sp
;
139 sp
= gnu_sname(name
,is_text
,0);
147 static struct newnlist
*gnu_sname( name
, is_text
, allflag
)
153 unsigned char sclass
;
156 register struct newnlist
*sp
;
157 register struct symtab_s
*tp
;
163 /* find and print all matching symbols */
164 for ( sp
= tp
->start
; sp
< tp
->end
; ++sp
)
166 if ( gnu_symprefix( name
, sp
) )
169 for ( s
= sp
->n_un
.n_name
, send
= s
+ strlen(s
);
170 *s
!= 0 && s
< send
; ++s
)
172 for ( ; s
<= send
; ++s
)
174 switch( sp
->n_type
& NN_TYPE
)
176 case NN_ABS
: schar
= 'a'; break;
177 case NN_TEXT
: schar
= 't'; break;
178 case NN_DATA
: schar
= 'd'; break;
179 case NN_BSS
: schar
= 'b'; break;
180 default: schar
= '?'; break;
182 if ( (sp
->n_type
& NN_EXT
) && schar
!= '?' )
186 outh32( sp
->n_value
);
193 /* find symbol by dumb linear search */
194 for ( sp
= tp
->start
; sp
< tp
->end
; ++sp
)
196 sclass
= sp
->n_type
& NN_TYPE
;
197 if ( (is_text
&& sclass
== NN_TEXT
||
198 !is_text
&& (sclass
== NN_DATA
||
199 sclass
== NN_BSS
)) &&
200 gnu_symeq( name
, sp
) )
207 static struct newnlist
*gnu_sval( value
, where
)
214 unsigned char sclass
;
215 register struct newnlist
*sp
;
216 register struct symtab_s
*tp
;
220 /* find last symbol with value <= desired one by binary search */
221 for ( left
= 0, right
= tp
->nsym
- 1; left
<= right
; )
223 middle
= (left
+ right
) / 2;
224 sp
= tp
->start
+ middle
;
225 if ( value
< sp
->n_value
)
231 /* otherwise tp->start + right may wrap around to > tp->start !! */
232 for ( sp
= tp
->start
+ right
; sp
>= tp
->start
; --sp
)
234 if ( !(sp
->n_type
& NN_EXT
) ) continue;
235 sclass
= sp
->n_type
& NN_TYPE
;
236 if ( (where
== CSEG
&& sclass
== NN_TEXT
) ||
238 (sclass
== NN_DATA
|| sclass
== NN_BSS
)) )
245 static void gnu_sym( sp
, off
)
252 for ( s
= sp
->n_un
.n_name
, send
= s
+ strlen(s
); *s
!= 0 && s
< send
; ++s
)
254 if ( (off
-= sp
->n_value
) != 0 )
261 /* shell sort symbols on value */
263 static void gnu_sort( array
, top
)
264 struct newnlist
*array
;
265 struct newnlist
*top
;
270 register struct newnlist
*left
;
271 register struct newnlist
*right
;
272 struct newnlist swaptemp
;
276 /* choose gaps according to Knuth V3 p95 */
277 for ( gap
= 1, i
= 4; (j
= 3 * i
+ 1) < size
; gap
= i
, i
= j
)
281 for ( j
= gap
; j
< size
; ++j
)
282 for ( i
= j
- gap
; i
>= 0; i
-= gap
)
285 right
= array
+ (i
+ gap
);
286 if ( (off_t
) left
->n_value
<=
294 while ( (gap
/= 3) != 0 );
297 void gnu_symbolic( value
, separator
)
301 register struct newnlist
*sp
;
304 if (value
< st_addr
|| value
> end_addr
) {
311 if ( (sp
= gnu_sval( value
, CSEG
)) != NULL
)
313 gnu_sym( sp
, value
);
315 else if ( (sp
= gnu_sval( value
, DSEG
)) != NULL
)
317 gnu_sym( sp
, value
);
322 off
= value
- st_addr
;
329 outbyte( separator
);
333 static int gnu_symeq( t
, sp
)
337 return strncmp( t
, sp
->n_un
.n_name
, strlen(t
) ) == 0;
340 static int gnu_symprefix( t
, sp
)
347 for ( ; *t
== '_'; ++t
)
349 for ( s
= sp
->n_un
.n_name
, send
= s
+ strlen(s
);
350 s
< send
&& *s
== '_'; ++s
)
352 return strncmp( s
, t
, send
- s
) == 0;
357 /* list all symbols - test for selection criteria */
359 void gnu_listsym( tchar
)
362 register struct symtab_s
*tp
;
363 register struct newnlist
*sp
;
370 for ( sp
= tp
->start
; sp
< tp
->end
; ++sp
)
372 switch( sp
->n_type
& NN_TYPE
)
374 case NN_ABS
: schar
= 'a'; break;
375 case NN_TEXT
: schar
= 't'; break;
376 case NN_DATA
: schar
= 'd'; break;
377 case NN_BSS
: schar
= 'b'; break;
378 default: schar
= '?'; break;
381 if ( (sp
->n_type
& NN_EXT
) && schar
!= '?' )
384 /* check for selection */
385 if ( tchar
!= '*' && schar
!= tchar
)
388 /* print symbol type and value */
389 outh32( sp
->n_value
);
393 for ( s
= sp
->n_un
.n_name
, send
= s
+ strlen(s
);
394 *s
!= 0 && s
< send
; ++s
) outbyte( *s
);
399 int gnu_text_symbol(value
)
404 if ((sp
= gnu_sval(value
, CSEG
)) != NULL
&& sp
->n_value
== value
)
413 int gnu_finds_data(off
,data_seg
)
419 if ((sp
= gnu_sval(off
, data_seg
)) != NULL
)
433 if ((sp
= gnu_sval(pc
, CSEG
)) != NULL
)
443 #endif /* EXTRA_SYMBOLS */