3 * copied and modified from sym.c
4 * Support GNU Exec symbol tables
16 #include <gnu/a.out.h>
21 _PROTOTYPE( PUBLIC
unsigned int gnu_load
, (char *filename
, struct nlist
**start
) );
31 PRIVATE
struct symtab_s symtab
;
33 FORWARD
_PROTOTYPE( void gnu_sort
, (struct nlist
*array
, struct nlist
*top
));
34 FORWARD
_PROTOTYPE( int gnu_symeq
, (char *t
, struct nlist
*sp
));
35 FORWARD
_PROTOTYPE( int gnu_symprefix
, (char *t
, struct nlist
*sp
));
36 FORWARD
_PROTOTYPE( struct nlist
*gnu_sname
, (char *name
, int is_text
, int allflag
) );
37 FORWARD
_PROTOTYPE( struct nlist
*gnu_sval
, (off_t value
, int where
) );
38 FORWARD
_PROTOTYPE( void gnu_sym
, (struct nlist
*sp
, off_t off
) );
40 PUBLIC
void gnu_init( filename
)
43 register struct symtab_s
*tp
;
47 tp
->nsym
= gnu_load(filename
, &tp
->start
);
48 tp
->end
= tp
->start
+ tp
->nsym
;
50 /* sort on value only, name search not used much and storage a problem */
51 Printf("Sorting %d GNU symbols ....", tp
->nsym
);
52 gnu_sort( tp
->start
, tp
->end
);
58 PUBLIC
long gnu_symbolvalue( name
, is_text
)
62 register struct nlist
*sp
;
63 sp
= gnu_sname(name
,is_text
,0);
71 PRIVATE
struct nlist
*gnu_sname( name
, is_text
, allflag
)
80 register struct nlist
*sp
;
81 register struct symtab_s
*tp
;
87 /* find and print all matching symbols */
88 for ( sp
= tp
->start
; sp
< tp
->end
; ++sp
)
90 if ( gnu_symprefix( name
, sp
) )
93 for ( s
= sp
->n_un
.n_name
, send
= s
+ strlen(s
);
94 *s
!= 0 && s
< send
; ++s
)
96 for ( ; s
<= send
; ++s
)
98 switch( sp
->n_type
& N_TYPE
)
100 case N_ABS
: schar
= 'a'; break;
101 case N_TEXT
: schar
= 't'; break;
102 case N_DATA
: schar
= 'd'; break;
103 case N_BSS
: schar
= 'b'; break;
104 default: schar
= '?'; break;
106 if ( (sp
->n_type
& N_EXT
) && schar
!= '?' )
110 outh32( sp
->n_value
);
117 /* find symbol by dumb linear search */
118 for ( sp
= tp
->start
; sp
< tp
->end
; ++sp
)
120 sclass
= sp
->n_type
& N_TYPE
;
121 if ( (is_text
&& sclass
== N_TEXT
||
122 !is_text
&& (sclass
== N_DATA
|| sclass
== N_BSS
)) &&
123 gnu_symeq( name
, sp
) )
130 PRIVATE
struct nlist
*gnu_sval( value
, where
)
137 unsigned char sclass
;
138 register struct nlist
*sp
;
139 register struct symtab_s
*tp
;
143 /* find last symbol with value <= desired one by binary search */
144 for ( left
= 0, right
= tp
->nsym
- 1; left
<= right
; )
146 middle
= (left
+ right
) / 2;
147 sp
= tp
->start
+ middle
;
148 if ( value
< sp
->n_value
)
154 /* otherwise tp->start + right may wrap around to > tp->start !! */
155 for ( sp
= tp
->start
+ right
; sp
>= tp
->start
; --sp
)
157 if ( !(sp
->n_type
& N_EXT
) ) continue;
158 sclass
= sp
->n_type
& N_TYPE
;
159 if ( (where
== CSEG
&& sclass
== N_TEXT
||
160 where
!= CSEG
&& (sclass
== N_DATA
|| sclass
== N_BSS
)) )
167 PRIVATE
void gnu_sym( sp
, off
)
174 for ( s
= sp
->n_un
.n_name
, send
= s
+ strlen(s
); *s
!= 0 && s
< send
; ++s
)
176 if ( (off
-= sp
->n_value
) != 0 )
183 /* shell sort symbols on value */
185 PRIVATE
void gnu_sort( array
, top
)
192 register struct nlist
*left
;
193 register struct nlist
*right
;
194 struct nlist swaptemp
;
198 /* choose gaps according to Knuth V3 p95 */
199 for ( gap
= 1, i
= 4; (j
= 3 * i
+ 1) < size
; gap
= i
, i
= j
)
203 for ( j
= gap
; j
< size
; ++j
)
204 for ( i
= j
- gap
; i
>= 0; i
-= gap
)
207 right
= array
+ (i
+ gap
);
208 if ( (off_t
) left
->n_value
<=
216 while ( (gap
/= 3) != 0 );
219 PUBLIC
void gnu_symbolic( value
, separator
)
223 register struct nlist
*sp
;
226 if (value
< st_addr
|| value
> end_addr
) {
233 if ( (sp
= gnu_sval( value
, CSEG
)) != NULL
)
235 gnu_sym( sp
, value
);
237 else if ( (sp
= gnu_sval( value
, DSEG
)) != NULL
)
239 gnu_sym( sp
, value
);
244 off
= value
- st_addr
;
251 outbyte( separator
);
255 PRIVATE
int gnu_symeq( t
, sp
)
259 return strncmp( t
, sp
->n_un
.n_name
, strlen(t
) ) == 0;
262 PRIVATE
int gnu_symprefix( t
, sp
)
269 for ( ; *t
== '_'; ++t
)
271 for ( s
= sp
->n_un
.n_name
, send
= s
+ strlen(s
);
272 s
< send
&& *s
== '_'; ++s
)
274 return strncmp( s
, t
, send
- s
) == 0;
279 /* list all symbols - test for selection criteria */
281 PUBLIC
void gnu_listsym( tchar
)
284 register struct symtab_s
*tp
;
285 register struct nlist
*sp
;
292 for ( sp
= tp
->start
; sp
< tp
->end
; ++sp
)
294 switch( sp
->n_type
& N_TYPE
)
296 case N_ABS
: schar
= 'a'; break;
297 case N_TEXT
: schar
= 't'; break;
298 case N_DATA
: schar
= 'd'; break;
299 case N_BSS
: schar
= 'b'; break;
300 default: schar
= '?'; break;
303 if ( (sp
->n_type
& N_EXT
) && schar
!= '?' )
306 /* check for selection */
307 if ( tchar
!= '*' && schar
!= tchar
)
310 /* print symbol type and value */
311 outh32( sp
->n_value
);
315 for ( s
= sp
->n_un
.n_name
, send
= s
+ strlen(s
);
316 *s
!= 0 && s
< send
; ++s
) outbyte( *s
);
321 PUBLIC
int gnu_text_symbol(value
)
326 if ((sp
= gnu_sval(value
, CSEG
)) != NULL
&& sp
->n_value
== value
)
335 PUBLIC
int gnu_finds_data(off
,data_seg
)
341 if ((sp
= gnu_sval(off
, data_seg
)) != NULL
)
350 PUBLIC
int gnu_finds_pc(pc
)
355 if ((sp
= gnu_sval(pc
, CSEG
)) != NULL
)
365 #endif /* EXTRA_SYMBOLS */