pci: don't do sanity check for missing pci bus, the check can misfire.
[minix.git] / commands / mdb / gnu_sym.c
blob2c3a54e75973db9d399438768c30a348a0bc1cb3
1 /*
2 * gnu_sym.c for mdb
3 * copied and modified from sym.c
4 * Support GNU Exec symbol tables
5 */
7 #include "mdb.h"
9 #ifdef EXTRA_SYMBOLS
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <string.h>
15 #include <fcntl.h>
16 #include <minix/a.out.h>
17 #include "proto.h"
19 #define NN_UNDF 0
20 #define NN_ABS 2
21 #define NN_TEXT 4
22 #define NN_DATA 6
23 #define NN_BSS 8
24 #define NN_FN 15
25 #define NN_EXT 1
26 #define NN_TYPE 036
28 struct newnlist {
29 union {
30 char *n_name;
31 struct newnlist *n_next;
32 long n_strx;
33 } n_un;
34 unsigned char n_type;
35 char n_other;
36 short n_desc;
37 unsigned long n_value;
40 struct symtab_s
42 struct newnlist *start;
43 struct newnlist *end;
44 unsigned int nsym;
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,
54 int allflag) );
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 )
60 char *filename;
62 struct exec header;
63 unsigned int string_size;
64 char *names;
65 struct newnlist *p;
66 int fd;
67 register struct symtab_s *tp;
69 tp = &symtab;
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 );
75 return;
78 if ( (string_size = lseek( fd, 0, SEEK_END ) ) == -1 )
80 do_error( "gnu_load - determining file size" );
81 close( fd );
82 return;
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 &&
91 header.a_syms != 0 )
93 do_error( "gnu_load - allocating memory" );
94 close( fd );
95 return;
98 if ( lseek( fd, A_SYMPOS( header ), SEEK_SET ) != A_SYMPOS( header ) )
100 do_error( "gnu_load - reading header" );
101 close( fd );
102 return;
105 if ( read( fd, (char *) tp->start, string_size ) < 0 )
107 do_error( "gnu_load - reading symbols" );
108 close( fd );
109 return;
111 close( fd );
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++)
119 if(p->n_un.n_strx)
120 p->n_un.n_name = names + p->n_un.n_strx;
121 else
122 p->n_un.n_name = "";
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 );
127 Printf("\n");
131 PUBLIC long gnu_symbolvalue( name, is_text )
132 char *name;
133 int is_text;
135 register struct newnlist *sp;
136 sp = gnu_sname(name,is_text,0);
137 if (sp != NULL)
138 return sp->n_value;
139 else
140 return 0L;
144 PRIVATE struct newnlist *gnu_sname( name, is_text, allflag )
145 char *name;
146 int is_text;
147 int allflag;
149 char *s;
150 unsigned char sclass;
151 int schar;
152 char *send;
153 register struct newnlist *sp;
154 register struct symtab_s *tp;
156 tp = &symtab;
158 if ( allflag )
160 /* find and print all matching symbols */
161 for ( sp = tp->start; sp < tp->end; ++sp )
163 if ( gnu_symprefix( name, sp ) )
165 sp = sp;
166 for ( s = sp->n_un.n_name, send = s + strlen(s);
167 *s != 0 && s < send; ++s )
168 outbyte( *s );
169 for ( ; s <= send; ++s )
170 outspace();
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 != '?' )
180 schar += 'A' - 'a';
181 outbyte( schar );
182 outspace();
183 outh32( sp->n_value );
184 outbyte('\n');
188 else
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 ) )
198 return sp;
201 return NULL;
204 PRIVATE struct newnlist *gnu_sval( value, where )
205 off_t value;
206 int where;
208 int left;
209 int middle;
210 int right;
211 unsigned char sclass;
212 register struct newnlist *sp;
213 register struct symtab_s *tp;
215 tp = &symtab;
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 )
223 right = middle - 1;
224 else
225 left = middle + 1;
227 if ( right >= 0 )
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) ||
234 (where != CSEG &&
235 (sclass == NN_DATA || sclass == NN_BSS)) )
236 return sp;
238 return NULL;
242 PRIVATE void gnu_sym( sp, off )
243 struct newnlist *sp;
244 off_t off;
246 register char *s;
247 char *send;
249 for ( s = sp->n_un.n_name, send = s + strlen(s); *s != 0 && s < send; ++s )
250 outbyte( *s );
251 if ( (off -= sp->n_value) != 0 )
253 outbyte( '+' );
254 printhex(off);
258 /* shell sort symbols on value */
260 PRIVATE void gnu_sort( array, top )
261 struct newnlist *array;
262 struct newnlist *top;
264 int gap;
265 int i;
266 int j;
267 register struct newnlist *left;
268 register struct newnlist *right;
269 struct newnlist swaptemp;
270 int size;
272 size = top - array;
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 )
281 left = array + i;
282 right = array + (i + gap);
283 if ( (off_t) left->n_value <=
284 right->n_value )
285 break;
286 swaptemp = *left;
287 *left = *right;
288 *right = swaptemp;
291 while ( (gap /= 3) != 0 );
294 PUBLIC void gnu_symbolic( value, separator )
295 off_t value;
296 int separator;
298 register struct newnlist *sp;
299 long off;
301 if (value < st_addr || value > end_addr) {
302 outstr("0x");
303 printhex(value);
304 outbyte(separator);
305 return;
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 );
316 else
318 outstr("_start");
319 off = value - st_addr;
320 if ( off != 0 )
322 outbyte( '+' );
323 printhex(off);
326 outbyte( separator );
330 PRIVATE int gnu_symeq( t, sp )
331 register char *t;
332 struct newnlist *sp;
334 return strncmp( t, sp->n_un.n_name, strlen(t) ) == 0;
337 PRIVATE int gnu_symprefix( t, sp )
338 register char *t;
339 struct newnlist *sp;
341 register char *s;
342 char *send;
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 )
357 char tchar;
359 register struct symtab_s *tp;
360 register struct newnlist *sp;
361 char *s;
362 char *send;
363 char schar;
365 outbyte('\n');
366 tp = &symtab;
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 != '?' )
379 schar += 'A' - 'a';
381 /* check for selection */
382 if ( tchar != '*' && schar != tchar)
383 continue;
385 /* print symbol type and value */
386 outh32( sp->n_value );
387 outspace();
388 outbyte( schar );
389 outbyte( '\t' );
390 for ( s = sp->n_un.n_name, send = s + strlen(s);
391 *s != 0 && s < send; ++s ) outbyte( *s );
392 outbyte('\n');
396 PUBLIC int gnu_text_symbol(value)
397 off_t value;
399 struct newnlist *sp;
401 if ((sp = gnu_sval(value, CSEG)) != NULL && sp->n_value == value)
403 gnu_sym(sp, value);
404 return TRUE;
406 else
407 return FALSE;
410 PUBLIC int gnu_finds_data(off,data_seg)
411 off_t off;
412 int data_seg;
414 struct newnlist *sp;
416 if ((sp = gnu_sval(off, data_seg)) != NULL)
418 gnu_sym(sp, off);
419 return TRUE;
421 else
422 return FALSE;
425 PUBLIC int gnu_finds_pc(pc)
426 off_t pc;
428 struct newnlist *sp;
430 if ((sp = gnu_sval(pc, CSEG)) != NULL)
432 gnu_sym(sp, pc);
433 return TRUE;
435 else
436 return FALSE;
440 #endif /* EXTRA_SYMBOLS */